Rewrite many parser tests
Also introduces pretty print crate for parsing tests.
This commit is contained in:
parent
08d66f0a43
commit
e7308485df
47
Cargo.lock
generated
47
Cargo.lock
generated
@ -20,6 +20,15 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "approx"
|
name = "approx"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -171,6 +180,16 @@ dependencies = [
|
|||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctor"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa"
|
||||||
|
dependencies = [
|
||||||
|
"quote 1.0.10",
|
||||||
|
"syn 1.0.80",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derivative"
|
name = "derivative"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@ -182,6 +201,12 @@ dependencies = [
|
|||||||
"syn 0.15.44",
|
"syn 0.15.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@ -524,6 +549,15 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "output_vt100"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.7.24"
|
version = "0.7.24"
|
||||||
@ -562,6 +596,18 @@ dependencies = [
|
|||||||
"siphasher",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0cfe1b2403f172ba0f234e500906ee0a3e493fb81092dac23ebefe129301cc"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"ctor",
|
||||||
|
"diff",
|
||||||
|
"output_vt100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "0.4.30"
|
version = "0.4.30"
|
||||||
@ -849,6 +895,7 @@ dependencies = [
|
|||||||
"ena",
|
"ena",
|
||||||
"failure",
|
"failure",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"pretty_assertions",
|
||||||
"radix_trie",
|
"radix_trie",
|
||||||
"schala-lang-codegen",
|
"schala-lang-codegen",
|
||||||
"schala-repl",
|
"schala-repl",
|
||||||
|
@ -20,3 +20,4 @@ schala-repl = { path = "../../schala-repl" }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
test-case = "1.2.0"
|
test-case = "1.2.0"
|
||||||
|
pretty_assertions = "1.0.0"
|
||||||
|
@ -165,11 +165,6 @@ impl Expression {
|
|||||||
pub fn new(id: ItemId, kind: ExpressionKind) -> Expression {
|
pub fn new(id: ItemId, kind: ExpressionKind) -> Expression {
|
||||||
Expression { id, kind, type_anno: None }
|
Expression { id, kind, type_anno: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn with_anno(id: ItemId, kind: ExpressionKind, type_anno: TypeIdentifier) -> Expression {
|
|
||||||
Expression { id, kind, type_anno: Some(type_anno) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
//!
|
//!
|
||||||
//! ## Expressions
|
//! ## Expressions
|
||||||
//! ```text
|
//! ```text
|
||||||
//! expression := precedence_expr type_anno+
|
//! expression := precedence_expr type_anno?
|
||||||
//! precedence_expr := prefix_expr
|
//! precedence_expr := prefix_expr
|
||||||
//! prefix_expr := prefix_op call_expr
|
//! prefix_expr := prefix_op call_expr
|
||||||
//! prefix_op := "+" | "-" | "!" | "~"
|
//! prefix_op := "+" | "-" | "!" | "~"
|
||||||
@ -83,7 +83,7 @@
|
|||||||
//!
|
//!
|
||||||
//! ```text
|
//! ```text
|
||||||
//! list_expr := "[" (expression, ",")* "]"
|
//! list_expr := "[" (expression, ",")* "]"
|
||||||
//! lambda_expr := "\\" lambda_param_list type_anno+ nonempty_func_body
|
//! lambda_expr := "\\" lambda_param_list type_anno? nonempty_func_body
|
||||||
//! lambda_param_list := formal_param_list | formal_param
|
//! lambda_param_list := formal_param_list | formal_param
|
||||||
//! paren_expr := "(" paren_inner ")"
|
//! paren_expr := "(" paren_inner ")"
|
||||||
//! paren_inner := (expression ",")*
|
//! paren_inner := (expression ",")*
|
||||||
@ -161,6 +161,7 @@
|
|||||||
//! module := 'module' IDENTIFIER '{' statement* '}'
|
//! module := 'module' IDENTIFIER '{' statement* '}'
|
||||||
//! ```
|
//! ```
|
||||||
mod test;
|
mod test;
|
||||||
|
mod new_tests;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -729,6 +730,9 @@ impl Parser {
|
|||||||
let primary = self.primary()?;
|
let primary = self.primary()?;
|
||||||
Ok(if let LSquareBracket = self.token_handler.peek_kind() {
|
Ok(if let LSquareBracket = self.token_handler.peek_kind() {
|
||||||
let indexers = delimited!(self, LSquareBracket, expression, Comma, RSquareBracket);
|
let indexers = delimited!(self, LSquareBracket, expression, Comma, RSquareBracket);
|
||||||
|
if indexers.is_empty() {
|
||||||
|
return ParseError::new_with_token("Empty index expressions are not allowed", self.token_handler.peek());
|
||||||
|
}
|
||||||
Expression::new(self.id_store.fresh(), ExpressionKind::Index {
|
Expression::new(self.id_store.fresh(), ExpressionKind::Index {
|
||||||
indexee: Box::new(Expression::new(self.id_store.fresh(), primary.kind)),
|
indexee: Box::new(Expression::new(self.id_store.fresh(), primary.kind)),
|
||||||
indexers,
|
indexers,
|
||||||
|
670
schala-lang/language/src/parsing/new_tests.rs
Normal file
670
schala-lang/language/src/parsing/new_tests.rs
Normal file
@ -0,0 +1,670 @@
|
|||||||
|
#![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() }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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::*;
|
||||||
|
let int_anno = TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] });
|
||||||
|
|
||||||
|
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.clone()), 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,
|
||||||
|
}))]
|
||||||
|
};
|
||||||
|
}
|
@ -13,7 +13,6 @@ use super::TypeIdentifier::*;
|
|||||||
use super::TypeSingletonName;
|
use super::TypeSingletonName;
|
||||||
use super::ExpressionKind::*;
|
use super::ExpressionKind::*;
|
||||||
use super::VariantKind::*;
|
use super::VariantKind::*;
|
||||||
use super::ForBody::*;
|
|
||||||
|
|
||||||
fn make_parser(input: &str) -> Parser {
|
fn make_parser(input: &str) -> Parser {
|
||||||
let tokens: Vec<crate::tokenizing::Token> = tokenize(input);
|
let tokens: Vec<crate::tokenizing::Token> = tokenize(input);
|
||||||
@ -50,9 +49,6 @@ macro_rules! parse_test {
|
|||||||
macro_rules! parse_test_wrap_ast {
|
macro_rules! parse_test_wrap_ast {
|
||||||
($string:expr, $correct:expr) => { parse_test!($string, AST { id: Default::default(), statements: vec![$correct].into() }) }
|
($string:expr, $correct:expr) => { parse_test!($string, AST { id: Default::default(), statements: vec![$correct].into() }) }
|
||||||
}
|
}
|
||||||
macro_rules! parse_error {
|
|
||||||
($string:expr) => { assert!(parse($string).is_err()) }
|
|
||||||
}
|
|
||||||
macro_rules! qname {
|
macro_rules! qname {
|
||||||
( $( $component:expr),* ) => {
|
( $( $component:expr),* ) => {
|
||||||
{
|
{
|
||||||
@ -80,18 +76,6 @@ macro_rules! decl {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! import {
|
|
||||||
($import_spec:expr) => {
|
|
||||||
make_statement(StatementKind::Import($import_spec))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! module {
|
|
||||||
($module_spec:expr) => {
|
|
||||||
make_statement(StatementKind::Module($module_spec))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! ex {
|
macro_rules! ex {
|
||||||
($expr_type:expr) => { Expression::new(Default::default(), $expr_type) };
|
($expr_type:expr) => { Expression::new(Default::default(), $expr_type) };
|
||||||
($expr_type:expr, $type_anno:expr) => { Expression::with_anno(Default::default(), $expr_type, $type_anno) };
|
($expr_type:expr, $type_anno:expr) => { Expression::with_anno(Default::default(), $expr_type, $type_anno) };
|
||||||
@ -107,12 +91,6 @@ macro_rules! inv {
|
|||||||
($expr_type:expr) => { InvocationArgument::Positional($expr_type) }
|
($expr_type:expr) => { InvocationArgument::Positional($expr_type) }
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! binexp {
|
|
||||||
($op:expr, $lhs:expr, $rhs:expr) => { BinExp(BinOp::from_sigil($op), bx!(Expression::new(Default::default(), $lhs).into()), bx!(Expression::new(Default::default(), $rhs).into())) }
|
|
||||||
}
|
|
||||||
macro_rules! prefexp {
|
|
||||||
($op:expr, $lhs:expr) => { PrefixExp(PrefixOp::from_sigil($op), bx!(Expression::new(Default::default(), $lhs).into())) }
|
|
||||||
}
|
|
||||||
macro_rules! exst {
|
macro_rules! exst {
|
||||||
($expr_type:expr) => { make_statement(StatementKind::Expression(Expression::new(Default::default(), $expr_type).into())) };
|
($expr_type:expr) => { make_statement(StatementKind::Expression(Expression::new(Default::default(), $expr_type).into())) };
|
||||||
($expr_type:expr, $type_anno:expr) => { make_statement(StatementKind::Expression(Expression::with_anno(Default::default(), $expr_type, $type_anno).into())) };
|
($expr_type:expr, $type_anno:expr) => { make_statement(StatementKind::Expression(Expression::with_anno(Default::default(), $expr_type, $type_anno).into())) };
|
||||||
@ -125,201 +103,6 @@ macro_rules! exst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 {
|
|
||||||
id: Default::default(),
|
|
||||||
statements: vec![exst!(NatLiteral(3)), exst!(NatLiteral(4)),
|
|
||||||
exst!(FloatLiteral(4.3))].into()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("1 + 2 * 3",
|
|
||||||
exst!(binexp!("+", NatLiteral(1), binexp!("*", NatLiteral(2), NatLiteral(3))))
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("1 * 2 + 3",
|
|
||||||
exst!(binexp!("+", binexp!("*", NatLiteral(1), NatLiteral(2)), NatLiteral(3)))
|
|
||||||
) ;
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("1 && 2", exst!(binexp!("&&", NatLiteral(1), NatLiteral(2))));
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("1 + 2 * 3 + 4", exst!(
|
|
||||||
binexp!("+",
|
|
||||||
binexp!("+", NatLiteral(1), binexp!("*", NatLiteral(2), NatLiteral(3))),
|
|
||||||
NatLiteral(4))));
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("(1 + 2) * 3",
|
|
||||||
exst!(binexp!("*", binexp!("+", NatLiteral(1), NatLiteral(2)), NatLiteral(3))));
|
|
||||||
|
|
||||||
parse_test_wrap_ast!(".1 + .2", exst!(binexp!("+", FloatLiteral(0.1), FloatLiteral(0.2))));
|
|
||||||
parse_test_wrap_ast!("1 / 2", exst!(binexp!("/", NatLiteral(1), NatLiteral(2))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_tuples() {
|
|
||||||
parse_test_wrap_ast!("()", exst!(TupleLiteral(vec![])));
|
|
||||||
parse_test_wrap_ast!("(\"hella\", 34)", exst!(
|
|
||||||
TupleLiteral(
|
|
||||||
vec![ex!(s r#""hella""#), ex!(s "34")]
|
|
||||||
)
|
|
||||||
));
|
|
||||||
parse_test_wrap_ast!("((1+2), \"slough\")", exst!(TupleLiteral(vec![
|
|
||||||
ex!(binexp!("+", NatLiteral(1), NatLiteral(2))),
|
|
||||||
ex!(StringLiteral(rc!(slough))),
|
|
||||||
])))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_identifiers() {
|
|
||||||
parse_test_wrap_ast!("a", exst!(val!("a")));
|
|
||||||
parse_test_wrap_ast!("some_value", exst!(val!("some_value")));
|
|
||||||
parse_test_wrap_ast!("a + b", 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_wrap_ast!("a[b,c]", exst!(Index { indexee: bx!(ex!(val!("a"))), indexers: vec![ex!(val!("b")), ex!(val!("c"))]} ));
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("None", exst!(val!("None")));
|
|
||||||
parse_test_wrap_ast!("Pandas { a: x + y }",
|
|
||||||
exst!(NamedStruct { name: qname!(Pandas), fields: vec![(rc!(a), ex!(binexp!("+", val!("x"), val!("y"))))]})
|
|
||||||
);
|
|
||||||
parse_test_wrap_ast! { "Pandas { a: n, b: q, }",
|
|
||||||
exst!(NamedStruct { name: qname!(Pandas), fields:
|
|
||||||
vec![(rc!(a), ex!(val!("n"))), (rc!(b), ex!(val!("q")))]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn qualified_identifiers() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"let q_q = Yolo::Swaggins",
|
|
||||||
decl!(Binding { name: rc!(q_q), constant: true, type_anno: None,
|
|
||||||
expr: Expression::new(Default::default(), Value(qname!(Yolo, Swaggins))),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"thing::item::call()",
|
|
||||||
exst!(Call { f: bx![ex!(Value(qname!(thing, item, call)))], arguments: vec![] })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn reserved_words() {
|
|
||||||
parse_error!("module::item::call()");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_complicated_operators() {
|
|
||||||
parse_test_wrap_ast!("a <- b", exst!(binexp!("<-", val!("a"), val!("b"))));
|
|
||||||
parse_test_wrap_ast!("a || b", exst!(binexp!("||", val!("a"), val!("b"))));
|
|
||||||
parse_test_wrap_ast!("a<>b", exst!(binexp!("<>", val!("a"), val!("b"))));
|
|
||||||
parse_test_wrap_ast!("a.b.c.d", exst!(binexp!(".",
|
|
||||||
binexp!(".",
|
|
||||||
binexp!(".", val!("a"), val!("b")),
|
|
||||||
val!("c")),
|
|
||||||
val!("d"))));
|
|
||||||
parse_test_wrap_ast!("-3", exst!(prefexp!("-", NatLiteral(3))));
|
|
||||||
parse_test_wrap_ast!("-0.2", exst!(prefexp!("-", FloatLiteral(0.2))));
|
|
||||||
parse_test_wrap_ast!("!3", exst!(prefexp!("!", NatLiteral(3))));
|
|
||||||
parse_test_wrap_ast!("a <- -b", exst!(binexp!("<-", val!("a"), prefexp!("-", val!("b")))));
|
|
||||||
parse_test_wrap_ast!("a <--b", exst!(binexp!("<--", val!("a"), val!("b"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_functions() {
|
|
||||||
parse_test_wrap_ast!("fn oi()", decl!(FuncSig(Signature { name: rc!(oi), operator: false, params: vec![], type_anno: None })));
|
|
||||||
parse_test_wrap_ast!("oi()", exst!(Call { f: bx!(ex!(val!("oi"))), arguments: vec![] }));
|
|
||||||
parse_test_wrap_ast!("oi(a, 2 + 2)", exst!(Call
|
|
||||||
{ f: bx!(ex!(val!("oi"))),
|
|
||||||
arguments: vec![inv!(ex!(val!("a"))), inv!(ex!(binexp!("+", NatLiteral(2), NatLiteral(2))))]
|
|
||||||
}));
|
|
||||||
parse_error!("a(b,,c)");
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("fn a(b, c: Int): Int", decl!(
|
|
||||||
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_wrap_ast!("fn a(x) { x() }", decl!(
|
|
||||||
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!(val!("x"))), arguments: vec![] })].into())));
|
|
||||||
parse_test_wrap_ast!("fn a(x) {\n x() }", decl!(
|
|
||||||
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!(val!("x"))), arguments: vec![] })].into())));
|
|
||||||
|
|
||||||
let multiline = r#"
|
|
||||||
fn a(x) {
|
|
||||||
x()
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
parse_test_wrap_ast!(multiline, decl!(
|
|
||||||
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!(val!("x"))), arguments: vec![] })].into())));
|
|
||||||
let multiline2 = r#"
|
|
||||||
fn a(x) {
|
|
||||||
|
|
||||||
x()
|
|
||||||
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
parse_test_wrap_ast!(multiline2, decl!(
|
|
||||||
FuncDecl(Signature { name: rc!(a), operator: false, params: vec![FormalParam { name: rc!(x), default: None, anno: None }], type_anno: None },
|
|
||||||
exst!(s "x()").into())));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn functions_with_default_args() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"fn func(x: Int, y: Int = 4) { }",
|
|
||||||
decl!(
|
|
||||||
FuncDecl(Signature { name: rc!(func), operator: false, type_anno: None, params: vec![
|
|
||||||
FormalParam { name: rc!(x), default: None, anno: Some(ty!("Int")) },
|
|
||||||
FormalParam { name: rc!(y), default: Some(ex!(s "4")), anno: Some(ty!("Int")) }
|
|
||||||
]}, vec![].into())
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_bools() {
|
|
||||||
parse_test_wrap_ast!("false", exst!(BoolLiteral(false)));
|
|
||||||
parse_test_wrap_ast!("true", exst!(BoolLiteral(true)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_strings() {
|
|
||||||
parse_test_wrap_ast!(r#""hello""#, exst!(StringLiteral(rc!(hello))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parsing_types() {
|
fn parsing_types() {
|
||||||
parse_test_wrap_ast!("type Yolo = Yolo", decl!(TypeDecl { name: tys!("Yolo"), body: TypeBody(vec![Variant { id: ItemId::default(), kind: UnitStruct, name: rc!(Yolo) }]), mutable: false} ));
|
parse_test_wrap_ast!("type Yolo = Yolo", decl!(TypeDecl { name: tys!("Yolo"), body: TypeBody(vec![Variant { id: ItemId::default(), kind: UnitStruct, name: rc!(Yolo) }]), mutable: false} ));
|
||||||
@ -363,16 +146,6 @@ fn parsing_types() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_bindings() {
|
|
||||||
parse_test_wrap_ast!("let mut a = 10", decl!(Binding { name: rc!(a), constant: false, type_anno: None, expr: ex!(NatLiteral(10)) } ));
|
|
||||||
parse_test_wrap_ast!("let a = 2 + 2", decl!(Binding { name: rc!(a), constant: true, type_anno: None, expr: ex!(binexp!("+", NatLiteral(2), NatLiteral(2))) }));
|
|
||||||
parse_test_wrap_ast!("let a: Nat = 2 + 2", decl!(
|
|
||||||
Binding { name: rc!(a), constant: true, type_anno: Some(Singleton(TypeSingletonName { name: rc!(Nat), params: vec![] })),
|
|
||||||
expr: ex!(binexp!("+", NatLiteral(2), NatLiteral(2))) }
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parsing_block_expressions() {
|
fn parsing_block_expressions() {
|
||||||
parse_test_wrap_ast! {
|
parse_test_wrap_ast! {
|
||||||
@ -439,25 +212,6 @@ fn parsing_block_expressions() {
|
|||||||
parse_error!("if A {a: 1} { b } else { c }");
|
parse_error!("if A {a: 1} { b } else { c }");
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn parsing_interfaces() {
|
|
||||||
parse_test_wrap_ast!("interface Unglueable { fn unglue(a: Glue); fn mar(): Glue }",
|
|
||||||
decl!(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]
|
#[test]
|
||||||
fn parsing_impls() {
|
fn parsing_impls() {
|
||||||
@ -497,33 +251,6 @@ fn parsing_impls() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_type_annotations() {
|
|
||||||
parse_test_wrap_ast!("let a = b : Int",
|
|
||||||
decl!(Binding { name: rc!(a), constant: true, type_anno: None, expr:
|
|
||||||
ex!(val!("b"), ty!("Int")) }));
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("a : Int",
|
|
||||||
exst!(val!("a"), ty!("Int"))
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("a : Option<Int>",
|
|
||||||
exst!(val!("a"), Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("Int")] }))
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("a : KoreanBBQSpecifier<Kimchi, Option<Bulgogi> >",
|
|
||||||
exst!(val!("a"), Singleton(TypeSingletonName { name: rc!(KoreanBBQSpecifier), params: vec![
|
|
||||||
ty!("Kimchi"), Singleton(TypeSingletonName { name: rc!(Option), params: vec![ty!("Bulgogi")] })
|
|
||||||
] }))
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_test_wrap_ast!("a : (Int, Yolo<a>)",
|
|
||||||
exst!(val!("a"), Tuple(
|
|
||||||
vec![ty!("Int"), Singleton(TypeSingletonName {
|
|
||||||
name: rc!(Yolo), params: vec![ty!("a")]
|
|
||||||
})])));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parsing_lambdas() {
|
fn parsing_lambdas() {
|
||||||
parse_test_wrap_ast! { r#"\(x) { x + 1}"#, exst!(
|
parse_test_wrap_ast! { r#"\(x) { x + 1}"#, exst!(
|
||||||
@ -615,37 +342,6 @@ fn more_advanced_lambdas() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn while_expr() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"while { }",
|
|
||||||
exst!(WhileExpression { condition: None, body: Block::default() })
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"while a == b { }",
|
|
||||||
exst!(WhileExpression { condition: Some(bx![ex![binexp!("==", val!("a"), val!("b"))]]), body: Block::default() })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn for_expr() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"for { a <- maybeValue } return 1",
|
|
||||||
exst!(ForExpression {
|
|
||||||
enumerators: vec![Enumerator { id: rc!(a), generator: ex!(val!("maybeValue")) }],
|
|
||||||
body: bx!(MonadicReturn(ex!(s "1")))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"for n <- someRange { f(n); }",
|
|
||||||
exst!(ForExpression { enumerators: vec![Enumerator { id: rc!(n), generator: ex!(val!("someRange"))}],
|
|
||||||
body: bx!(ForBody::StatementBlock(vec![exst!(s "f(n)")].into()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn patterns() {
|
fn patterns() {
|
||||||
parse_test_wrap_ast! {
|
parse_test_wrap_ast! {
|
||||||
@ -751,58 +447,6 @@ fn pattern_literals() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn imports() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"import harbinger::draughts::Norgleheim",
|
|
||||||
import!(ImportSpecifier {
|
|
||||||
id: Default::default(),
|
|
||||||
path_components: vec![rc!(harbinger), rc!(draughts), rc!(Norgleheim)],
|
|
||||||
imported_names: ImportedNames::LastOfPath
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn imports_2() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"import harbinger::draughts::{Norgleheim, Xraksenlaigar}",
|
|
||||||
import!(ImportSpecifier {
|
|
||||||
id: Default::default(),
|
|
||||||
path_components: vec![rc!(harbinger), rc!(draughts)],
|
|
||||||
imported_names: ImportedNames::List(vec![
|
|
||||||
rc!(Norgleheim),
|
|
||||||
rc!(Xraksenlaigar)
|
|
||||||
])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn imports_3() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"import bespouri::{}",
|
|
||||||
import!(ImportSpecifier {
|
|
||||||
id: Default::default(),
|
|
||||||
path_components: vec![rc!(bespouri)],
|
|
||||||
imported_names: ImportedNames::List(vec![])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn imports_4() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
"import bespouri::*",
|
|
||||||
import!(ImportSpecifier {
|
|
||||||
id: Default::default(),
|
|
||||||
path_components: vec![rc!(bespouri)],
|
|
||||||
imported_names: ImportedNames::All
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn if_expr() {
|
fn if_expr() {
|
||||||
@ -878,64 +522,3 @@ if (45, "panda", false, 2.2) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn modules() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
r#"
|
|
||||||
module ephraim {
|
|
||||||
let a = 10
|
|
||||||
fn nah() { 33 }
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
module!(
|
|
||||||
ModuleSpecifier { name: rc!(ephraim), contents: vec![
|
|
||||||
decl!(Binding { name: rc!(a), constant: true, type_anno: None, expr: ex!(s "10") }),
|
|
||||||
decl!(FuncDecl(Signature { name: rc!(nah), operator: false, params: vec![], type_anno: None }, vec![exst!(NatLiteral(33))].into())),
|
|
||||||
].into() }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn annotations() {
|
|
||||||
parse_test! {
|
|
||||||
r#"
|
|
||||||
@test_annotation
|
|
||||||
fn some_function() {
|
|
||||||
|
|
||||||
}"#,
|
|
||||||
AST {
|
|
||||||
id: Default::default(),
|
|
||||||
statements: vec![
|
|
||||||
decl!(Annotation { name: rc!(test_annotation), arguments: vec![] }),
|
|
||||||
decl!(FuncDecl(
|
|
||||||
Signature { name: rc!(some_function), operator: false, params: vec![], type_anno: None }
|
|
||||||
, vec![].into()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
].into()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
parse_test! {
|
|
||||||
r#"
|
|
||||||
@test_annotation(some, value)
|
|
||||||
fn some_function() {
|
|
||||||
|
|
||||||
}"#,
|
|
||||||
AST {
|
|
||||||
id: Default::default(),
|
|
||||||
statements: vec![
|
|
||||||
decl!(Annotation { name: rc!(test_annotation), arguments: vec![
|
|
||||||
ex!(val!("some")),
|
|
||||||
ex!(val!("value"))
|
|
||||||
] }),
|
|
||||||
decl!(FuncDecl(
|
|
||||||
Signature { name: rc!(some_function), operator: false, params: vec![], type_anno: None }
|
|
||||||
, vec![].into()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
].into()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user