#[derive(Debug)] pub struct Program { pub stanzas: Vec, } impl Program { pub fn new() -> Self { Self { stanzas: Vec::new(), } } pub fn from_str(mut self, i: &str) -> Result> { use nom::Finish; let (remaining_input, stanzas) = crate::parser::parse_file(i).finish()?; assert!(remaining_input.trim().is_empty(), "{remaining_input}"); self.stanzas = stanzas; Ok(self) } } #[derive(Debug, PartialEq, Eq)] pub struct Stanza { pub pattern: Pattern, pub statements: Block, } #[derive(Debug, Eq, PartialEq, Clone)] pub enum Pattern { Begin, End, Node(NodePattern), } #[derive(Debug, Eq, PartialEq, Clone)] pub struct NodePattern { pub modifier: Modifier, pub kind: String, } #[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] pub enum Modifier { #[default] Enter, Leave, } #[derive(Debug, Default, Eq, PartialEq, Clone)] pub struct Block { pub body: Vec, } #[derive(Debug, Eq, PartialEq, Clone)] pub enum Statement { Bare(Expr), Declaration(Declaration), } impl Statement { #[cfg(test)] pub fn decl(ty: Type, ident: &str, init: Expr) -> Self { Self::Declaration(Declaration { ty, name: ident.to_owned(), init: Some(init.boxed()), }) } } #[derive(Debug, Eq, PartialEq, Clone)] pub enum Expr { Node, Unit, Lit(Literal), Ident(Identifier), FieldAccess(Box, Identifier), Index(Box, Box), Bin(Box, BinOp, Box), Unary(Box, UnaryOp), Call(Call), List(List), If(IfExpr), Block(Block), } impl Expr { pub fn boxed(self) -> Box { Box::new(self) } #[cfg(test)] pub fn bin(lhs: Expr, op: &str, rhs: Expr) -> Expr { use std::str::FromStr; Self::Bin(lhs.boxed(), BinOp::from_str(op).unwrap(), rhs.boxed()) } #[cfg(test)] pub fn ident(i: &str) -> Expr { Self::Ident(i.to_owned()) } #[cfg(test)] pub fn call(fun: &str, params: [Expr; N]) -> Expr { Self::Call(Call { function: fun.to_owned(), parameters: params.to_vec(), }) } #[cfg(test)] pub fn list(items: [Expr; N]) -> Expr { Self::List(List { items: items.to_vec() }) } } #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum UnaryOp { Not, } #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum BinOp { Arith(ArithOp), Cmp(CmpOp), Logic(LogicOp), // = Assign(AssignOp), } impl std::str::FromStr for BinOp { type Err = (); fn from_str(val: &str) -> Result { match val { "+" => Ok(Self::Arith(ArithOp::Add)), "-" => Ok(Self::Arith(ArithOp::Sub)), "*" => Ok(Self::Arith(ArithOp::Mul)), "/" => Ok(Self::Arith(ArithOp::Div)), "%" => Ok(Self::Arith(ArithOp::Mod)), ">" => Ok(Self::Cmp(CmpOp::Gt)), "<" => Ok(Self::Cmp(CmpOp::Lt)), ">=" => Ok(Self::Cmp(CmpOp::Gte)), "<=" => Ok(Self::Cmp(CmpOp::Lte)), "==" => Ok(Self::Cmp(CmpOp::Eq)), "!=" => Ok(Self::Cmp(CmpOp::Neq)), "&&" => Ok(Self::Logic(LogicOp::And)), "||" => Ok(Self::Logic(LogicOp::Or)), "=" => Ok(Self::Assign(AssignOp { op: None })), "+=" => Ok(Self::Assign(AssignOp { op: Some(ArithOp::Add), })), "-=" => Ok(Self::Assign(AssignOp { op: Some(ArithOp::Sub), })), "*=" => Ok(Self::Assign(AssignOp { op: Some(ArithOp::Mul), })), "/=" => Ok(Self::Assign(AssignOp { op: Some(ArithOp::Div), })), "%=" => Ok(Self::Assign(AssignOp { op: Some(ArithOp::Mod), })), _ => Err(()), } } } // + - * / #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum ArithOp { Add, Sub, Mul, Div, Mod, } // && || #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum LogicOp { And, Or, } // == != > < >= <= #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum CmpOp { Eq, Neq, Gt, Lt, Gte, Lte, } // =, +=, -=, *=, /= #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub struct AssignOp { pub op: Option, } pub type Identifier = String; #[derive(Debug, Eq, PartialEq, Clone)] pub enum Literal { Str(String), Int(i128), Bool(bool), } /// A function call #[derive(Debug, Eq, PartialEq, Clone)] pub struct Call { pub function: Identifier, pub parameters: Vec, } impl From for Expr { fn from(expr: Call) -> Expr { Expr::Call(expr) } } /// A list construction expression #[derive(Debug, Eq, PartialEq, Clone)] pub struct List { pub items: Vec, } impl From for Expr { fn from(list: List) -> Expr { Expr::List(list) } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Type { Unit, Integer, String, Boolean, Node, List, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Declaration { pub ty: Type, pub name: Identifier, pub init: Option>, } #[derive(Debug, Eq, PartialEq, Clone)] pub struct IfExpr { pub condition: Box, pub then: Block, pub else_: Block, }