diff options
author | Greg Brown <gmb60@cam.ac.uk> | 2020-11-19 17:11:09 +0000 |
---|---|---|
committer | Greg Brown <gmb60@cam.ac.uk> | 2020-11-19 17:11:09 +0000 |
commit | 8939af712e6c3ae5d23019ec5dd941f1dae6c7fb (patch) | |
tree | a2d811bec55374124fda9f4c9dc0dfd1092d69ba /src/ast/typed.rs | |
parent | e362e83b996f9ba914c88630bec28b703c535dcc (diff) |
Switch typing to use traits
Diffstat (limited to 'src/ast/typed.rs')
-rw-r--r-- | src/ast/typed.rs | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/ast/typed.rs b/src/ast/typed.rs new file mode 100644 index 0000000..48ca740 --- /dev/null +++ b/src/ast/typed.rs @@ -0,0 +1,132 @@ +use super::Typed; +use std::collections::BTreeSet; +use std::fmt::Display; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct FirstSet { + inner: BTreeSet<char>, +} + +impl FirstSet { + pub fn new() -> Self { + Self { + inner: BTreeSet::new(), + } + } + + pub fn of_str(s: &str) -> Self { + let mut inner = BTreeSet::new(); + s.chars().next().map(|c| inner.insert(c)); + + Self { inner } + } + + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + pub fn union(mut self, mut other: Self) -> Self { + self.inner.append(&mut other.inner); + self + } + + pub fn intersect(&self, other: &Self) -> Self { + Self { + inner: self.inner.intersection(&other.inner).copied().collect(), + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct FlastSet { + inner: BTreeSet<char>, +} + +impl FlastSet { + pub fn new() -> Self { + Self { + inner: BTreeSet::new(), + } + } + + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + pub fn union_first(mut self, mut other: FirstSet) -> Self { + self.inner.append(&mut other.inner); + self + } + + pub fn union(mut self, mut other: Self) -> Self { + self.inner.append(&mut other.inner); + self + } + + pub fn intersect_first(&self, other: &FirstSet) -> Self { + Self { + inner: self.inner.intersection(&other.inner).copied().collect(), + } + } + + pub fn intersect(&self, other: &Self) -> Self { + Self { + inner: self.inner.intersection(&other.inner).copied().collect(), + } + } +} + +pub trait NullContext { + type PushNull: NullContext; + + 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; +} + +pub trait FirstSetContext: NullContext { + type PushFirstSet: FirstSetContext; + + fn get_first_set(&self, index: usize) -> Option<FirstSet>; + + fn push_first_set<F: FnOnce(&mut Self::PushFirstSet) -> R, R>( + &mut self, + nullable: bool, + first_set: FirstSet, + f: F, + ) -> R; +} + +pub trait FlastSetContext: FirstSetContext { + type PushFlastSet: FlastSetContext; + + fn get_flast_set(&self, index: usize) -> Option<FlastSet>; + + fn push_flast_set<F: FnOnce(&mut Self::PushFlastSet) -> R, R>( + &mut self, + nullable: bool, + first_set: FirstSet, + flast_set: FlastSet, + f: F, + ) -> R; +} + +pub trait Type { + type Err: Display; + + /// # Errors + /// Returns [`None`] if the nullity cannot be determined. + fn is_nullable<C: NullContext>(&self, context: &mut C) -> Option<bool>; + + /// # Errors + /// Returns [`None`] if the first set cannot be determined. + fn first_set<C: FirstSetContext>(&self, context: &mut C) -> Option<FirstSet>; + + /// # Errors + /// Returns [`None`] if the flast set cannot be determined. + fn flast_set<C: FlastSetContext>(&self, context: &mut C) -> 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>; +} |