Skip to content

Commit

Permalink
Rewrite RuleState
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanBrouwer committed Aug 5, 2024
1 parent 141a83f commit dc72553
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 161 deletions.
108 changes: 59 additions & 49 deletions prism-parser/src/core/adaptive.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::core::cache::Allocs;
use crate::core::pos::Pos;
use crate::core::toposet::TopoSet;
use crate::grammar::{AnnotatedRuleExpr, Block, GrammarFile, Rule};
use crate::parser::var_map::{VarMap, VarMapValue};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
use std::sync::Arc;
use std::{iter, mem};
use std::alloc::alloc;

pub struct GrammarState<'arn, 'grm> {
rules: Vec<Arc<RuleState<'arn, 'grm>>>,
Expand Down Expand Up @@ -92,10 +92,8 @@ impl<'arn, 'grm: 'arn> GrammarState<'arn, 'grm> {

// Update each rule that is to be adopted, stored in `result`
for (&(_, id), rule) in result.iter().zip(grammar.rules.iter()) {
let mut r = (*s.rules[id.0]).clone();
r.update(rule, new_ctx)
.map_err(|_| AdaptError::InvalidRuleMutation(rule.name))?;
s.rules[id.0] = Arc::new(r);
s.rules[id.0] = Arc::new(s.rules[id.0].update(rule, new_ctx, alloc)
.map_err(|_| AdaptError::InvalidRuleMutation(rule.name))?);
}

Ok((s, new_ctx))
Expand Down Expand Up @@ -124,87 +122,99 @@ impl<'arn, 'grm: 'arn> GrammarState<'arn, 'grm> {
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
pub struct GrammarStateId(usize);

#[derive(Clone)]
#[derive(Copy, Clone)]
pub struct RuleState<'arn, 'grm> {
pub name: &'grm str,
pub blocks: Vec<BlockState<'arn, 'grm>>,
order: TopoSet<'grm>,
pub arg_names: &'arn [&'grm str],
pub args: &'arn [&'grm str],
pub blocks: &'arn [BlockState<'arn, 'grm>],
}

pub enum UpdateError {
ToposortCycle,
}

