diff --git a/src/compiler/ast.rs b/src/compiler/ast.rs index 29c9204..5246da8 100644 --- a/src/compiler/ast.rs +++ b/src/compiler/ast.rs @@ -21,6 +21,11 @@ pub enum Expression<'source> { Box>, Option>>, ), + While( + CodeLocation, + Box>, + Box>, + ), FunCall(CodeLocation, &'source str, Vec>), Block(CodeLocation, Vec>), } @@ -36,6 +41,7 @@ impl<'source> Expression<'source> { Expression::VarDeclaration(loc, _, _) => *loc, Expression::BinaryOp(loc, _, _, _) => *loc, Expression::Conditional(loc, _, _, _) => *loc, + Expression::While(loc, _, _) => *loc, Expression::FunCall(loc, _, _) => *loc, Expression::Block(loc, _) => *loc, } @@ -51,6 +57,7 @@ impl<'source> Expression<'source> { Expression::VarDeclaration(..) => "Variable declaration", Expression::BinaryOp(..) => "Binary operation", Expression::Conditional(..) => "Conditional", + Expression::While(_, _, _) => "While loop", Expression::FunCall(..) => "Function call", Expression::Block(..) => "Block", } @@ -66,6 +73,7 @@ impl<'source> Expression<'source> { Expression::VarDeclaration(_, name, _) => name.to_string(), Expression::BinaryOp(_, _, op, _) => op.to_string(), Expression::Conditional(_, condition, _, _) => format!("if {}", condition), + Expression::While(_, condition, _) => format!("while {}", condition), Expression::FunCall(_, name, args) => format!("{} with {} args", name, args.len()), Expression::Block(_, expressions) => format!("with {} expressions", expressions.len()), } diff --git a/src/compiler/parser/tests.rs b/src/compiler/parser/tests.rs index db123bf..e63ea04 100644 --- a/src/compiler/parser/tests.rs +++ b/src/compiler/parser/tests.rs @@ -109,6 +109,18 @@ macro_rules! var_ast { }; } +macro_rules! while_ast { + ($x:expr, $y:expr) => { + While(CodeLocation::new(usize::MAX, usize::MAX), $x, $y) + }; +} + +macro_rules! while_ast_b { + ($x:expr, $y:expr) => { + Box::new(while_ast!($x, $y)) + }; +} + #[test] #[should_panic] fn test_empty() { @@ -599,3 +611,43 @@ fn test_omitting_semicolons() { fn test_omitting_semicolons_invalid() { parse(&tokenize("{ if true then { a } b c }")); } + +#[test] +fn test_while_do() { + let result = parse(&tokenize("while 1 + 2 do 3")); + assert_eq!( + result, + while_ast!(bin_ast_b!(int_ast_b!(1), "+", int_ast_b!(2)), int_ast_b!(3)) + ); +} + +#[test] +fn test_while_do_embedded() { + let result = parse(&tokenize("1 + while true do 2")); + assert_eq!( + result, + bin_ast!( + int_ast_b!(1), + "+", + while_ast_b!(bool_ast_b!(true), int_ast_b!(2)) + ) + ); +} + +#[test] +fn test_while_do_nested() { + let result = parse(&tokenize("while true do while false do 1")); + assert_eq!( + result, + while_ast!( + bool_ast_b!(true), + while_ast_b!(bool_ast_b!(false), int_ast_b!(1)) + ) + ); +} + +#[test] +#[should_panic] +fn test_while_no_do() { + parse(&tokenize("while true")); +}