diff --git a/Cargo.lock b/Cargo.lock index 13b6e31..3b4741d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -561,8 +561,7 @@ dependencies = [ [[package]] name = "peg" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" +source = "git+https://github.com/kevinmehall/rust-peg?rev=960222580c8da25b17d32c2aae6f52f902728b62#960222580c8da25b17d32c2aae6f52f902728b62" dependencies = [ "peg-macros", "peg-runtime", @@ -571,8 +570,7 @@ dependencies = [ [[package]] name = "peg-macros" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" +source = "git+https://github.com/kevinmehall/rust-peg?rev=960222580c8da25b17d32c2aae6f52f902728b62#960222580c8da25b17d32c2aae6f52f902728b62" dependencies = [ "peg-runtime", "proc-macro2 1.0.30", @@ -582,8 +580,7 @@ dependencies = [ [[package]] name = "peg-runtime" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" +source = "git+https://github.com/kevinmehall/rust-peg?rev=960222580c8da25b17d32c2aae6f52f902728b62#960222580c8da25b17d32c2aae6f52f902728b62" [[package]] name = "phf" diff --git a/schala-lang/language/Cargo.toml b/schala-lang/language/Cargo.toml index 72e259b..94026da 100644 --- a/schala-lang/language/Cargo.toml +++ b/schala-lang/language/Cargo.toml @@ -14,7 +14,9 @@ derivative = "1.0.3" colored = "1.8" radix_trie = "0.1.5" assert_matches = "1.5" -peg = "0.7.0" +#peg = "0.7.0" +peg = { git = "https://github.com/kevinmehall/rust-peg", rev = "960222580c8da25b17d32c2aae6f52f902728b62" } + schala-lang-codegen = { path = "../codegen" } schala-repl = { path = "../../schala-repl" } diff --git a/schala-lang/language/src/parsing/new.rs b/schala-lang/language/src/parsing/new.rs index db3b62b..c6937fd 100644 --- a/schala-lang/language/src/parsing/new.rs +++ b/schala-lang/language/src/parsing/new.rs @@ -7,7 +7,7 @@ peg::parser! { rule whitespace() = [' ' | '\t' | '\n']* - rule _ = quiet!{ whitespace() } + rule _ = quiet!{ whitespace() } pub rule program() -> AST = n:(statement() ** delimiter() ) { AST { id: Default::default(), statements: n.into() } } @@ -55,15 +55,49 @@ peg::parser! { quiet!{$( ['+' | '-' | '*' | '/' | '%' | '<' | '>' | '=' | '!' | '$' | '&' | '|' | '?' | '^' | '`']+ )} / expected!("operator") + #[cache_left_rec] rule extended_expr() -> ExpressionKind = + indexee:extended_expr() indexers:index_part() { + ExpressionKind::Index { + indexee: Box::new(Expression::new(Default::default(), indexee)), + indexers, + } + } / + f:extended_expr() arguments:call_part() { + ExpressionKind::Call { + f: Box::new(Expression::new(Default::default(), f)), + arguments, + } + + } / + expr:extended_expr() "." name:identifier() { ExpressionKind::Access { + name: Rc::new(name.to_string()), + expr: Box::new(Expression::new(Default::default(),expr)), + } } / primary() + rule index_part() -> Vec = + "[" indexers:(expression() ++ ",") "]" { indexers } + + rule call_part() -> Vec = + "(" arguments:(invocation_argument() ** ",") ")" { arguments } + + //TODO this shouldn't be an expression b/c type annotations disallowed here + rule invocation_argument() -> InvocationArgument = + _ "_" _ { InvocationArgument::Ignored } / + _ ident:identifier() _ "=" _ expr:expression() { InvocationArgument::Keyword { + name: Rc::new(ident.to_string()), + expr + } } / + _ expr:expression() _ { InvocationArgument::Positional(expr) } + + rule primary() -> ExpressionKind = float_literal() / nat_literal() / bool_literal() / string_literal() / paren_expr() / - list_expr() / if_expr() / identifier_expr() + list_expr() / if_expr() / named_struct() / identifier_expr() rule identifier_expr() -> ExpressionKind = - named_struct() / qn:qualified_identifier() { ExpressionKind::Value(qn) } + qn:qualified_identifier() { ExpressionKind::Value(qn) } rule named_struct() -> ExpressionKind = name:qualified_identifier() _ fields:record_block() { diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index 7ba4a93..ca4d03d 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -152,13 +152,6 @@ macro_rules! assert_fail_expr2 { }; } -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::*; @@ -250,15 +243,15 @@ fn operators() { fn accessors() { use ExpressionKind::*; - assert_expr!("a.b", expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) })); - assert_expr!( + assert_expr2!("a.b", expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) })); + assert_expr2!( "a.b.c", expr(Access { name: rc("c"), expr: bx(expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) })) }) ); - assert_expr!( + assert_expr2!( "a.b.c(3)", expr(Call { f: bx(expr(Access { @@ -268,7 +261,7 @@ fn accessors() { arguments: vec![InvocationArgument::Positional(expr(NatLiteral(3)))], }) ); - assert_expr!( + assert_expr2!( "a.b().c", expr(Access { name: rc("c"), @@ -307,7 +300,7 @@ fn identifiers() { assert_expr2!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma)))); assert_expr2!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b))))); assert_expr2!("None", expr(Value(qn!(None)))); - assert_expr!( + assert_expr2!( "thing::item::call()", expr(Call { f: bx(expr(Value(qn!(thing, item, call)))), arguments: vec![] }) ); @@ -335,14 +328,24 @@ fn named_struct() { #[test] fn index() { use ExpressionKind::*; - assert_expr!( - "a[b,c]", + assert_expr2!( + "armok[b,c]", expr(Index { - indexee: bx(expr(Value(qn!(a)))), + indexee: bx(expr(Value(qn!(armok)))), indexers: vec![expr(Value(qn!(b))), expr(Value(qn!(c)))] }) ); - assert_expr!( + assert_expr2!( + "a[b,c][1]", + expr(Index { + indexee: bx(expr(Index { + indexee: bx(expr(Value(qn!(a)))), + indexers: vec![expr(Value(qn!(b))), expr(Value(qn!(c)))] + })), + indexers: vec![expr(NatLiteral(1))] + }) + ); + assert_expr2!( "perspicacity()[a]", expr(Index { indexee: bx(expr(Call { f: bx(expr(Value(qn!(perspicacity)))), arguments: vec![] })), @@ -354,9 +357,9 @@ fn index() { 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_expr2!("a()[b]()[d]", d); - assert_fail_expr!("a[]", "Empty index expressions are not allowed"); + assert_fail_expr2!("a[]", "Empty index expressions are not allowed"); } #[test]