From c332747c3eb803adf39d18b120d463bac9cfd30f Mon Sep 17 00:00:00 2001 From: greg Date: Sun, 16 Jun 2019 14:59:11 -0700 Subject: [PATCH] Move parse test code into separate module --- schala-lang/language/src/parsing.rs | 652 +---------------------- schala-lang/language/src/parsing/test.rs | 647 ++++++++++++++++++++++ 2 files changed, 649 insertions(+), 650 deletions(-) create mode 100644 schala-lang/language/src/parsing/test.rs diff --git a/schala-lang/language/src/parsing.rs b/schala-lang/language/src/parsing.rs index 2c4d790..a43378f 100644 --- a/schala-lang/language/src/parsing.rs +++ b/schala-lang/language/src/parsing.rs @@ -142,6 +142,8 @@ //! ``` //! +mod test; + use std::rc::Rc; use crate::tokenizing::*; @@ -1180,653 +1182,3 @@ fn parse_hex(digits: String, tok: Token) -> ParseResult { } Ok(result) } - -#[cfg(test)] -mod parse_tests { - use ::std::rc::Rc; - use super::tokenize; - use super::ParseResult; - use crate::builtin::{PrefixOp, BinOp}; - use crate::ast::{AST, Meta, Expression, Statement, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam}; - use super::Statement::*; - use super::Declaration::*; - use super::Signature; - use super::TypeIdentifier::*; - use super::TypeSingletonName; - use super::ExpressionKind::*; - use super::Variant::*; - use super::ForBody::*; - - fn parse(input: &str) -> ParseResult { - let tokens: Vec = tokenize(input); - let mut parser = super::Parser::new(tokens); - parser.parse() - } - - macro_rules! parse_test { - ($string:expr, $correct:expr) => { assert_eq!(parse($string).unwrap(), $correct) }; - } - macro_rules! parse_test_wrap_ast { - ($string:expr, $correct:expr) => { parse_test!($string, AST(vec![$correct])) } - } - macro_rules! parse_error { - ($string:expr) => { assert!(parse($string).is_err()) } - } - macro_rules! val { - ($var:expr) => { Value(Rc::new($var.to_string())) } - } - macro_rules! ty { - ($name:expr) => { Singleton(tys!($name)) } - } - macro_rules! tys { - ($name:expr) => { TypeSingletonName { name: Rc::new($name.to_string()), params: vec![] } }; - } - - macro_rules! ex { - ($expr_type:expr) => { Expression($expr_type, None) }; - (m $expr_type:expr) => { Meta::new(Expression($expr_type, None)) }; - (m $expr_type:expr, $type_anno:expr) => { Meta::new(Expression($expr_type, Some($type_anno))) }; - (s $expr_text:expr) => { - { - let tokens: Vec = tokenize($expr_text); - let mut parser = super::Parser::new(tokens); - parser.expression().unwrap() - } - }; - } - - macro_rules! inv { - ($expr_type:expr) => { Meta::new(InvocationArgument::Positional($expr_type)) } - } - - macro_rules! binexp { - ($op:expr, $lhs:expr, $rhs:expr) => { BinExp(BinOp::from_sigil($op), bx!(Expression($lhs, None).into()), bx!(Expression($rhs, None).into())) } - } - macro_rules! prefexp { - ($op:expr, $lhs:expr) => { PrefixExp(PrefixOp::from_sigil($op), bx!(Expression($lhs, None).into())) } - } - macro_rules! exst { - ($expr_type:expr) => { Meta::new(Statement::ExpressionStatement(Expression($expr_type, None).into())) }; - ($expr_type:expr, $type_anno:expr) => { Meta::new(Statement::ExpressionStatement(Expression($expr_type, Some($type_anno)).into())) }; - ($op:expr, $lhs:expr, $rhs:expr) => { Meta::new(Statement::ExpressionStatement(ex!(binexp!($op, $lhs, $rhs)))) }; - (s $statement_text:expr) => { - { - let tokens: Vec = tokenize($statement_text); - let mut parser = super::Parser::new(tokens); - Meta::new(parser.statement().unwrap()) - } - } - } - - #[test] - fn parsing_number_literals_and_binexps() { - parse_test_wrap_ast! { ".2", exst!(FloatLiteral(0.2)) }; - parse_test_wrap_ast! { "8.1", exst!(FloatLiteral(8.1)) }; - - parse_test_wrap_ast! { "0b010", exst!(NatLiteral(2)) }; - parse_test_wrap_ast! { "0b0_1_0_", exst!(NatLiteral(2)) } - - parse_test_wrap_ast! {"0xff", exst!(NatLiteral(255)) }; - parse_test_wrap_ast! {"0xf_f_", exst!(NatLiteral(255)) }; - - parse_test_wrap_ast! {"0xf_f_+1", exst!(binexp!("+", NatLiteral(255), NatLiteral(1))) }; - - parse_test! {"3; 4; 4.3", AST( - vec![exst!(NatLiteral(3)), exst!(NatLiteral(4)), - exst!(FloatLiteral(4.3))]) - }; - - parse_test!("1 + 2 * 3", AST(vec! - [ - exst!(binexp!("+", NatLiteral(1), binexp!("*", NatLiteral(2), NatLiteral(3)))) - ])); - - parse_test!("1 * 2 + 3", AST(vec! - [ - exst!(binexp!("+", binexp!("*", NatLiteral(1), NatLiteral(2)), NatLiteral(3))) - ])); - - parse_test!("1 && 2", AST(vec![exst!(binexp!("&&", NatLiteral(1), NatLiteral(2)))])); - - parse_test!("1 + 2 * 3 + 4", AST(vec![exst!( - binexp!("+", - binexp!("+", NatLiteral(1), binexp!("*", NatLiteral(2), NatLiteral(3))), - NatLiteral(4)))])); - - parse_test!("(1 + 2) * 3", AST(vec! - [exst!(binexp!("*", binexp!("+", NatLiteral(1), NatLiteral(2)), NatLiteral(3)))])); - - parse_test!(".1 + .2", AST(vec![exst!(binexp!("+", FloatLiteral(0.1), FloatLiteral(0.2)))])); - parse_test!("1 / 2", AST(vec![exst!(binexp!("/", NatLiteral(1), NatLiteral(2)))])); - } - - #[test] - fn parsing_tuples() { - parse_test!("()", AST(vec![exst!(TupleLiteral(vec![]))])); - parse_test!("(\"hella\", 34)", AST(vec![exst!( - TupleLiteral( - vec![ex!(s r#""hella""#).into(), ex!(s "34").into()] - ) - )])); - parse_test!("((1+2), \"slough\")", AST(vec![exst!(TupleLiteral(vec![ - ex!(binexp!("+", NatLiteral(1), NatLiteral(2))).into(), - ex!(StringLiteral(rc!(slough))).into(), - ]))])) - } - - #[test] - fn parsing_identifiers() { - parse_test!("a", AST(vec![exst!(val!("a"))])); - parse_test!("some_value", AST(vec![exst!(val!("some_value"))])); - parse_test!("a + b", AST(vec![exst!(binexp!("+", val!("a"), val!("b")))])); - //parse_test!("a[b]", AST(vec![Expression( - //parse_test!("a[]", <- TODO THIS NEEDS TO FAIL - //parse_test("a()[b]()[d]") - //TODO fix this parsing stuff - /* - parse_test! { "perspicacity()[a]", AST(vec![ - exst!(Index { - indexee: bx!(ex!(Call { f: bx!(ex!(val!("perspicacity"))), arguments: vec![] })), - indexers: vec![ex!(val!("a"))] - }) - ]) - } - */ - parse_test!("a[b,c]", AST(vec![exst!(Index { indexee: bx!(ex!(m val!("a"))), indexers: vec![ex!(m val!("b")), ex!(m val!("c"))]} )])); - - parse_test!("None", AST(vec![exst!(val!("None"))])); - parse_test!("Pandas { a: x + y }", AST(vec![ - exst!(NamedStruct { name: rc!(Pandas), fields: vec![(rc!(a), ex!(m binexp!("+", val!("x"), val!("y"))))]}) - ])); - parse_test! { "Pandas { a: n, b: q, }", - AST(vec![ - exst!(NamedStruct { name: rc!(Pandas), fields: - vec![(rc!(a), ex!(m val!("n"))), (rc!(b), ex!(m val!("q")))] - } - ) - ]) - }; - } - - #[test] - fn parsing_complicated_operators() { - parse_test!("a <- b", AST(vec![exst!(binexp!("<-", val!("a"), val!("b")))])); - parse_test!("a || b", AST(vec![exst!(binexp!("||", val!("a"), val!("b")))])); - parse_test!("a<>b", AST(vec![exst!(binexp!("<>", val!("a"), val!("b")))])); - parse_test!("a.b.c.d", AST(vec![exst!(binexp!(".", - binexp!(".", - binexp!(".", val!("a"), val!("b")), - val!("c")), - val!("d")))])); - parse_test!("-3", AST(vec![exst!(prefexp!("-", NatLiteral(3)))])); - parse_test!("-0.2", AST(vec![exst!(prefexp!("-", FloatLiteral(0.2)))])); - parse_test!("!3", AST(vec![exst!(prefexp!("!", NatLiteral(3)))])); - parse_test!("a <- -b", AST(vec![exst!(binexp!("<-", val!("a"), prefexp!("-", val!("b"))))])); - parse_test!("a <--b", AST(vec![exst!(binexp!("<--", val!("a"), val!("b")))])); - } - - #[test] - fn parsing_functions() { - parse_test!("fn oi()", AST(vec![Meta::new(Declaration(FuncSig(Signature { name: rc!(oi), operator: false, params: vec![], type_anno: None })))])); - parse_test!("oi()", AST(vec![exst!(Call { f: bx!(ex!(m val!("oi"))), arguments: vec![] })])); - parse_test!("oi(a, 2 + 2)", AST(vec![exst!(Call - { f: bx!(ex!(m val!("oi"))), - arguments: vec![inv!(ex!(val!("a"))).into(), inv!(ex!(binexp!("+", NatLiteral(2), NatLiteral(2)))).into()] - })])); - parse_error!("a(b,,c)"); - - parse_test!("fn a(b, c: Int): Int", AST(vec![Meta::new(Declaration( - FuncSig(Signature { name: rc!(a), operator: false, params: vec![ - FormalParam { name: rc!(b), anno: None, default: None }, - FormalParam { name: rc!(c), anno: Some(ty!("Int")), default: None } - ], type_anno: Some(ty!("Int")) })))])); - - - parse_test!("fn a(x) { x() }", AST(vec![Meta::new(Declaration( - FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), anno: None, default: None }], type_anno: None }, - vec![exst!(Call { f: bx!(ex!(m val!("x"))), arguments: vec![] })])))])); - parse_test!("fn a(x) {\n x() }", AST(vec![Meta::new(Declaration( - FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), anno: None, default: None }], type_anno: None }, - vec![exst!(Call { f: bx!(ex!(m val!("x"))), arguments: vec![] })])))])); - - let multiline = r#" -fn a(x) { - x() -} -"#; - parse_test!(multiline, AST(vec![Meta::new(Declaration( - FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), default: None, anno: None }], type_anno: None }, - vec![exst!(Call { f: bx!(ex!(m val!("x"))), arguments: vec![] })])))])); - let multiline2 = r#" -fn a(x) { - - x() - -} -"#; - parse_test!(multiline2, AST(vec![Meta::new(Declaration( - FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), default: None, anno: None }], type_anno: None }, - vec![exst!(s "x()")])))])); - } - - #[test] - fn parsing_bools() { - parse_test!("false", AST(vec![exst!(BoolLiteral(false))])); - parse_test!("true", AST(vec![exst!(BoolLiteral(true))])); - } - - #[test] - fn parsing_strings() { - parse_test!(r#""hello""#, AST(vec![exst!(StringLiteral(rc!(hello)))])); - } - - #[test] - fn parsing_types() { - parse_test!("type Yolo = Yolo", AST(vec![Meta::new(Declaration(TypeDecl { name: tys!("Yolo"), body: TypeBody(vec![UnitStruct(rc!(Yolo))]), mutable: false} ))])); - parse_test!("type mut Yolo = Yolo", AST(vec![Meta::new(Declaration(TypeDecl { name: tys!("Yolo"), body: TypeBody(vec![UnitStruct(rc!(Yolo))]), mutable: true} ))])); - parse_test!("type alias Sex = Drugs", AST(vec![Meta::new(Declaration(TypeAlias(rc!(Sex), rc!(Drugs))))])); - parse_test!("type Sanchez = Miguel | Alejandro(Int, Option) | Esperanza { a: Int, b: String }", - AST(vec![Meta::new(Declaration(TypeDecl{ - name: tys!("Sanchez"), - body: TypeBody(vec![ - UnitStruct(rc!(Miguel)), - TupleStruct(rc!(Alejandro), vec![ - Singleton(TypeSingletonName { name: rc!(Int), params: vec![] }), - Singleton(TypeSingletonName { name: rc!(Option), params: vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })] }), - ]), - Record{ - name: rc!(Esperanza), - members: vec![ - (rc!(a), Singleton(TypeSingletonName { name: rc!(Int), params: vec![] })), - (rc!(b), Singleton(TypeSingletonName { name: rc!(String), params: vec![] })), - ] - } - ]), - mutable: false - }))])); - - parse_test!("type Jorge = Diego | Kike(a)", AST(vec![ - Meta::new(Declaration(TypeDecl{ - name: TypeSingletonName { name: rc!(Jorge), params: vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })] }, - body: TypeBody(vec![UnitStruct(rc!(Diego)), TupleStruct(rc!(Kike), vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })])]), - mutable: false - } - ))])); - } - - #[test] - fn parsing_bindings() { - parse_test!("let mut a = 10", AST(vec![Meta::new(Declaration(Binding { name: rc!(a), constant: false, type_anno: None, expr: ex!(m NatLiteral(10)) } ))])); - parse_test!("let a = 2 + 2", AST(vec![Meta::new(Declaration(Binding { name: rc!(a), constant: true, type_anno: None, expr: ex!(m binexp!("+", NatLiteral(2), NatLiteral(2))) }) )])); - parse_test!("let a: Nat = 2 + 2", AST(vec![Meta::new(Declaration( - Binding { name: rc!(a), constant: true, type_anno: Some(Singleton(TypeSingletonName { name: rc!(Nat), params: vec![] })), - expr: Meta::new(ex!(binexp!("+", NatLiteral(2), NatLiteral(2)))) } - ))])); - } - - #[test] - fn parsing_block_expressions() { - parse_test! { - "if a() then { b(); c() }", AST(vec![exst!( - IfExpression { - discriminator: bx! { - Discriminator::Simple(ex!(Call { f: bx!(ex!(m val!("a"))), arguments: vec![]})) - }, - body: bx! { - IfExpressionBody::SimpleConditional( - vec![exst!(Call { f: bx!(ex!(m val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(m val!("c"))), arguments: vec![] })], - None - ) - } - } - )]) - }; - - parse_test! { - "if a() then { b(); c() } else { q }", AST(vec![exst!( - IfExpression { - discriminator: bx! { - Discriminator::Simple(ex!(Call { f: bx!(ex!(m val!("a"))), arguments: vec![]})) - }, - body: bx! { - IfExpressionBody::SimpleConditional( - vec![exst!(Call { f: bx!(ex!(m val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(m val!("c"))), arguments: vec![] })], - Some( - vec![exst!(val!("q"))], - ) - ) - } - } - )]) - }; - - /* - parse_test!("if a() then { b(); c() }", AST(vec![exst!( - IfExpression(bx!(ex!(Call { f: bx!(ex!(val!("a"))), arguments: vec![]})), - vec![exst!(Call { f: bx!(ex!(val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(val!("c"))), arguments: vec![] })], - None) - )])); - parse_test!(r#" - if true then { - const a = 10 - b - } else { - c - }"#, - AST(vec![exst!(IfExpression(bx!(ex!(BoolLiteral(true))), - vec![Declaration(Binding { name: rc!(a), constant: true, expr: ex!(NatLiteral(10)) }), - exst!(val!(rc!(b)))], - Some(vec![exst!(val!(rc!(c)))])))]) - ); - - parse_test!("if a { b } else { c }", AST(vec![exst!( - IfExpression(bx!(ex!(val!("a"))), - vec![exst!(val!("b"))], - Some(vec![exst!(val!("c"))])))])); - - parse_test!("if (A {a: 1}) { b } else { c }", AST(vec![exst!( - IfExpression(bx!(ex!(NamedStruct { name: rc!(A), fields: vec![(rc!(a), ex!(NatLiteral(1)))]})), - vec![exst!(val!("b"))], - Some(vec![exst!(val!("c"))])))])); - - parse_error!("if A {a: 1} { b } else { c }"); - */ - } - #[test] - fn parsing_interfaces() { - parse_test!("interface Unglueable { fn unglue(a: Glue); fn mar(): Glue }", AST(vec![ - Meta::new(Declaration(Interface { - name: rc!(Unglueable), - signatures: vec![ - Signature { - name: rc!(unglue), - operator: false, - params: vec![ - FormalParam { name: rc!(a), anno: Some(Singleton(TypeSingletonName { name: rc!(Glue), params: vec![] })), default: None } - ], - type_anno: None - }, - Signature { name: rc!(mar), operator: false, params: vec![], type_anno: Some(Singleton(TypeSingletonName { name: rc!(Glue), params: vec![] })) }, - ] - })) - ])); - } - - #[test] - fn parsing_impls() { - parse_test!("impl Heh { fn yolo(); fn swagg(); }", AST(vec![ - Meta::new( - Declaration(Impl { - type_name: ty!("Heh"), - interface_name: None, - block: vec![ - FuncSig(Signature { name: rc!(yolo), operator: false, params: vec![], type_anno: None }), - FuncSig(Signature { name: rc!(swagg), operator: false, params: vec![], type_anno: None }) - ] }))])); - - parse_test!("impl Mondai for Lollerino { fn yolo(); fn swagg(); }", AST(vec![ - Meta::new(Declaration(Impl { - type_name: ty!("Lollerino"), - interface_name: Some(TypeSingletonName { name: rc!(Mondai), params: vec![] }), - block: vec![ - FuncSig(Signature { name: rc!(yolo), operator: false, params: vec![], type_anno: None}), - FuncSig(Signature { name: rc!(swagg), operator: false, params: vec![], type_anno: None }) - ] }))])); - - parse_test!("impl Hella for (Alpha, Omega) { }", AST(vec![ - Meta::new(Declaration(Impl { - type_name: Tuple(vec![ty!("Alpha"), ty!("Omega")]), - interface_name: Some(TypeSingletonName { name: rc!(Hella), params: vec![ty!("T")] }), - block: vec![] - })) - ])); - - parse_test!("impl Option { fn oi() }", AST(vec![ - Meta::new( - Declaration(Impl { - type_name: Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("WTFMate")]}), - interface_name: None, - block: vec![ - FuncSig(Signature { name: rc!(oi), operator: false, params: vec![], type_anno: None }), - ] - }))])); - } - - #[test] - fn parsing_type_annotations() { - parse_test!("let a = b : Int", AST(vec![ - Meta::new( - Declaration(Binding { name: rc!(a), constant: true, type_anno: None, expr: - ex!(m val!("b"), ty!("Int")) }))])); - - parse_test!("a : Int", AST(vec![ - exst!(val!("a"), ty!("Int")) - ])); - - parse_test!("a : Option", AST(vec![ - exst!(val!("a"), Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("Int")] })) - ])); - - parse_test!("a : KoreanBBQSpecifier >", AST(vec![ - exst!(val!("a"), Singleton(TypeSingletonName { name: rc!(KoreanBBQSpecifier), params: vec![ - ty!("Kimchi"), Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("Bulgogi")] }) - ] })) - ])); - - parse_test!("a : (Int, Yolo)", AST(vec![ - exst!(val!("a"), Tuple( - vec![ty!("Int"), Singleton(TypeSingletonName { - name: rc!(Yolo), params: vec![ty!("a")] - })]))])); - } - - #[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: vec![exst!(s "x + 1")] } - ) - } - - parse_test!(r#"\ (x: Int, y) { a;b;c;}"#, AST(vec![ - 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")] - }) - ])); - - parse_test!(r#"\(x){y}(1)"#, AST(vec![ - exst!(Call { f: bx!(ex!(m - Lambda { - params: vec![ - FormalParam { name: rc!(x), anno: None, default: None } - ], - type_anno: None, - body: vec![exst!(s "y")] } - )), - arguments: vec![inv!(ex!(NatLiteral(1))).into()] })])); - - 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: vec![exst!(s r#""q""#)] - }) - } - } - - #[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: vec![exst!(s r"x + 10")] - }) - } - - 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: vec![exst!(s r"x + 10")] - }) - } - } - - #[test] - fn more_advanced_lambdas() { - parse_test! { - r#"fn wahoo() { let a = 10; \(x) { x + a } }; - wahoo()(3) "#, AST(vec![ - exst!(s r"fn wahoo() { let a = 10; \(x) { x + a } }"), - exst! { - Call { - f: bx!(ex!(m Call { f: bx!(ex!(m val!("wahoo"))), arguments: vec![] })), - arguments: vec![inv!(ex!(NatLiteral(3))).into()], - } - } - ]) - } - } - - #[test] - fn list_literals() { - parse_test! { - "[1,2]", AST(vec![ - exst!(ListLiteral(vec![ex!(m NatLiteral(1)), ex!(m NatLiteral(2))]))]) - }; - } - - #[test] - fn while_expr() { - parse_test! { - "while { }", AST(vec![ - exst!(WhileExpression { condition: None, body: vec![] })]) - } - - parse_test! { - "while a == b { }", AST(vec![ - exst!(WhileExpression { condition: Some(bx![ex![m binexp!("==", val!("a"), val!("b"))]]), body: vec![] })]) - } - } - - #[test] - fn for_expr() { - parse_test! { - "for { a <- maybeValue } return 1", AST(vec![ - exst!(ForExpression { - enumerators: vec![Enumerator { id: rc!(a), generator: ex!(m val!("maybeValue")) }], - body: bx!(MonadicReturn(Meta::new(ex!(s "1")))) - })]) - } - - parse_test! { - "for n <- someRange { f(n); }", AST(vec![ - exst!(ForExpression { enumerators: vec![Enumerator { id: rc!(n), generator: ex!(m val!("someRange"))}], - body: bx!(ForBody::StatementBlock(vec![exst!(s "f(n)")])) - })]) - } - } - - #[test] - fn patterns() { - parse_test_wrap_ast! { - "if x is Some(a) then { 4 } else { 9 }", exst!( - IfExpression { - discriminator: bx!(Discriminator::Simple(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch(Pattern::TupleStruct(rc!(Some), vec![Pattern::Literal(PatternLiteral::VarPattern(rc!(a)))]), vec![exst!(s "4")], Some(vec![exst!(s "9")]))) } - ) - } - - parse_test_wrap_ast! { - "if x is Some(a) then 4 else 9", exst!( - IfExpression { - discriminator: bx!(Discriminator::Simple(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch(Pattern::TupleStruct(rc!(Some), vec![Pattern::Literal(PatternLiteral::VarPattern(rc!(a)))]), vec![exst!(s "4")], Some(vec![exst!(s "9")]))) } - ) - } - - parse_test_wrap_ast! { - "if x is Something { a, b: x } then { 4 } else { 9 }", exst!( - IfExpression { - discriminator: bx!(Discriminator::Simple(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch( - Pattern::Record(rc!(Something), vec![ - (rc!(a),Pattern::Literal(PatternLiteral::StringPattern(rc!(a)))), - (rc!(b),Pattern::Literal(PatternLiteral::VarPattern(rc!(x)))) - ]), - vec![exst!(s "4")], Some(vec![exst!(s "9")]))) - } - ) - } - } - - #[test] - fn pattern_literals() { - parse_test_wrap_ast! { - "if x is -1 then 1 else 2", - exst!( - IfExpression { - discriminator: bx!(Discriminator::Simple(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch( - Pattern::Literal(PatternLiteral::NumPattern { neg: true, num: NatLiteral(1) }), - vec![exst!(NatLiteral(1))], - Some(vec![exst!(NatLiteral(2))]), - )) - } - ) - } - - parse_test_wrap_ast! { - "if x is 1 then 1 else 2", - exst!( - IfExpression { - discriminator: bx!(Discriminator::Simple(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch( - Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(1) }), - vec![exst!(s "1")], - Some(vec![exst!(s "2")]), - )) - } - ) - } - - parse_test! { - "if x is true then 1 else 2", AST(vec![ - exst!( - IfExpression { - discriminator: bx!(Discriminator::Simple(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch( - Pattern::Literal(PatternLiteral::BoolPattern(true)), - vec![exst!(NatLiteral(1))], - Some(vec![exst!(NatLiteral(2))]), - )) - } - ) - ]) - } - - parse_test_wrap_ast! { - "if x is \"gnosticism\" then 1 else 2", - exst!( - IfExpression { - discriminator: bx!(Discriminator::Simple(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch( - Pattern::Literal(PatternLiteral::StringPattern(rc!(gnosticism))), - vec![exst!(s "1")], - Some(vec![exst!(s "2")]), - )) - } - ) - } - } -} diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs new file mode 100644 index 0000000..aae22bf --- /dev/null +++ b/schala-lang/language/src/parsing/test.rs @@ -0,0 +1,647 @@ +#![cfg(test)] +use ::std::rc::Rc; +use super::tokenize; +use super::ParseResult; +use crate::builtin::{PrefixOp, BinOp}; +use crate::ast::{AST, Meta, Expression, Statement, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam}; +use super::Statement::*; +use super::Declaration::*; +use super::Signature; +use super::TypeIdentifier::*; +use super::TypeSingletonName; +use super::ExpressionKind::*; +use super::Variant::*; +use super::ForBody::*; + +fn parse(input: &str) -> ParseResult { + let tokens: Vec = tokenize(input); + let mut parser = super::Parser::new(tokens); + parser.parse() +} + +macro_rules! parse_test { + ($string:expr, $correct:expr) => { assert_eq!(parse($string).unwrap(), $correct) }; +} +macro_rules! parse_test_wrap_ast { + ($string:expr, $correct:expr) => { parse_test!($string, AST(vec![$correct])) } +} +macro_rules! parse_error { + ($string:expr) => { assert!(parse($string).is_err()) } +} +macro_rules! val { + ($var:expr) => { Value(Rc::new($var.to_string())) } +} +macro_rules! ty { + ($name:expr) => { Singleton(tys!($name)) } +} +macro_rules! tys { + ($name:expr) => { TypeSingletonName { name: Rc::new($name.to_string()), params: vec![] } }; +} + +macro_rules! ex { + ($expr_type:expr) => { Expression($expr_type, None) }; + (m $expr_type:expr) => { Meta::new(Expression($expr_type, None)) }; + (m $expr_type:expr, $type_anno:expr) => { Meta::new(Expression($expr_type, Some($type_anno))) }; + (s $expr_text:expr) => { + { + let tokens: Vec = tokenize($expr_text); + let mut parser = super::Parser::new(tokens); + parser.expression().unwrap() + } + }; +} + +macro_rules! inv { + ($expr_type:expr) => { Meta::new(InvocationArgument::Positional($expr_type)) } +} + +macro_rules! binexp { + ($op:expr, $lhs:expr, $rhs:expr) => { BinExp(BinOp::from_sigil($op), bx!(Expression($lhs, None).into()), bx!(Expression($rhs, None).into())) } +} +macro_rules! prefexp { + ($op:expr, $lhs:expr) => { PrefixExp(PrefixOp::from_sigil($op), bx!(Expression($lhs, None).into())) } +} +macro_rules! exst { + ($expr_type:expr) => { Meta::new(Statement::ExpressionStatement(Expression($expr_type, None).into())) }; + ($expr_type:expr, $type_anno:expr) => { Meta::new(Statement::ExpressionStatement(Expression($expr_type, Some($type_anno)).into())) }; + ($op:expr, $lhs:expr, $rhs:expr) => { Meta::new(Statement::ExpressionStatement(ex!(binexp!($op, $lhs, $rhs)))) }; + (s $statement_text:expr) => { + { + let tokens: Vec = tokenize($statement_text); + let mut parser = super::Parser::new(tokens); + Meta::new(parser.statement().unwrap()) + } + } +} + +#[test] +fn parsing_number_literals_and_binexps() { + parse_test_wrap_ast! { ".2", exst!(FloatLiteral(0.2)) }; + parse_test_wrap_ast! { "8.1", exst!(FloatLiteral(8.1)) }; + + parse_test_wrap_ast! { "0b010", exst!(NatLiteral(2)) }; + parse_test_wrap_ast! { "0b0_1_0_", exst!(NatLiteral(2)) } + + parse_test_wrap_ast! {"0xff", exst!(NatLiteral(255)) }; + parse_test_wrap_ast! {"0xf_f_", exst!(NatLiteral(255)) }; + + parse_test_wrap_ast! {"0xf_f_+1", exst!(binexp!("+", NatLiteral(255), NatLiteral(1))) }; + + parse_test! {"3; 4; 4.3", AST( + vec![exst!(NatLiteral(3)), exst!(NatLiteral(4)), + exst!(FloatLiteral(4.3))]) + }; + + parse_test!("1 + 2 * 3", AST(vec! + [ + exst!(binexp!("+", NatLiteral(1), binexp!("*", NatLiteral(2), NatLiteral(3)))) + ])); + + parse_test!("1 * 2 + 3", AST(vec! + [ + exst!(binexp!("+", binexp!("*", NatLiteral(1), NatLiteral(2)), NatLiteral(3))) + ])); + + parse_test!("1 && 2", AST(vec![exst!(binexp!("&&", NatLiteral(1), NatLiteral(2)))])); + + parse_test!("1 + 2 * 3 + 4", AST(vec![exst!( + binexp!("+", + binexp!("+", NatLiteral(1), binexp!("*", NatLiteral(2), NatLiteral(3))), + NatLiteral(4)))])); + + parse_test!("(1 + 2) * 3", AST(vec! + [exst!(binexp!("*", binexp!("+", NatLiteral(1), NatLiteral(2)), NatLiteral(3)))])); + + parse_test!(".1 + .2", AST(vec![exst!(binexp!("+", FloatLiteral(0.1), FloatLiteral(0.2)))])); + parse_test!("1 / 2", AST(vec![exst!(binexp!("/", NatLiteral(1), NatLiteral(2)))])); +} + +#[test] +fn parsing_tuples() { + parse_test!("()", AST(vec![exst!(TupleLiteral(vec![]))])); + parse_test!("(\"hella\", 34)", AST(vec![exst!( + TupleLiteral( + vec![ex!(s r#""hella""#).into(), ex!(s "34").into()] + ) + )])); + parse_test!("((1+2), \"slough\")", AST(vec![exst!(TupleLiteral(vec![ + ex!(binexp!("+", NatLiteral(1), NatLiteral(2))).into(), + ex!(StringLiteral(rc!(slough))).into(), + ]))])) +} + +#[test] +fn parsing_identifiers() { + parse_test!("a", AST(vec![exst!(val!("a"))])); + parse_test!("some_value", AST(vec![exst!(val!("some_value"))])); + parse_test!("a + b", AST(vec![exst!(binexp!("+", val!("a"), val!("b")))])); + //parse_test!("a[b]", AST(vec![Expression( + //parse_test!("a[]", <- TODO THIS NEEDS TO FAIL + //parse_test("a()[b]()[d]") + //TODO fix this parsing stuff + /* + parse_test! { "perspicacity()[a]", AST(vec![ + exst!(Index { + indexee: bx!(ex!(Call { f: bx!(ex!(val!("perspicacity"))), arguments: vec![] })), + indexers: vec![ex!(val!("a"))] + }) + ]) + } + */ + parse_test!("a[b,c]", AST(vec![exst!(Index { indexee: bx!(ex!(m val!("a"))), indexers: vec![ex!(m val!("b")), ex!(m val!("c"))]} )])); + + parse_test!("None", AST(vec![exst!(val!("None"))])); + parse_test!("Pandas { a: x + y }", AST(vec![ + exst!(NamedStruct { name: rc!(Pandas), fields: vec![(rc!(a), ex!(m binexp!("+", val!("x"), val!("y"))))]}) + ])); + parse_test! { "Pandas { a: n, b: q, }", + AST(vec![ + exst!(NamedStruct { name: rc!(Pandas), fields: + vec![(rc!(a), ex!(m val!("n"))), (rc!(b), ex!(m val!("q")))] + } + ) + ]) + }; +} + +#[test] +fn parsing_complicated_operators() { + parse_test!("a <- b", AST(vec![exst!(binexp!("<-", val!("a"), val!("b")))])); + parse_test!("a || b", AST(vec![exst!(binexp!("||", val!("a"), val!("b")))])); + parse_test!("a<>b", AST(vec![exst!(binexp!("<>", val!("a"), val!("b")))])); + parse_test!("a.b.c.d", AST(vec![exst!(binexp!(".", + binexp!(".", + binexp!(".", val!("a"), val!("b")), + val!("c")), + val!("d")))])); + parse_test!("-3", AST(vec![exst!(prefexp!("-", NatLiteral(3)))])); + parse_test!("-0.2", AST(vec![exst!(prefexp!("-", FloatLiteral(0.2)))])); + parse_test!("!3", AST(vec![exst!(prefexp!("!", NatLiteral(3)))])); + parse_test!("a <- -b", AST(vec![exst!(binexp!("<-", val!("a"), prefexp!("-", val!("b"))))])); + parse_test!("a <--b", AST(vec![exst!(binexp!("<--", val!("a"), val!("b")))])); +} + +#[test] +fn parsing_functions() { + parse_test!("fn oi()", AST(vec![Meta::new(Declaration(FuncSig(Signature { name: rc!(oi), operator: false, params: vec![], type_anno: None })))])); + parse_test!("oi()", AST(vec![exst!(Call { f: bx!(ex!(m val!("oi"))), arguments: vec![] })])); + parse_test!("oi(a, 2 + 2)", AST(vec![exst!(Call + { f: bx!(ex!(m val!("oi"))), + arguments: vec![inv!(ex!(val!("a"))).into(), inv!(ex!(binexp!("+", NatLiteral(2), NatLiteral(2)))).into()] + })])); + parse_error!("a(b,,c)"); + + parse_test!("fn a(b, c: Int): Int", AST(vec![Meta::new(Declaration( + FuncSig(Signature { name: rc!(a), operator: false, params: vec![ + FormalParam { name: rc!(b), anno: None, default: None }, + FormalParam { name: rc!(c), anno: Some(ty!("Int")), default: None } + ], type_anno: Some(ty!("Int")) })))])); + + + parse_test!("fn a(x) { x() }", AST(vec![Meta::new(Declaration( + FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), anno: None, default: None }], type_anno: None }, + vec![exst!(Call { f: bx!(ex!(m val!("x"))), arguments: vec![] })])))])); + parse_test!("fn a(x) {\n x() }", AST(vec![Meta::new(Declaration( + FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), anno: None, default: None }], type_anno: None }, + vec![exst!(Call { f: bx!(ex!(m val!("x"))), arguments: vec![] })])))])); + + let multiline = r#" +fn a(x) { +x() +} +"#; + parse_test!(multiline, AST(vec![Meta::new(Declaration( + FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), default: None, anno: None }], type_anno: None }, + vec![exst!(Call { f: bx!(ex!(m val!("x"))), arguments: vec![] })])))])); + let multiline2 = r#" +fn a(x) { + +x() + +} +"#; + parse_test!(multiline2, AST(vec![Meta::new(Declaration( + FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), default: None, anno: None }], type_anno: None }, + vec![exst!(s "x()")])))])); +} + +#[test] +fn parsing_bools() { + parse_test!("false", AST(vec![exst!(BoolLiteral(false))])); + parse_test!("true", AST(vec![exst!(BoolLiteral(true))])); +} + +#[test] +fn parsing_strings() { + parse_test!(r#""hello""#, AST(vec![exst!(StringLiteral(rc!(hello)))])); +} + +#[test] +fn parsing_types() { + parse_test!("type Yolo = Yolo", AST(vec![Meta::new(Declaration(TypeDecl { name: tys!("Yolo"), body: TypeBody(vec![UnitStruct(rc!(Yolo))]), mutable: false} ))])); + parse_test!("type mut Yolo = Yolo", AST(vec![Meta::new(Declaration(TypeDecl { name: tys!("Yolo"), body: TypeBody(vec![UnitStruct(rc!(Yolo))]), mutable: true} ))])); + parse_test!("type alias Sex = Drugs", AST(vec![Meta::new(Declaration(TypeAlias(rc!(Sex), rc!(Drugs))))])); + parse_test!("type Sanchez = Miguel | Alejandro(Int, Option) | Esperanza { a: Int, b: String }", + AST(vec![Meta::new(Declaration(TypeDecl{ + name: tys!("Sanchez"), + body: TypeBody(vec![ + UnitStruct(rc!(Miguel)), + TupleStruct(rc!(Alejandro), vec![ + Singleton(TypeSingletonName { name: rc!(Int), params: vec![] }), + Singleton(TypeSingletonName { name: rc!(Option), params: vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })] }), + ]), + Record{ + name: rc!(Esperanza), + members: vec![ + (rc!(a), Singleton(TypeSingletonName { name: rc!(Int), params: vec![] })), + (rc!(b), Singleton(TypeSingletonName { name: rc!(String), params: vec![] })), + ] + } + ]), + mutable: false + }))])); + + parse_test!("type Jorge = Diego | Kike(a)", AST(vec![ + Meta::new(Declaration(TypeDecl{ + name: TypeSingletonName { name: rc!(Jorge), params: vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })] }, + body: TypeBody(vec![UnitStruct(rc!(Diego)), TupleStruct(rc!(Kike), vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })])]), + mutable: false + } + ))])); +} + +#[test] +fn parsing_bindings() { + parse_test!("let mut a = 10", AST(vec![Meta::new(Declaration(Binding { name: rc!(a), constant: false, type_anno: None, expr: ex!(m NatLiteral(10)) } ))])); + parse_test!("let a = 2 + 2", AST(vec![Meta::new(Declaration(Binding { name: rc!(a), constant: true, type_anno: None, expr: ex!(m binexp!("+", NatLiteral(2), NatLiteral(2))) }) )])); + parse_test!("let a: Nat = 2 + 2", AST(vec![Meta::new(Declaration( + Binding { name: rc!(a), constant: true, type_anno: Some(Singleton(TypeSingletonName { name: rc!(Nat), params: vec![] })), + expr: Meta::new(ex!(binexp!("+", NatLiteral(2), NatLiteral(2)))) } + ))])); +} + +#[test] +fn parsing_block_expressions() { + parse_test! { + "if a() then { b(); c() }", AST(vec![exst!( + IfExpression { + discriminator: bx! { + Discriminator::Simple(ex!(Call { f: bx!(ex!(m val!("a"))), arguments: vec![]})) + }, + body: bx! { + IfExpressionBody::SimpleConditional( + vec![exst!(Call { f: bx!(ex!(m val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(m val!("c"))), arguments: vec![] })], + None + ) + } + } + )]) + }; + + parse_test! { + "if a() then { b(); c() } else { q }", AST(vec![exst!( + IfExpression { + discriminator: bx! { + Discriminator::Simple(ex!(Call { f: bx!(ex!(m val!("a"))), arguments: vec![]})) + }, + body: bx! { + IfExpressionBody::SimpleConditional( + vec![exst!(Call { f: bx!(ex!(m val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(m val!("c"))), arguments: vec![] })], + Some( + vec![exst!(val!("q"))], + ) + ) + } + } + )]) + }; + + /* + parse_test!("if a() then { b(); c() }", AST(vec![exst!( + IfExpression(bx!(ex!(Call { f: bx!(ex!(val!("a"))), arguments: vec![]})), + vec![exst!(Call { f: bx!(ex!(val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(val!("c"))), arguments: vec![] })], + None) + )])); + parse_test!(r#" + if true then { + const a = 10 + b + } else { + c + }"#, + AST(vec![exst!(IfExpression(bx!(ex!(BoolLiteral(true))), + vec![Declaration(Binding { name: rc!(a), constant: true, expr: ex!(NatLiteral(10)) }), + exst!(val!(rc!(b)))], + Some(vec![exst!(val!(rc!(c)))])))]) + ); + + parse_test!("if a { b } else { c }", AST(vec![exst!( + IfExpression(bx!(ex!(val!("a"))), + vec![exst!(val!("b"))], + Some(vec![exst!(val!("c"))])))])); + + parse_test!("if (A {a: 1}) { b } else { c }", AST(vec![exst!( + IfExpression(bx!(ex!(NamedStruct { name: rc!(A), fields: vec![(rc!(a), ex!(NatLiteral(1)))]})), + vec![exst!(val!("b"))], + Some(vec![exst!(val!("c"))])))])); + + parse_error!("if A {a: 1} { b } else { c }"); + */ +} +#[test] +fn parsing_interfaces() { + parse_test!("interface Unglueable { fn unglue(a: Glue); fn mar(): Glue }", AST(vec![ + Meta::new(Declaration(Interface { + name: rc!(Unglueable), + signatures: vec![ + Signature { + name: rc!(unglue), + operator: false, + params: vec![ + FormalParam { name: rc!(a), anno: Some(Singleton(TypeSingletonName { name: rc!(Glue), params: vec![] })), default: None } + ], + type_anno: None + }, + Signature { name: rc!(mar), operator: false, params: vec![], type_anno: Some(Singleton(TypeSingletonName { name: rc!(Glue), params: vec![] })) }, + ] + })) + ])); +} + +#[test] +fn parsing_impls() { + parse_test!("impl Heh { fn yolo(); fn swagg(); }", AST(vec![ + Meta::new( + Declaration(Impl { + type_name: ty!("Heh"), + interface_name: None, + block: vec![ + FuncSig(Signature { name: rc!(yolo), operator: false, params: vec![], type_anno: None }), + FuncSig(Signature { name: rc!(swagg), operator: false, params: vec![], type_anno: None }) + ] }))])); + + parse_test!("impl Mondai for Lollerino { fn yolo(); fn swagg(); }", AST(vec![ + Meta::new(Declaration(Impl { + type_name: ty!("Lollerino"), + interface_name: Some(TypeSingletonName { name: rc!(Mondai), params: vec![] }), + block: vec![ + FuncSig(Signature { name: rc!(yolo), operator: false, params: vec![], type_anno: None}), + FuncSig(Signature { name: rc!(swagg), operator: false, params: vec![], type_anno: None }) + ] }))])); + + parse_test!("impl Hella for (Alpha, Omega) { }", AST(vec![ + Meta::new(Declaration(Impl { + type_name: Tuple(vec![ty!("Alpha"), ty!("Omega")]), + interface_name: Some(TypeSingletonName { name: rc!(Hella), params: vec![ty!("T")] }), + block: vec![] + })) + ])); + + parse_test!("impl Option { fn oi() }", AST(vec![ + Meta::new( + Declaration(Impl { + type_name: Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("WTFMate")]}), + interface_name: None, + block: vec![ + FuncSig(Signature { name: rc!(oi), operator: false, params: vec![], type_anno: None }), + ] + }))])); +} + +#[test] +fn parsing_type_annotations() { + parse_test!("let a = b : Int", AST(vec![ + Meta::new( + Declaration(Binding { name: rc!(a), constant: true, type_anno: None, expr: + ex!(m val!("b"), ty!("Int")) }))])); + + parse_test!("a : Int", AST(vec![ + exst!(val!("a"), ty!("Int")) + ])); + + parse_test!("a : Option", AST(vec![ + exst!(val!("a"), Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("Int")] })) + ])); + + parse_test!("a : KoreanBBQSpecifier >", AST(vec![ + exst!(val!("a"), Singleton(TypeSingletonName { name: rc!(KoreanBBQSpecifier), params: vec![ + ty!("Kimchi"), Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("Bulgogi")] }) + ] })) + ])); + + parse_test!("a : (Int, Yolo)", AST(vec![ + exst!(val!("a"), Tuple( + vec![ty!("Int"), Singleton(TypeSingletonName { + name: rc!(Yolo), params: vec![ty!("a")] + })]))])); +} + +#[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: vec![exst!(s "x + 1")] } + ) + } + + parse_test!(r#"\ (x: Int, y) { a;b;c;}"#, AST(vec![ + 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")] + }) + ])); + + parse_test!(r#"\(x){y}(1)"#, AST(vec![ + exst!(Call { f: bx!(ex!(m + Lambda { + params: vec![ + FormalParam { name: rc!(x), anno: None, default: None } + ], + type_anno: None, + body: vec![exst!(s "y")] } + )), + arguments: vec![inv!(ex!(NatLiteral(1))).into()] })])); + + 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: vec![exst!(s r#""q""#)] + }) + } +} + +#[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: vec![exst!(s r"x + 10")] + }) + } + + 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: vec![exst!(s r"x + 10")] + }) + } +} + +#[test] +fn more_advanced_lambdas() { + parse_test! { + r#"fn wahoo() { let a = 10; \(x) { x + a } }; + wahoo()(3) "#, AST(vec![ + exst!(s r"fn wahoo() { let a = 10; \(x) { x + a } }"), + exst! { + Call { + f: bx!(ex!(m Call { f: bx!(ex!(m val!("wahoo"))), arguments: vec![] })), + arguments: vec![inv!(ex!(NatLiteral(3))).into()], + } + } + ]) + } +} + +#[test] + fn list_literals() { + parse_test! { + "[1,2]", AST(vec![ + exst!(ListLiteral(vec![ex!(m NatLiteral(1)), ex!(m NatLiteral(2))]))]) + }; + } + +#[test] +fn while_expr() { + parse_test! { + "while { }", AST(vec![ + exst!(WhileExpression { condition: None, body: vec![] })]) + } + + parse_test! { + "while a == b { }", AST(vec![ + exst!(WhileExpression { condition: Some(bx![ex![m binexp!("==", val!("a"), val!("b"))]]), body: vec![] })]) + } +} + +#[test] +fn for_expr() { + parse_test! { + "for { a <- maybeValue } return 1", AST(vec![ + exst!(ForExpression { + enumerators: vec![Enumerator { id: rc!(a), generator: ex!(m val!("maybeValue")) }], + body: bx!(MonadicReturn(Meta::new(ex!(s "1")))) + })]) + } + + parse_test! { + "for n <- someRange { f(n); }", AST(vec![ + exst!(ForExpression { enumerators: vec![Enumerator { id: rc!(n), generator: ex!(m val!("someRange"))}], + body: bx!(ForBody::StatementBlock(vec![exst!(s "f(n)")])) + })]) + } +} + +#[test] +fn patterns() { + parse_test_wrap_ast! { + "if x is Some(a) then { 4 } else { 9 }", exst!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(s "x"))), + body: bx!(IfExpressionBody::SimplePatternMatch(Pattern::TupleStruct(rc!(Some), vec![Pattern::Literal(PatternLiteral::VarPattern(rc!(a)))]), vec![exst!(s "4")], Some(vec![exst!(s "9")]))) } + ) + } + + parse_test_wrap_ast! { + "if x is Some(a) then 4 else 9", exst!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(s "x"))), + body: bx!(IfExpressionBody::SimplePatternMatch(Pattern::TupleStruct(rc!(Some), vec![Pattern::Literal(PatternLiteral::VarPattern(rc!(a)))]), vec![exst!(s "4")], Some(vec![exst!(s "9")]))) } + ) + } + + parse_test_wrap_ast! { + "if x is Something { a, b: x } then { 4 } else { 9 }", exst!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(s "x"))), + body: bx!(IfExpressionBody::SimplePatternMatch( + Pattern::Record(rc!(Something), vec![ + (rc!(a),Pattern::Literal(PatternLiteral::StringPattern(rc!(a)))), + (rc!(b),Pattern::Literal(PatternLiteral::VarPattern(rc!(x)))) + ]), + vec![exst!(s "4")], Some(vec![exst!(s "9")]))) + } + ) + } +} + +#[test] +fn pattern_literals() { + parse_test_wrap_ast! { + "if x is -1 then 1 else 2", + exst!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(s "x"))), + body: bx!(IfExpressionBody::SimplePatternMatch( + Pattern::Literal(PatternLiteral::NumPattern { neg: true, num: NatLiteral(1) }), + vec![exst!(NatLiteral(1))], + Some(vec![exst!(NatLiteral(2))]), + )) + } + ) + } + + parse_test_wrap_ast! { + "if x is 1 then 1 else 2", + exst!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(s "x"))), + body: bx!(IfExpressionBody::SimplePatternMatch( + Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(1) }), + vec![exst!(s "1")], + Some(vec![exst!(s "2")]), + )) + } + ) + } + + parse_test! { + "if x is true then 1 else 2", AST(vec![ + exst!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(s "x"))), + body: bx!(IfExpressionBody::SimplePatternMatch( + Pattern::Literal(PatternLiteral::BoolPattern(true)), + vec![exst!(NatLiteral(1))], + Some(vec![exst!(NatLiteral(2))]), + )) + } + ) + ]) + } + + parse_test_wrap_ast! { + "if x is \"gnosticism\" then 1 else 2", + exst!( + IfExpression { + discriminator: bx!(Discriminator::Simple(ex!(s "x"))), + body: bx!(IfExpressionBody::SimplePatternMatch( + Pattern::Literal(PatternLiteral::StringPattern(rc!(gnosticism))), + vec![exst!(s "1")], + Some(vec![exst!(s "2")]), + )) + } + ) + } +}