Move parse test code into separate module
This commit is contained in:
parent
33c2786ea1
commit
c332747c3e
@ -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<u64> {
|
||||
}
|
||||
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<AST> {
|
||||
let tokens: Vec<crate::tokenizing::Token> = 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<crate::tokenizing::Token> = 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<crate::tokenizing::Token> = 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<a>) | 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<a> = 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<T> 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<WTFMate> { 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<Int>", AST(vec![
|
||||
exst!(val!("a"), Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("Int")] }))
|
||||
]));
|
||||
|
||||
parse_test!("a : KoreanBBQSpecifier<Kimchi, Option<Bulgogi> >", 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<a>)", 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")]),
|
||||
))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
647
schala-lang/language/src/parsing/test.rs
Normal file
647
schala-lang/language/src/parsing/test.rs
Normal file
@ -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<AST> {
|
||||
let tokens: Vec<crate::tokenizing::Token> = 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<crate::tokenizing::Token> = 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<crate::tokenizing::Token> = 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<a>) | 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<a> = 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<T> 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<WTFMate> { 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<Int>", AST(vec![
|
||||
exst!(val!("a"), Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("Int")] }))
|
||||
]));
|
||||
|
||||
parse_test!("a : KoreanBBQSpecifier<Kimchi, Option<Bulgogi> >", 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<a>)", 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")]),
|
||||
))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user