Compare commits
2 Commits
ea494bb328
...
1c6545fb74
Author | SHA1 | Date | |
---|---|---|---|
|
1c6545fb74 | ||
|
46fe03b43f |
@ -69,15 +69,21 @@
|
|||||||
//! ```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 extended_expr
|
||||||
//! prefix_op := "+" | "-" | "!" | "~"
|
//!
|
||||||
//! call_expr := index_expr ( "(" invocation_list ")" )* | ε
|
//! prefix_op := "+" | "-" | "!" | "~" | ε
|
||||||
//! invocation_list := invocation_argument ("," invocation_argument)* | ε
|
//!
|
||||||
//! invocation_argument := expression | IDENTIFIER "=" expression | "_"
|
//! extended_expr := primary (ε | index | call | access)*
|
||||||
//! index_expr := primary ( "[" (expression ("," (expression)* | ε) "]" )*
|
//! index := "[" (expression ("," expression)*) "]"
|
||||||
|
//! call := "(" invocation_list ")"
|
||||||
|
//! access := "." identifier
|
||||||
//! primary := literal | paren_expr | if_expr | for_expr | while_expr | identifier_expr | lambda_expr | anonymous_struct | list_expr
|
//! primary := literal | paren_expr | if_expr | for_expr | while_expr | identifier_expr | lambda_expr | anonymous_struct | list_expr
|
||||||
//! expr_or_block := "{" (statement delimiter)* "}" | expr
|
//! expr_or_block := "{" (statement delimiter)* "}" | expr
|
||||||
|
//!
|
||||||
|
//! invocation_list := invocation_argument ("," invocation_argument)* | ε
|
||||||
|
//! invocation_argument := expression | IDENTIFIER "=" expression | "_"
|
||||||
//! ```
|
//! ```
|
||||||
|
//! //TODO fix expressions, add accessor_expr as a new thing
|
||||||
//!
|
//!
|
||||||
//! ### Primary expressions
|
//! ### Primary expressions
|
||||||
//!
|
//!
|
||||||
@ -688,20 +694,39 @@ impl Parser {
|
|||||||
ExpressionKind::PrefixExp(prefix_op, Box::new(expr))
|
ExpressionKind::PrefixExp(prefix_op, Box::new(expr))
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
_ => self.call_expr()
|
_ => self.extended_expr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[recursive_descent_method]
|
#[recursive_descent_method]
|
||||||
fn call_expr(&mut self) -> ParseResult<Expression> {
|
fn extended_expr(&mut self) -> ParseResult<Expression> {
|
||||||
let mut expr = self.index_expr()?;
|
let mut expression = self.primary()?;
|
||||||
//TODO look at this
|
loop {
|
||||||
while let LParen = self.token_handler.peek_kind() {
|
//TODO need a next non whitespace
|
||||||
let arguments = delimited!(self, LParen, invocation_argument, Comma, RParen);
|
let next = self.token_handler.peek_kind();
|
||||||
expr = Expression::new(self.id_store.fresh(), ExpressionKind::Call { f: Box::new(expr), arguments }); //TODO no type anno is incorrect
|
match next {
|
||||||
|
Period => unimplemented!(),
|
||||||
|
LSquareBracket => {
|
||||||
|
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 = Expression::new(self.id_store.fresh(), ExpressionKind::Index {
|
||||||
Ok(expr)
|
indexee: Box::new(expression),
|
||||||
|
indexers,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
LParen => {
|
||||||
|
let arguments = delimited!(self, LParen, invocation_argument, Comma, RParen);
|
||||||
|
expression = Expression::new(self.id_store.fresh(), ExpressionKind::Call {
|
||||||
|
f: Box::new(expression),
|
||||||
|
arguments,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[recursive_descent_method]
|
#[recursive_descent_method]
|
||||||
|
@ -85,6 +85,10 @@ macro_rules! qn {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn int_anno() -> TypeIdentifier {
|
||||||
|
TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] })
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! assert_ast {
|
macro_rules! assert_ast {
|
||||||
($input:expr, $statements:expr) => {
|
($input:expr, $statements:expr) => {
|
||||||
let ast = parse($input).unwrap();
|
let ast = parse($input).unwrap();
|
||||||
@ -116,7 +120,6 @@ macro_rules! assert_fail_expr {
|
|||||||
assert_eq!(err.msg, $failure);
|
assert_eq!(err.msg, $failure);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_literals() {
|
fn basic_literals() {
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
@ -198,14 +201,14 @@ fn operators() {
|
|||||||
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
|
#[test]
|
||||||
/*
|
fn accessors() {
|
||||||
assert_expr!("a.b.c.d", exst!(binexp!(".",
|
/*
|
||||||
binexp!(".",
|
assert_expr!("a.b");
|
||||||
binexp!(".", val!("a"), val!("b")),
|
assert_expr!("a.b.c.d()");
|
||||||
val!("c")),
|
assert_expr!("a.b().c.d()");
|
||||||
val!("d"))));
|
*/
|
||||||
*/
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tuples() {
|
fn tuples() {
|
||||||
@ -269,17 +272,19 @@ fn index() {
|
|||||||
indexers: vec![expr(Value(qn!(b))), expr(Value(qn!(c)))]
|
indexers: vec![expr(Value(qn!(b))), expr(Value(qn!(c)))]
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
//TODO this is a parser bug
|
assert_expr!(
|
||||||
/*
|
"perspicacity()[a]",
|
||||||
assert_expr!("perspicacity()[a]", expr(Index{
|
expr(Index {
|
||||||
indexee: bx(expr(Call {
|
indexee: bx(expr(Call { f: bx(expr(Value(qn!(perspicacity)))), arguments: vec![] })),
|
||||||
f: bx(expr(Value(qn!(perspicacity)))),
|
|
||||||
arguments: vec![]
|
|
||||||
})),
|
|
||||||
indexers: vec![expr(Value(qn!(a)))]
|
indexers: vec![expr(Value(qn!(a)))]
|
||||||
}));
|
})
|
||||||
*/
|
);
|
||||||
//TODO parse_test("a()[b]()[d]")
|
|
||||||
|
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");
|
assert_fail_expr!("a[]", "Empty index expressions are not allowed");
|
||||||
}
|
}
|
||||||
@ -325,6 +330,134 @@ fn for_expression() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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]
|
#[test]
|
||||||
fn reserved_words() {
|
fn reserved_words() {
|
||||||
assert_fail!("module::item::call()", "Expected an identifier, got Colon");
|
assert_fail!("module::item::call()", "Expected an identifier, got Colon");
|
||||||
@ -532,7 +665,6 @@ fn functions_with_different_whitespace() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn functions_with_default_args() {
|
fn functions_with_default_args() {
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
let int_anno = TypeIdentifier::Singleton(TypeSingletonName { name: rc("Int"), params: vec![] });
|
|
||||||
|
|
||||||
assert_ast!(
|
assert_ast!(
|
||||||
"fn func(x: Int, y: Int = 4) { }",
|
"fn func(x: Int, y: Int = 4) { }",
|
||||||
@ -542,8 +674,8 @@ fn functions_with_default_args() {
|
|||||||
operator: false,
|
operator: false,
|
||||||
type_anno: None,
|
type_anno: None,
|
||||||
params: vec![
|
params: vec![
|
||||||
FormalParam { name: rc("x"), anno: Some(int_anno.clone()), default: None },
|
FormalParam { name: rc("x"), anno: Some(int_anno()), default: None },
|
||||||
FormalParam { name: rc("y"), anno: Some(int_anno), default: Some(expr(NatLiteral(4))) },
|
FormalParam { name: rc("y"), anno: Some(int_anno()), default: Some(expr(NatLiteral(4))) },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
vec![].into()
|
vec![].into()
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#![allow(clippy::upper_case_acronyms)]
|
#![allow(clippy::upper_case_acronyms)]
|
||||||
#![allow(clippy::vec_init_then_push)]
|
#![allow(clippy::vec_init_then_push)]
|
||||||
|
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::tokenizing::Location;
|
use crate::tokenizing::Location;
|
||||||
@ -87,10 +88,6 @@ macro_rules! ex {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! inv {
|
|
||||||
($expr_type:expr) => { InvocationArgument::Positional($expr_type) }
|
|
||||||
}
|
|
||||||
|
|
||||||
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())) };
|
||||||
@ -251,89 +248,6 @@ fn parsing_impls() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parsing_lambdas() {
|
|
||||||
parse_test_wrap_ast! { r#"\(x) { x + 1}"#, exst!(
|
|
||||||
Lambda { params: vec![FormalParam { name: rc!(x), anno: None, default: None } ], type_anno: None, body: exst!(s "x + 1").into() }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_test_wrap_ast!(r#"\ (x: Int, y) { a;b;c;}"#,
|
|
||||||
exst!(Lambda {
|
|
||||||
params: vec![
|
|
||||||
FormalParam { name: rc!(x), anno: Some(ty!("Int")), default: None },
|
|
||||||
FormalParam { name: rc!(y), anno: None, default: None }
|
|
||||||
],
|
|
||||||
type_anno: None,
|
|
||||||
body: vec![exst!(s "a"), exst!(s "b"), exst!(s "c")].into()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_test_wrap_ast! { r#"\(x){y}(1)"#,
|
|
||||||
exst!(Call { f: bx!(ex!(
|
|
||||||
Lambda {
|
|
||||||
params: vec![
|
|
||||||
FormalParam { name: rc!(x), anno: None, default: None }
|
|
||||||
],
|
|
||||||
type_anno: None,
|
|
||||||
body: exst!(s "y").into() }
|
|
||||||
)),
|
|
||||||
arguments: vec![inv!(ex!(NatLiteral(1)))] })
|
|
||||||
};
|
|
||||||
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
r#"\(x: Int): String { "q" }"#,
|
|
||||||
exst!(Lambda {
|
|
||||||
params: vec![
|
|
||||||
FormalParam { name: rc!(x), anno: Some(ty!("Int")), default: None },
|
|
||||||
],
|
|
||||||
type_anno: Some(ty!("String")),
|
|
||||||
body: exst!(s r#""q""#).into()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn single_param_lambda() {
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
r"\x { x + 10 }",
|
|
||||||
exst!(Lambda {
|
|
||||||
params: vec![FormalParam { name: rc!(x), anno: None, default: None }],
|
|
||||||
type_anno: None,
|
|
||||||
body: exst!(s r"x + 10").into()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_test_wrap_ast! {
|
|
||||||
r"\x: Nat { x + 10 }",
|
|
||||||
exst!(Lambda {
|
|
||||||
params: vec![FormalParam { name: rc!(x), anno: Some(ty!("Nat")), default: None }],
|
|
||||||
type_anno: None,
|
|
||||||
body: exst!(s r"x + 10").into()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn more_advanced_lambdas() {
|
|
||||||
parse_test! {
|
|
||||||
r#"fn wahoo() { let a = 10; \(x) { x + a } };
|
|
||||||
wahoo()(3) "#,
|
|
||||||
AST {
|
|
||||||
id: Default::default(),
|
|
||||||
statements: vec![
|
|
||||||
exst!(s r"fn wahoo() { let a = 10; \(x) { x + a } }"),
|
|
||||||
exst! {
|
|
||||||
Call {
|
|
||||||
f: bx!(ex!(Call { f: bx!(ex!(val!("wahoo"))), arguments: vec![] })),
|
|
||||||
arguments: vec![inv!(ex!(NatLiteral(3)))],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
].into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_literals() {
|
fn list_literals() {
|
||||||
parse_test_wrap_ast! {
|
parse_test_wrap_ast! {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![cfg(test)]
|
#![cfg(test)]
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
symbol_table::SymbolTable,
|
symbol_table::SymbolTable,
|
||||||
|
Loading…
Reference in New Issue
Block a user