2025-01-29 16:46:28 +02:00
use super ::* ;
2025-01-31 13:03:38 +02:00
use crate ::compiler ::tokenizer ::tokenize ;
2025-01-29 16:46:28 +02:00
macro_rules ! int_ast {
( $x :expr ) = > {
Box ::new ( IntLiteral ( $x ) )
} ;
}
macro_rules ! id_ast {
( $x :expr ) = > {
Box ::new ( Identifier ( $x ) )
} ;
}
2025-01-31 13:30:05 +02:00
macro_rules ! un_ast {
( $x :expr , $y :expr ) = > {
Box ::new ( UnaryOp ( $x , $y ) )
} ;
}
2025-01-29 16:46:28 +02:00
macro_rules ! bin_ast {
( $x :expr , $y :expr , $z :expr ) = > {
Box ::new ( BinaryOp ( $x , $y , $z ) )
} ;
}
macro_rules ! bool_ast {
( $x :expr ) = > {
Box ::new ( BoolLiteral ( $x ) )
} ;
}
2025-01-29 16:51:33 +02:00
#[ test ]
#[ should_panic ]
fn test_empty ( ) {
parse ( & vec! [ ] ) ;
}
#[ test ]
#[ should_panic ]
fn test_invalid_start ( ) {
2025-01-31 13:03:38 +02:00
parse ( & tokenize ( " 1 2 + 3 " ) ) ;
2025-01-29 16:51:33 +02:00
}
#[ test ]
#[ should_panic ]
fn test_invalid_middle ( ) {
2025-01-31 13:03:38 +02:00
parse ( & tokenize ( " 1 + 2 2 + 3 " ) ) ;
2025-01-29 16:51:33 +02:00
}
#[ test ]
#[ should_panic ]
fn test_invalid_end ( ) {
2025-01-31 13:03:38 +02:00
parse ( & tokenize ( " 1 + 2 3 " ) ) ;
2025-01-29 16:51:33 +02:00
}
2025-01-29 16:46:28 +02:00
#[ test ]
fn test_binary_op_basic ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 + 23 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! ( result , BinaryOp ( int_ast! ( 1 ) , " + " , int_ast! ( 23 ) ) ) ;
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 4 - 56 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! ( result , BinaryOp ( int_ast! ( 4 ) , " - " , int_ast! ( 56 ) ) ) ;
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 * 2 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! ( result , BinaryOp ( int_ast! ( 1 ) , " * " , int_ast! ( 2 ) ) ) ;
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 / 2 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! ( result , BinaryOp ( int_ast! ( 1 ) , " / " , int_ast! ( 2 ) ) ) ;
}
2025-01-31 13:19:40 +02:00
#[ test ]
fn test_binary_op_all_levels ( ) {
let result = parse ( & tokenize ( " 1 * 2 + 3 < 4 == 5 and 6 or 7 " ) ) ;
assert_eq! (
result ,
BinaryOp (
bin_ast! (
bin_ast! (
bin_ast! (
bin_ast! ( bin_ast! ( int_ast! ( 1 ) , " * " , int_ast! ( 2 ) ) , " + " , int_ast! ( 3 ) ) ,
" < " ,
int_ast! ( 4 )
) ,
" == " ,
int_ast! ( 5 )
) ,
" and " ,
int_ast! ( 6 )
) ,
" or " ,
int_ast! ( 7 )
)
) ;
}
2025-01-29 16:46:28 +02:00
#[ test ]
fn test_binary_op_identifier ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " a + 1 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! ( result , BinaryOp ( id_ast! ( " a " ) , " + " , int_ast! ( 1 ) ) ) ;
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 - a " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! ( result , BinaryOp ( int_ast! ( 1 ) , " - " , id_ast! ( " a " ) ) ) ;
}
#[ test ]
fn test_binary_op_multiple ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 + 2 - 3 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
BinaryOp ( bin_ast! ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) ) , " - " , int_ast! ( 3 ) )
) ;
}
#[ test ]
fn test_binary_op_precedence ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 + 2 * 3 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
BinaryOp ( int_ast! ( 1 ) , " + " , bin_ast! ( int_ast! ( 2 ) , " * " , int_ast! ( 3 ) ) , )
) ;
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 - 2 / 3 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
BinaryOp ( int_ast! ( 1 ) , " - " , bin_ast! ( int_ast! ( 2 ) , " / " , int_ast! ( 3 ) ) , )
) ;
}
2025-01-31 13:30:05 +02:00
#[ test ]
2025-01-31 13:58:04 +02:00
fn test_assignment_basic ( ) {
let result = parse ( & tokenize ( " a = 1 + 2 " ) ) ;
assert_eq! (
result ,
BinaryOp ( id_ast! ( " a " ) , " = " , bin_ast! ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) ) )
) ;
}
#[ test ]
fn test_assignment_chain ( ) {
2025-01-31 13:30:05 +02:00
let result = parse ( & tokenize ( " a = b = 1 + 2 " ) ) ;
assert_eq! (
result ,
BinaryOp (
id_ast! ( " a " ) ,
" = " ,
bin_ast! ( id_ast! ( " b " ) , " = " , bin_ast! ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) ) )
)
) ;
}
2025-01-31 14:19:01 +02:00
#[ test ]
#[ should_panic ]
fn test_assignment_invalid ( ) {
parse ( & tokenize ( " a = " ) ) ;
}
2025-01-31 13:30:05 +02:00
#[ test ]
2025-01-31 13:58:04 +02:00
fn test_unary_basic ( ) {
let result = parse ( & tokenize ( " not x " ) ) ;
assert_eq! ( result , UnaryOp ( " not " , id_ast! ( " x " ) ) ) ;
let result = parse ( & tokenize ( " -x " ) ) ;
assert_eq! ( result , UnaryOp ( " - " , id_ast! ( " x " ) ) ) ;
let result = parse ( & tokenize ( " -1 " ) ) ;
assert_eq! ( result , UnaryOp ( " - " , int_ast! ( 1 ) ) ) ;
2025-01-31 14:03:20 +02:00
let result = parse ( & tokenize ( " -1 + 2 " ) ) ;
assert_eq! (
result ,
BinaryOp ( un_ast! ( " - " , int_ast! ( 1 ) ) , " + " , int_ast! ( 2 ) )
) ;
2025-01-31 13:58:04 +02:00
}
#[ test ]
fn test_unary_chain ( ) {
2025-01-31 13:30:05 +02:00
let result = parse ( & tokenize ( " not not x " ) ) ;
assert_eq! ( result , UnaryOp ( " not " , un_ast! ( " not " , id_ast! ( " x " ) ) ) ) ;
let result = parse ( & tokenize ( " --x " ) ) ;
assert_eq! ( result , UnaryOp ( " - " , un_ast! ( " - " , id_ast! ( " x " ) ) ) ) ;
let result = parse ( & tokenize ( " --1 " ) ) ;
assert_eq! ( result , UnaryOp ( " - " , un_ast! ( " - " , int_ast! ( 1 ) ) ) ) ;
2025-01-31 14:03:20 +02:00
let result = parse ( & tokenize ( " --1 + 2 " ) ) ;
assert_eq! (
result ,
BinaryOp ( un_ast! ( " - " , un_ast! ( " - " , int_ast! ( 1 ) ) ) , " + " , int_ast! ( 2 ) )
) ;
2025-01-31 13:30:05 +02:00
}
2025-01-29 16:46:28 +02:00
#[ test ]
fn test_parenthesized ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " (1+2)*3 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
BinaryOp ( bin_ast! ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) ) , " * " , int_ast! ( 3 ) , )
) ;
2025-01-29 16:51:33 +02:00
}
2025-01-29 16:46:28 +02:00
2025-01-29 16:51:33 +02:00
#[ test ]
fn test_parenthesized_nested ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " ((1 - 2))/3 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
BinaryOp ( bin_ast! ( int_ast! ( 1 ) , " - " , int_ast! ( 2 ) ) , " / " , int_ast! ( 3 ) , )
) ;
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " ((1 + 2)*3) / 4 " ) ) ;
assert_eq! (
result ,
BinaryOp (
bin_ast! ( bin_ast! ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) ) , " * " , int_ast! ( 3 ) ) ,
" / " ,
int_ast! ( 4 )
)
) ;
2025-01-29 16:46:28 +02:00
}
2025-01-29 16:51:33 +02:00
#[ test ]
#[ should_panic ]
fn test_parenthesized_mismatched ( ) {
2025-01-31 13:03:38 +02:00
parse ( & tokenize ( " (1+2*3 " ) ) ;
2025-01-29 16:51:33 +02:00
}
2025-01-29 16:46:28 +02:00
#[ test ]
fn test_if_then ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " if 1 + 2 then 3 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
Conditional ( bin_ast! ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) ) , int_ast! ( 3 ) , None , )
) ;
}
#[ test ]
fn test_if_then_else ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " if a then b + c else 1 * 2 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
Conditional (
id_ast! ( " a " ) ,
bin_ast! ( id_ast! ( " b " ) , " + " , id_ast! ( " c " ) ) ,
Some ( bin_ast! ( int_ast! ( 1 ) , " * " , int_ast! ( 2 ) ) )
)
) ;
}
#[ test ]
2025-01-29 16:51:33 +02:00
fn test_if_then_else_embedded ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 + if true then 2 else 3 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
BinaryOp (
int_ast! ( 1 ) ,
" + " ,
Box ::new ( Conditional ( bool_ast! ( true ) , int_ast! ( 2 ) , Some ( int_ast! ( 3 ) ) ) )
)
) ;
}
#[ test ]
2025-01-29 16:51:33 +02:00
fn test_if_then_else_nested ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " if true then if false then 1 else 2 else 3 " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
Conditional (
bool_ast! ( true ) ,
Box ::new ( Conditional (
bool_ast! ( false ) ,
int_ast! ( 1 ) ,
Some ( int_ast! ( 2 ) )
) ) ,
Some ( int_ast! ( 3 ) )
)
) ;
}
2025-01-29 16:51:33 +02:00
#[ test ]
#[ should_panic ]
fn test_if_no_then ( ) {
2025-01-31 13:03:38 +02:00
parse ( & tokenize ( " if true " ) ) ;
2025-01-29 16:51:33 +02:00
}
2025-01-29 16:46:28 +02:00
#[ test ]
fn test_func_basic ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " f(a, b) " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
FunCall ( " f " , vec! [ Identifier ( " a " ) , Identifier ( " b " ) , ] )
) ;
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " f(a, 1 + 2) " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
FunCall (
" f " ,
vec! [ Identifier ( " a " ) , BinaryOp ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) , ) , ]
)
) ;
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " f() " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! ( result , FunCall ( " f " , vec! [ ] ) ) ;
}
#[ test ]
2025-01-29 16:51:33 +02:00
fn test_func_embedded ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " 1 + f(a) " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
2025-01-29 16:51:33 +02:00
BinaryOp (
int_ast! ( 1 ) ,
" + " ,
Box ::new ( FunCall ( " f " , vec! [ Identifier ( " a " ) ] ) )
2025-01-29 16:46:28 +02:00
)
) ;
}
#[ test ]
2025-01-29 16:51:33 +02:00
fn test_func_nested ( ) {
2025-01-31 13:03:38 +02:00
let result = parse ( & tokenize ( " f(a, g(b)) " ) ) ;
2025-01-29 16:46:28 +02:00
assert_eq! (
result ,
2025-01-29 16:51:33 +02:00
FunCall (
" f " ,
vec! [ Identifier ( " a " ) , FunCall ( " g " , vec! [ Identifier ( " b " ) ] ) , ]
2025-01-29 16:46:28 +02:00
)
) ;
}
#[ test ]
#[ should_panic ]
fn test_func_missing_comma ( ) {
2025-01-31 13:03:38 +02:00
parse ( & tokenize ( " f(a b) " ) ) ;
2025-01-29 16:46:28 +02:00
}
#[ test ]
#[ should_panic ]
fn test_func_missing_close ( ) {
2025-01-31 13:03:38 +02:00
parse ( & tokenize ( " f(a " ) ) ;
2025-01-29 16:46:28 +02:00
}
2025-01-31 16:09:47 +02:00
#[ test ]
fn test_block_basic ( ) {
let result = parse ( & tokenize ( " { a = 1; b; } " ) ) ;
assert_eq! (
result ,
Block ( vec! [
BinaryOp ( id_ast! ( " a " ) , " = " , int_ast! ( 1 ) ) ,
Identifier ( " b " ) ,
EmptyLiteral ( )
] )
) ;
let result = parse ( & tokenize ( " { a = 1; b } " ) ) ;
assert_eq! (
result ,
Block ( vec! [
BinaryOp ( id_ast! ( " a " ) , " = " , int_ast! ( 1 ) ) ,
Identifier ( " b " ) ,
] )
) ;
}
#[ test ]
fn test_block_embedded ( ) {
let result = parse ( & tokenize ( " { 1 + 2 } * 3 " ) ) ;
assert_eq! (
result ,
BinaryOp (
Box ::new ( Block ( vec! [ BinaryOp ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) ) ] ) ) ,
" * " ,
int_ast! ( 3 )
)
) ;
}
#[ test ]
fn test_block_nested ( ) {
let result = parse ( & tokenize ( " { a = { 1 + 2}} " ) ) ;
assert_eq! (
result ,
Block ( vec! [ BinaryOp (
id_ast! ( " a " ) ,
" = " ,
Box ::new ( Block ( vec! [ BinaryOp ( int_ast! ( 1 ) , " + " , int_ast! ( 2 ) ) ] ) ) ,
) ] )
) ;
}
#[ test ]
#[ should_panic ]
fn test_block_unmatched ( ) {
parse ( & tokenize ( " { a = 1 " ) ) ;
}
#[ test ]
#[ should_panic ]
fn test_block_missing_semicolon ( ) {
parse ( & tokenize ( " { a = 1 \n b } " ) ) ;
}