diff --git a/schala-lang/language/src/ast/mod.rs b/schala-lang/language/src/ast/mod.rs index 55eaef9..6078bd2 100644 --- a/schala-lang/language/src/ast/mod.rs +++ b/schala-lang/language/src/ast/mod.rs @@ -117,7 +117,7 @@ pub enum Declaration { FuncSig(Signature), FuncDecl(Signature, Block), TypeDecl { name: TypeSingletonName, body: TypeBody, mutable: bool }, - //TODO this needs to be more sophisticated + //TODO TypeAlias `original` needs to be a more complex type definition TypeAlias { alias: Rc, original: Rc }, Binding { name: Rc, constant: bool, type_anno: Option, expr: Expression }, Impl { type_name: TypeIdentifier, interface_name: Option, block: Vec }, @@ -133,6 +133,7 @@ pub struct Signature { pub type_anno: Option, } +//TODO I can probably get rid of TypeBody #[derive(Debug, PartialEq, Clone)] pub struct TypeBody(pub Vec); @@ -158,6 +159,7 @@ pub struct Expression { #[derivative(PartialEq = "ignore")] pub id: ItemId, pub kind: ExpressionKind, + //TODO this should only allow singletons, not tuples pub type_anno: Option, } diff --git a/schala-lang/language/src/parsing/mod.rs b/schala-lang/language/src/parsing/mod.rs index e668561..9636c37 100644 --- a/schala-lang/language/src/parsing/mod.rs +++ b/schala-lang/language/src/parsing/mod.rs @@ -689,6 +689,13 @@ impl Parser { #[recursive_descent_method] fn prefix_expr(&mut self) -> ParseResult { + loop { + match self.token_handler.peek_kind() { + Semicolon | Newline => { self.token_handler.next(); }, + _ => break, + } + } + match self.token_handler.peek_kind() { Operator(ref op) if PrefixOp::is_prefix(&*op) => { let sigil = match self.token_handler.next().kind { diff --git a/schala-lang/language/src/parsing/new_tests.rs b/schala-lang/language/src/parsing/new_tests.rs index eb5969b..1ea2899 100644 --- a/schala-lang/language/src/parsing/new_tests.rs +++ b/schala-lang/language/src/parsing/new_tests.rs @@ -33,6 +33,14 @@ fn stmt(kind: StatementKind) -> Statement { Statement { location: Location::default(), id: ItemId::default(), kind } } +fn exst(kind: ExpressionKind) -> Statement { + Statement { + location: Location::default(), + id: ItemId::default(), + kind: StatementKind::Expression(expr(kind)), + } +} + fn decl(declaration: Declaration) -> Statement { Statement { location: Location::default(), @@ -85,8 +93,8 @@ macro_rules! qn { }; } -fn int_anno() -> TypeIdentifier { - TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] }) +fn ty_simple(name: &str) -> TypeIdentifier { + TypeIdentifier::Singleton(TypeSingletonName { name: rc(name), params: vec![] }) } macro_rules! assert_ast { @@ -136,6 +144,14 @@ fn basic_literals() { assert_expr!(r#""hello""#, expr(StringLiteral(rc("hello")))); } +#[test] +fn list_literals() { + use ExpressionKind::*; + + assert_expr!("[]", expr(ListLiteral(vec![]))); + assert_expr!("[1,2]", expr(ListLiteral(vec![expr(NatLiteral(1)), expr(NatLiteral(2)),]))); +} + #[test] fn binexps() { use ExpressionKind::*; @@ -374,7 +390,7 @@ fn lambda_expressions() { r#"\ (x: Int, y) { a;b;c;}"#, expr(Lambda { params: vec![ - FormalParam { name: rc!(x), anno: Some(int_anno()), default: None }, + FormalParam { name: rc!(x), anno: Some(ty_simple("Int")), default: None }, FormalParam { name: rc!(y), anno: None, default: None }, ], type_anno: None, @@ -402,7 +418,7 @@ fn lambda_expressions() { assert_expr!( r#"\(x: Int): String { "q" }"#, expr(Lambda { - params: vec![FormalParam { name: rc!(x), anno: Some(int_anno()), default: None },], + params: vec![FormalParam { name: rc!(x), anno: Some(ty_simple("Int")), default: None },], type_anno: Some(TypeIdentifier::Singleton(TypeSingletonName { name: rc("String"), params: vec![] @@ -433,7 +449,7 @@ fn single_param_lambda() { assert_expr!( r#"\x: Int { x + 10 }"#, expr(Lambda { - params: vec![FormalParam { name: rc!(x), anno: Some(int_anno()), default: None },], + params: vec![FormalParam { name: rc!(x), anno: Some(ty_simple("Int")), default: None },], type_anno: None, body: vec![stmt(StatementKind::Expression(binop( "+", @@ -548,18 +564,131 @@ fn type_annotations() { ); } +#[test] +fn type_declarations() { + use Declaration::TypeDecl; + assert_ast! { + "type Alpha = Alpha", vec![ + decl(TypeDecl { + name: TypeSingletonName { name: rc("Alpha"), params: vec![] }, + mutable: false, + body: TypeBody(vec![ + Variant { + id: Default::default(), + name: rc("Alpha"), + kind: VariantKind::UnitStruct + } + ]) + }) + ] + }; + + assert_ast!( + "type mut Kuah = Kuah", + decl(TypeDecl { + name: TypeSingletonName { name: rc("Kuah"), params: vec![] }, + mutable: true, + body: TypeBody(vec![Variant { + id: Default::default(), + name: rc("Kuah"), + kind: VariantKind::UnitStruct + }]) + }) + ); + + //TODO support this + let specs = ["type Alpha = Alpha { a: Int, b: Int }" /* "type Alpha = { a: Int, b: Int }"*/]; + for spec in specs { + assert_ast! { + spec, vec![decl(TypeDecl { + name: TypeSingletonName { name: rc("Alpha"), params: vec![] }, + mutable: false, + body: TypeBody(vec![ + Variant { + id: Default::default(), + name: rc("Alpha"), + kind: VariantKind::Record(vec![ + (rc("a"), ty_simple("Int")), + (rc("b"), ty_simple("Int")) + ]) + } + ]) + })] + }; + } + + assert_ast!( + "type Option = None | Some(T)", + vec![decl(TypeDecl { + name: TypeSingletonName { + name: rc("Option"), + params: vec![TypeIdentifier::Singleton(TypeSingletonName { name: rc("T"), params: vec![] })] + }, + mutable: false, + body: TypeBody(vec![ + Variant { id: Default::default(), name: rc("None"), kind: VariantKind::UnitStruct }, + Variant { + id: Default::default(), + name: rc("Some"), + kind: VariantKind::TupleStruct(vec![TypeIdentifier::Singleton(TypeSingletonName { + name: rc("T"), + params: vec![] + })]) + }, + ]) + })] + ); + + assert_ast!( + "type alias Alpha = Beta", + decl(Declaration::TypeAlias { alias: rc("Alpha"), original: rc("Beta") }) + ); + + assert_ast!("type Complex = Unit | Record { field: AnotherType, field2: (Nat, Int), field3: T } | Tuple(Int, (String, T))", + decl(TypeDecl { + name: TypeSingletonName { name: rc("Complex"), params: vec![ + TypeIdentifier::Singleton(TypeSingletonName { name: rc("T"), params: vec![] }), + TypeIdentifier::Singleton(TypeSingletonName { name: rc("U"), params: vec![] }), + ] }, + mutable: false, + body: TypeBody(vec![ + Variant { id: Default::default(), name: rc("Unit"), kind: VariantKind::UnitStruct }, + Variant { id: Default::default(), name: rc("Record"), kind: VariantKind::Record( + vec![ + (rc("field"), TypeIdentifier::Singleton(TypeSingletonName { name: rc("AnotherType"), params: vec![TypeIdentifier::Singleton(TypeSingletonName { name: rc("Bool"), params: vec![] })] })), + (rc("field2"), TypeIdentifier::Tuple(vec![ + TypeIdentifier::Singleton(TypeSingletonName { name: rc("Nat"), params: vec![] }), + TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] }), + ] + )), + (rc("field3"), TypeIdentifier::Singleton(TypeSingletonName { name: rc("T"), params: vec![] })), + ] + )}, + Variant { id: Default::default(), name: rc("Tuple"), kind: VariantKind::TupleStruct( + vec![ + TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] }), + TypeIdentifier::Tuple(vec![ + TypeIdentifier::Singleton(TypeSingletonName { name: rc("String"), params: vec![] }), + TypeIdentifier::Singleton(TypeSingletonName { name: rc("T"), params: vec![] }), + ]) + ] + )}, + ]), + })); +} + #[test] fn declarations() { use ExpressionKind::*; assert_ast!( "let q_q = Yolo::Swaggins", - vec![stmt(StatementKind::Declaration(Declaration::Binding { + vec![decl(Declaration::Binding { name: rc("q_q"), constant: true, type_anno: None, expr: expr(Value(qn!(Yolo, Swaggins))) - }))] + })] ); } @@ -699,8 +828,12 @@ fn functions_with_default_args() { operator: false, type_anno: None, params: vec![ - FormalParam { name: rc("x"), anno: Some(int_anno()), default: None }, - FormalParam { name: rc("y"), anno: Some(int_anno()), default: Some(expr(NatLiteral(4))) }, + FormalParam { name: rc("x"), anno: Some(ty_simple("Int")), default: None }, + FormalParam { + name: rc("y"), + anno: Some(ty_simple("Int")), + default: Some(expr(NatLiteral(4))) + }, ], }, vec![].into() @@ -728,6 +861,59 @@ fn interface() { ); } +#[test] +fn impls() { + use Declaration::{FuncSig, Impl}; + + assert_ast!( + "impl Heh { fn yolo(); fn swagg(); }", + vec![decl(Impl { + type_name: ty_simple("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 }) + ] + })] + ); + + assert_ast!( + "impl Heh { fn yolo(); fn swagg(); }", + vec![decl(Impl { + type_name: TypeIdentifier::Singleton(TypeSingletonName { + name: rc("Heh"), + params: vec![ty_simple("X")] + }), + 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 }) + ] + })] + ); + + assert_ast!( + "impl Heh for Saraz { fn yolo(); fn swagg(); }", + vec![decl(Impl { + type_name: ty_simple("Saraz"), + interface_name: Some(TypeSingletonName { name: rc("Heh"), 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 }) + ] + })] + ); + + assert_ast!( + "impl Heh for (Int, Codepoint) {}", + vec![decl(Impl { + type_name: TypeIdentifier::Tuple(vec![ty_simple("Int"), ty_simple("Codepoint")]), + interface_name: Some(TypeSingletonName { name: rc("Heh"), params: vec![ty_simple("T")] }), + block: vec![] + })] + ); +} + #[test] fn annotations() { use ExpressionKind::*; @@ -825,3 +1011,197 @@ fn imports() { }))] }; } + +#[test] +fn if_exprs() { + use ExpressionKind::*; + assert_expr!( + "if a() then { tuah(); }", + expr(IfExpression { + discriminator: Some(bx(expr(Call { f: bx(expr(Value(qn!(a)))), arguments: vec![] }))), + body: bx(IfExpressionBody::SimpleConditional { + then_case: vec![exst(Call { f: bx(expr(Value(qn!(tuah)))), arguments: vec![] })].into(), + else_case: None, + }) + }) + ); + + assert_expr!( + "if a then b else c", + expr(IfExpression { + discriminator: Some(bx(expr(Value(qn!(a))))), + body: bx(IfExpressionBody::SimpleConditional { + then_case: vec![exst(Value(qn!(b)))].into(), + else_case: Some(vec![exst(Value(qn!(c)))].into()), + }) + }) + ); + + assert_expr!( + r#" + if true then { + let a = 10 + b + } else { + c + }"#, + expr(IfExpression { + discriminator: Some(bx(expr(BoolLiteral(true)))), + body: bx(IfExpressionBody::SimpleConditional { + then_case: vec![ + decl(Declaration::Binding { + name: rc("a"), + constant: true, + type_anno: None, + expr: expr(NatLiteral(10)) + }), + exst(Value(qn!(b))), + ] + .into(), + else_case: Some(vec![exst(Value(qn!(c))),].into()) + }) + }) + ); +} + +#[test] +fn pattern_matching() { + use ExpressionKind::*; + + for item in ["if x is Some(a) then { 4 } else { 9 }", "if x is Some(a) then 4 else 9"] { + assert_expr!( + item, + expr(IfExpression { + discriminator: Some(bx(expr(Value(qn!(x))))), + body: bx(IfExpressionBody::SimplePatternMatch { + pattern: Pattern::TupleStruct(qn!(Some), vec![Pattern::VarOrName(qn!(a))]), + then_case: vec![exst(NatLiteral(4))].into(), + else_case: Some(vec![exst(NatLiteral(9))].into()), + }) + }) + ); + } + + assert_expr!( + "if x is Something { a, b: x } then { 4 } else { 9 }", + expr(IfExpression { + discriminator: Some(bx(expr(Value(qn!(x))))), + body: bx(IfExpressionBody::SimplePatternMatch { + pattern: Pattern::Record( + qn!(Something), + vec![ + (rc("a"), Pattern::Literal(PatternLiteral::StringPattern(rc("a")))), + (rc("b"), Pattern::VarOrName(qn!(x))) + ] + ), + then_case: vec![exst(NatLiteral(4))].into(), + else_case: Some(vec![exst(NatLiteral(9))].into()), + }) + }) + ); + + assert_expr!( + "if x is -1 then 1 else 2", + expr(IfExpression { + discriminator: Some(bx(expr(Value(qn!(x))))), + body: bx(IfExpressionBody::SimplePatternMatch { + pattern: Pattern::Literal(PatternLiteral::NumPattern { neg: true, num: NatLiteral(1) }), + then_case: vec![exst(NatLiteral(1))].into(), + else_case: Some(vec![exst(NatLiteral(2))].into()), + }) + }) + ); + + assert_expr!( + "if x is true then 1 else 2", + expr(IfExpression { + discriminator: Some(bx(expr(Value(qn!(x))))), + body: bx(IfExpressionBody::SimplePatternMatch { + pattern: Pattern::Literal(PatternLiteral::BoolPattern(true)), + then_case: vec![exst(NatLiteral(1))].into(), + else_case: Some(vec![exst(NatLiteral(2))].into()), + }) + }) + ); + + assert_expr!( + "if x { is 1 then 5, else 20 }", + expr(IfExpression { + discriminator: Some(bx(expr(Value(qn!(x))))), + body: bx(IfExpressionBody::CondList(vec![ + ConditionArm { + condition: Condition::Pattern(Pattern::Literal(PatternLiteral::NumPattern { + neg: false, + num: NatLiteral(1) + })), + guard: None, + body: vec![exst(NatLiteral(5))].into(), + }, + ConditionArm { + condition: Condition::Else, + guard: None, + body: vec![exst(NatLiteral(20))].into(), + }, + ])) + }) + ); + + assert_expr!( + r#"if x is "gnosticism" then 1 else 2"#, + expr(IfExpression { + discriminator: Some(bx(expr(Value(qn!(x))))), + body: bx(IfExpressionBody::SimplePatternMatch { + pattern: Pattern::Literal(PatternLiteral::StringPattern(rc("gnosticism"))), + then_case: vec![exst(NatLiteral(1))].into(), + else_case: Some(vec![exst(NatLiteral(2))].into()), + }) + }) + ); + + assert_expr! { + r#" +if (45, "panda", false, 2.2) { + is (49, "pablo", _, 28.4) then "no" + is (_, "panda", _, -2.2) then "yes" + is _ then "maybe" +}"#, + expr( + IfExpression { + discriminator: Some(bx(expr(TupleLiteral(vec![ + expr(NatLiteral(45)), expr(StringLiteral(rc("panda"))), expr(BoolLiteral(false)), expr(FloatLiteral(2.2)) + ])))), + body: bx(IfExpressionBody::CondList(vec![ + ConditionArm { + condition: Condition::Pattern(Pattern::TuplePattern( + vec![ + Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(49) }), + Pattern::Literal(PatternLiteral::StringPattern(rc("pablo"))), + Pattern::Ignored, + Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: FloatLiteral(28.4) }), + ] + )), + guard: None, + body: vec![stmt(StatementKind::Expression(expr(StringLiteral(rc("no")))))].into(), + }, + ConditionArm { + condition: Condition::Pattern(Pattern::TuplePattern( + vec![ + Pattern::Ignored, + Pattern::Literal(PatternLiteral::StringPattern(rc!(panda))), + Pattern::Ignored, + Pattern::Literal(PatternLiteral::NumPattern { neg: true, num: FloatLiteral(2.2) }), + ] + )), + guard: None, + body: vec![stmt(StatementKind::Expression(expr(StringLiteral(rc("yes")))))].into(), + }, + ConditionArm { + condition: Condition::Pattern(Pattern::Ignored), + guard: None, + body: vec![exst(StringLiteral(rc("maybe")))].into(), + }, + ])) + } + ) + }; +} diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index c80bcb0..9df787e 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -100,48 +100,6 @@ macro_rules! exst { } } -#[test] -fn parsing_types() { - parse_test_wrap_ast!("type Yolo = Yolo", decl!(TypeDecl { name: tys!("Yolo"), body: TypeBody(vec![Variant { id: ItemId::default(), kind: UnitStruct, name: rc!(Yolo) }]), mutable: false} )); - parse_test_wrap_ast!("type mut Yolo = Yolo", decl!(TypeDecl { name: tys!("Yolo"), body: TypeBody(vec![Variant { id: ItemId::default(), kind: UnitStruct, name: rc!(Yolo) }]), mutable: true} )); - parse_test_wrap_ast!("type alias Sex = Drugs", decl!(TypeAlias { alias: rc!(Sex), original: rc!(Drugs) })); - parse_test_wrap_ast!("type Sanchez = Miguel | Alejandro(Int, Option) | Esperanza { a: Int, b: String }", - decl!(TypeDecl { - name: tys!("Sanchez"), - body: TypeBody(vec![ - Variant { - id: ItemId::default(), - kind: UnitStruct, name: rc!(Miguel) }, - Variant { - id: ItemId::default(), - name: rc!(Alejandro), - kind: TupleStruct(vec![ - Singleton(TypeSingletonName { name: rc!(Int), params: vec![] }), - Singleton(TypeSingletonName { name: rc!(Option), params: vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })] }), - ]) - }, - Variant { - id: ItemId::default(), - name: rc!(Esperanza), - kind: Record(vec![ - (rc!(a), Singleton(TypeSingletonName { name: rc!(Int), params: vec![] })), - (rc!(b), Singleton(TypeSingletonName { name: rc!(String), params: vec![] })), - ]) - } - ]), - mutable: false - })); - - parse_test_wrap_ast! { - "type Jorge = Diego | Kike(a)", - decl!(TypeDecl{ - name: TypeSingletonName { name: rc!(Jorge), params: vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })] }, - body: TypeBody(vec![Variant{ id: ItemId::default(), kind: UnitStruct, name: rc!(Diego) }, Variant { id: ItemId::default(), name: rc!(Kike), kind: TupleStruct( vec![Singleton(TypeSingletonName { name: rc!(a), params: vec![] })]) }]), - mutable: false - } - ) - }; -} #[test] fn parsing_block_expressions() { @@ -212,227 +170,4 @@ fn parsing_block_expressions() { #[test] fn parsing_impls() { - parse_test_wrap_ast!("impl Heh { fn yolo(); fn swagg(); }", - decl!(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_wrap_ast!("impl Mondai for Lollerino { fn yolo(); fn swagg(); }", - decl!(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_wrap_ast!("impl Hella for (Alpha, Omega) { }", - decl!(Impl { - type_name: Tuple(vec![ty!("Alpha"), ty!("Omega")]), - interface_name: Some(TypeSingletonName { name: rc!(Hella), params: vec![ty!("T")] }), - block: vec![] - }) - ); - - parse_test_wrap_ast!("impl Option { fn oi() }", - decl!(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 list_literals() { - parse_test_wrap_ast! { - "[1,2]", - exst!(ListLiteral(vec![ex!(NatLiteral(1)), ex!(NatLiteral(2))])) - }; - } - -#[test] -fn patterns() { - parse_test_wrap_ast! { - "if x is Some(a) then { 4 } else { 9 }", exst!( - IfExpression { - discriminator: Some(bx!(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch { - pattern: Pattern::TupleStruct(qname!(Some), vec![Pattern::VarOrName(qname!(a))]), - then_case: vec![exst!(s "4")].into(), - else_case: Some(vec![exst!(s "9")].into()) }) - } - ) - } - - parse_test_wrap_ast! { - "if x is Some(a) then 4 else 9", exst!( - IfExpression { - discriminator: Some(bx!(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch { - pattern: Pattern::TupleStruct(qname!(Some), vec![Pattern::VarOrName(qname!(a))]), - then_case: vec![exst!(s "4")].into(), - else_case: Some(vec![exst!(s "9")].into()) } - ) - } - ) - } - - parse_test_wrap_ast! { - "if x is Something { a, b: x } then { 4 } else { 9 }", exst!( - IfExpression { - discriminator: Some(bx!(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch { - pattern: Pattern::Record(qname!(Something), vec![ - (rc!(a),Pattern::Literal(PatternLiteral::StringPattern(rc!(a)))), - (rc!(b),Pattern::VarOrName(qname!(x))) - ]), - then_case: vec![exst!(s "4")].into(), - else_case: Some(vec![exst!(s "9")].into()) - } - ) - } - ) - } -} - -#[test] -fn pattern_literals() { - parse_test_wrap_ast! { - "if x is -1 then 1 else 2", - exst!( - IfExpression { - discriminator: Some(bx!(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch { - pattern: Pattern::Literal(PatternLiteral::NumPattern { neg: true, num: NatLiteral(1) }), - then_case: vec![exst!(NatLiteral(1))].into(), - else_case: Some(vec![exst!(NatLiteral(2))].into()), - }) - } - ) - } - - parse_test_wrap_ast! { - "if x is 1 then 1 else 2", - exst!( - IfExpression { - discriminator: Some(bx!(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch { - pattern: Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(1) }), - then_case: vec![exst!(s "1")].into(), - else_case: Some(vec![exst!(s "2")].into()), - }) - } - ) - } - - parse_test_wrap_ast! { - "if x is true then 1 else 2", - exst!( - IfExpression { - discriminator: Some(bx!(ex!(s "x"))), - body: bx!( - IfExpressionBody::SimplePatternMatch { - pattern: Pattern::Literal(PatternLiteral::BoolPattern(true)), - then_case: vec![exst!(NatLiteral(1))].into(), - else_case: Some(vec![exst!(NatLiteral(2))].into()), - }) - } - ) - } - - parse_test_wrap_ast! { - "if x is \"gnosticism\" then 1 else 2", - exst!( - IfExpression { - discriminator: Some(bx!(ex!(s "x"))), - body: bx!(IfExpressionBody::SimplePatternMatch { - pattern: Pattern::Literal(PatternLiteral::StringPattern(rc!(gnosticism))), - then_case: vec![exst!(s "1")].into(), - else_case: Some(vec![exst!(s "2")].into()), - }) - } - ) - } -} - - -#[test] -fn if_expr() { - parse_test_wrap_ast! { - "if x { is 1 then 5, else 20 }", - exst! { - IfExpression { - discriminator: Some(bx!(ex!(s "x"))), - body: bx!(IfExpressionBody::CondList( - vec![ - ConditionArm { - condition: Condition::Pattern(Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(1)})), - guard: None, - body: vec![exst!(s "5")].into(), - }, - ConditionArm { - condition: Condition::Else, - guard: None, - body: vec![exst!(s "20")].into(), - }, - ] - )) - } - } - } -} - -#[test] -fn advanced_if_expr() { - - parse_test_wrap_ast! { - r#" -if (45, "panda", false, 2.2) { - is (49, "pablo", _, 28.4) then "no" - is (_, "panda", _, -2.2) then "yes" - is _ then "maybe" -}"#, - exst!( - IfExpression { - discriminator: Some(bx!(ex!(s r#"(45, "panda", false, 2.2)"#))), - body: bx!(IfExpressionBody::CondList(vec![ - ConditionArm { - condition: Condition::Pattern(Pattern::TuplePattern( - vec![ - Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(49) }), - Pattern::Literal(PatternLiteral::StringPattern(rc!(pablo))), - Pattern::Ignored, - Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: FloatLiteral(28.4) }), - ] - )), - guard: None, - body: vec![exst!(s r#""no""#)].into(), - }, - ConditionArm { - condition: Condition::Pattern(Pattern::TuplePattern( - vec![ - Pattern::Ignored, - Pattern::Literal(PatternLiteral::StringPattern(rc!(panda))), - Pattern::Ignored, - Pattern::Literal(PatternLiteral::NumPattern { neg: true, num: FloatLiteral(2.2) }), - ] - )), - guard: None, - body: vec![exst!(s r#""yes""#)].into(), - }, - ConditionArm { - condition: Condition::Pattern(Pattern::Ignored), - guard: None, - body: vec![exst!(s r#""maybe""#)].into(), - }, - ])) - } - ) - } }