impl<'arn, 'grm> RuleState<'arn, 'grm> {
pub fn new_empty(name: &'grm str, arg_names: &'arn [&'grm str]) -> Self {
pub fn new_empty(name: &'grm str, args: &'arn [&'grm str]) -> Self {
Self {
name,
blocks: Vec::new(),
order: TopoSet::new(),
arg_names,
blocks: &[],
args,
}
}

pub fn update(
&mut self,
&self,
r: &'arn Rule<'arn, 'grm>,
ctx: VarMap<'arn, 'grm>,
) -> Result<(), UpdateError> {
self.order.update(r);

let order: HashMap<&'grm str, usize> = self
.order
.toposort()?
.into_iter()
.enumerate()
.map(|(k, v)| (v, k))
.collect();

let mut res = vec![None; order.len()];
let old_blocks = mem::take(&mut self.blocks);

for block in old_blocks {
let i = order[block.name];
res[i] = Some(block);
}
allocs: Allocs<'arn>
) -> Result<Self, UpdateError> {
assert_eq!(self.name, r.name);
assert_eq!(self.args, r.args);

//TODO remove this allocation?
let new_nodes: HashSet<&'grm str> = r.blocks.iter().map(|n| n.0).collect();
let mut result = Vec::with_capacity(self.blocks.len() + r.blocks.len());
let mut new_iter = r.blocks.iter();

for old_block in self.blocks {
// If this block is only present in the old rule, take it first
if !new_nodes.contains(old_block.name) {
result.push(*old_block);
continue
}

for block in r.blocks {
let i = order[block.0];
match &mut res[i] {
None => {
res[i] = Some(BlockState::new(block, ctx));
}
Some(bs) => {
bs.update(block, ctx);
// Take all rules from the new rule until we found the matching block
loop {
// Add all blocks that don't match
let Some(new_block) = new_iter.next() else {
return Err(UpdateError::ToposortCycle)
};
if new_block.0 != old_block.name {
result.push(BlockState::new(new_block, ctx, allocs));
continue;
}

// Merge blocks
result.push(old_block.update(new_block, ctx, allocs));
break
}
}

self.blocks = res.into_iter().map(|m| m.unwrap()).collect();
// Add remaining blocks from new iter
for new_block in new_iter {
result.push(BlockState::new(new_block, ctx, allocs));
}

Ok(())
Ok(Self {
name: self.name,
args: self.args,
blocks: allocs.alloc_extend(result),
})
}
}

#[derive(Clone)]
#[derive(Copy, Clone)]
pub struct BlockState<'arn, 'grm> {
pub name: &'grm str,
pub constructors: Vec<Constructor<'arn, 'grm>>,
pub constructors: &'arn [Constructor<'arn, 'grm>],
}

pub type Constructor<'arn, 'grm> = (&'arn AnnotatedRuleExpr<'arn, 'grm>, VarMap<'arn, 'grm>);

impl<'arn, 'grm> BlockState<'arn, 'grm> {
pub fn new(block: &'arn Block<'arn, 'grm>, ctx: VarMap<'arn, 'grm>) -> Self {
pub fn new(block: &'arn Block<'arn, 'grm>, ctx: VarMap<'arn, 'grm>, allocs: Allocs<'arn>) -> Self {
Self {
name: block.0,
constructors: block.1.iter().map(|r| (r, ctx)).collect(),
constructors: allocs.alloc_extend(block.1.iter().map(|r| (r, ctx))),
}
}

pub fn update(&mut self, b: &'arn Block<'arn, 'grm>, ctx: VarMap<'arn, 'grm>) {
#[must_use]
pub fn update(&self, b: &'arn Block<'arn, 'grm>, ctx: VarMap<'arn, 'grm>, allocs: Allocs<'arn>) -> Self {
assert_eq!(self.name, b.0);
self.constructors.extend(b.1.iter().map(|r| (r, ctx)));
Self {
name: self.name,
constructors: allocs.alloc_extend_len(self.constructors.len() + b.1.len(), self.constructors.iter().cloned().chain(b.1.iter().map(|r| (r, ctx)))),
}
}
}
36 changes: 12 additions & 24 deletions prism-parser/src/core/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,36 +58,20 @@ impl<'arn> Allocs<'arn> {
self.bump.alloc_slice_fill_iter(iter)
}

pub fn try_alloc_extend<T: Copy, I: IntoIterator<Item = Option<T>, IntoIter: ExactSizeIterator>>(
pub fn alloc_extend_len<T: Copy, I: IntoIterator<Item = T>>(
&self,
len: usize,
iter: I,
) -> Option<&'arn [T]> {
) -> &'arn [T] {
let mut iter = iter.into_iter();
let mut all_ok = true;
let slice = self.bump.alloc_slice_fill_with(iter.len(), |_| {
let v = iter.next().expect("Exact size iter has enough elements");
if let Some(v) = v {
v
} else {
all_ok = false;
todo!()
}
let slice = self.bump.alloc_slice_fill_with(len, |_| {
iter.next().expect("Iterator supplied too few elements")
});
all_ok.then_some(slice)
}

pub fn alloc_leak<T>(&self, t: T) -> &'arn T {
self.bump.alloc(t)
assert!(iter.next().is_none());
slice
}

pub fn alloc_extend_leak<T, I: IntoIterator<Item = T, IntoIter: ExactSizeIterator>>(
&self,
iter: I,
) -> &'arn [T] {
self.bump.alloc_slice_fill_iter(iter)
}

pub fn try_alloc_extend_leak<T, I: IntoIterator<Item = Option<T>, IntoIter: ExactSizeIterator>>(
pub fn try_alloc_extend<T: Copy, I: IntoIterator<Item = Option<T>, IntoIter: ExactSizeIterator>>(
&self,
iter: I,
) -> Option<&'arn [T]> {
Expand All @@ -104,6 +88,10 @@ impl<'arn> Allocs<'arn> {
});
all_ok.then_some(slice)
}

pub fn alloc_leak<T>(&self, t: T) -> &'arn T {
self.bump.alloc(t)
}
}

pub struct ParserCacheEntry<PR> {
Expand Down
1 change: 0 additions & 1 deletion prism-parser/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@ pub mod primitives;
pub mod recovery;
pub mod span;
pub mod state;
pub mod toposet;
86 changes: 0 additions & 86 deletions prism-parser/src/core/toposet.rs

This file was deleted.

2 changes: 1 addition & 1 deletion prism-parser/src/parser/parser_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn parser_rule<'a, 'arn: 'a, 'grm: 'arn, E: ParseError<L = ErrorLabel<'grm>>

let rule_args = VarMap::from_iter(
rule_state
.arg_names
.args
.iter()
.cloned()
.zip_eq(args.iter().cloned()),
Expand Down

0 comments on commit dc72553

Please sign in to comment.