//! Ast definition for Ayin. use std::collections::BTreeMap; /// An expression. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Expr { 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), /* Loop { body: Box, }, Continue, Break, */ } #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Op { Assign, // Equals, } /// A statement. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Statement { Expr(Expr), Let(Definition), Return(Option), } #[derive(PartialEq, PartialOrd, Debug, Clone)] pub struct Definition { pub mutable: bool, pub name: Name, pub expr: Expr, } /// A reduced value. #[derive(PartialEq, PartialOrd, Debug, Clone)] pub enum Value { Int(i64), Float(f64), String(String), Boolean(bool), Record(Record), Vector(Vector), Label(Label), Ref(Ref), Closure { env: EnvName, expr: Box }, } /// 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, 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); /// A Program. #[derive(PartialEq, PartialOrd, Debug)] pub struct Program(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 Value { fn from(rec: Vec<(&str, Expr)>) -> Value { Value::Record(Record({ rec.into_iter() .map(|(lbl, expr)| (Label(lbl.into()), expr)) .collect() })) } } impl From> for Expr { fn from(rec: Vec<(&str, Expr)>) -> Expr { Expr::Value(rec.into()) } } 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: i64) -> Value { Value::Int(i) } } impl From for Expr { fn from(i: i64) -> Expr { Expr::Value(i.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) } } impl From> for Expr { fn from(stmts: Vec) -> Expr { Expr::Block(stmts) } } impl Record { pub fn get(&self, label: &Label) -> Result<&Expr, Error> { match self.0.get(label) { Some(v) => Ok(v), None => Err(Error::LabelNotFound(label.clone())), } } } pub const UNIT: Expr = Expr::Value(Value::Record(Record(BTreeMap::new()))); #[derive(PartialEq, Debug, thiserror::Error)] pub enum Error { #[error("Label not found: {0:?}")] LabelNotFound(Label), }