summaryrefslogtreecommitdiff
path: root/src/ast/typed.rs
diff options
context:
space:
mode:
authorGreg Brown <gmb60@cam.ac.uk>2020-11-19 17:11:09 +0000
committerGreg Brown <gmb60@cam.ac.uk>2020-11-19 17:11:09 +0000
commit8939af712e6c3ae5d23019ec5dd941f1dae6c7fb (patch)
treea2d811bec55374124fda9f4c9dc0dfd1092d69ba /src/ast/typed.rs
parente362e83b996f9ba914c88630bec28b703c535dcc (diff)
Switch typing to use traits
Diffstat (limited to 'src/ast/typed.rs')
-rw-r--r--src/ast/typed.rs132
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>;
+}