Move rest of parse tests over to new format

This commit is contained in:
Greg Shuflin 2021-10-31 01:04:58 -07:00
parent 8db9176fce
commit 81bfe22974
4 changed files with 399 additions and 275 deletions

View File

@ -117,7 +117,7 @@ pub enum Declaration {
FuncSig(Signature), FuncSig(Signature),
FuncDecl(Signature, Block), FuncDecl(Signature, Block),
TypeDecl { name: TypeSingletonName, body: TypeBody, mutable: bool }, 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<String>, original: Rc<String> }, TypeAlias { alias: Rc<String>, original: Rc<String> },
Binding { name: Rc<String>, constant: bool, type_anno: Option<TypeIdentifier>, expr: Expression }, Binding { name: Rc<String>, constant: bool, type_anno: Option<TypeIdentifier>, expr: Expression },
Impl { type_name: TypeIdentifier, interface_name: Option<TypeSingletonName>, block: Vec<Declaration> }, Impl { type_name: TypeIdentifier, interface_name: Option<TypeSingletonName>, block: Vec<Declaration> },
@ -133,6 +133,7 @@ pub struct Signature {
pub type_anno: Option<TypeIdentifier>, pub type_anno: Option<TypeIdentifier>,
} }
//TODO I can probably get rid of TypeBody
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct TypeBody(pub Vec<Variant>); pub struct TypeBody(pub Vec<Variant>);
@ -158,6 +159,7 @@ pub struct Expression {
#[derivative(PartialEq = "ignore")] #[derivative(PartialEq = "ignore")]
pub id: ItemId, pub id: ItemId,
pub kind: ExpressionKind, pub kind: ExpressionKind,
//TODO this should only allow singletons, not tuples
pub type_anno: Option<TypeIdentifier>, pub type_anno: Option<TypeIdentifier>,
} }

View File

@ -689,6 +689,13 @@ impl Parser {
#[recursive_descent_method] #[recursive_descent_method]
fn prefix_expr(&mut self) -> ParseResult<Expression> { fn prefix_expr(&mut self) -> ParseResult<Expression> {
loop {
match self.token_handler.peek_kind() {
Semicolon | Newline => { self.token_handler.next(); },
_ => break,
}
}
match self.token_handler.peek_kind() { match self.token_handler.peek_kind() {
Operator(ref op) if PrefixOp::is_prefix(&*op) => { Operator(ref op) if PrefixOp::is_prefix(&*op) => {
let sigil = match self.token_handler.next().kind { let sigil = match self.token_handler.next().kind {

View File

@ -33,6 +33,14 @@ fn stmt(kind: StatementKind) -> Statement {
Statement { location: Location::default(), id: ItemId::default(), kind } 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 { fn decl(declaration: Declaration) -> Statement {
Statement { Statement {
location: Location::default(), location: Location::default(),
@ -85,8 +93,8 @@ macro_rules! qn {
}; };
} }
fn int_anno() -> TypeIdentifier { fn ty_simple(name: &str) -> TypeIdentifier {
TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] }) TypeIdentifier::Singleton(TypeSingletonName { name: rc(name), params: vec![] })
} }
macro_rules! assert_ast { macro_rules! assert_ast {
@ -136,6 +144,14 @@ fn basic_literals() {
assert_expr!(r#""hello""#, expr(StringLiteral(rc("hello")))); 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] #[test]
fn binexps() { fn binexps() {
use ExpressionKind::*; use ExpressionKind::*;
@ -374,7 +390,7 @@ fn lambda_expressions() {
r#"\ (x: Int, y) { a;b;c;}"#, r#"\ (x: Int, y) { a;b;c;}"#,
expr(Lambda { expr(Lambda {
params: vec![ 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 }, FormalParam { name: rc!(y), anno: None, default: None },
], ],
type_anno: None, type_anno: None,
@ -402,7 +418,7 @@ fn lambda_expressions() {
assert_expr!( assert_expr!(
r#"\(x: Int): String { "q" }"#, r#"\(x: Int): String { "q" }"#,
expr(Lambda { 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 { type_anno: Some(TypeIdentifier::Singleton(TypeSingletonName {
name: rc("String"), name: rc("String"),
params: vec![] params: vec![]
@ -433,7 +449,7 @@ fn single_param_lambda() {
assert_expr!( assert_expr!(
r#"\x: Int { x + 10 }"#, r#"\x: Int { x + 10 }"#,
expr(Lambda { 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, type_anno: None,
body: vec![stmt(StatementKind::Expression(binop( 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<T> = 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<T, U> = Unit | Record { field: AnotherType<Bool>, 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] #[test]
fn declarations() { fn declarations() {
use ExpressionKind::*; use ExpressionKind::*;
assert_ast!( assert_ast!(
"let q_q = Yolo::Swaggins", "let q_q = Yolo::Swaggins",
vec![stmt(StatementKind::Declaration(Declaration::Binding { vec![decl(Declaration::Binding {
name: rc("q_q"), name: rc("q_q"),
constant: true, constant: true,
type_anno: None, type_anno: None,
expr: expr(Value(qn!(Yolo, Swaggins))) expr: expr(Value(qn!(Yolo, Swaggins)))
}))] })]
); );
} }
@ -699,8 +828,12 @@ fn functions_with_default_args() {
operator: false, operator: false,
type_anno: None, type_anno: None,
params: vec![ 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: Some(int_anno()), default: Some(expr(NatLiteral(4))) }, FormalParam {
name: rc("y"),
anno: Some(ty_simple("Int")),
default: Some(expr(NatLiteral(4)))
},
], ],
}, },
vec![].into() 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<X> { 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<T> 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] #[test]
fn annotations() { fn annotations() {
use ExpressionKind::*; 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(),
},
]))
}
)
};
}

View File

@ -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<a>) | 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<a> = 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] #[test]
fn parsing_block_expressions() { fn parsing_block_expressions() {
@ -212,227 +170,4 @@ fn parsing_block_expressions() {
#[test] #[test]
fn parsing_impls() { 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<T> 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<WTFMate> { 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(),
},
]))
}
)
}
} }