use std::rc::Rc; use ast::{AST, Statement, Expression, ExpressionType, Declaration, Discriminator, IfExpressionBody, Pattern, PatternLiteral, Guard, HalfExpr}; use symbol_table::{Symbol, SymbolSpec, SymbolTable}; use builtin::{BinOp, PrefixOp}; #[derive(Debug)] pub struct ReducedAST(pub Vec); #[derive(Debug, Clone)] pub enum Stmt { PreBinding { name: Rc, func: Func, }, Binding { name: Rc, constant: bool, expr: Expr, }, Expr(Expr), Noop, } #[derive(Debug, Clone)] pub enum Expr { Unit, Lit(Lit), Tuple(Vec), Func(Func), Val(Rc), Constructor { type_name: Rc, name: Rc, tag: usize, arity: usize, }, Call { f: Box, args: Vec, }, Assign { val: Box, expr: Box, }, Conditional { cond: Box, then_clause: Vec, else_clause: Vec, }, CaseMatch { cond: Box, alternatives: Vec }, UnimplementedSigilValue } #[derive(Debug, Clone)] pub struct Alternative { pub tag: Option, pub guard: Option, pub bound_vars: Vec>>, //remember that order matters here pub item: Vec, } impl Alternative { fn default(item: Vec) -> Alternative { Alternative { tag: None, guard: None, bound_vars: vec![], item } } } #[derive(Debug, Clone)] pub enum Lit { Nat(u64), Int(i64), Float(f64), Bool(bool), StringLit(Rc), } #[derive(Debug, Clone)] pub enum Func { BuiltIn(Rc), UserDefined { name: Option>, params: Vec>, body: Vec, } } impl AST { pub fn reduce(&self, symbol_table: &SymbolTable) -> ReducedAST { let mut output = vec![]; for statement in self.0.iter() { output.push(statement.reduce(symbol_table)); } ReducedAST(output) } } impl Statement { fn reduce(&self, symbol_table: &SymbolTable) -> Stmt { use ast::Statement::*; match self { ExpressionStatement(expr) => Stmt::Expr(expr.reduce(symbol_table)), Declaration(decl) => decl.reduce(symbol_table), } } } impl Expression { fn reduce(&self, symbol_table: &SymbolTable) -> Expr { use ast::ExpressionType::*; let ref input = self.0; match input { NatLiteral(n) => Expr::Lit(Lit::Nat(*n)), FloatLiteral(f) => Expr::Lit(Lit::Float(*f)), StringLiteral(s) => Expr::Lit(Lit::StringLit(s.clone())), BoolLiteral(b) => Expr::Lit(Lit::Bool(*b)), BinExp(binop, lhs, rhs) => binop.reduce(symbol_table, lhs, rhs), PrefixExp(op, arg) => op.reduce(symbol_table, arg), Value(name) => match symbol_table.lookup_by_name(name) { Some(Symbol { spec: SymbolSpec::DataConstructor { index, type_args, type_name}, .. }) => Expr::Constructor { type_name: type_name.clone(), name: name.clone(), tag: index.clone(), arity: type_args.len(), }, _ => Expr::Val(name.clone()), }, Call { f, arguments } => Expr::Call { f: Box::new(f.reduce(symbol_table)), args: arguments.iter().map(|arg| arg.reduce(symbol_table)).collect(), }, TupleLiteral(exprs) => Expr::Tuple(exprs.iter().map(|e| e.reduce(symbol_table)).collect()), IfExpression { discriminator, body } => reduce_if_expression(discriminator, body, symbol_table), _ => Expr::UnimplementedSigilValue, } } } fn reduce_if_expression(discriminator: &Discriminator, body: &IfExpressionBody, symbol_table: &SymbolTable) -> Expr { let cond = Box::new(match *discriminator { Discriminator::Simple(ref expr) => expr.reduce(symbol_table), Discriminator::BinOp(ref expr, ref binop) => panic!("Can't yet handle binop discriminators") }); match *body { IfExpressionBody::SimpleConditional(ref then_clause, ref else_clause) => { let then_clause = then_clause.iter().map(|expr| expr.reduce(symbol_table)).collect(); let else_clause = match else_clause { None => vec![], Some(stmts) => stmts.iter().map(|expr| expr.reduce(symbol_table)).collect(), }; Expr::Conditional { cond, then_clause, else_clause } }, IfExpressionBody::SimplePatternMatch(ref pat, ref then_clause, ref else_clause) => { let then_clause = then_clause.iter().map(|expr| expr.reduce(symbol_table)).collect(); let else_clause = match else_clause { None => vec![], Some(stmts) => stmts.iter().map(|expr| expr.reduce(symbol_table)).collect(), }; let alternatives = vec![ pat.to_alternative(&cond, then_clause, symbol_table), Alternative::default(else_clause), ]; Expr::CaseMatch { cond, alternatives, } }, IfExpressionBody::GuardList(ref guard_arms) => { let alternatives = guard_arms.iter().map(|arm| match arm.guard { Guard::Pat(ref p) => { let item = arm.body.iter().map(|expr| expr.reduce(symbol_table)).collect(); p.to_alternative(&cond, item, symbol_table) }, Guard::HalfExpr(HalfExpr { op: _, expr: _ }) => { unimplemented!() } }).collect(); Expr::CaseMatch { cond, alternatives } } } } impl Pattern { fn to_alternative(&self, cond: &Box, item: Vec, symbol_table: &SymbolTable) -> Alternative { use self::Pattern::*; fn handle_symbol(symbol: &Symbol, subpatterns: &Vec, item: Vec) -> Alternative { let tag = match symbol.spec { SymbolSpec::DataConstructor { index, .. } => index.clone(), _ => panic!("Symbol is not a data constructor - this should've been caught in type-checking"), }; let bound_vars = subpatterns.iter().map(|p| match p { Literal(PatternLiteral::VarPattern(var)) => Some(var.clone()), Ignored => None, _ => None, }).collect(); Alternative { tag: Some(tag), guard: None, bound_vars, item, } } match self { TupleStruct(name, subpatterns) => { let symbol = symbol_table.lookup_by_name(name).expect(&format!("Symbol {} not found", name)); handle_symbol(symbol, subpatterns, item) }, TuplePattern(_items) => { unimplemented!() }, Record(_name, _pairs) => { unimplemented!() }, Ignored => Alternative::default(item), Literal(lit) => match lit { PatternLiteral::NumPattern { neg, num } => { let comparison = Expr::Lit(match (neg, num) { (false, ExpressionType::NatLiteral(n)) => Lit::Nat(*n), (false, ExpressionType::FloatLiteral(f)) => Lit::Float(*f), (true, ExpressionType::NatLiteral(n)) => Lit::Int(-1*(*n as i64)), (true, ExpressionType::FloatLiteral(f)) => Lit::Float(-1.0*f), _ => panic!("This should never happen") }); let guard = Some(Expr::Call { f: Box::new(Expr::Func(Func::BuiltIn(Rc::new("==".to_string())))), args: vec![comparison, *cond.clone()] }); Alternative { tag: None, guard, bound_vars: vec![], item } }, PatternLiteral::StringPattern(_s) => unimplemented!(), PatternLiteral::BoolPattern(b) => { let guard = Some(if *b { *cond.clone() } else { Expr::Call { f: Box::new(Expr::Func(Func::BuiltIn(Rc::new("!".to_string())))), args: vec![*cond.clone()] } }); Alternative { tag: None, guard, bound_vars: vec![], item } }, PatternLiteral::VarPattern(var) => match symbol_table.lookup_by_name(var) { Some(symbol) => handle_symbol(symbol, &vec![], item), None => Alternative { tag: None, guard: None, bound_vars: vec![Some(var.clone())], item } } }, } } } impl Declaration { fn reduce(&self, symbol_table: &SymbolTable) -> Stmt { use self::Declaration::*; use ::ast::Signature; match self { Binding {name, constant, expr } => Stmt::Binding { name: name.clone(), constant: *constant, expr: expr.reduce(symbol_table) }, FuncDecl(Signature { name, params, .. }, statements) => Stmt::PreBinding { name: name.clone(), func: Func::UserDefined { name: Some(name.clone()), params: params.iter().map(|param| param.0.clone()).collect(), body: statements.iter().map(|stmt| stmt.reduce(symbol_table)).collect(), } }, TypeDecl { .. } => Stmt::Noop, TypeAlias(_, _) => Stmt::Noop, Interface { .. } => Stmt::Noop, Impl { .. } => Stmt::Expr(Expr::UnimplementedSigilValue), _ => Stmt::Expr(Expr::UnimplementedSigilValue) } } } impl BinOp { fn reduce(&self, symbol_table: &SymbolTable, lhs: &Box, rhs: &Box) -> Expr { if **self.sigil() == "=" { Expr::Assign { val: Box::new(lhs.reduce(symbol_table)), expr: Box::new(rhs.reduce(symbol_table)), } } else { let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); Expr::Call { f, args: vec![lhs.reduce(symbol_table), rhs.reduce(symbol_table)]} } } } impl PrefixOp { fn reduce(&self, symbol_table: &SymbolTable, arg: &Box) -> Expr { let f = Box::new(Expr::Func(Func::BuiltIn(self.sigil().clone()))); Expr::Call { f, args: vec![arg.reduce(symbol_table)]} } }