diff --git a/schala-lang/language/src/parsing/new_tests.rs b/schala-lang/language/src/parsing/new_tests.rs index fa31bdb..2e90ba2 100644 --- a/schala-lang/language/src/parsing/new_tests.rs +++ b/schala-lang/language/src/parsing/new_tests.rs @@ -85,6 +85,10 @@ macro_rules! qn { }; } +fn int_anno() -> TypeIdentifier { + TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] }) +} + macro_rules! assert_ast { ($input:expr, $statements:expr) => { let ast = parse($input).unwrap(); @@ -325,6 +329,134 @@ fn for_expression() { ); } +#[test] +fn lambda_expressions() { + use ExpressionKind::*; + + assert_expr!( + r#"\(x) { x + 1}"#, + expr(Lambda { + params: vec![FormalParam { name: rc!(x), anno: None, default: None }], + type_anno: None, + body: + vec![stmt(StatementKind::Expression(binop("+", expr(Value(qn!(x))), expr(NatLiteral(1))))),] + .into() + }) + ); + + assert_expr!( + r#"\ (x: Int, y) { a;b;c;}"#, + expr(Lambda { + params: vec![ + FormalParam { name: rc!(x), anno: Some(int_anno()), default: None }, + FormalParam { name: rc!(y), anno: None, default: None }, + ], + type_anno: None, + body: vec![ + stmt(StatementKind::Expression(expr(Value(qn!(a))))), + stmt(StatementKind::Expression(expr(Value(qn!(b))))), + stmt(StatementKind::Expression(expr(Value(qn!(c))))), + ] + .into() + }) + ); + + assert_expr!( + r#"\(x){y}(1)"#, + expr(Call { + f: bx(expr(Lambda { + params: vec![FormalParam { name: rc!(x), anno: None, default: None },], + type_anno: None, + body: vec![stmt(StatementKind::Expression(expr(Value(qn!(y))))),].into() + })), + arguments: vec![InvocationArgument::Positional(expr(NatLiteral(1)))], + }) + ); + + assert_expr!( + r#"\(x: Int): String { "q" }"#, + expr(Lambda { + params: vec![FormalParam { name: rc!(x), anno: Some(int_anno()), default: None },], + type_anno: Some(TypeIdentifier::Singleton(TypeSingletonName { + name: rc("String"), + params: vec![] + })), + body: vec![stmt(StatementKind::Expression(expr(StringLiteral(rc("q"))))),].into() + }) + ); +} + +#[test] +fn single_param_lambda() { + use ExpressionKind::*; + + assert_expr!( + r#"\x { x + 10 }"#, + expr(Lambda { + params: vec![FormalParam { name: rc!(x), anno: None, default: None },], + type_anno: None, + body: vec![stmt(StatementKind::Expression(binop( + "+", + expr(Value(qn!(x))), + expr(NatLiteral(10)) + )))] + .into() + }) + ); + + assert_expr!( + r#"\x: Int { x + 10 }"#, + expr(Lambda { + params: vec![FormalParam { name: rc!(x), anno: Some(int_anno()), default: None },], + type_anno: None, + body: vec![stmt(StatementKind::Expression(binop( + "+", + expr(Value(qn!(x))), + expr(NatLiteral(10)) + )))] + .into() + }) + ); +} + +#[test] +fn complex_lambdas() { + use ExpressionKind::*; + + assert_ast! { + r#"fn wahoo() { let a = 10; \(x) { x + a } }; + wahoo()(3) "#, + vec![ + fn_decl(Signature { name: rc("wahoo"), operator: false, type_anno: None, params: vec![] }, + vec![ + decl(Declaration::Binding { + name: rc("a"), + constant: true, + type_anno: None, + expr: expr(NatLiteral(10)) + }), + stmt(StatementKind::Expression(expr(Lambda { + params: vec![ + FormalParam { name: rc("x"), default: None, anno: None } + ], + type_anno: None, + body: vec![ + stmt(StatementKind::Expression(binop("+", expr(Value(qn!(x))), expr(Value(qn!(a)))))), + ].into() + }))), + ].into()), + stmt(StatementKind::Expression(expr(Call { + f: bx(expr(Call { + f: bx(expr(Value(qn!(wahoo)))), + arguments: vec![] })), + arguments: vec![ + InvocationArgument::Positional(expr(NatLiteral(3))) + ] + }))) + ] + }; +} + #[test] fn reserved_words() { assert_fail!("module::item::call()", "Expected an identifier, got Colon"); @@ -532,7 +664,6 @@ fn functions_with_different_whitespace() { #[test] fn functions_with_default_args() { use ExpressionKind::*; - let int_anno = TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] }); assert_ast!( "fn func(x: Int, y: Int = 4) { }", @@ -542,8 +673,8 @@ fn functions_with_default_args() { operator: false, type_anno: None, params: vec![ - FormalParam { name: rc("x"), anno: Some(int_anno.clone()), default: None }, - FormalParam { name: rc("y"), anno: Some(int_anno), default: Some(expr(NatLiteral(4))) }, + FormalParam { name: rc("x"), anno: Some(int_anno()), default: None }, + FormalParam { name: rc("y"), anno: Some(int_anno()), default: Some(expr(NatLiteral(4))) }, ], }, vec![].into() diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index ffdd2af..c80bcb0 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -2,6 +2,7 @@ #![allow(clippy::upper_case_acronyms)] #![allow(clippy::vec_init_then_push)] +use pretty_assertions::assert_eq; use std::rc::Rc; use crate::tokenizing::Location; @@ -87,10 +88,6 @@ macro_rules! ex { }; } -macro_rules! inv { - ($expr_type:expr) => { InvocationArgument::Positional($expr_type) } -} - macro_rules! exst { ($expr_type:expr) => { make_statement(StatementKind::Expression(Expression::new(Default::default(), $expr_type).into())) }; ($expr_type:expr, $type_anno:expr) => { make_statement(StatementKind::Expression(Expression::with_anno(Default::default(), $expr_type, $type_anno).into())) }; @@ -251,89 +248,6 @@ fn parsing_impls() { })); } -#[test] -fn parsing_lambdas() { - parse_test_wrap_ast! { r#"\(x) { x + 1}"#, exst!( - Lambda { params: vec![FormalParam { name: rc!(x), anno: None, default: None } ], type_anno: None, body: exst!(s "x + 1").into() } - ) - } - - parse_test_wrap_ast!(r#"\ (x: Int, y) { a;b;c;}"#, - exst!(Lambda { - params: vec![ - FormalParam { name: rc!(x), anno: Some(ty!("Int")), default: None }, - FormalParam { name: rc!(y), anno: None, default: None } - ], - type_anno: None, - body: vec![exst!(s "a"), exst!(s "b"), exst!(s "c")].into() - }) - ); - - parse_test_wrap_ast! { r#"\(x){y}(1)"#, - exst!(Call { f: bx!(ex!( - Lambda { - params: vec![ - FormalParam { name: rc!(x), anno: None, default: None } - ], - type_anno: None, - body: exst!(s "y").into() } - )), - arguments: vec![inv!(ex!(NatLiteral(1)))] }) - }; - - parse_test_wrap_ast! { - r#"\(x: Int): String { "q" }"#, - exst!(Lambda { - params: vec![ - FormalParam { name: rc!(x), anno: Some(ty!("Int")), default: None }, - ], - type_anno: Some(ty!("String")), - body: exst!(s r#""q""#).into() - }) - } -} - -#[test] -fn single_param_lambda() { - parse_test_wrap_ast! { - r"\x { x + 10 }", - exst!(Lambda { - params: vec![FormalParam { name: rc!(x), anno: None, default: None }], - type_anno: None, - body: exst!(s r"x + 10").into() - }) - } - - parse_test_wrap_ast! { - r"\x: Nat { x + 10 }", - exst!(Lambda { - params: vec![FormalParam { name: rc!(x), anno: Some(ty!("Nat")), default: None }], - type_anno: None, - body: exst!(s r"x + 10").into() - }) - } -} - -#[test] -fn more_advanced_lambdas() { - parse_test! { - r#"fn wahoo() { let a = 10; \(x) { x + a } }; - wahoo()(3) "#, - AST { - id: Default::default(), - statements: vec![ - exst!(s r"fn wahoo() { let a = 10; \(x) { x + a } }"), - exst! { - Call { - f: bx!(ex!(Call { f: bx!(ex!(val!("wahoo"))), arguments: vec![] })), - arguments: vec![inv!(ex!(NatLiteral(3)))], - } - } - ].into() - } - } -} - #[test] fn list_literals() { parse_test_wrap_ast! {