Skip to content

Commit

Permalink
Allow parentheses in expressions (#148)
Browse files Browse the repository at this point in the history
Closes #66
  • Loading branch information
lethalgem authored Jul 31, 2023
2 parents 4973891 + 8990538 commit ec682b9
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 2 deletions.
1 change: 1 addition & 0 deletions yurtc/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub(super) enum Expr {
tuple: Box<Expr>,
field: Either<usize, Ident>,
},
Parens(Box<Expr>),
}

#[derive(Clone, Debug, PartialEq)]
Expand Down
6 changes: 6 additions & 0 deletions yurtc/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,11 @@ fn expr<'sc>() -> impl Parser<Token<'sc>, ast::Expr, Error = ParseError<'sc>> +
})
.map(ast::Expr::Tuple);

let parens = expr
.clone()
.delimited_by(just(Token::ParenOpen), just(Token::ParenClose))
.map(|expr| ast::Expr::Parens(Box::new(expr)));

let atom = choice((
immediate().map(ast::Expr::Immediate),
unary_op(expr.clone()),
Expand All @@ -303,6 +308,7 @@ fn expr<'sc>() -> impl Parser<Token<'sc>, ast::Expr, Error = ParseError<'sc>> +
cond_expr(expr.clone()),
call,
tuple,
parens,
ident().map(ast::Expr::Ident),
));

Expand Down
96 changes: 94 additions & 2 deletions yurtc/src/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,98 @@ fn complex_exprs() {
);
}

