Use BinOp type instead of strings

This commit is contained in:
greg 2017-01-13 20:05:17 -08:00
parent 0ace370fc2
commit d804efdc5e
3 changed files with 61 additions and 57 deletions

View File

@ -3,7 +3,7 @@ extern crate llvm_sys;
use std::collections::HashMap; use std::collections::HashMap;
use self::llvm_sys::prelude::*; use self::llvm_sys::prelude::*;
use parser::{AST, Statement, Function, Expression}; use parser::{AST, Statement, Function, Expression, BinOp};
use llvm_wrap as LLVMWrap; use llvm_wrap as LLVMWrap;
@ -128,6 +128,7 @@ impl CodeGen for Function {
impl CodeGen for Expression { impl CodeGen for Expression {
fn codegen(&self, data: &mut CompilationData) -> LLVMValueRef { fn codegen(&self, data: &mut CompilationData) -> LLVMValueRef {
use self::BinOp::*;
use self::Expression::*; use self::Expression::*;
let int_type = LLVMWrap::Int64TypeInContext(data.context); let int_type = LLVMWrap::Int64TypeInContext(data.context);
@ -135,7 +136,7 @@ impl CodeGen for Expression {
match *self { match *self {
Variable(ref name) => *data.variables.get(&**name).unwrap(), 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 { if let Variable(ref name) = **left {
let new_value = right.codegen(data); let new_value = right.codegen(data);
data.variables.insert((**name).clone(), new_value); data.variables.insert((**name).clone(), new_value);
@ -147,13 +148,13 @@ impl CodeGen for Expression {
BinExp(ref op, ref left, ref right) => { BinExp(ref op, ref left, ref right) => {
let lhs = left.codegen(data); let lhs = left.codegen(data);
let rhs = right.codegen(data); let rhs = right.codegen(data);
let generator = match op.as_ref().as_ref() { let generator = match *op {
"+" => LLVMWrap::BuildAdd, Add => LLVMWrap::BuildAdd,
"-" => LLVMWrap::BuildSub, Sub => LLVMWrap::BuildSub,
"*" => LLVMWrap::BuildMul, Mul => LLVMWrap::BuildMul,
"/" => LLVMWrap::BuildUDiv, Div => LLVMWrap::BuildUDiv,
"%" => LLVMWrap::BuildSRem, Mod => LLVMWrap::BuildSRem,
_ => panic!("Bad operator {}", op), _ => panic!("Bad operator {:?}", op),
}; };
generator(data.builder, lhs, rhs, "temp") generator(data.builder, lhs, rhs, "temp")

View File

@ -2,7 +2,7 @@ extern crate take_mut;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::VecDeque; 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::rc::Rc;
use std::io::{Write, Stdout, BufWriter}; use std::io::{Write, Stdout, BufWriter};
use std::convert::From; use std::convert::From;
@ -125,10 +125,11 @@ impl Expression {
} }
} }
fn is_assignment(op: &str) -> bool { fn is_assignment(op: &BinOp) -> bool {
match op { use self::BinOp::*;
"=" | "+=" | "-=" | match *op {
"*=" | "/=" => true, Assign | AddAssign | SubAssign |
MulAssign | DivAssign => true,
_ => false, _ => false,
} }
} }
@ -221,7 +222,7 @@ impl<'a> Evaluator<'a> {
return (BinExp(op, left, right), side_effect); return (BinExp(op, left, right), side_effect);
} }
if *op == "=" { if let BinOp::Assign = op {
return match *left { return match *left {
Variable(var) => { Variable(var) => {
let reduced_value: ReducedValue = ReducedValue::from(*right); let reduced_value: ReducedValue = ReducedValue::from(*right);
@ -232,17 +233,18 @@ impl<'a> Evaluator<'a> {
}; };
} }
if is_assignment(&*op) { if is_assignment(&op) {
let new_op = Rc::new(String::from(match &op[..] { use self::BinOp::*;
"+=" => "+", let new_op = match op {
"-=" => "-", AddAssign => Add,
"*=" => "*", SubAssign => Sub,
"/=" => "/", MulAssign => Mul,
DivAssign => Div,
_ => unreachable!(), _ => unreachable!(),
})); };
let reduction = let reduction =
BinExp(Rc::new(String::from("=")), BinExp(BinOp::Assign,
Box::new(*left.clone()), Box::new(*left.clone()),
Box::new(BinExp(new_op, left, right)) Box::new(BinExp(new_op, left, right))
); );
@ -316,26 +318,27 @@ impl<'a> Evaluator<'a> {
} }
} }
fn reduce_binop(&mut self, op: Rc<String>, 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 truthy = Number(1.0);
let falsy = Null; let falsy = Null;
match (&op[..], left, right) { match (op, left, right) {
("+", Number(l), Number(r)) => Number(l + r), (Add, Number(l), Number(r)) => Number(l + r),
("+", StringLiteral(s1), StringLiteral(s2)) => StringLiteral(Rc::new(format!("{}{}", *s1, *s2))), (Add, StringLiteral(s1), StringLiteral(s2)) => StringLiteral(Rc::new(format!("{}{}", *s1, *s2))),
("+", StringLiteral(s1), Number(r)) => StringLiteral(Rc::new(format!("{}{}", *s1, r))), (Add, StringLiteral(s1), Number(r)) => StringLiteral(Rc::new(format!("{}{}", *s1, r))),
("+", Number(l), StringLiteral(s1)) => StringLiteral(Rc::new(format!("{}{}", l, *s1))), (Add, Number(l), StringLiteral(s1)) => StringLiteral(Rc::new(format!("{}{}", l, *s1))),
("-", Number(l), Number(r)) => Number(l - r), (Sub, Number(l), Number(r)) => Number(l - r),
("*", Number(l), Number(r)) => Number(l * r), (Mul, Number(l), Number(r)) => Number(l * r),
("/", Number(l), Number(r)) if r != 0.0 => Number(l / r), (Div, Number(l), Number(r)) if r != 0.0 => Number(l / r),
("%", Number(l), Number(r)) => Number(l % r), (Mod, Number(l), Number(r)) => Number(l % r),
("<", Number(l), Number(r)) => if l < r { truthy } else { falsy }, (Less, Number(l), Number(r)) => if l < r { truthy } else { falsy },
("<=", Number(l), Number(r)) => if l <= r { truthy } else { falsy }, (LessEq, Number(l), Number(r)) => if l <= r { truthy } else { falsy },
(">", Number(l), Number(r)) => if l > r { truthy } else { falsy }, (Greater, Number(l), Number(r)) => if l > r { truthy } else { falsy },
(">=", Number(l), Number(r)) => if l >= r { truthy } else { falsy }, (GreaterEq, Number(l), Number(r)) => if l >= r { truthy } else { falsy },
("==", Number(l), Number(r)) => if l == r { truthy } else { falsy }, (Equal, Number(l), Number(r)) => if l == r { truthy } else { falsy },
("==", Null, Null) => truthy, (Equal, Null, Null) => truthy,
("==", StringLiteral(s1), StringLiteral(s2)) => if s1 == s2 { truthy } else { falsy }, (Equal, StringLiteral(s1), StringLiteral(s2)) => if s1 == s2 { truthy } else { falsy },
("==", _, _) => falsy, (Equal, _, _) => falsy,
_ => falsy, _ => falsy,
} }
} }

View File

@ -64,7 +64,7 @@ pub enum Expression {
StringLiteral(Rc<String>), StringLiteral(Rc<String>),
Number(f64), Number(f64),
Variable(Rc<String>), Variable(Rc<String>),
BinExp(Rc<String>, Box<Expression>, Box<Expression>), BinExp(BinOp, Box<Expression>, Box<Expression>),
Call(Callable, Vec<Expression>), Call(Callable, Vec<Expression>),
Conditional(Box<Expression>, Box<Expression>, Option<Box<Expression>>), Conditional(Box<Expression>, Box<Expression>, Option<Box<Expression>>),
Lambda(Function), Lambda(Function),
@ -94,7 +94,7 @@ impl fmt::Display for Expression {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Op { pub enum BinOp {
Add, Add,
AddAssign, AddAssign,
Sub, Sub,
@ -113,10 +113,10 @@ pub enum Op {
Custom(String), Custom(String),
} }
impl<'a> From<&'a str> for Op { impl From<OpTok> for BinOp {
fn from(s: &'a str) -> Op { fn from(token: OpTok) -> BinOp {
use self::Op::*; use self::BinOp::*;
match s { match &token.0[..] {
"+" => Add, "+" => Add,
"+=" => AddAssign, "+=" => AddAssign,
"-" => Sub, "-" => Sub,
@ -132,7 +132,7 @@ impl<'a> From<&'a str> for Op {
">=" => GreaterEq, ">=" => GreaterEq,
"==" => Equal, "==" => Equal,
"=" => Assign, "=" => 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) Ok(lhs)
} }
@ -569,17 +569,17 @@ mod tests {
fn expression_parse_test() { fn expression_parse_test() {
parsetest!("a", &[ExprNode(Variable(ref s))], **s == "a"); parsetest!("a", &[ExprNode(Variable(ref s))], **s == "a");
parsetest!("a + b", parsetest!("a + b",
&[ExprNode(BinExp(ref plus, box Variable(ref a), box Variable(ref b)))], &[ExprNode(BinExp(Op::Plus, box Variable(ref a), box Variable(ref b)))],
**plus == "+" && **a == "a" && **b == "b"); **a == "a" && **b == "b");
parsetest!("a + b * c", parsetest!("a + b * c",
&[ExprNode(BinExp(ref plus, box Variable(ref a), box BinExp(ref mul, box Variable(ref b), box Variable(ref c))))], &[ExprNode(BinExp(Op::Plus, box Variable(ref a), box BinExp(Op::Mul, box Variable(ref b), box Variable(ref c))))],
**plus == "+" && **mul == "*" && **a == "a" && **b == "b" && **c == "c"); **a == "a" && **b == "b" && **c == "c");
parsetest!("a * b + 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)))], &[ExprNode(BinExp(Op::Plus, box BinExp(Op::Mul, box Variable(ref a), box Variable(ref b)), box Variable(ref c)))],
**plus == "+" && **mul == "*" && **a == "a" && **b == "b" && **c == "c"); **a == "a" && **b == "b" && **c == "c");
parsetest!("(a + b) * 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)))], &[ExprNode(BinExp(Op::Mul, box BinExp(Op::Plus, box Variable(ref a), box Variable(ref b)), box Variable(ref c)))],
**plus == "+" && **mul == "*" && **a == "a" && **b == "b" && **c == "c"); **a == "a" && **b == "b" && **c == "c");
} }
#[test] #[test]