diff options
author | Griffin Smith <root@gws.fyi> | 2021-03-07T20·29-0500 |
---|---|---|
committer | Griffin Smith <root@gws.fyi> | 2021-03-07T20·29-0500 |
commit | 80f8ede0bbc9799d5199707e1e1ad8e80e4ca7ac (patch) | |
tree | cbb418b042583714fe09f946f1b9a03d1d98857f /src/ast/mod.rs |
Initial commit
Diffstat (limited to 'src/ast/mod.rs')
-rw-r--r-- | src/ast/mod.rs | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/ast/mod.rs b/src/ast/mod.rs new file mode 100644 index 000000000000..2dcf955fe67c --- /dev/null +++ b/src/ast/mod.rs @@ -0,0 +1,166 @@ +use std::borrow::Cow; +use std::convert::TryFrom; +use std::fmt::{self, Display, Formatter}; + +#[derive(Debug, PartialEq, Eq)] +pub struct InvalidIdentifier<'a>(Cow<'a, str>); + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct Ident<'a>(pub Cow<'a, str>); + +impl<'a> From<&'a Ident<'a>> for &'a str { + fn from(id: &'a Ident<'a>) -> Self { + id.0.as_ref() + } +} + +impl<'a> Display for Ident<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl<'a> Ident<'a> { + pub fn to_owned(&self) -> Ident<'static> { + Ident(Cow::Owned(self.0.clone().into_owned())) + } + + pub fn from_str_unchecked(s: &'a str) -> Self { + debug_assert!(is_valid_identifier(s)); + Self(Cow::Borrowed(s)) + } + + pub fn from_string_unchecked(s: String) -> Self { + debug_assert!(is_valid_identifier(&s)); + Self(Cow::Owned(s)) + } +} + +pub fn is_valid_identifier<S>(s: &S) -> bool +where + S: AsRef<str> + ?Sized, +{ + s.as_ref() + .chars() + .any(|c| !c.is_alphanumeric() || !"_".contains(c)) +} + +impl<'a> TryFrom<&'a str> for Ident<'a> { + type Error = InvalidIdentifier<'a>; + + fn try_from(s: &'a str) -> Result<Self, Self::Error> { + if is_valid_identifier(s) { + Ok(Ident(Cow::Borrowed(s))) + } else { + Err(InvalidIdentifier(Cow::Borrowed(s))) + } + } +} + +impl<'a> TryFrom<String> for Ident<'a> { + type Error = InvalidIdentifier<'static>; + + fn try_from(s: String) -> Result<Self, Self::Error> { + if is_valid_identifier(&s) { + Ok(Ident(Cow::Owned(s))) + } else { + Err(InvalidIdentifier(Cow::Owned(s))) + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub enum BinaryOperator { + /// `+` + Add, + + /// `-` + Sub, + + /// `*` + Mul, + + /// `/` + Div, + + /// `^` + Pow, + + /// `==` + Equ, + + /// `!=` + Neq, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum UnaryOperator { + /// ! + Not, + + /// - + Neg, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Literal { + Int(u64), +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Expr<'a> { + Ident(Ident<'a>), + + Literal(Literal), + + UnaryOp { + op: UnaryOperator, + rhs: Box<Expr<'a>>, + }, + + BinaryOp { + lhs: Box<Expr<'a>>, + op: BinaryOperator, + rhs: Box<Expr<'a>>, + }, + + Let { + bindings: Vec<(Ident<'a>, Expr<'a>)>, + body: Box<Expr<'a>>, + }, + + If { + condition: Box<Expr<'a>>, + then: Box<Expr<'a>>, + else_: Box<Expr<'a>>, + }, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Fun<'a> { + pub name: Ident<'a>, + pub args: Vec<Ident<'a>>, + pub body: Expr<'a>, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Decl<'a> { + Fun(Fun<'a>), +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Type { + Int, + Float, + Bool, +} + +impl Display for Type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Int => f.write_str("int"), + Self::Float => f.write_str("float"), + Self::Bool => f.write_str("bool"), + } + } +} |