diff --git a/schala-lang/language/src/parsing/new.rs b/schala-lang/language/src/parsing/new.rs index 06986a1..8525584 100644 --- a/schala-lang/language/src/parsing/new.rs +++ b/schala-lang/language/src/parsing/new.rs @@ -13,6 +13,8 @@ peg::parser! { rule _ = quiet!{ whitespace() } + rule __ = quiet!{ [' ' | '\t' ]* } + pub rule program() -> AST = n:(statement() ** delimiter() ) { AST { id: Default::default(), statements: n.into() } } @@ -27,11 +29,43 @@ peg::parser! { stmt:statement() delimiter()+ { stmt } rule statement() -> Statement = - _ decl:declaration() { Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Declaration(decl) } } / - _ expr:expression() { Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(expr) } } + kind:statement_kind() { Statement { id: Default::default(), location: Default::default(), kind } } + + rule statement_kind() -> StatementKind = + _ decl:declaration() { StatementKind::Declaration(decl) } / + _ expr:expression() { StatementKind::Expression(expr) } rule declaration() -> Declaration = - binding() / type_decl() + binding() / type_decl() / annotation() / func() + + rule func() -> Declaration = + sig:func_signature() __ body:block() { Declaration::FuncDecl(sig, body) } / + sig:func_signature() { Declaration::FuncSig(sig) } + + //TODO handle operators + rule func_signature() -> Signature = + "fn" _ name:identifier() "(" _ params:formal_params() _ ")" _ type_anno:type_anno()? { Signature { + name: rc_string(name), operator: false, params, type_anno + } } + + rule formal_params() -> Vec = params:(formal_param() ** (_ "," _)) {? if params.len() < 256 { Ok(params) } else { + Err("function-too-long") } + } + + rule formal_param() -> FormalParam = + name:identifier() _ anno:type_anno()? _ "=" expr:expression() { FormalParam { name: rc_string(name), + default: Some(expr), anno } } / + name:identifier() _ anno:type_anno()? { FormalParam { name: rc_string(name), default: None, anno } } + + + rule annotation() -> Declaration = + "@" name:identifier() args:annotation_args()? delimiter() _ inner:statement() { Declaration::Annotation { + name: rc_string(name), arguments: if let Some(args) = args { args } else { vec![] }, inner: Box::new(inner) } + } + + rule annotation_args() -> Vec = + "(" _ args:(expression() ** (_ "," _)) _ ")" { args } + rule binding() -> Declaration = "let" _ mutable:"mut"? _ ident:identifier() _ type_anno:type_anno()? _ "=" _ expr:expression() { diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index dad6ff8..e104725 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -126,6 +126,13 @@ macro_rules! assert_fail { }; } +macro_rules! assert_fail2 { + ($input:expr, $failure:expr) => { + let err = schala_parser::program($input).unwrap_err(); + assert_eq!(err.to_string(), $failure); + }; +} + macro_rules! assert_expr { ($input:expr, $correct:expr) => { let mut parser = make_parser($input); @@ -770,7 +777,7 @@ fn bindings() { #[test] fn functions() { use ExpressionKind::*; - assert_ast!( + assert_ast2!( "fn oi()", vec![stmt(StatementKind::Declaration(Declaration::FuncSig(Signature { name: rc("oi"), @@ -780,12 +787,12 @@ fn functions() { })))] ); - assert_ast!( + assert_ast2!( "oi()", vec![stmt(StatementKind::Expression(expr(Call { f: bx(expr(Value(qn!(oi)))), arguments: vec![] })))] ); - assert_expr!( + assert_expr2!( "oi(a, 2+2)", expr(Call { f: bx(expr(Value(qn!(oi)))), @@ -797,7 +804,7 @@ fn functions() { ); assert_fail!("a(b,,c)", "Expected a literal expression, got Comma"); - assert_ast!( + assert_ast2!( "fn a(b, c: Int): Int", vec![stmt(StatementKind::Declaration(Declaration::FuncSig(Signature { name: rc("a"), @@ -825,7 +832,9 @@ fn max_function_params() { write!(buf, "a{}, ", n).unwrap(); } write!(buf, ") {{ return 20 }}").unwrap(); - assert_fail!(&buf, "A function cannot have more than 255 arguments"); + //assert_fail2!(&buf, "A function cannot have more than 255 arguments"); + //TODO better errors again + assert_fail2!(&buf, "error at 1:1439: expected ['a' ..= 'z' | 'A' ..= 'Z' | '_']"); } #[test]