diff --git a/src/compilation.rs b/src/compilation.rs index 207b02e..fe21e12 100644 --- a/src/compilation.rs +++ b/src/compilation.rs @@ -3,7 +3,7 @@ extern crate llvm_sys; use std::collections::HashMap; use self::llvm_sys::prelude::*; -use parser::{AST, Statement, Function, Expression}; +use parser::{AST, Statement, Function, Expression, BinOp}; use llvm_wrap as LLVMWrap; @@ -128,6 +128,7 @@ impl CodeGen for Function { impl CodeGen for Expression { fn codegen(&self, data: &mut CompilationData) -> LLVMValueRef { + use self::BinOp::*; use self::Expression::*; let int_type = LLVMWrap::Int64TypeInContext(data.context); @@ -135,7 +136,7 @@ impl CodeGen for Expression { match *self { Variable(ref name) => *data.variables.get(&**name).unwrap(), - BinExp(ref op, ref left, ref right) if **op == "=" => { + BinExp(Assign, ref left, ref right) => { if let Variable(ref name) = **left { let new_value = right.codegen(data); data.variables.insert((**name).clone(), new_value); @@ -147,13 +148,13 @@ impl CodeGen for Expression { BinExp(ref op, ref left, ref right) => { let lhs = left.codegen(data); let rhs = right.codegen(data); - let generator = match op.as_ref().as_ref() { - "+" => LLVMWrap::BuildAdd, - "-" => LLVMWrap::BuildSub, - "*" => LLVMWrap::BuildMul, - "/" => LLVMWrap::BuildUDiv, - "%" => LLVMWrap::BuildSRem, - _ => panic!("Bad operator {}", op), + let generator = match *op { + Add => LLVMWrap::BuildAdd, + Sub => LLVMWrap::BuildSub, + Mul => LLVMWrap::BuildMul, + Div => LLVMWrap::BuildUDiv, + Mod => LLVMWrap::BuildSRem, + _ => panic!("Bad operator {:?}", op), }; generator(data.builder, lhs, rhs, "temp") diff --git a/src/eval.rs b/src/eval.rs index 5f99faa..48049ba 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -2,7 +2,7 @@ extern crate take_mut; use std::collections::HashMap; use std::collections::VecDeque; -use parser::{AST, Statement, Expression, Function, Callable}; +use parser::{AST, Statement, Expression, Function, Callable, BinOp}; use std::rc::Rc; use std::io::{Write, Stdout, BufWriter}; use std::convert::From; @@ -125,10 +125,11 @@ impl Expression { } } -fn is_assignment(op: &str) -> bool { - match op { - "=" | "+=" | "-=" | - "*=" | "/=" => true, +fn is_assignment(op: &BinOp) -> bool { + use self::BinOp::*; + match *op { + Assign | AddAssign | SubAssign | + MulAssign | DivAssign => true, _ => false, } } @@ -221,7 +222,7 @@ impl<'a> Evaluator<'a> { return (BinExp(op, left, right), side_effect); } - if *op == "=" { + if let BinOp::Assign = op { return match *left { Variable(var) => { let reduced_value: ReducedValue = ReducedValue::from(*right); @@ -232,17 +233,18 @@ impl<'a> Evaluator<'a> { }; } - if is_assignment(&*op) { - let new_op = Rc::new(String::from(match &op[..] { - "+=" => "+", - "-=" => "-", - "*=" => "*", - "/=" => "/", + if is_assignment(&op) { + use self::BinOp::*; + let new_op = match op { + AddAssign => Add, + SubAssign => Sub, + MulAssign => Mul, + DivAssign => Div, _ => unreachable!(), - })); + }; let reduction = - BinExp(Rc::new(String::from("=")), + BinExp(BinOp::Assign, Box::new(*left.clone()), Box::new(BinExp(new_op, left, right)) ); @@ -316,26 +318,27 @@ impl<'a> Evaluator<'a> { } } - fn reduce_binop(&mut self, op: Rc, left: Expression, right: Expression) -> Expression { + fn reduce_binop(&mut self, op: BinOp, left: Expression, right: Expression) -> Expression { + use self::BinOp::*; let truthy = Number(1.0); let falsy = Null; - match (&op[..], left, right) { - ("+", Number(l), Number(r)) => Number(l + r), - ("+", StringLiteral(s1), StringLiteral(s2)) => StringLiteral(Rc::new(format!("{}{}", *s1, *s2))), - ("+", StringLiteral(s1), Number(r)) => StringLiteral(Rc::new(format!("{}{}", *s1, r))), - ("+", Number(l), StringLiteral(s1)) => StringLiteral(Rc::new(format!("{}{}", l, *s1))), - ("-", Number(l), Number(r)) => Number(l - r), - ("*", Number(l), Number(r)) => Number(l * r), - ("/", Number(l), Number(r)) if r != 0.0 => Number(l / r), - ("%", Number(l), Number(r)) => Number(l % r), - ("<", Number(l), Number(r)) => if l < r { truthy } else { falsy }, - ("<=", Number(l), Number(r)) => if l <= r { truthy } else { falsy }, - (">", Number(l), Number(r)) => if l > r { truthy } else { falsy }, - (">=", Number(l), Number(r)) => if l >= r { truthy } else { falsy }, - ("==", Number(l), Number(r)) => if l == r { truthy } else { falsy }, - ("==", Null, Null) => truthy, - ("==", StringLiteral(s1), StringLiteral(s2)) => if s1 == s2 { truthy } else { falsy }, - ("==", _, _) => falsy, + match (op, left, right) { + (Add, Number(l), Number(r)) => Number(l + r), + (Add, StringLiteral(s1), StringLiteral(s2)) => StringLiteral(Rc::new(format!("{}{}", *s1, *s2))), + (Add, StringLiteral(s1), Number(r)) => StringLiteral(Rc::new(format!("{}{}", *s1, r))), + (Add, Number(l), StringLiteral(s1)) => StringLiteral(Rc::new(format!("{}{}", l, *s1))), + (Sub, Number(l), Number(r)) => Number(l - r), + (Mul, Number(l), Number(r)) => Number(l * r), + (Div, Number(l), Number(r)) if r != 0.0 => Number(l / r), + (Mod, Number(l), Number(r)) => Number(l % r), + (Less, Number(l), Number(r)) => if l < r { truthy } else { falsy }, + (LessEq, Number(l), Number(r)) => if l <= r { truthy } else { falsy }, + (Greater, Number(l), Number(r)) => if l > r { truthy } else { falsy }, + (GreaterEq, Number(l), Number(r)) => if l >= r { truthy } else { falsy }, + (Equal, Number(l), Number(r)) => if l == r { truthy } else { falsy }, + (Equal, Null, Null) => truthy, + (Equal, StringLiteral(s1), StringLiteral(s2)) => if s1 == s2 { truthy } else { falsy }, + (Equal, _, _) => falsy, _ => falsy, } } diff --git a/src/parser.rs b/src/parser.rs index 5a8e041..443ee52 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -64,7 +64,7 @@ pub enum Expression { StringLiteral(Rc), Number(f64), Variable(Rc), - BinExp(Rc, Box, Box), + BinExp(BinOp, Box, Box), Call(Callable, Vec), Conditional(Box, Box, Option>), Lambda(Function), @@ -94,7 +94,7 @@ impl fmt::Display for Expression { } #[derive(Debug, Clone)] -pub enum Op { +pub enum BinOp { Add, AddAssign, Sub, @@ -113,10 +113,10 @@ pub enum Op { Custom(String), } -impl<'a> From<&'a str> for Op { - fn from(s: &'a str) -> Op { - use self::Op::*; - match s { +impl From for BinOp { + fn from(token: OpTok) -> BinOp { + use self::BinOp::*; + match &token.0[..] { "+" => Add, "+=" => AddAssign, "-" => Sub, @@ -132,7 +132,7 @@ impl<'a> From<&'a str> for Op { ">=" => GreaterEq, "==" => Equal, "=" => Assign, - op => Custom(op.to_string()), + op => Custom(op.to_string()), } } } @@ -380,7 +380,7 @@ impl Parser { } } - lhs = Expression::BinExp(op.0, Box::new(lhs), Box::new(rhs)); + lhs = Expression::BinExp(op.into(), Box::new(lhs), Box::new(rhs)); } Ok(lhs) } @@ -569,17 +569,17 @@ mod tests { fn expression_parse_test() { parsetest!("a", &[ExprNode(Variable(ref s))], **s == "a"); parsetest!("a + b", - &[ExprNode(BinExp(ref plus, box Variable(ref a), box Variable(ref b)))], - **plus == "+" && **a == "a" && **b == "b"); + &[ExprNode(BinExp(Op::Plus, box Variable(ref a), box Variable(ref b)))], + **a == "a" && **b == "b"); parsetest!("a + b * c", - &[ExprNode(BinExp(ref plus, box Variable(ref a), box BinExp(ref mul, box Variable(ref b), box Variable(ref c))))], - **plus == "+" && **mul == "*" && **a == "a" && **b == "b" && **c == "c"); + &[ExprNode(BinExp(Op::Plus, box Variable(ref a), box BinExp(Op::Mul, box Variable(ref b), box Variable(ref c))))], + **a == "a" && **b == "b" && **c == "c"); parsetest!("a * b + c", - &[ExprNode(BinExp(ref plus, box BinExp(ref mul, box Variable(ref a), box Variable(ref b)), box Variable(ref c)))], - **plus == "+" && **mul == "*" && **a == "a" && **b == "b" && **c == "c"); + &[ExprNode(BinExp(Op::Plus, box BinExp(Op::Mul, box Variable(ref a), box Variable(ref b)), box Variable(ref c)))], + **a == "a" && **b == "b" && **c == "c"); parsetest!("(a + b) * c", - &[ExprNode(BinExp(ref mul, box BinExp(ref plus, box Variable(ref a), box Variable(ref b)), box Variable(ref c)))], - **plus == "+" && **mul == "*" && **a == "a" && **b == "b" && **c == "c"); + &[ExprNode(BinExp(Op::Mul, box BinExp(Op::Plus, box Variable(ref a), box Variable(ref b)), box Variable(ref c)))], + **a == "a" && **b == "b" && **c == "c"); } #[test]