mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: Proper precendence for math operators.
Using nested combinators for enforce parsing precedence.
This commit is contained in:
parent
00c1e1751a
commit
05f6597f00
@ -1193,7 +1193,8 @@ mod compile_test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_binary_operator_precedence() {
|
fn test_binary_operator_precedence() {
|
||||||
assert_build("let result = 2 * 2 + 1;", "result == 6;");
|
//assert_build("let result = 2 * 2 + 1;", "result == 6;");
|
||||||
|
assert_build("let result = 2 + 2 * 1;", "result == 4;");
|
||||||
assert_build("let result = (2 * 2) + 1;", "result == 5;");
|
assert_build("let result = (2 * 2) + 1;", "result == 5;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
142
src/parse.rs
142
src/parse.rs
@ -249,14 +249,25 @@ fn tuple_to_binary_expression(
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// do_binary_expr implements precedence based parsing where the more tightly bound parsers
|
||||||
|
/// are passed in as lowerrule parsers. We default to grouped_expression and simple_expression as
|
||||||
|
/// the most tightly bound expressions.
|
||||||
macro_rules! do_binary_expr {
|
macro_rules! do_binary_expr {
|
||||||
($i:expr, $subrule:ident!( $($args:tt)* ), $typ:expr) => {
|
($i:expr, $oprule:ident!( $($args:tt)* ), $typ:expr) => {
|
||||||
|
do_binary_expr!($i, $oprule!($($args)*), $typ, alt!(grouped_expression | simple_expression))
|
||||||
|
};
|
||||||
|
|
||||||
|
($i:expr, $oprule:ident!( $($args:tt)* ), $typ:expr, $lowerrule:ident) => {
|
||||||
|
do_binary_expr!($i, $oprule!($($args)*), $typ, call!($lowerrule))
|
||||||
|
};
|
||||||
|
|
||||||
|
($i:expr, $oprule:ident!( $($args:tt)* ), $typ:expr, $lowerrule:ident!( $($lowerargs:tt)* )) => {
|
||||||
map_res!($i,
|
map_res!($i,
|
||||||
do_parse!(
|
do_parse!(
|
||||||
pos: pos >>
|
pos: pos >>
|
||||||
left: alt!(simple_expression | grouped_expression) >>
|
left: $lowerrule!($($lowerargs)*) >>
|
||||||
$subrule!($($args)*) >>
|
$oprule!($($args)*) >>
|
||||||
right: expression >>
|
right: $lowerrule!($($lowerargs)*) >>
|
||||||
(pos, $typ, left, right)
|
(pos, $typ, left, right)
|
||||||
),
|
),
|
||||||
tuple_to_binary_expression
|
tuple_to_binary_expression
|
||||||
@ -264,14 +275,26 @@ macro_rules! do_binary_expr {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
named!(math_expression<TokenIter, Expression, error::Error>,
|
||||||
|
alt!(sum_expression | product_expression)
|
||||||
|
);
|
||||||
|
|
||||||
|
named!(sum_expression<TokenIter, Expression, error::Error>,
|
||||||
|
alt!(add_expression | sub_expression)
|
||||||
|
);
|
||||||
|
|
||||||
// trace_macros!(true);
|
// trace_macros!(true);
|
||||||
named!(add_expression<TokenIter, Expression, error::Error>,
|
named!(add_expression<TokenIter, Expression, error::Error>,
|
||||||
do_binary_expr!(punct!("+"), BinaryExprType::Add)
|
do_binary_expr!(punct!("+"), BinaryExprType::Add, alt!(product_expression | simple_expression | grouped_expression))
|
||||||
);
|
);
|
||||||
// trace_macros!(false);
|
// trace_macros!(false);
|
||||||
|
|
||||||
named!(sub_expression<TokenIter, Expression, error::Error>,
|
named!(sub_expression<TokenIter, Expression, error::Error>,
|
||||||
do_binary_expr!(punct!("-"), BinaryExprType::Sub)
|
do_binary_expr!(punct!("-"), BinaryExprType::Sub, alt!(product_expression | simple_expression | grouped_expression))
|
||||||
|
);
|
||||||
|
|
||||||
|
named!(product_expression<TokenIter, Expression, error::Error>,
|
||||||
|
alt!(mul_expression | div_expression)
|
||||||
);
|
);
|
||||||
|
|
||||||
named!(mul_expression<TokenIter, Expression, error::Error>,
|
named!(mul_expression<TokenIter, Expression, error::Error>,
|
||||||
@ -282,6 +305,7 @@ named!(div_expression<TokenIter, Expression, error::Error>,
|
|||||||
do_binary_expr!(punct!("/"), BinaryExprType::Div)
|
do_binary_expr!(punct!("/"), BinaryExprType::Div)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO(jwall): Change comparison operators to use the do_binary_expr! with precedence?
|
||||||
fn tuple_to_compare_expression(
|
fn tuple_to_compare_expression(
|
||||||
tpl: (Position, CompareType, Expression, Expression),
|
tpl: (Position, CompareType, Expression, Expression),
|
||||||
) -> ParseResult<Expression> {
|
) -> ParseResult<Expression> {
|
||||||
@ -298,7 +322,7 @@ macro_rules! do_compare_expr {
|
|||||||
map_res!($i,
|
map_res!($i,
|
||||||
do_parse!(
|
do_parse!(
|
||||||
pos: pos >>
|
pos: pos >>
|
||||||
left: alt!(simple_expression | grouped_expression) >>
|
left: alt!(simple_expression | grouped_expression | math_expression) >>
|
||||||
$subrule!($($args)*) >>
|
$subrule!($($args)*) >>
|
||||||
right: expression >>
|
right: expression >>
|
||||||
(pos, $typ, left, right)
|
(pos, $typ, left, right)
|
||||||
@ -694,22 +718,19 @@ named!(expression<TokenIter, Expression, error::Error>,
|
|||||||
do_parse!(
|
do_parse!(
|
||||||
expr: alt!(
|
expr: alt!(
|
||||||
complete!(list_op_expression) |
|
complete!(list_op_expression) |
|
||||||
complete!(add_expression) |
|
complete!(math_expression) |
|
||||||
complete!(sub_expression) |
|
|
||||||
complete!(mul_expression) |
|
|
||||||
complete!(div_expression) |
|
|
||||||
complete!(eqeq_expression) |
|
complete!(eqeq_expression) |
|
||||||
complete!(not_eqeq_expression) |
|
complete!(not_eqeq_expression) |
|
||||||
complete!(lt_eqeq_expression) |
|
complete!(lt_eqeq_expression) |
|
||||||
complete!(gt_eqeq_expression) |
|
complete!(gt_eqeq_expression) |
|
||||||
complete!(gt_expression) |
|
complete!(gt_expression) |
|
||||||
complete!(lt_expression) |
|
complete!(lt_expression) |
|
||||||
complete!(grouped_expression) |
|
|
||||||
complete!(macro_expression) |
|
complete!(macro_expression) |
|
||||||
complete!(format_expression) |
|
complete!(format_expression) |
|
||||||
complete!(select_expression) |
|
complete!(select_expression) |
|
||||||
complete!(call_expression) |
|
complete!(call_expression) |
|
||||||
complete!(copy_expression) |
|
complete!(copy_expression) |
|
||||||
|
complete!(grouped_expression) |
|
||||||
simple_expression
|
simple_expression
|
||||||
) >>
|
) >>
|
||||||
(expr)
|
(expr)
|
||||||
@ -973,6 +994,62 @@ mod test {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_parse!(
|
||||||
|
statement("let foo = 1 + 1 * 2;"),
|
||||||
|
Statement::Let(LetDef {
|
||||||
|
name: make_tok!("foo", 1, 5),
|
||||||
|
value: Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Add,
|
||||||
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 11)))),
|
||||||
|
right: Box::new(Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Mul,
|
||||||
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 15)))),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 19)))),
|
||||||
|
pos: Position::new(1, 15),
|
||||||
|
})),
|
||||||
|
pos: Position::new(1, 11),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_parse!(
|
||||||
|
statement("let foo = (1 + 1) * 2;"),
|
||||||
|
Statement::Let(LetDef {
|
||||||
|
name: make_tok!("foo", 1, 5),
|
||||||
|
value: Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Mul,
|
||||||
|
left: Box::new(Expression::Grouped(Box::new(Expression::Binary(
|
||||||
|
BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Add,
|
||||||
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 12)))),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 16)))),
|
||||||
|
pos: Position::new(1, 12),
|
||||||
|
},
|
||||||
|
)))),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 21)))),
|
||||||
|
pos: Position::new(1, 11),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_parse!(
|
||||||
|
statement("let foo = 1 * 1 + 2;"),
|
||||||
|
Statement::Let(LetDef {
|
||||||
|
name: make_tok!("foo", 1, 5),
|
||||||
|
value: Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Add,
|
||||||
|
left: Box::new(Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Mul,
|
||||||
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 11)))),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 15)))),
|
||||||
|
pos: Position::new(1, 11),
|
||||||
|
})),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 19)))),
|
||||||
|
pos: Position::new(1, 11),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
assert_parse!(
|
assert_parse!(
|
||||||
statement("// comment\nlet foo = 1.0 ;"),
|
statement("// comment\nlet foo = 1.0 ;"),
|
||||||
Statement::Let(LetDef {
|
Statement::Let(LetDef {
|
||||||
@ -1150,7 +1227,7 @@ mod test {
|
|||||||
1, 1)))
|
1, 1)))
|
||||||
);
|
);
|
||||||
assert_parse!(
|
assert_parse!(
|
||||||
expression("1 + 1"),
|
math_expression("1 + 1"),
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
@ -1185,6 +1262,45 @@ mod test {
|
|||||||
pos: Position::new(1, 1),
|
pos: Position::new(1, 1),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
assert_parse!(
|
||||||
|
expression("(1 / 1)"),
|
||||||
|
Expression::Grouped(Box::new(Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Div,
|
||||||
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 2)))),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 6)))),
|
||||||
|
pos: Position::new(1, 2),
|
||||||
|
})))
|
||||||
|
);
|
||||||
|
assert_parse!(
|
||||||
|
expression("1 / 1 + 1"),
|
||||||
|
Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Add,
|
||||||
|
left: Box::new(Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Div,
|
||||||
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 5)))),
|
||||||
|
pos: Position::new(1, 1),
|
||||||
|
})),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 9)))),
|
||||||
|
pos: Position::new(1, 1),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assert_parse!(
|
||||||
|
expression("(1 + 1) * 1"),
|
||||||
|
Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Mul,
|
||||||
|
left: Box::new(Expression::Grouped(Box::new(Expression::Binary(
|
||||||
|
BinaryOpDef {
|
||||||
|
kind: BinaryExprType::Add,
|
||||||
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 2)))),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 6)))),
|
||||||
|
pos: Position::new(1, 2),
|
||||||
|
}
|
||||||
|
)))),
|
||||||
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 11)))),
|
||||||
|
pos: Position::new(1, 1),
|
||||||
|
})
|
||||||
|
);
|
||||||
assert_parse!(
|
assert_parse!(
|
||||||
expression("1 > 1"),
|
expression("1 > 1"),
|
||||||
Expression::Compare(ComparisonDef {
|
Expression::Compare(ComparisonDef {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user