//! Ast definition for Ayin. use std::collections::BTreeMap; /// A Program. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub struct Program { pub includes: Vec, pub defs: Vec, } #[derive(PartialEq, Eq, Hash, PartialOrd, Debug, Clone)] pub struct File(pub String); #[derive(PartialEq, PartialOrd, Debug, Clone)] pub struct Definition { pub mutable: bool, pub name: Name, pub expr: Expr, } /// An expression. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Expr { Not(Box), Op { lhs: Box, op: Op, rhs: Box, }, Value(Value), Var(Name), Func(Box), FunCall { func: Box, args: Vec, }, Block(Vec), If { condition: Box, then: Box, r#else: Box, }, Access { expr: Box, field: Label, }, Record(BTreeMap), Vector(Vec), } #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Op { Assign, Compare(Cmp), Calc(Calc), Bool(BoolOp), } #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum BoolOp { And, Or, } #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Cmp { Eq, NotEq, Gt, Lt, Gte, Lte, } #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Calc { Add, Sub, Div, Mul, Mod, BinAnd, BinOr, } /// A statement. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Statement { Expr(Expr), Let(Definition), Return(Option), Loop(Box), Break, } /// A reduced value. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Value { Int(i32), Float(f32), String(String), Boolean(bool), Record(Record), Vector(Vector), Label(Label), Ref(Ref), Closure { env: EnvName, expr: Box }, PrimitiveFunc(Name), Return(Box), Break, } /// A mutable variable. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone)] pub struct Ref(pub u64); /// An anonymous function. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub struct Fn { pub args: Vec, pub body: Expr, } /// A function argument. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub struct Arg { pub name: Name, } /// A symbol. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone)] pub struct Name(pub String); /// A field. #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)] pub struct Label(pub String); /// A reference to the environment. #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)] pub struct EnvName(pub String); #[derive(PartialEq, PartialOrd, Debug, Clone)] pub struct Record(pub BTreeMap); #[derive(PartialEq, PartialOrd, Debug, Clone)] pub struct Vector(pub Vec); // ----- // // Impls // // ----- // impl From<&str> for Name { fn from(value: &str) -> Name { Name(value.into()) } } impl From<&str> for Label { fn from(value: &str) -> Label { Label(value.into()) } } impl From<&str> for Expr { fn from(value: &str) -> Expr { Expr::Var(value.into()) } } impl From> for Expr { fn from(rec: Vec<(&str, Expr)>) -> Expr { Expr::Record( rec.into_iter() .map(|(lbl, expr)| (Label(lbl.into()), expr)) .collect(), ) } } impl Expr { pub fn field(self, label: &str) -> Expr { Expr::Access { expr: Box::new(self), field: label.into(), } } pub fn call(self, args: Vec) -> Expr { Expr::FunCall { func: Box::new(self), args, } } } impl From for Value { fn from(i: i32) -> Value { Value::Int(i) } } impl From for Expr { fn from(i: i32) -> Expr { Expr::Value(i.into()) } } impl From for Value { fn from(f: f32) -> Value { Value::Float(f) } } impl From for Expr { fn from(f: f32) -> Expr { Expr::Value(f.into()) } } impl From for Value { fn from(b: bool) -> Value { Value::Boolean(b) } } impl From for Expr { fn from(b: bool) -> Expr { Expr::Value(b.into()) } } impl From> for Program { fn from(defs: Vec) -> Program { Program { defs, includes: vec![], } } } impl From> for Expr { fn from(stmts: Vec) -> Expr { Expr::Block(stmts) } } impl Record { pub fn get(&self, label: &Label) -> Result<&Ref, Error> { match self.0.get(label) { Some(v) => Ok(v), None => Err(Error::LabelNotFound(label.clone())), } } } impl Vector { pub fn get(&self, index: usize) -> Result<&Ref, Error> { match self.0.get(index) { Some(v) => Ok(v), None => Err(Error::IndexOutOfBounds(index)), } } } impl std::fmt::Display for Expr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut string = "".to_string(); match self { Expr::Value(value) => match value { Value::Int(i) => string.push_str(&format!("{i}")), Value::Float(f) => string.push_str(&format!("{f:2}")), Value::String(s) => string.push_str(&format!("{s:?}")), Value::Boolean(b) => string.push_str(&format!("{b}")), Value::Closure { .. } => string.push_str(""), _ => {} }, Expr::Func(_) => string.push_str(""), Expr::Record(map) => { string.push_str("{"); for (key, val) in map { string.push_str(&format!(" .{}: {},", key.0, val)); } if map.len() > 0 { string.push_str(" }"); } else { string.push_str("}"); } } Expr::Vector(vec) => { string.push_str("["); for val in vec { string.push_str(&format!(" {},", val)); } if vec.len() > 0 { string.push_str(" ]"); } else { string.push_str("]"); } } _ => {} } f.write_str(&string) } } pub const UNIT_VALUE: Value = Value::Record(Record(BTreeMap::new())); pub const UNIT: Expr = Expr::Value(UNIT_VALUE); pub enum Error { LabelNotFound(Label), IndexOutOfBounds(usize), } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::LabelNotFound(a) => { write!(f, "Label not found: {a:?}") } Error::IndexOutOfBounds(a) => { write!(f, "Indexout of bounds: {a:?}") } } } }