summaryrefslogtreecommitdiff
path: root/src/chomp/typed.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/chomp/typed.rs')
-rw-r--r--src/chomp/typed.rs321
1 files changed, 321 insertions, 0 deletions
diff --git a/src/chomp/typed.rs b/src/chomp/typed.rs
new file mode 100644
index 0000000..69108ae
--- /dev/null
+++ b/src/chomp/typed.rs
@@ -0,0 +1,321 @@
+use std::hash::{Hash, Hasher};
+
+use proc_macro2::Span;
+use syn::{Ident, LitStr, Token};
+
+use super::{
+ ast,
+ set::{FirstSet, FlastSet},
+};
+
+#[derive(Debug, Default, Clone, Eq, Hash, PartialEq)]
+pub struct Type {
+ nullable: bool,
+ first_set: FirstSet,
+ flast_set: FlastSet,
+}
+
+impl Type {
+ pub const fn new(nullable: bool, first_set: FirstSet, flast_set: FlastSet) -> Self {
+ Self {
+ nullable,
+ first_set,
+ flast_set,
+ }
+ }
+
+ pub fn of_str(s: &str) -> Self {
+ Self {
+ nullable: s.is_empty(),
+ first_set: FirstSet::of_str(s),
+ flast_set: FlastSet::default(),
+ }
+ }
+
+ pub fn nullable(&self) -> bool {
+ self.nullable
+ }
+
+ pub fn first_set(&self) -> &FirstSet {
+ &self.first_set
+ }
+
+ pub fn flast_set(&self) -> &FlastSet {
+ &self.flast_set
+ }
+
+ pub fn cat(self, other: Self) -> Self {
+ Self {
+ nullable: self.nullable && other.nullable,
+ first_set: self.first_set.union(if self.nullable {
+ other.first_set.clone()
+ } else {
+ FirstSet::default()
+ }),
+ flast_set: other.flast_set.union(if other.nullable {
+ self.flast_set.union_first(other.first_set)
+ } else {
+ FlastSet::default()
+ }),
+ }
+ }
+
+ pub fn alt(self, other: Self) -> Self {
+ Self {
+ nullable: self.nullable || other.nullable,
+ first_set: self.first_set.union(other.first_set),
+ flast_set: self.flast_set.union(other.flast_set),
+ }
+ }
+}
+
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub struct Epsilon {
+ inner: Token![_],
+ ty: Type,
+}
+
+impl From<ast::Epsilon> for Epsilon {
+ fn from(inner: ast::Epsilon) -> Self {
+ Self {
+ inner,
+ ty: Type::new(true, FirstSet::default(), FlastSet::default()),
+ }
+ }
+}
+
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub struct Literal {
+ inner: LitStr,
+ ty: Type,
+}
+
+impl Literal {
+ pub fn inner(&self) -> &LitStr {
+ &self.inner
+ }
+
+ pub fn span(&self) -> Span {
+ self.inner.span()
+ }
+}
+
+impl From<ast::Literal> for Literal {
+ fn from(inner: ast::Literal) -> Self {
+ let ty = Type::of_str(&inner.value());
+ Self { inner, ty }
+ }
+}
+
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub struct Cat {
+ fst: Box<TypedExpression>,
+ punct: Option<Token![.]>,
+ snd: Box<TypedExpression>,
+ ty: Type,
+}
+
+impl Cat {
+ pub(crate) fn new(
+ fst: TypedExpression,
+ punct: Option<Token![.]>,
+ snd: TypedExpression,
+ ty: Type,
+ ) -> Self {
+ Self {
+ fst: Box::new(fst),
+ punct,
+ snd: Box::new(snd),
+ ty,
+ }
+ }
+
+ pub fn unwrap(self) -> (TypedExpression, Option<Token![.]>, TypedExpression) {
+ (*self.fst, self.punct, *self.snd)
+ }
+}
+
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub struct Alt {
+ left: Box<TypedExpression>,
+ punct: Option<Token![|]>,
+ right: Box<TypedExpression>,
+ ty: Type,
+}
+
+impl Alt {
+ pub(crate) fn new(
+ left: TypedExpression,
+ punct: Option<Token![|]>,
+ right: TypedExpression,
+ ty: Type,
+ ) -> Self {
+ Self {
+ left: Box::new(left),
+ punct,
+ right: Box::new(right),
+ ty,
+ }
+ }
+
+ pub fn unwrap(self) -> (TypedExpression, Option<Token![|]>, TypedExpression) {
+ (*self.left, self.punct, *self.right)
+ }
+}
+
+#[derive(Debug)]
+pub struct Fix {
+ arg: Ident,
+ inner: Box<TypedExpression>,
+ span: Option<Span>,
+ ty: Type,
+}
+
+impl Fix {
+ pub(crate) fn new(arg: Ident, inner: TypedExpression, span: Option<Span>, ty: Type) -> Self {
+ Self {
+ arg,
+ inner: Box::new(inner),
+ span,
+ ty,
+ }
+ }
+
+ pub fn unwrap(self) -> (Ident, TypedExpression, Option<Span>) {
+ (self.arg, *self.inner, self.span)
+ }
+}
+
+impl PartialEq for Fix {
+ fn eq(&self, other: &Self) -> bool {
+ self.arg == other.arg && self.inner == other.inner && self.ty == other.ty
+ }
+}
+
+impl Eq for Fix {}
+
+impl Hash for Fix {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.arg.hash(state);
+ self.inner.hash(state);
+ self.ty.hash(state);
+ }
+}
+
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub struct Variable {
+ ident: Ident,
+ index: usize,
+ ty: Type,
+}
+
+impl Variable {
+ pub(crate) fn new(var: ast::Variable, ty: Type) -> Self {
+ Self {
+ ident: var.name,
+ index: var.index,
+ ty,
+ }
+ }
+
+ pub fn index(&self) -> usize {
+ self.index
+ }
+}
+
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub(crate) enum RawTypedExpression {
+ Epsilon(Epsilon),
+ Literal(Literal),
+ Cat(Cat),
+ Alt(Alt),
+ Fix(Fix),
+ Variable(Variable),
+}
+
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub struct TypedExpression {
+ pub(crate) inner: RawTypedExpression,
+}
+
+impl From<Epsilon> for TypedExpression {
+ fn from(eps: Epsilon) -> Self {
+ Self {
+ inner: RawTypedExpression::Epsilon(eps),
+ }
+ }
+}
+
+impl From<Literal> for TypedExpression {
+ fn from(lit: Literal) -> Self {
+ Self {
+ inner: RawTypedExpression::Literal(lit),
+ }
+ }
+}
+
+impl From<Cat> for TypedExpression {
+ fn from(cat: Cat) -> Self {
+ Self {
+ inner: RawTypedExpression::Cat(cat),
+ }
+ }
+}
+
+impl From<Alt> for TypedExpression {
+ fn from(alt: Alt) -> Self {
+ Self {
+ inner: RawTypedExpression::Alt(alt),
+ }
+ }
+}
+
+impl From<Fix> for TypedExpression {
+ fn from(fix: Fix) -> Self {
+ Self {
+ inner: RawTypedExpression::Fix(fix),
+ }
+ }
+}
+
+impl From<Variable> for TypedExpression {
+ fn from(var: Variable) -> Self {
+ Self {
+ inner: RawTypedExpression::Variable(var),
+ }
+ }
+}
+
+pub trait Typed {
+ fn get_type(&self) -> &Type;
+}
+
+macro_rules! leaf_typed {
+ ($ty:ty, $field:ident) => {
+ impl Typed for $ty {
+ fn get_type(&self) -> &Type {
+ &self.$field
+ }
+ }
+ };
+}
+
+leaf_typed!(Epsilon, ty);
+leaf_typed!(Literal, ty);
+leaf_typed!(Cat, ty);
+leaf_typed!(Alt, ty);
+leaf_typed!(Fix, ty);
+leaf_typed!(Variable, ty);
+
+impl Typed for TypedExpression {
+ fn get_type(&self) -> &Type {
+ match &self.inner {
+ RawTypedExpression::Epsilon(e) => e.get_type(),
+ RawTypedExpression::Literal(l) => l.get_type(),
+ RawTypedExpression::Cat(c) => c.get_type(),
+ RawTypedExpression::Alt(a) => a.get_type(),
+ RawTypedExpression::Fix(f) => f.get_type(),
+ RawTypedExpression::Variable(v) => v.get_type(),
+ }
+ }
+}