use std::string::ToString; pub trait AstNode: ToString {} pub trait Expr: AstNode { fn get_base(&self) -> BaseType; } pub trait Statement: AstNode {} #[derive(Copy, Clone)] pub enum Quantifier { Const, Var, } impl ToString for Quantifier { fn to_string(&self) -> String { match *self { Quantifier::Const => "const", Quantifier::Var => "var", }.to_string() } } #[derive(Copy, Clone)] pub enum BaseType { Int, Real, Never, } impl ToString for BaseType { fn to_string(&self) -> String { // TODO: Use typedefs when possible. Might fit better on a high level node match *self { BaseType::Int => "integer", BaseType::Real => "real", BaseType::Never => panic!("Attempting to get string of never type"), }.to_string() } } #[derive(Default)] pub struct GlobalBlock { statements: Vec>, } impl ToString for GlobalBlock { fn to_string(&self) -> String { let mut s = String::new(); for stat in &self.statements { s.push_str(&stat.to_string()); s.push(' '); } s.push('\n'); s } } pub struct Block { statements: Vec>, } impl ToString for Block { fn to_string(&self) -> String { let mut s = String::from("{ "); for stat in &self.statements { s.push_str(&stat.to_string()); s.push(' '); } s.push('}'); s } } impl AstNode for Block {} impl Statement for Block {} pub enum Literal { Int(i32), Real(f32), } impl ToString for Literal { fn to_string(&self) -> String { match *self { Literal::Int(x) => x.to_string(), Literal::Real(x) => x.to_string(), } } } impl AstNode for Literal {} impl Expr for Literal { fn get_base(&self) -> BaseType { match *self { Literal::Int(_) => BaseType::Int, Literal::Real(_) => BaseType::Real, } } } #[derive(Builder)] pub struct Declaration { variable: Variable, assn: T, } impl ToString for Declaration { fn to_string(&self) -> String { let mut s = String::new(); s.push_str(&self.variable.quantifer.to_string()); s.push(' '); s.push_str(&self.variable.get_base().to_string()); s.push(' '); s.push_str(&self.variable.to_string()); s.push_str(" = "); s.push_str(&self.assn.to_string()); s.push(';'); s } } impl AstNode for Declaration {} impl Statement for Declaration {} #[derive(Clone, Builder)] pub struct Variable { type_: BaseType, quantifer: Quantifier, name: String, } impl ToString for Variable { fn to_string(&self) -> String { self.name.clone() } } impl AstNode for Variable {} impl Expr for Variable { fn get_base(&self) -> BaseType { self.type_ } } pub enum BinaryOperator { Add(L, R), Subtract(L, R), Multiply(L, R), Divide(L, R), } impl ToString for BinaryOperator { fn to_string(&self) -> String { let mut s = String::new(); s.push('('); match self { BinaryOperator::Add(l, _) => s.push_str(&l.to_string()), BinaryOperator::Subtract(l, _) => s.push_str(&l.to_string()), BinaryOperator::Multiply(l, _) => s.push_str(&l.to_string()), BinaryOperator::Divide(l, _) => s.push_str(&l.to_string()), } s.push(')'); s.push( match self { &BinaryOperator::Add(_, _) => '+', &BinaryOperator::Subtract(_, _) => '-', &BinaryOperator::Multiply(_, _) => '*', &BinaryOperator::Divide(_, _) => '/', } ); s.push('('); match self { BinaryOperator::Add(_, r) => s.push_str(&r.to_string()), BinaryOperator::Subtract(_, r) => s.push_str(&r.to_string()), BinaryOperator::Multiply(_, r) => s.push_str(&r.to_string()), BinaryOperator::Divide(_, r) => s.push_str(&r.to_string()), } s.push(')'); s } } impl AstNode for BinaryOperator {} impl Expr for BinaryOperator { fn get_base(&self) -> BaseType { // TODO: This get_base is clearly wrong match self { BinaryOperator::Add(l, _) => l.get_base(), BinaryOperator::Subtract(l, _) => l.get_base(), BinaryOperator::Multiply(l, _) => l.get_base(), BinaryOperator::Divide(l, _) => l.get_base(), } } }