REFACTOR: Unify the Binary Operator AST data structures.

This commit is contained in:
Jeremy Wall 2018-12-25 14:04:12 -06:00
parent 2b7c8e65f8
commit fb292b4684
5 changed files with 62 additions and 88 deletions

View File

@ -286,6 +286,7 @@ macro_rules! make_selector {
#[derive(PartialEq, Clone)] #[derive(PartialEq, Clone)]
pub struct SelectorList { pub struct SelectorList {
pub head: Box<Expression>, pub head: Box<Expression>,
// TODO This should now work more like a binary operator. Perhaps move into the precendence parser code?
pub tail: Option<Vec<Token>>, pub tail: Option<Vec<Token>>,
} }
@ -579,10 +580,6 @@ impl MacroDef {
stack.push(&bexpr.left); stack.push(&bexpr.left);
stack.push(&bexpr.right); stack.push(&bexpr.right);
} }
&Expression::Compare(ref cexpr) => {
stack.push(&cexpr.left);
stack.push(&cexpr.right);
}
&Expression::Grouped(ref expr) => { &Expression::Grouped(ref expr) => {
stack.push(expr); stack.push(expr);
} }
@ -644,26 +641,14 @@ pub enum BinaryExprType {
Sub, Sub,
Mul, Mul,
Div, Div,
} // Comparison
/// CompareType signals the type of a comparison for a binary expression.
#[derive(Debug, PartialEq, Clone)]
pub enum CompareType {
Equal, Equal,
GT, GT,
LT, LT,
NotEqual, NotEqual,
GTEqual, GTEqual,
LTEqual, LTEqual,
} // TODO DOT Selector operator
/// ComparisonDef Represents a comparison between two expressions.
#[derive(Debug, PartialEq, Clone)]
pub struct ComparisonDef {
pub kind: CompareType,
pub left: Box<Expression>,
pub right: Box<Expression>,
pub pos: Position,
} }
/// Represents an expression with a left and a right side. /// Represents an expression with a left and a right side.
@ -759,7 +744,6 @@ pub enum Expression {
// Binary expressions // Binary expressions
Binary(BinaryOpDef), Binary(BinaryOpDef),
Compare(ComparisonDef),
// Complex Expressions // Complex Expressions
Copy(CopyDef), Copy(CopyDef),
@ -779,7 +763,6 @@ impl Expression {
match self { match self {
&Expression::Simple(ref v) => v.pos(), &Expression::Simple(ref v) => v.pos(),
&Expression::Binary(ref def) => &def.pos, &Expression::Binary(ref def) => &def.pos,
&Expression::Compare(ref def) => &def.pos,
&Expression::Copy(ref def) => &def.pos, &Expression::Copy(ref def) => &def.pos,
&Expression::Grouped(ref expr) => expr.pos(), &Expression::Grouped(ref expr) => expr.pos(),
&Expression::Format(ref def) => &def.pos, &Expression::Format(ref def) => &def.pos,
@ -801,9 +784,6 @@ impl fmt::Display for Expression {
&Expression::Binary(_) => { &Expression::Binary(_) => {
write!(w, "<Expr>")?; write!(w, "<Expr>")?;
} }
&Expression::Compare(_) => {
write!(w, "<Expr>")?;
}
&Expression::ListOp(_) => { &Expression::ListOp(_) => {
write!(w, "<Expr>")?; write!(w, "<Expr>")?;
} }

View File

@ -866,20 +866,12 @@ impl<'a> FileBuilder<'a> {
&BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right), &BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right),
&BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right), &BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right),
&BinaryExprType::Div => self.divide_vals(&def.pos, left, right), &BinaryExprType::Div => self.divide_vals(&def.pos, left, right),
} &BinaryExprType::Equal => self.do_deep_equal(&def.pos, left, right),
} &BinaryExprType::GT => self.do_gt(&def.pos, left, right),
&BinaryExprType::LT => self.do_lt(&def.pos, left, right),
fn eval_compare(&mut self, def: &ComparisonDef, scope: &Scope) -> Result<Rc<Val>, Box<Error>> { &BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
let kind = &def.kind; &BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right),
let left = self.eval_expr(&def.left, scope)?; &BinaryExprType::NotEqual => self.do_not_deep_equal(&def.pos, left, right),
let right = self.eval_expr(&def.right, scope)?;
match kind {
&CompareType::Equal => self.do_deep_equal(&def.pos, left, right),
&CompareType::GT => self.do_gt(&def.pos, left, right),
&CompareType::LT => self.do_lt(&def.pos, left, right),
&CompareType::GTEqual => self.do_gtequal(&def.pos, left, right),
&CompareType::LTEqual => self.do_ltequal(&def.pos, left, right),
&CompareType::NotEqual => self.do_not_deep_equal(&def.pos, left, right),
} }
} }
@ -1247,7 +1239,6 @@ impl<'a> FileBuilder<'a> {
match expr { match expr {
&Expression::Simple(ref val) => self.eval_value(val, scope), &Expression::Simple(ref val) => self.eval_value(val, scope),
&Expression::Binary(ref def) => self.eval_binary(def, scope), &Expression::Binary(ref def) => self.eval_binary(def, scope),
&Expression::Compare(ref def) => self.eval_compare(def, scope),
&Expression::Copy(ref def) => self.eval_copy(def, scope), &Expression::Copy(ref def) => self.eval_copy(def, scope),
&Expression::Grouped(ref expr) => self.eval_expr(expr, scope), &Expression::Grouped(ref expr) => self.eval_expr(expr, scope),
&Expression::Format(ref def) => self.eval_format(def, scope), &Expression::Format(ref def) => self.eval_format(def, scope),

View File

@ -277,6 +277,8 @@ make_fn!(
make_fn!( make_fn!(
value<SliceIter<Token>, Value>, value<SliceIter<Token>, Value>,
either!( either!(
// TODO This should move to op_expression instead of a value now.
// We probably still need a bareword parser though?
trace_parse!(selector_value), trace_parse!(selector_value),
trace_parse!(compound_value), trace_parse!(compound_value),
trace_parse!(boolean_value), trace_parse!(boolean_value),
@ -426,6 +428,7 @@ make_fn!(
copy_expression<SliceIter<Token>, Expression>, copy_expression<SliceIter<Token>, Expression>,
do_each!( do_each!(
pos => pos, pos => pos,
// TODO This should become just a bareword symbol now
selector => trace_parse!(selector_list), selector => trace_parse!(selector_list),
_ => punct!("{"), _ => punct!("{"),
fields => optional!(trace_parse!(field_list)), fields => optional!(trace_parse!(field_list)),
@ -635,6 +638,7 @@ make_fn!(
fn call_expression(input: SliceIter<Token>) -> Result<SliceIter<Token>, Expression> { fn call_expression(input: SliceIter<Token>) -> Result<SliceIter<Token>, Expression> {
let parsed = do_each!(input.clone(), let parsed = do_each!(input.clone(),
// TODO This should become just a bareword symbol now
callee_name => trace_parse!(selector_value), callee_name => trace_parse!(selector_value),
_ => punct!("("), _ => punct!("("),
args => optional!(separated!(punct!(","), trace_parse!(expression))), args => optional!(separated!(punct!(","), trace_parse!(expression))),
@ -723,6 +727,7 @@ make_fn!(
do_each!(_ => word!("map"), (ListOpType::Map)), do_each!(_ => word!("map"), (ListOpType::Map)),
do_each!(_ => word!("filter"), (ListOpType::Filter)) do_each!(_ => word!("filter"), (ListOpType::Filter))
), ),
// TODO This should become just a bareword symbol now
macroname => trace_parse!(selector_value), macroname => trace_parse!(selector_value),
list => trace_parse!(non_op_expression), list => trace_parse!(non_op_expression),
(tuple_to_list_op(&input, optype, macroname, list).unwrap()) (tuple_to_list_op(&input, optype, macroname, list).unwrap())

View File

@ -24,8 +24,7 @@ use crate::ast::*;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Element { pub enum Element {
Expr(Expression), Expr(Expression),
MathOp(BinaryExprType), Op(BinaryExprType),
CompareOp(CompareType),
} }
make_fn!( make_fn!(
@ -33,16 +32,16 @@ make_fn!(
either!( either!(
do_each!( do_each!(
_ => punct!("+"), _ => punct!("+"),
(Element::MathOp(BinaryExprType::Add))), (Element::Op(BinaryExprType::Add))),
do_each!( do_each!(
_ => punct!("-"), _ => punct!("-"),
(Element::MathOp(BinaryExprType::Sub))), (Element::Op(BinaryExprType::Sub))),
do_each!( do_each!(
_ => punct!("*"), _ => punct!("*"),
(Element::MathOp(BinaryExprType::Mul))), (Element::Op(BinaryExprType::Mul))),
do_each!( do_each!(
_ => punct!("/"), _ => punct!("/"),
(Element::MathOp(BinaryExprType::Div))) (Element::Op(BinaryExprType::Div)))
) )
); );
@ -76,7 +75,7 @@ fn parse_sum_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, Binar
)); ));
} }
let el = i_.next(); let el = i_.next();
if let Some(&Element::MathOp(ref op)) = el { if let Some(&Element::Op(ref op)) = el {
match op { match op {
&BinaryExprType::Add => { &BinaryExprType::Add => {
return Result::Complete(i_.clone(), op.clone()); return Result::Complete(i_.clone(), op.clone());
@ -121,7 +120,7 @@ fn parse_product_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, B
)); ));
} }
let el = i_.next(); let el = i_.next();
if let Some(&Element::MathOp(ref op)) = el { if let Some(&Element::Op(ref op)) = el {
match op { match op {
&BinaryExprType::Mul => { &BinaryExprType::Mul => {
return Result::Complete(i_.clone(), op.clone()); return Result::Complete(i_.clone(), op.clone());
@ -201,34 +200,19 @@ make_fn!(
) )
); );
// TODO(jwall): Change comparison operators to use the do_binary_expr! with precedence?
fn tuple_to_compare_expression(
kind: CompareType,
left: Expression,
right: Expression,
) -> Expression {
let pos = left.pos().clone();
Expression::Compare(ComparisonDef {
kind: kind,
left: Box::new(left),
right: Box::new(right),
pos: pos,
})
}
make_fn!( make_fn!(
compare_op_type<SliceIter<Token>, Element>, compare_op_type<SliceIter<Token>, Element>,
either!( either!(
do_each!(_ => punct!("=="), (Element::CompareOp(CompareType::Equal))), do_each!(_ => punct!("=="), (Element::Op(BinaryExprType::Equal))),
do_each!(_ => punct!("!="), (Element::CompareOp(CompareType::NotEqual))), do_each!(_ => punct!("!="), (Element::Op(BinaryExprType::NotEqual))),
do_each!(_ => punct!("<="), (Element::CompareOp(CompareType::LTEqual))), do_each!(_ => punct!("<="), (Element::Op(BinaryExprType::LTEqual))),
do_each!(_ => punct!(">="), (Element::CompareOp(CompareType::GTEqual))), do_each!(_ => punct!(">="), (Element::Op(BinaryExprType::GTEqual))),
do_each!(_ => punct!("<"), (Element::CompareOp(CompareType::LT))), do_each!(_ => punct!("<"), (Element::Op(BinaryExprType::LT))),
do_each!(_ => punct!(">"), (Element::CompareOp(CompareType::GT))) do_each!(_ => punct!(">"), (Element::Op(BinaryExprType::GT)))
) )
); );
fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, CompareType> { fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
let mut i_ = i.clone(); let mut i_ = i.clone();
if eoi(i_.clone()).is_complete() { if eoi(i_.clone()).is_complete() {
return Result::Fail(Error::new( return Result::Fail(Error::new(
@ -237,8 +221,20 @@ fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, C
)); ));
} }
let el = i_.next(); let el = i_.next();
if let Some(&Element::CompareOp(ref op)) = el { if let Some(&Element::Op(ref op)) = el {
return Result::Complete(i_.clone(), op.clone()); match op {
&BinaryExprType::GT
| &BinaryExprType::GTEqual
| &BinaryExprType::LT
| &BinaryExprType::LTEqual
| &BinaryExprType::NotEqual
| &BinaryExprType::Equal => {
return Result::Complete(i_.clone(), op.clone());
}
_other => {
// noop
}
};
} }
return Result::Fail(Error::new( return Result::Fail(Error::new(
format!( format!(
@ -249,13 +245,19 @@ fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, C
)); ));
} }
make_fn!(
binary_expression<SliceIter<Element>, Expression>,
either!(compare_expression, math_expression, parse_expression)
);
make_fn!( make_fn!(
compare_expression<SliceIter<Element>, Expression>, compare_expression<SliceIter<Element>, Expression>,
do_each!( do_binary_expr!(
left => either!(trace_parse!(math_expression), trace_parse!(parse_expression)), parse_compare_operator,
typ => parse_compare_operator, either!(
right => either!(trace_parse!(math_expression), trace_parse!(parse_expression)), trace_parse!(math_expression),
(tuple_to_compare_expression(typ, left, right)) trace_parse!(parse_expression)
)
) )
); );
@ -340,11 +342,7 @@ pub fn op_expression<'a>(i: SliceIter<'a, Token>) -> Result<SliceIter<Token>, Ex
Result::Incomplete(i) => Result::Incomplete(i), Result::Incomplete(i) => Result::Incomplete(i),
Result::Complete(rest, oplist) => { Result::Complete(rest, oplist) => {
let i_ = SliceIter::new(&oplist); let i_ = SliceIter::new(&oplist);
let parse_result = either!( let parse_result = binary_expression(i_);
i_.clone(),
trace_parse!(compare_expression),
trace_parse!(math_expression)
);
match parse_result { match parse_result {
Result::Fail(_e) => { Result::Fail(_e) => {

View File

@ -619,8 +619,8 @@ fn test_expression_parse() {
); );
assert_parse!( assert_parse!(
expression("1 > 1"), expression("1 > 1"),
Expression::Compare(ComparisonDef { Expression::Binary(BinaryOpDef {
kind: CompareType::GT, kind: BinaryExprType::GT,
left: Box::new(Expression::Simple(Value::Int(value_node!( left: Box::new(Expression::Simple(Value::Int(value_node!(
1, 1,
Position::new(1, 1, 0) Position::new(1, 1, 0)
@ -634,8 +634,8 @@ fn test_expression_parse() {
); );
assert_parse!( assert_parse!(
expression("1 < 1"), expression("1 < 1"),
Expression::Compare(ComparisonDef { Expression::Binary(BinaryOpDef {
kind: CompareType::LT, kind: BinaryExprType::LT,
left: Box::new(Expression::Simple(Value::Int(value_node!( left: Box::new(Expression::Simple(Value::Int(value_node!(
1, 1,
Position::new(1, 1, 0) Position::new(1, 1, 0)
@ -649,8 +649,8 @@ fn test_expression_parse() {
); );
assert_parse!( assert_parse!(
expression("1 <= 1"), expression("1 <= 1"),
Expression::Compare(ComparisonDef { Expression::Binary(BinaryOpDef {
kind: CompareType::LTEqual, kind: BinaryExprType::LTEqual,
left: Box::new(Expression::Simple(Value::Int(value_node!( left: Box::new(Expression::Simple(Value::Int(value_node!(
1, 1,
Position::new(1, 1, 0) Position::new(1, 1, 0)
@ -664,8 +664,8 @@ fn test_expression_parse() {
); );
assert_parse!( assert_parse!(
expression("1 >= 1"), expression("1 >= 1"),
Expression::Compare(ComparisonDef { Expression::Binary(BinaryOpDef {
kind: CompareType::GTEqual, kind: BinaryExprType::GTEqual,
left: Box::new(Expression::Simple(Value::Int(value_node!( left: Box::new(Expression::Simple(Value::Int(value_node!(
1, 1,
Position::new(1, 1, 0) Position::new(1, 1, 0)