#[test]
fn parens_exprs() {
check(
&run_parser!(expr(), "(1 + 2) * 3"),
expect_test::expect!["BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(1)), rhs: Immediate(Int(2)) }), rhs: Immediate(Int(3)) }"],
);
check(
&run_parser!(expr(), "1 * (2 + 3)"),
expect_test::expect!["BinaryOp { op: Mul, lhs: Immediate(Int(1)), rhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(2)), rhs: Immediate(Int(3)) }) }"],
);
check(
&run_parser!(expr(), "(1 + 2) * (3 + 4)"),
expect_test::expect!["BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(1)), rhs: Immediate(Int(2)) }), rhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(3)), rhs: Immediate(Int(4)) }) }"],
);
check(
&run_parser!(expr(), "(1 + (2 * 3)) * 4"),
expect_test::expect!["BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(1)), rhs: Parens(BinaryOp { op: Mul, lhs: Immediate(Int(2)), rhs: Immediate(Int(3)) }) }), rhs: Immediate(Int(4)) }"],
);
check(
&run_parser!(expr(), "(1 * (2 + 3)) * 4"),
expect_test::expect!["BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Mul, lhs: Immediate(Int(1)), rhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(2)), rhs: Immediate(Int(3)) }) }), rhs: Immediate(Int(4)) }"],
);
check(
&run_parser!(expr(), "((1 + 2) * 3) * 4"),
expect_test::expect!["BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(1)), rhs: Immediate(Int(2)) }), rhs: Immediate(Int(3)) }), rhs: Immediate(Int(4)) }"],
);
check(
&run_parser!(expr(), "((1 + 2) * (3 + 4)) * 5"),
expect_test::expect!["BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(1)), rhs: Immediate(Int(2)) }), rhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(3)), rhs: Immediate(Int(4)) }) }), rhs: Immediate(Int(5)) }"],
);
check(
&run_parser!(expr(), "(1 + 2) * 3 / 4"),
expect_test::expect!["BinaryOp { op: Div, lhs: BinaryOp { op: Mul, lhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(1)), rhs: Immediate(Int(2)) }), rhs: Immediate(Int(3)) }, rhs: Immediate(Int(4)) }"],
);
check(
&run_parser!(expr(), "1 / (2 + 3) * 4"),
expect_test::expect!["BinaryOp { op: Mul, lhs: BinaryOp { op: Div, lhs: Immediate(Int(1)), rhs: Parens(BinaryOp { op: Add, lhs: Immediate(Int(2)), rhs: Immediate(Int(3)) }) }, rhs: Immediate(Int(4)) }"],
);
check(
&run_parser!(expr(), "(1 < 2) && (3 > 4)"),
expect_test::expect!["BinaryOp { op: LogicalAnd, lhs: Parens(BinaryOp { op: LessThan, lhs: Immediate(Int(1)), rhs: Immediate(Int(2)) }), rhs: Parens(BinaryOp { op: GreaterThan, lhs: Immediate(Int(3)), rhs: Immediate(Int(4)) }) }"],
);
check(
&run_parser!(expr(), "(1 == 2) || (3 != 4)"),
expect_test::expect!["BinaryOp { op: LogicalOr, lhs: Parens(BinaryOp { op: Equal, lhs: Immediate(Int(1)), rhs: Immediate(Int(2)) }), rhs: Parens(BinaryOp { op: NotEqual, lhs: Immediate(Int(3)), rhs: Immediate(Int(4)) }) }"],
);
check(
&run_parser!(expr(), "1 < (2 && 3) > 4"),
expect_test::expect!["BinaryOp { op: GreaterThan, lhs: BinaryOp { op: LessThan, lhs: Immediate(Int(1)), rhs: Parens(BinaryOp { op: LogicalAnd, lhs: Immediate(Int(2)), rhs: Immediate(Int(3)) }) }, rhs: Immediate(Int(4)) }"],
);
check(
&run_parser!(expr(), "1 && (2 || 3)"),
expect_test::expect!["BinaryOp { op: LogicalAnd, lhs: Immediate(Int(1)), rhs: Parens(BinaryOp { op: LogicalOr, lhs: Immediate(Int(2)), rhs: Immediate(Int(3)) }) }"],
);
check(
&run_parser!(expr(), "1 == (2 || 3) != 4"),
expect_test::expect!["BinaryOp { op: NotEqual, lhs: BinaryOp { op: Equal, lhs: Immediate(Int(1)), rhs: Parens(BinaryOp { op: LogicalOr, lhs: Immediate(Int(2)), rhs: Immediate(Int(3)) }) }, rhs: Immediate(Int(4)) }"],
);
check(
&run_parser!(expr(), "-(1 + 2)"),
expect_test::expect!["UnaryOp { op: Neg, expr: Parens(BinaryOp { op: Add, lhs: Immediate(Int(1)), rhs: Immediate(Int(2)) }) }"],
);
check(
&run_parser!(expr(), "!(a < b)"),
expect_test::expect!["UnaryOp { op: Not, expr: Parens(BinaryOp { op: LessThan, lhs: Ident(Ident(\"a\")), rhs: Ident(Ident(\"b\")) }) }"],
);
check(
&run_parser!(expr(), "(1)"),
expect_test::expect!["Parens(Immediate(Int(1)))"],
);
check(
&run_parser!(expr(), "(a)"),
expect_test::expect!["Parens(Ident(Ident(\"a\")))"],
);
check(
&run_parser!(expr(), "()"),
expect_test::expect![[r#"
@1..2: found ")" but expected "!", "+", "-", "{", "{", "(", "if", or "cond"
"#]],
);
check(
&run_parser!(expr(), "(if a < b { 1 } else { 2 })"),
expect_test::expect![[r#"
Parens(If(IfExpr { condition: BinaryOp { op: LessThan, lhs: Ident(Ident("a")), rhs: Ident(Ident("b")) }, then_block: Block { statements: [], final_expr: Immediate(Int(1)) }, else_block: Block { statements: [], final_expr: Immediate(Int(2)) } }))"#]],
);
check(
&run_parser!(expr(), "(foo(a, b, c))"),
expect_test::expect![[r#"
Parens(Call { name: Ident("foo"), args: [Ident(Ident("a")), Ident(Ident("b")), Ident(Ident("c"))] })"#]],
);
}

#[test]
fn idents() {
check(
Expand Down Expand Up @@ -964,7 +1056,7 @@ fn cond_exprs() {
check(
&run_parser!(cond_expr(expr()), r#"cond { a => b, }"#),
expect_test::expect![[r#"
@15..16: found "}" but expected "!", "+", "-", "{", "{", "if", "else", or "cond"
@15..16: found "}" but expected "!", "+", "-", "{", "{", "(", "if", "else", or "cond"
"#]],
);

Expand Down Expand Up @@ -1019,7 +1111,7 @@ fn fn_errors() {
check(
&run_parser!(yurt_program(), "fn foo() -> real {}"),
expect_test::expect![[r#"
@18..19: found "}" but expected "!", "+", "-", "{", "{", "if", "cond", "let", or "constraint"
@18..19: found "}" but expected "!", "+", "-", "{", "{", "(", "if", "cond", "let", or "constraint"
"#]],
);
}
Expand Down

0 comments on commit ec682b9

Please sign in to comment.