Compare commits
2 Commits
8db9176fce
...
663e99df23
Author | SHA1 | Date | |
---|---|---|---|
|
663e99df23 | ||
|
81bfe22974 |
@ -117,7 +117,7 @@ pub enum Declaration {
|
||||
FuncSig(Signature),
|
||||
FuncDecl(Signature, Block),
|
||||
TypeDecl { name: TypeSingletonName, body: TypeBody, mutable: bool },
|
||||
//TODO this needs to be more sophisticated
|
||||
//TODO TypeAlias `original` needs to be a more complex type definition
|
||||
TypeAlias { alias: Rc<String>, original: Rc<String> },
|
||||
Binding { name: Rc<String>, constant: bool, type_anno: Option<TypeIdentifier>, expr: Expression },
|
||||
Impl { type_name: TypeIdentifier, interface_name: Option<TypeSingletonName>, block: Vec<Declaration> },
|
||||
@ -133,6 +133,7 @@ pub struct Signature {
|
||||
pub type_anno: Option<TypeIdentifier>,
|
||||
}
|
||||
|
||||
//TODO I can probably get rid of TypeBody
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct TypeBody(pub Vec<Variant>);
|
||||
|
||||
@ -158,6 +159,7 @@ pub struct Expression {
|
||||
#[derivative(PartialEq = "ignore")]
|
||||
pub id: ItemId,
|
||||
pub kind: ExpressionKind,
|
||||
//TODO this should only allow singletons, not tuples
|
||||
pub type_anno: Option<TypeIdentifier>,
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,6 @@
|
||||
//!
|
||||
//! module := 'module' IDENTIFIER '{' statement* '}'
|
||||
//! ```
|
||||
mod new_tests;
|
||||
mod test;
|
||||
|
||||
use std::rc::Rc;
|
||||
@ -689,6 +688,13 @@ impl Parser {
|
||||
|
||||
#[recursive_descent_method]
|
||||
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() {
|
||||
Operator(ref op) if PrefixOp::is_prefix(&*op) => {
|
||||
let sigil = match self.token_handler.next().kind {
|
||||
|
@ -1,827 +0,0 @@
|
||||
#![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))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accessors() {
|
||||
use ExpressionKind::*;
|
||||
|
||||
assert_expr!("a.b", expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) }));
|
||||
assert_expr!(
|
||||
"a.b.c",
|
||||
expr(Access {
|
||||
name: rc("c"),
|
||||
expr: bx(expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) }))
|
||||
})
|
||||
);
|
||||
assert_expr!(
|
||||
"a.b.c(3)",
|
||||
expr(Call {
|
||||
f: bx(expr(Access {
|
||||
name: rc("c"),
|
||||
expr: bx(expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) }))
|
||||
})),
|
||||
arguments: vec![InvocationArgument::Positional(expr(NatLiteral(3)))],
|
||||
})
|
||||
);
|
||||
assert_expr!(
|
||||
"a.b().c",
|
||||
expr(Access {
|
||||
name: rc("c"),
|
||||
expr: bx(expr(Call {
|
||||
f: bx(expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) })),
|
||||
arguments: vec![]
|
||||
}))
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[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)))]
|
||||
})
|
||||
);
|
||||
assert_expr!(
|
||||
"perspicacity()[a]",
|
||||
expr(Index {
|
||||
indexee: bx(expr(Call { f: bx(expr(Value(qn!(perspicacity)))), arguments: vec![] })),
|
||||
indexers: vec![expr(Value(qn!(a)))]
|
||||
})
|
||||
);
|
||||
|
||||
let a = expr(Call { f: bx(expr(Value(qn!(a)))), arguments: vec![] });
|
||||
let b = expr(Index { indexee: bx(a), indexers: vec![expr(Value(qn!(b)))] });
|
||||
let c = expr(Call { f: bx(b), arguments: vec![] });
|
||||
let d = expr(Index { indexee: bx(c), indexers: vec![expr(Value(qn!(d)))] });
|
||||
assert_expr!("a()[b]()[d]", 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,
|
||||
}))]
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user