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 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")

View File

@ -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<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 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,
}
}

View File

@ -64,7 +64,7 @@ pub enum Expression {
StringLiteral(Rc<String>),
Number(f64),
Variable(Rc<String>),
BinExp(Rc<String>, Box<Expression>, Box<Expression>),
BinExp(BinOp, Box<Expression>, Box<Expression>),
Call(Callable, Vec<Expression>),
Conditional(Box<Expression>, Box<Expression>, Option<Box<Expression>>),
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<OpTok> 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]