802 lines
23 KiB
Rust
802 lines
23 KiB
Rust
#![cfg(test)]
|
|
#![allow(clippy::upper_case_acronyms)]
|
|
#![allow(clippy::vec_init_then_push)]
|
|
//use test_case::test_case;
|
|
use std::rc::Rc;
|
|
|
|
use pretty_assertions::assert_eq;
|
|
|
|
use super::{tokenize, ParseResult, Parser};
|
|
use crate::{ast::*, tokenizing::Location};
|
|
|
|
fn rc(s: &str) -> Rc<String> {
|
|
Rc::new(s.to_owned())
|
|
}
|
|
|
|
fn bx<T>(item: T) -> Box<T> {
|
|
Box::new(item)
|
|
}
|
|
|
|
fn make_parser(input: &str) -> Parser {
|
|
let tokens: Vec<crate::tokenizing::Token> = tokenize(input);
|
|
let mut parser = super::Parser::new();
|
|
parser.add_new_tokens(tokens);
|
|
parser
|
|
}
|
|
|
|
fn parse(input: &str) -> ParseResult<AST> {
|
|
let mut parser = make_parser(input);
|
|
parser.parse()
|
|
}
|
|
|
|
fn stmt(kind: StatementKind) -> Statement {
|
|
Statement { location: Location::default(), id: ItemId::default(), kind }
|
|
}
|
|
|
|
fn decl(declaration: Declaration) -> Statement {
|
|
Statement {
|
|
location: Location::default(),
|
|
id: ItemId::default(),
|
|
kind: StatementKind::Declaration(declaration),
|
|
}
|
|
}
|
|
|
|
fn fn_decl(sig: Signature, stmts: Block) -> Statement {
|
|
Statement {
|
|
kind: StatementKind::Declaration(Declaration::FuncDecl(sig, stmts)),
|
|
location: Default::default(),
|
|
id: Default::default(),
|
|
}
|
|
}
|
|
|
|
fn expr_anno(kind: ExpressionKind, anno: TypeIdentifier) -> Expression {
|
|
Expression { id: ItemId::default(), kind, type_anno: Some(anno) }
|
|
}
|
|
|
|
fn expr(kind: ExpressionKind) -> Expression {
|
|
Expression { id: ItemId::default(), kind, type_anno: None }
|
|
}
|
|
|
|
fn binop(sigil: &str, lhs: Expression, rhs: Expression) -> Expression {
|
|
Expression {
|
|
id: Default::default(),
|
|
type_anno: None,
|
|
kind: ExpressionKind::BinExp(BinOp::from_sigil(sigil), Box::new(lhs), Box::new(rhs)),
|
|
}
|
|
}
|
|
|
|
fn prefixop(sigil: &str, exp: Expression) -> Expression {
|
|
Expression {
|
|
id: Default::default(),
|
|
type_anno: None,
|
|
kind: ExpressionKind::PrefixExp(PrefixOp::from_sigil(sigil), Box::new(exp)),
|
|
}
|
|
}
|
|
|
|
macro_rules! qn {
|
|
( $( $component:ident),* ) => {
|
|
{
|
|
let mut components = vec![];
|
|
$(
|
|
components.push(rc(stringify!($component)));
|
|
)*
|
|
QualifiedName { components, id: Default::default() }
|
|
}
|
|
};
|
|
}
|
|
|
|
fn int_anno() -> TypeIdentifier {
|
|
TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] })
|
|
}
|
|
|
|
macro_rules! assert_ast {
|
|
($input:expr, $statements:expr) => {
|
|
let ast = parse($input).unwrap();
|
|
let expected = AST { id: Default::default(), statements: $statements.into() };
|
|
println!("Expected: {}", expected);
|
|
println!("Actual: {}", ast);
|
|
assert_eq!(ast, expected);
|
|
};
|
|
}
|
|
|
|
macro_rules! assert_fail {
|
|
($input:expr, $failure:expr) => {
|
|
let err = parse($input).unwrap_err();
|
|
assert_eq!(err.msg, $failure);
|
|
};
|
|
}
|
|
|
|
macro_rules! assert_expr {
|
|
($input:expr, $correct:expr) => {
|
|
let mut parser = make_parser($input);
|
|
assert_eq!(parser.expression().unwrap(), $correct);
|
|
};
|
|
}
|
|
|
|
macro_rules! assert_fail_expr {
|
|
($input:expr, $failure:expr) => {
|
|
let mut parser = make_parser($input);
|
|
let err = parser.expression().unwrap_err();
|
|
assert_eq!(err.msg, $failure);
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn basic_literals() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!(".2", expr(FloatLiteral(0.2)));
|
|
assert_expr!("8.1", expr(FloatLiteral(8.1)));
|
|
assert_expr!("0b010", expr(NatLiteral(2)));
|
|
assert_expr!("0b0_1_0", expr(NatLiteral(2)));
|
|
assert_expr!("0xff", expr(NatLiteral(255)));
|
|
assert_expr!("0x032f", expr(NatLiteral(815)));
|
|
assert_expr!("0xf_f_", expr(NatLiteral(255)));
|
|
assert_expr!("false", expr(BoolLiteral(false)));
|
|
assert_expr!("true", expr(BoolLiteral(true)));
|
|
assert_expr!(r#""hello""#, expr(StringLiteral(rc("hello"))));
|
|
}
|
|
|
|
#[test]
|
|
fn binexps() {
|
|
use ExpressionKind::*;
|
|
use StatementKind::Expression;
|
|
|
|
assert_expr!("0xf_f_+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1))));
|
|
assert_eq!(
|
|
parse("3; 4; 4.3").unwrap(),
|
|
AST {
|
|
id: Default::default(),
|
|
statements: vec![
|
|
stmt(Expression(expr(NatLiteral(3)))),
|
|
stmt(Expression(expr(NatLiteral(4)))),
|
|
stmt(Expression(expr(FloatLiteral(4.3)))),
|
|
]
|
|
.into()
|
|
}
|
|
);
|
|
|
|
assert_expr!(
|
|
"1 + 2 * 3",
|
|
binop("+", expr(NatLiteral(1)), binop("*", expr(NatLiteral(2)), expr(NatLiteral(3))))
|
|
);
|
|
assert_expr!(
|
|
"1 * 2 + 3",
|
|
binop("+", binop("*", expr(NatLiteral(1)), expr(NatLiteral(2))), expr(NatLiteral(3)))
|
|
);
|
|
assert_expr!("1 && 2", binop("&&", expr(NatLiteral(1)), expr(NatLiteral(2))));
|
|
assert_expr!(
|
|
"1 + 2 * 3 + 4",
|
|
binop(
|
|
"+",
|
|
binop("+", expr(NatLiteral(1)), binop("*", expr(NatLiteral(2)), expr(NatLiteral(3)))),
|
|
expr(NatLiteral(4))
|
|
)
|
|
);
|
|
assert_expr!(
|
|
"(1 + 2) * 3",
|
|
binop("*", binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))), expr(NatLiteral(3)))
|
|
);
|
|
assert_expr!(".1 + .2", binop("+", expr(FloatLiteral(0.1)), expr(FloatLiteral(0.2))));
|
|
assert_expr!("1 / 2.", binop("/", expr(NatLiteral(1)), expr(FloatLiteral(2.))));
|
|
}
|
|
|
|
#[test]
|
|
fn prefix_exps() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!("-3", prefixop("-", expr(NatLiteral(3))));
|
|
assert_expr!("-0.2", prefixop("-", expr(FloatLiteral(0.2))));
|
|
assert_expr!("!3", prefixop("!", expr(NatLiteral(3))));
|
|
assert_expr!("!t", prefixop("!", expr(Value(qn!(t)))));
|
|
assert_expr!("a <- -b", binop("<-", expr(Value(qn!(a))), prefixop("-", expr(Value(qn!(b))))));
|
|
assert_expr!("a <--b", binop("<--", expr(Value(qn!(a))), expr(Value(qn!(b)))));
|
|
}
|
|
|
|
#[test]
|
|
fn operators() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
|
assert_expr!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
|
assert_expr!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
|
}
|
|
|
|
//TODO have a test for dot accessors
|
|
/*
|
|
assert_expr!("a.b.c.d", exst!(binexp!(".",
|
|
binexp!(".",
|
|
binexp!(".", val!("a"), val!("b")),
|
|
val!("c")),
|
|
val!("d"))));
|
|
*/
|
|
|
|
#[test]
|
|
fn tuples() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!("()", expr(TupleLiteral(vec![])));
|
|
assert_expr!(
|
|
r#"("hella", 34)"#,
|
|
expr(TupleLiteral(vec![expr(StringLiteral(rc("hella"))), expr(NatLiteral(34))]))
|
|
);
|
|
assert_expr!(
|
|
r#"(1+2, "slough")"#,
|
|
expr(TupleLiteral(vec![
|
|
binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))),
|
|
expr(StringLiteral(rc("slough"))),
|
|
]))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn identifiers() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!("a", expr(Value(qn!(a))));
|
|
assert_expr!("some_value", expr(Value(qn!(some_value))));
|
|
assert_expr!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma))));
|
|
assert_expr!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b)))));
|
|
assert_expr!("None", expr(Value(qn!(None))));
|
|
assert_expr!(
|
|
"thing::item::call()",
|
|
expr(Call { f: bx(expr(Value(qn!(thing, item, call)))), arguments: vec![] })
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn named_struct() {
|
|
use ExpressionKind::*;
|
|
assert_expr!(
|
|
"Pandas { a: x + y }",
|
|
expr(NamedStruct {
|
|
name: qn!(Pandas),
|
|
fields: vec![(rc("a"), binop("+", expr(Value(qn!(x))), expr(Value(qn!(y)))))]
|
|
})
|
|
);
|
|
assert_expr!(
|
|
"Trousers { a:1, b:800 }",
|
|
expr(NamedStruct {
|
|
name: qn!(Trousers),
|
|
fields: vec![(rc("a"), expr(NatLiteral(1))), (rc("b"), expr(NatLiteral(800)))]
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn index() {
|
|
use ExpressionKind::*;
|
|
assert_expr!(
|
|
"a[b,c]",
|
|
expr(Index {
|
|
indexee: bx(expr(Value(qn!(a)))),
|
|
indexers: vec![expr(Value(qn!(b))), expr(Value(qn!(c)))]
|
|
})
|
|
);
|
|
//TODO this is a parser bug
|
|
/*
|
|
assert_expr!("perspicacity()[a]", expr(Index{
|
|
indexee: bx(expr(Call {
|
|
f: bx(expr(Value(qn!(perspicacity)))),
|
|
arguments: vec![]
|
|
})),
|
|
indexers: vec![expr(Value(qn!(a)))]
|
|
}));
|
|
*/
|
|
//TODO parse_test("a()[b]()[d]")
|
|
|
|
assert_fail_expr!("a[]", "Empty index expressions are not allowed");
|
|
}
|
|
|
|
#[test]
|
|
fn while_expression() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!("while { }", expr(WhileExpression { condition: None, body: Block::default() }));
|
|
assert_expr!(
|
|
"while a == b { }",
|
|
expr(WhileExpression {
|
|
condition: Some(bx(binop("==", expr(Value(qn!(a))), expr(Value(qn!(b)))))),
|
|
body: Block::default()
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn for_expression() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!(
|
|
"for { a <- garodzny::maybeValue } return 1",
|
|
expr(ForExpression {
|
|
enumerators: vec![Enumerator { id: rc("a"), generator: expr(Value(qn!(garodzny, maybeValue))) }],
|
|
body: bx(ForBody::MonadicReturn(expr(NatLiteral(1))))
|
|
})
|
|
);
|
|
|
|
assert_expr!(
|
|
"for n <- someRange { f(n); }",
|
|
expr(ForExpression {
|
|
enumerators: vec![Enumerator { id: rc("n"), generator: expr(Value(qn!(someRange))) }],
|
|
body: bx(ForBody::StatementBlock(
|
|
vec![stmt(StatementKind::Expression(expr(Call {
|
|
f: bx(expr(Value(qn!(f)))),
|
|
arguments: vec![InvocationArgument::Positional(expr(Value(qn!(n))))],
|
|
}))),]
|
|
.into()
|
|
)),
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn lambda_expressions() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!(
|
|
r#"\(x) { x + 1}"#,
|
|
expr(Lambda {
|
|
params: vec![FormalParam { name: rc!(x), anno: None, default: None }],
|
|
type_anno: None,
|
|
body:
|
|
vec![stmt(StatementKind::Expression(binop("+", expr(Value(qn!(x))), expr(NatLiteral(1))))),]
|
|
.into()
|
|
})
|
|
);
|
|
|
|
assert_expr!(
|
|
r#"\ (x: Int, y) { a;b;c;}"#,
|
|
expr(Lambda {
|
|
params: vec![
|
|
FormalParam { name: rc!(x), anno: Some(int_anno()), default: None },
|
|
FormalParam { name: rc!(y), anno: None, default: None },
|
|
],
|
|
type_anno: None,
|
|
body: vec![
|
|
stmt(StatementKind::Expression(expr(Value(qn!(a))))),
|
|
stmt(StatementKind::Expression(expr(Value(qn!(b))))),
|
|
stmt(StatementKind::Expression(expr(Value(qn!(c))))),
|
|
]
|
|
.into()
|
|
})
|
|
);
|
|
|
|
assert_expr!(
|
|
r#"\(x){y}(1)"#,
|
|
expr(Call {
|
|
f: bx(expr(Lambda {
|
|
params: vec![FormalParam { name: rc!(x), anno: None, default: None },],
|
|
type_anno: None,
|
|
body: vec![stmt(StatementKind::Expression(expr(Value(qn!(y))))),].into()
|
|
})),
|
|
arguments: vec![InvocationArgument::Positional(expr(NatLiteral(1)))],
|
|
})
|
|
);
|
|
|
|
assert_expr!(
|
|
r#"\(x: Int): String { "q" }"#,
|
|
expr(Lambda {
|
|
params: vec![FormalParam { name: rc!(x), anno: Some(int_anno()), default: None },],
|
|
type_anno: Some(TypeIdentifier::Singleton(TypeSingletonName {
|
|
name: rc("String"),
|
|
params: vec![]
|
|
})),
|
|
body: vec![stmt(StatementKind::Expression(expr(StringLiteral(rc("q"))))),].into()
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn single_param_lambda() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_expr!(
|
|
r#"\x { x + 10 }"#,
|
|
expr(Lambda {
|
|
params: vec![FormalParam { name: rc!(x), anno: None, default: None },],
|
|
type_anno: None,
|
|
body: vec![stmt(StatementKind::Expression(binop(
|
|
"+",
|
|
expr(Value(qn!(x))),
|
|
expr(NatLiteral(10))
|
|
)))]
|
|
.into()
|
|
})
|
|
);
|
|
|
|
assert_expr!(
|
|
r#"\x: Int { x + 10 }"#,
|
|
expr(Lambda {
|
|
params: vec![FormalParam { name: rc!(x), anno: Some(int_anno()), default: None },],
|
|
type_anno: None,
|
|
body: vec![stmt(StatementKind::Expression(binop(
|
|
"+",
|
|
expr(Value(qn!(x))),
|
|
expr(NatLiteral(10))
|
|
)))]
|
|
.into()
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn complex_lambdas() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_ast! {
|
|
r#"fn wahoo() { let a = 10; \(x) { x + a } };
|
|
wahoo()(3) "#,
|
|
vec![
|
|
fn_decl(Signature { name: rc("wahoo"), operator: false, type_anno: None, params: vec![] },
|
|
vec![
|
|
decl(Declaration::Binding {
|
|
name: rc("a"),
|
|
constant: true,
|
|
type_anno: None,
|
|
expr: expr(NatLiteral(10))
|
|
}),
|
|
stmt(StatementKind::Expression(expr(Lambda {
|
|
params: vec![
|
|
FormalParam { name: rc("x"), default: None, anno: None }
|
|
],
|
|
type_anno: None,
|
|
body: vec![
|
|
stmt(StatementKind::Expression(binop("+", expr(Value(qn!(x))), expr(Value(qn!(a)))))),
|
|
].into()
|
|
}))),
|
|
].into()),
|
|
stmt(StatementKind::Expression(expr(Call {
|
|
f: bx(expr(Call {
|
|
f: bx(expr(Value(qn!(wahoo)))),
|
|
arguments: vec![] })),
|
|
arguments: vec![
|
|
InvocationArgument::Positional(expr(NatLiteral(3)))
|
|
]
|
|
})))
|
|
]
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn reserved_words() {
|
|
assert_fail!("module::item::call()", "Expected an identifier, got Colon");
|
|
}
|
|
|
|
#[test]
|
|
fn type_annotations() {
|
|
use ExpressionKind::*;
|
|
use TypeIdentifier::*;
|
|
|
|
assert_ast!(
|
|
"let a = b : Int",
|
|
vec![decl(Declaration::Binding {
|
|
name: rc("a"),
|
|
constant: true,
|
|
type_anno: None,
|
|
expr: expr_anno(Value(qn!(b)), Singleton(TypeSingletonName { name: rc("Int"), params: vec![] })),
|
|
})]
|
|
);
|
|
|
|
assert_expr!(
|
|
"a: Int",
|
|
expr_anno(Value(qn!(a)), Singleton(TypeSingletonName { name: rc("Int"), params: vec![] }))
|
|
);
|
|
assert_expr!(
|
|
"a: Option<Int>",
|
|
expr_anno(
|
|
Value(qn!(a)),
|
|
Singleton(TypeSingletonName {
|
|
name: rc("Option"),
|
|
params: vec![Singleton(TypeSingletonName { name: rc("Int"), params: vec![] })]
|
|
})
|
|
)
|
|
);
|
|
assert_expr!(
|
|
"a: KoreanBBQSpecifier<Kimchi, Option<Bulgogi> >",
|
|
expr_anno(
|
|
Value(qn!(a)),
|
|
Singleton(TypeSingletonName {
|
|
name: rc("KoreanBBQSpecifier"),
|
|
params: vec![
|
|
Singleton(TypeSingletonName { name: rc("Kimchi"), params: vec![] }),
|
|
Singleton(TypeSingletonName {
|
|
name: rc("Option"),
|
|
params: vec![Singleton(TypeSingletonName { name: rc("Bulgogi"), params: vec![] })]
|
|
})
|
|
]
|
|
})
|
|
)
|
|
);
|
|
assert_expr!(
|
|
"a: (Int, Yolo<a>)",
|
|
expr_anno(
|
|
Value(qn!(a)),
|
|
Tuple(vec![
|
|
Singleton(TypeSingletonName { name: rc("Int"), params: vec![] }),
|
|
Singleton(TypeSingletonName {
|
|
name: rc("Yolo"),
|
|
params: vec![Singleton(TypeSingletonName { name: rc("a"), params: vec![] })]
|
|
}),
|
|
]),
|
|
)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn declarations() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_ast!(
|
|
"let q_q = Yolo::Swaggins",
|
|
vec![stmt(StatementKind::Declaration(Declaration::Binding {
|
|
name: rc("q_q"),
|
|
constant: true,
|
|
type_anno: None,
|
|
expr: expr(Value(qn!(Yolo, Swaggins)))
|
|
}))]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn bindings() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_ast!(
|
|
"let mut a = 10",
|
|
vec![decl(Declaration::Binding {
|
|
name: rc("a"),
|
|
constant: false,
|
|
type_anno: None,
|
|
expr: expr(NatLiteral(10)),
|
|
})]
|
|
);
|
|
|
|
assert_ast!(
|
|
"let a = 2 + a",
|
|
vec![stmt(StatementKind::Declaration(Declaration::Binding {
|
|
name: rc("a"),
|
|
constant: true,
|
|
type_anno: None,
|
|
expr: binop("+", expr(NatLiteral(2)), expr(Value(qn!(a)))),
|
|
}))]
|
|
);
|
|
|
|
assert_ast!(
|
|
"let a: Nat = 2",
|
|
vec![stmt(StatementKind::Declaration(Declaration::Binding {
|
|
name: rc("a"),
|
|
constant: true,
|
|
type_anno: Some(TypeIdentifier::Singleton(TypeSingletonName { name: rc("Nat"), params: vec![] })),
|
|
expr: expr(NatLiteral(2)),
|
|
}))]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn functions() {
|
|
use ExpressionKind::*;
|
|
assert_ast!(
|
|
"fn oi()",
|
|
vec![stmt(StatementKind::Declaration(Declaration::FuncSig(Signature {
|
|
name: rc("oi"),
|
|
operator: false,
|
|
params: vec![],
|
|
type_anno: None
|
|
})))]
|
|
);
|
|
|
|
assert_ast!(
|
|
"oi()",
|
|
vec![stmt(StatementKind::Expression(expr(Call { f: bx(expr(Value(qn!(oi)))), arguments: vec![] })))]
|
|
);
|
|
|
|
assert_expr!(
|
|
"oi(a, 2+2)",
|
|
expr(Call {
|
|
f: bx(expr(Value(qn!(oi)))),
|
|
arguments: vec![
|
|
InvocationArgument::Positional(expr(Value(qn!(a)))),
|
|
InvocationArgument::Positional(binop("+", expr(NatLiteral(2)), expr(NatLiteral(2)))),
|
|
]
|
|
})
|
|
);
|
|
assert_fail!("a(b,,c)", "Expected a literal expression, got Comma");
|
|
|
|
assert_ast!(
|
|
"fn a(b, c: Int): Int",
|
|
vec![stmt(StatementKind::Declaration(Declaration::FuncSig(Signature {
|
|
name: rc("a"),
|
|
operator: false,
|
|
params: vec![
|
|
FormalParam { name: rc("b"), default: None, anno: None },
|
|
FormalParam {
|
|
name: rc("c"),
|
|
default: None,
|
|
anno: Some(TypeIdentifier::Singleton(TypeSingletonName {
|
|
name: rc("Int"),
|
|
params: vec![]
|
|
})),
|
|
},
|
|
],
|
|
type_anno: Some(TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] })),
|
|
})))]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn functions_with_different_whitespace() {
|
|
use ExpressionKind::*;
|
|
|
|
let a = "fn a(x) { x() }";
|
|
let b = "fn a(x) {\n x() }";
|
|
let c = r#"
|
|
|
|
fn a(x) {
|
|
|
|
|
|
x()
|
|
|
|
|
|
}
|
|
|
|
"#;
|
|
|
|
for item in [a, b, c].iter() {
|
|
assert_ast!(
|
|
item,
|
|
vec![fn_decl(
|
|
Signature {
|
|
name: rc("a"),
|
|
operator: false,
|
|
type_anno: None,
|
|
params: vec![FormalParam { name: rc("x"), default: None, anno: None }]
|
|
},
|
|
vec![stmt(StatementKind::Expression(expr(Call {
|
|
f: bx(expr(Value(qn!(x)))),
|
|
arguments: vec![],
|
|
})))]
|
|
.into()
|
|
)]
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn functions_with_default_args() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_ast!(
|
|
"fn func(x: Int, y: Int = 4) { }",
|
|
vec![fn_decl(
|
|
Signature {
|
|
name: rc("func"),
|
|
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))) },
|
|
],
|
|
},
|
|
vec![].into()
|
|
)]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn interface() {
|
|
let glue = TypeIdentifier::Singleton(TypeSingletonName { name: rc("Glue"), params: vec![] });
|
|
assert_ast!(
|
|
"interface Unglueable { fn unglue(a: Glue); fn mar(): Glue }",
|
|
vec![decl(Declaration::Interface {
|
|
name: rc("Unglueable"),
|
|
signatures: vec![
|
|
Signature {
|
|
name: rc("unglue"),
|
|
operator: false,
|
|
params: vec![FormalParam { name: rc("a"), default: None, anno: Some(glue.clone()) },],
|
|
type_anno: None,
|
|
},
|
|
Signature { name: rc("mar"), operator: false, params: vec![], type_anno: Some(glue) },
|
|
],
|
|
})]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn annotations() {
|
|
use ExpressionKind::*;
|
|
|
|
assert_ast! {
|
|
r#"
|
|
@test_annotation
|
|
fn some_function() {
|
|
|
|
}"#,
|
|
vec![decl(Declaration::Annotation {
|
|
name: rc("test_annotation"),
|
|
arguments: vec![]
|
|
}),
|
|
fn_decl(Signature { name: rc("some_function"), operator: false, params: vec![], type_anno: None },
|
|
vec![].into())
|
|
]
|
|
};
|
|
|
|
assert_ast! {
|
|
r#"
|
|
@test_annotation(some,value)
|
|
fn some_function() {
|
|
|
|
}"#,
|
|
vec![decl(Declaration::Annotation {
|
|
name: rc("test_annotation"),
|
|
arguments: vec![expr(Value(qn!(some))), expr(Value(qn!(value)))]
|
|
}),
|
|
fn_decl(Signature { name: rc("some_function"), operator: false, params: vec![], type_anno: None },
|
|
vec![].into())
|
|
]
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn modules() {
|
|
assert_ast! {
|
|
r#"
|
|
module ephraim {
|
|
let mut a = 10
|
|
fn nah() { 33 }
|
|
}
|
|
"#,
|
|
vec![stmt(StatementKind::Module(ModuleSpecifier {
|
|
name: rc("ephraim"),
|
|
contents: vec![
|
|
decl(Declaration::Binding {
|
|
name: rc("a"), constant: false, type_anno: None,
|
|
expr: expr(ExpressionKind::NatLiteral(10))
|
|
}),
|
|
fn_decl(Signature { name: rc("nah"), operator: false, params: vec![], type_anno: None },
|
|
vec![stmt(StatementKind::Expression(expr(ExpressionKind::NatLiteral(33))))].into()),
|
|
].into()
|
|
}))]
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn imports() {
|
|
assert_ast! {
|
|
"import harbinger::draughts::Norgleheim",
|
|
vec![stmt(StatementKind::Import(ImportSpecifier {
|
|
id: ItemId::default(),
|
|
path_components: vec![rc("harbinger"), rc("draughts"), rc("Norgleheim")],
|
|
imported_names: ImportedNames::LastOfPath
|
|
}))]
|
|
};
|
|
|
|
assert_ast! {
|
|
"import harbinger::draughts::{Norgleheim, Xraksenlaigar}",
|
|
vec![stmt(StatementKind::Import(ImportSpecifier {
|
|
id: ItemId::default(),
|
|
path_components: vec![rc("harbinger"), rc("draughts")],
|
|
imported_names: ImportedNames::List(vec![
|
|
rc("Norgleheim"), rc("Xraksenlaigar")])
|
|
}))]
|
|
};
|
|
|
|
assert_ast! {
|
|
"import bespouri::{}",
|
|
vec![stmt(StatementKind::Import(ImportSpecifier {
|
|
id: Default::default(),
|
|
path_components: vec![rc("bespouri")],
|
|
imported_names: ImportedNames::List(vec![]),
|
|
}))]
|
|
};
|
|
|
|
assert_ast! {
|
|
"import bespouri::*",
|
|
vec![stmt(StatementKind::Import(ImportSpecifier {
|
|
id: Default::default(),
|
|
path_components: vec![rc("bespouri")],
|
|
imported_names: ImportedNames::All,
|
|
}))]
|
|
};
|
|
}
|