diff options
author | Greg Brown <gmb60@cam.ac.uk> | 2020-11-23 14:34:36 +0000 |
---|---|---|
committer | Greg Brown <gmb60@cam.ac.uk> | 2020-11-23 14:34:36 +0000 |
commit | fce22234591b4e3bdd2cd4227459d7779e4859c9 (patch) | |
tree | f0ed7e087c939cc3eaa1377da31a2bec538e5af4 /src/ast/typed.rs | |
parent | 1183a0996d560fda9d992a9bb8ca1328465a2b33 (diff) |
Introduce guarded variables
Diffstat (limited to 'src/ast/typed.rs')
-rw-r--r-- | src/ast/typed.rs | 224 |
1 files changed, 126 insertions, 98 deletions
diff --git a/src/ast/typed.rs b/src/ast/typed.rs index a0b8d1b..6ccd0ac 100644 --- a/src/ast/typed.rs +++ b/src/ast/typed.rs @@ -1,3 +1,5 @@ +use proc_macro2::Span; + use super::Typed; use super::VariableError; use std::collections::BTreeSet; @@ -36,8 +38,14 @@ impl FirstSet { inner: self.inner.intersection(&other.inner).copied().collect(), } } +} + +impl IntoIterator for FirstSet { + type Item = char; - pub fn into_iter(self) -> impl Iterator<Item = char> { + type IntoIter = <BTreeSet<char> as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { self.inner.into_iter() } } @@ -81,163 +89,183 @@ impl FlastSet { } } -pub trait NullContext { - type PushNull: NullContext; - - fn get_depth(&self) -> usize; - - fn get_nullable(&self, index: usize) -> Option<bool>; - - fn push_nullable<F: FnOnce(&mut Self::PushNull) -> R, R>(&mut self, nullable: bool, f: F) -> R; +#[derive(Debug)] +pub struct NullContext<'a> { + inner: &'a mut FlastContext } -impl NullContext for Vec<bool> { - type PushNull = Self; - - fn get_depth(&self) -> usize { - self.len() +impl NullContext<'_> { + pub fn depth(&self) -> usize { + self.inner.depth() } - fn get_nullable(&self, index: usize) -> Option<bool> { - self.get(self.len() - index - 1).copied() + pub fn is_guarded(&self, index: usize) -> Option<bool> { + self.inner.is_guarded(index) } - fn push_nullable<F: FnOnce(&mut Self::PushNull) -> R, R>(&mut self, nullable: bool, f: F) -> R { - self.push(nullable); - let res = f(self); - self.pop(); - res - } -} - -impl NullContext for Vec<(bool, FirstSet)> { - type PushNull = Self; - - fn get_depth(&self) -> usize { - self.len() + pub fn unguard<F: FnOnce(&mut NullContext<'_>) -> R, R>(&mut self, f: F) -> R { + self.inner.unguard(|ctx| f(&mut NullContext {inner: ctx})) } - fn get_nullable(&self, index: usize) -> Option<bool> { - self.get(self.len() - index - 1).map(|(null, _)| null).copied() + pub fn is_nullable(&self, index: usize) -> Option<bool> { + self.inner.is_nullable(index) } - fn push_nullable<F: FnOnce(&mut Self::PushNull) -> R, R>(&mut self, nullable: bool, f: F) -> R { - self.push((nullable, FirstSet::new())); - let res = f(self); - self.pop(); - res + pub fn push_nullable<F: FnOnce(&mut NullContext<'_>) -> R, R>( + &mut self, + nullable: bool, + f: F, + ) -> R { + self.inner.push_nullable(nullable, f) } } -impl NullContext for Vec<(bool, FirstSet, FlastSet)> { - type PushNull = Self; +#[derive(Debug)] +pub struct FirstContext<'a> { + inner: &'a mut FlastContext, +} - fn get_depth(&self) -> usize { - self.len() +impl FirstContext<'_> { + pub fn depth(&self) -> usize { + self.inner.depth() } - fn get_nullable(&self, index: usize) -> Option<bool> { - self.get(self.len() - index - 1).map(|(null, _, _)| null).copied() + pub fn is_guarded(&self, index: usize) -> Option<bool> { + self.inner.is_guarded(index) } - fn push_nullable<F: FnOnce(&mut Self::PushNull) -> R, R>(&mut self, nullable: bool, f: F) -> R { - self.push((nullable, FirstSet::new(), FlastSet::new())); - let res = f(self); - self.pop(); - res + pub fn unguard<F: FnOnce(&mut FirstContext<'_>) -> R, R>(&mut self, f: F) -> R { + self.inner.unguard(|ctx| { + f(&mut FirstContext{inner: ctx}) + }) } -} -pub trait FirstSetContext: NullContext { - type PushFirstSet: FirstSetContext; - - fn get_first_set(&self, index: usize) -> Option<&FirstSet>; + pub fn is_nullable(&self, index: usize) -> Option<bool> { + self.inner.is_nullable(index) + } - fn push_first_set<F: FnOnce(&mut Self::PushFirstSet) -> R, R>( + pub fn push_nullable<F: FnOnce(&mut NullContext<'_>) -> R, R>( &mut self, nullable: bool, - first_set: FirstSet, f: F, - ) -> R; -} - -impl FirstSetContext for Vec<(bool, FirstSet)> { - type PushFirstSet = Self; + ) -> R { + self.inner.push_nullable(nullable, f) + } - fn get_first_set(&self, index: usize) -> Option<&FirstSet> { - self.get(self.len() - index - 1).map(|(_, first_set)| first_set) + pub fn first_set(&self, index: usize) -> Option<&FirstSet> { + self.inner.first_set(index) } - fn push_first_set<F: FnOnce(&mut Self::PushFirstSet) -> R, R>( + pub fn push_first_set<F: FnOnce(&mut FirstContext<'_>) -> R, R>( &mut self, nullable: bool, first_set: FirstSet, f: F, ) -> R { - self.push((nullable, first_set)); - let res = f(self); - self.pop(); - res + self.inner.push_first_set(nullable, first_set, f) + } + + pub fn as_null(&mut self) -> NullContext<'_> { + NullContext { + inner: self.inner + } } } -impl FirstSetContext for Vec<(bool, FirstSet, FlastSet)> { - type PushFirstSet = Self; +#[derive(Debug)] +pub struct FlastContext { + data: Vec<(bool, FirstSet, FlastSet)>, + guard: Vec<usize>, +} + +impl FlastContext { + pub fn new() -> Self { + Self { + data: Vec::new(), + guard: Vec::new(), + } + } + + pub fn depth(&self) -> usize { + self.data.len() + } + + pub fn is_guarded(&self, index: usize) -> Option<bool> { + if self.data.len() <= index { + None + } else if self.guard.is_empty() { + Some(false) + } else { + Some(self.guard[self.guard.len() - 1] + index >= self.data.len()) + } + } + + pub fn unguard<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R { + self.guard.push(self.data.len()); + let res = f(self); + self.guard.pop(); + res + } - fn get_first_set(&self, index: usize) -> Option<&FirstSet> { - self.get(self.len() - index - 1).map(|(_, first_set, _)| first_set) + pub fn is_nullable(&self, index: usize) -> Option<bool> { + self.data.get(index).map(|(null, _, _)| *null) } - fn push_first_set<F: FnOnce(&mut Self::PushFirstSet) -> R, R>( + pub fn push_nullable<F: FnOnce(&mut NullContext<'_>) -> R, R>( &mut self, nullable: bool, - first_set: FirstSet, f: F, ) -> R { - self.push((nullable, first_set, FlastSet::new())); - let res = f(self); - self.pop(); - res + self.push_first_set(nullable, FirstSet::new(), |ctx| { + f(&mut ctx.as_null()) + }) } -} - -pub trait FlastSetContext: FirstSetContext { - type PushFlastSet: FlastSetContext; - fn get_flast_set(&self, index: usize) -> Option<&FlastSet>; + pub fn first_set(&self, index: usize) -> Option<&FirstSet> { + self.data.get(index).map(|(_, first, _)| first) + } - fn push_flast_set<F: FnOnce(&mut Self::PushFlastSet) -> R, R>( + pub fn push_first_set<F: FnOnce(&mut FirstContext<'_>) -> R, R>( &mut self, nullable: bool, first_set: FirstSet, - flast_set: FlastSet, f: F, - ) -> R; -} - -impl FlastSetContext for Vec<(bool, FirstSet, FlastSet)> { - type PushFlastSet = Self; + ) -> R { + self.push_flast_set(nullable, first_set, FlastSet::new(), |ctx| f(&mut ctx.as_first())) + } - fn get_flast_set(&self, index: usize) -> Option<&FlastSet> { - self.get(self.len() - index - 1).map(|(_, _, flast_set)| flast_set) + pub fn flast_set(&self, index: usize) -> Option<&FlastSet> { + self.data.get(index).map(|(_, _, flast)| flast) } - fn push_flast_set<F: FnOnce(&mut Self::PushFlastSet) -> R, R>( + pub fn push_flast_set<F: FnOnce(&mut Self) -> R, R>( &mut self, nullable: bool, first_set: FirstSet, flast_set: FlastSet, f: F, ) -> R { - self.push((nullable, first_set, flast_set)); + self.data.push((nullable, first_set, flast_set)); let res = f(self); - self.pop(); + self.data.pop(); res } + + pub fn as_first(&mut self) -> FirstContext<'_> { + FirstContext { + inner: self + } + } + + pub fn as_null(&mut self) -> NullContext<'_> { + NullContext{ + inner: self + } + } } pub trait Type { - type Err: Display; + type Err: Into<syn::Error>; /// # Errors /// Returns [`Err`] if there is a variable with an index greater than or equal @@ -247,19 +275,19 @@ pub trait Type { /// # Errors /// Returns [`None`] only if `self.closed(context.get_depth())` returns an /// [`Err`]. - fn is_nullable<C: NullContext>(&self, context: &mut C) -> Option<bool>; + fn is_nullable(&self, context: &mut NullContext<'_>) -> Option<bool>; /// # Errors /// Returns [`None`] only if `self.closed(context.get_depth())` returns an /// [`Err`]. - fn first_set<C: FirstSetContext>(&self, context: &mut C) -> Option<FirstSet>; + fn first_set(&self, context: &mut FirstContext<'_>) -> Option<FirstSet>; /// # Errors /// Returns [`None`] only if `self.closed(context.get_depth())` returns an /// [`Err`]. - fn flast_set<C: FlastSetContext>(&self, context: &mut C) -> Option<FlastSet>; + fn flast_set(&self, context: &mut FlastContext) -> Option<FlastSet>; /// # Errors /// Returns an [`Err`] if this term is not well typed. - fn well_typed<C: FlastSetContext>(self, context: &mut C) -> Result<Typed, Self::Err>; + fn well_typed(self, context: &mut FlastContext) -> Result<(Typed, Span), Self::Err>; } |