diff --git a/schala-lang/src/parsing/combinator.rs b/schala-lang/src/parsing/combinator.rs index 157278d..7045bc1 100644 --- a/schala-lang/src/parsing/combinator.rs +++ b/schala-lang/src/parsing/combinator.rs @@ -7,7 +7,7 @@ use nom::{ complete::{alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space1}, is_alphanumeric, }, - combinator::{cond, flat_map, map, not, opt, peek, recognize, value}, + combinator::{cut, map, not, opt, peek, recognize, value}, error::{context, ParseError, VerboseError}, multi::{many0, many1, separated_list0, separated_list1}, sequence::{delimited, pair, preceded, separated_pair, tuple}, @@ -126,6 +126,7 @@ fn statement(input: Span) -> ParseResult { "Parsing-statement", alt(( map(flow, StatementKind::Flow), + map(import, StatementKind::Import), map(declaration, StatementKind::Declaration), map(expression, StatementKind::Expression), )), @@ -133,6 +134,42 @@ fn statement(input: Span) -> ParseResult { Ok((rest, Statement { id, location, kind })) } +fn import(input: Span) -> ParseResult { + fn path_components(input: Span) -> ParseResult>> { + map( + tuple((opt(tag("::")), identifier, many0(preceded(tag("::"), identifier_span)))), + |(_maybe_root, first, rest)| { + let mut components = vec![rc_string(first.fragment())]; + components.extend(rest.into_iter().map(|n| rc_string(n.fragment()))); + components + }, + )(input) + } + + fn import_suffix(input: Span) -> ParseResult { + alt(( + value(ImportedNames::All, tag("::*")), + map( + preceded( + tag("::"), + delimited(char('{'), separated_list0(tok(char(',')), identifier), char('}')), + ), + |names| ImportedNames::List(names.into_iter().map(|n| rc_string(n.fragment())).collect()), + ), + ))(input) + } + + let id = fresh_id(&input); + map( + preceded(kw("import"), cut(pair(path_components, opt(import_suffix)))), + move |(path_components, suffix)| ImportSpecifier { + id, + path_components, + imported_names: suffix.unwrap_or(ImportedNames::LastOfPath), + }, + )(input) +} + fn flow(input: Span) -> ParseResult { alt(( map(kw("continue"), |_| FlowControl::Continue), @@ -693,7 +730,7 @@ fn bare_string_literal(input: Span) -> ParseResult { alt((value("\\", tag("\\")), value("\"", tag("\"")), value("\n", tag("n")), value("\t", tag("t")))); alt(( map(tag(r#""""#), |_| String::new()), - delimited(char('"'), escaped_transform(none_of(r#""\"#), '\\', string_escape_transforms), char('"')) + delimited(char('"'), escaped_transform(none_of(r#""\"#), '\\', string_escape_transforms), char('"')), ))(input) } diff --git a/schala-lang/src/parsing/peg_parser.rs b/schala-lang/src/parsing/peg_parser.rs index 3fc771b..b1cc6e7 100644 --- a/schala-lang/src/parsing/peg_parser.rs +++ b/schala-lang/src/parsing/peg_parser.rs @@ -80,7 +80,6 @@ peg::parser! { "::*" { ImportedNames::All } / "::{" __ names:(identifier() ** (_ "," _)) __ "}" { ImportedNames::List(names.into_iter().map(rc_string).collect()) } - rule declaration(parser: &mut Parser) -> Declaration = binding(parser) / type_decl(parser) / annotation(parser) / func(parser) / interface(parser) / implementation(parser) / module(parser) diff --git a/schala-lang/src/parsing/test.rs b/schala-lang/src/parsing/test.rs index 3ab2b6c..522fe91 100644 --- a/schala-lang/src/parsing/test.rs +++ b/schala-lang/src/parsing/test.rs @@ -119,6 +119,7 @@ macro_rules! assert_fail { }; } +/* macro_rules! assert_expr { ($input:expr, $correct:expr) => { let mut parser = Parser::new(); @@ -130,8 +131,9 @@ macro_rules! assert_expr { assert_eq!(expr.unwrap(), $correct); }; } +*/ -macro_rules! assert_expr_comb { +macro_rules! assert_expr { ($input:expr, $correct:expr) => { let mut parser = Parser::new(); let expr = parser.expression_comb($input.trim_start()); @@ -155,35 +157,35 @@ macro_rules! assert_fail_expr { fn basic_literals() { use ExpressionKind::*; - assert_expr_comb!(".2", expr(FloatLiteral(0.2))); - assert_expr_comb!("8.1", expr(FloatLiteral(8.1))); - assert_expr_comb!("0b010", expr(NatLiteral(2))); - assert_expr_comb!("0b0_1_0", expr(NatLiteral(2))); - assert_expr_comb!("0xff", expr(NatLiteral(255))); - assert_expr_comb!("0x032f", expr(NatLiteral(815))); - assert_expr_comb!("0xf_f_", expr(NatLiteral(255))); - assert_expr_comb!("false", expr(BoolLiteral(false))); - assert_expr_comb!("true", expr(BoolLiteral(true))); + 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))); } #[test] fn string_literals() { use ExpressionKind::*; - assert_expr_comb!(r#""""#, expr(StringLiteral(rc("")))); - assert_expr_comb!(r#""hello""#, expr(StringLiteral(rc("hello")))); - assert_expr_comb!(r#"b"some bytestring""#, expr(StringLiteral(rc("some bytestring")))); + assert_expr!(r#""""#, expr(StringLiteral(rc("")))); + assert_expr!(r#""hello""#, expr(StringLiteral(rc("hello")))); + assert_expr!(r#"b"some bytestring""#, expr(StringLiteral(rc("some bytestring")))); //NOTE I'm not 100% sure this case is correct, but I'll deal with it later - assert_expr_comb!(r#""Do \n \" escapes work\t""#, expr(StringLiteral(rc("Do \n \" escapes work\t")))); + assert_expr!(r#""Do \n \" escapes work\t""#, expr(StringLiteral(rc("Do \n \" escapes work\t")))); } #[test] fn list_literals() { use ExpressionKind::*; - assert_expr_comb!("[]", expr(ListLiteral(vec![]))); - assert_expr_comb!("[1,2]", expr(ListLiteral(vec![expr(NatLiteral(1)), expr(NatLiteral(2)),]))); - assert_expr_comb!("[1, /*no*/2]", expr(ListLiteral(vec![expr(NatLiteral(1)), expr(NatLiteral(2)),]))); + assert_expr!("[]", expr(ListLiteral(vec![]))); + assert_expr!("[1,2]", expr(ListLiteral(vec![expr(NatLiteral(1)), expr(NatLiteral(2)),]))); + assert_expr!("[1, /*no*/2]", expr(ListLiteral(vec![expr(NatLiteral(1)), expr(NatLiteral(2)),]))); assert_fail_expr!("[1,,2]", "some failure"); } @@ -192,7 +194,7 @@ fn binexps() { use ExpressionKind::*; use StatementKind::Expression; - assert_expr_comb!("0xf_f+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1)))); + assert_expr!("0xf_f+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1)))); assert_ast_comb!( "3; 4; 4.3", vec![ @@ -202,16 +204,16 @@ fn binexps() { ] ); - assert_expr_comb!( + assert_expr!( "1 + 2 * 3", binop("+", expr(NatLiteral(1)), binop("*", expr(NatLiteral(2)), expr(NatLiteral(3)))) ); - assert_expr_comb!( + assert_expr!( "1 * 2 + 3", binop("+", binop("*", expr(NatLiteral(1)), expr(NatLiteral(2))), expr(NatLiteral(3))) ); - assert_expr_comb!("1 && 2", binop("&&", expr(NatLiteral(1)), expr(NatLiteral(2)))); - assert_expr_comb!( + assert_expr!("1 && 2", binop("&&", expr(NatLiteral(1)), expr(NatLiteral(2)))); + assert_expr!( "1 + 2 * 3 + 4", binop( "+", @@ -219,48 +221,48 @@ fn binexps() { expr(NatLiteral(4)) ) ); - assert_expr_comb!( + assert_expr!( "(1 + 2) * 3", binop("*", binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))), expr(NatLiteral(3))) ); - assert_expr_comb!(".1 + .2", binop("+", expr(FloatLiteral(0.1)), expr(FloatLiteral(0.2)))); - assert_expr_comb!("1 / 2.", binop("/", expr(NatLiteral(1)), expr(FloatLiteral(2.)))); + 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_comb!("-3", prefixop("-", expr(NatLiteral(3)))); - assert_expr_comb!("-0.2", prefixop("-", expr(FloatLiteral(0.2)))); - assert_expr_comb!("!3", prefixop("!", expr(NatLiteral(3)))); - assert_expr_comb!("!t", prefixop("!", expr(Value(qn!(t))))); - assert_expr_comb!("a <- -b", binop("<-", expr(Value(qn!(a))), prefixop("-", expr(Value(qn!(b)))))); - assert_expr_comb!("a <--b", binop("<--", expr(Value(qn!(a))), expr(Value(qn!(b))))); + 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_comb!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1)))); - assert_expr_comb!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1)))); - assert_expr_comb!("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)))); + assert_expr!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1)))); } #[test] fn accessors() { use ExpressionKind::*; - assert_expr_comb!("a.b", expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) })); - assert_expr_comb!( + 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_comb!( + assert_expr!( "a.b.c(3)", expr(Call { f: bx(expr(Access { @@ -270,7 +272,7 @@ fn accessors() { arguments: vec![InvocationArgument::Positional(expr(NatLiteral(3)))], }) ); - assert_expr_comb!( + assert_expr!( "a.b().c", expr(Access { name: rc("c"), @@ -286,12 +288,12 @@ fn accessors() { fn tuples() { use ExpressionKind::*; - assert_expr_comb!("()", expr(TupleLiteral(vec![]))); - assert_expr_comb!( + assert_expr!("()", expr(TupleLiteral(vec![]))); + assert_expr!( r#"("hella", 34)"#, expr(TupleLiteral(vec![expr(StringLiteral(rc("hella"))), expr(NatLiteral(34))])) ); - assert_expr_comb!( + assert_expr!( r#"(1+2, "slough")"#, expr(TupleLiteral(vec![ binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))), @@ -304,12 +306,12 @@ fn tuples() { fn identifiers() { use ExpressionKind::*; - assert_expr_comb!("a", expr(Value(qn!(a)))); - assert_expr_comb!("some_value", expr(Value(qn!(some_value)))); - assert_expr_comb!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma)))); - assert_expr_comb!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b))))); - assert_expr_comb!("None", expr(Value(qn!(None)))); - assert_expr_comb!( + 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![] }) ); @@ -318,14 +320,14 @@ fn identifiers() { #[test] fn named_struct() { use ExpressionKind::*; - assert_expr_comb!( + 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_comb!( + assert_expr!( "Trousers { a:1, b:800 }", expr(NamedStruct { name: qn!(Trousers), @@ -337,14 +339,14 @@ fn named_struct() { #[test] fn index() { use ExpressionKind::*; - assert_expr_comb!( + assert_expr!( "armok[b,c]", expr(Index { indexee: bx(expr(Value(qn!(armok)))), indexers: vec![expr(Value(qn!(b))), expr(Value(qn!(c)))] }) ); - assert_expr_comb!( + assert_expr!( "a[b,c][1]", expr(Index { indexee: bx(expr(Index { @@ -354,7 +356,7 @@ fn index() { indexers: vec![expr(NatLiteral(1))] }) ); - assert_expr_comb!( + assert_expr!( "perspicacity()[a]", expr(Index { indexee: bx(expr(Call { f: bx(expr(Value(qn!(perspicacity)))), arguments: vec![] })), @@ -366,7 +368,7 @@ 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_comb!("a()[b]()[d]", d); + assert_expr!("a()[b]()[d]", d); assert_fail_expr!("a[]", "Empty index expressions are not allowed"); } @@ -376,7 +378,7 @@ fn while_expression() { use ExpressionKind::*; // assert_expr_comb!("while { }", expr(WhileExpression { condition: None, body: Block::default() })); - assert_expr_comb!( + assert_expr!( "while a == b { }", expr(WhileExpression { condition: Some(bx(binop("==", expr(Value(qn!(a))), expr(Value(qn!(b)))))), @@ -389,7 +391,7 @@ fn while_expression() { fn for_expression() { use ExpressionKind::*; - assert_expr_comb!( + assert_expr!( "for { a <- garodzny::maybeValue } return 1", expr(ForExpression { enumerators: vec![Enumerator { id: rc("a"), generator: expr(Value(qn!(garodzny, maybeValue))) }], @@ -397,7 +399,7 @@ fn for_expression() { }) ); - assert_expr_comb!( + assert_expr!( "for n <- someRange { f(n) ; }", expr(ForExpression { enumerators: vec![Enumerator { id: rc("n"), generator: expr(Value(qn!(someRange))) }], @@ -416,7 +418,7 @@ fn for_expression() { fn lambda_expressions() { use ExpressionKind::*; - assert_expr_comb!( + assert_expr!( r#"\(x) { x + 1}"#, expr(Lambda { params: vec![FormalParam { name: rc!(x), anno: None, default: None }], @@ -427,7 +429,7 @@ fn lambda_expressions() { }) ); - assert_expr_comb!( + assert_expr!( r#"\ (x: Int, y) { a;b;c;}"#, expr(Lambda { params: vec![ @@ -444,7 +446,7 @@ fn lambda_expressions() { }) ); - assert_expr_comb!( + assert_expr!( r#"\(x){y}(1)"#, expr(Call { f: bx(expr(Lambda { @@ -456,7 +458,7 @@ fn lambda_expressions() { }) ); - assert_expr_comb!( + assert_expr!( r#"\(x: Int): String { "q" }"#, expr(Lambda { params: vec![FormalParam { name: rc!(x), anno: Some(ty_simple("Int")), default: None },], @@ -473,7 +475,7 @@ fn lambda_expressions() { fn single_param_lambda() { use ExpressionKind::*; - assert_expr_comb!( + assert_expr!( r#"\x { x + 10 }"#, expr(Lambda { params: vec![FormalParam { name: rc!(x), anno: None, default: None },], @@ -487,7 +489,7 @@ fn single_param_lambda() { }) ); - assert_expr_comb!( + assert_expr!( r#"\x: Int { x + 10 }"#, expr(Lambda { params: vec![FormalParam { name: rc!(x), anno: Some(ty_simple("Int")), default: None },], @@ -561,11 +563,11 @@ fn type_annotations() { })] ); - assert_expr_comb!( + assert_expr!( "a: Int", expr_anno(Value(qn!(a)), Singleton(TypeSingletonName { name: rc("Int"), params: vec![] })) ); - assert_expr_comb!( + assert_expr!( "a: Option", expr_anno( Value(qn!(a)), @@ -575,7 +577,7 @@ fn type_annotations() { }) ) ); - assert_expr_comb!( + assert_expr!( "a: KoreanBBQSpecifier >", expr_anno( Value(qn!(a)), @@ -591,7 +593,7 @@ fn type_annotations() { }) ) ); - assert_expr_comb!( + assert_expr!( "a: (Int, Yolo)", expr_anno( Value(qn!(a)), @@ -797,7 +799,7 @@ fn functions() { vec![stmt(StatementKind::Expression(expr(Call { f: bx(expr(Value(qn!(oi)))), arguments: vec![] })))] ); - assert_expr_comb!( + assert_expr!( "oi(a, 2+2)", expr(Call { f: bx(expr(Value(qn!(oi)))), @@ -1056,7 +1058,7 @@ fn modules() { #[test] fn imports() { - assert_ast! { + assert_ast_comb! { "import harbinger::draughts::Norgleheim", vec![stmt(StatementKind::Import(ImportSpecifier { id: ItemId::default(), @@ -1065,7 +1067,7 @@ fn imports() { }))] }; - assert_ast! { + assert_ast_comb! { "import harbinger::draughts::{Norgleheim, Xraksenlaigar}", vec![stmt(StatementKind::Import(ImportSpecifier { id: ItemId::default(), @@ -1075,7 +1077,8 @@ fn imports() { }))] }; - assert_ast! { + //TODO this shouldn't be legal + assert_ast_comb! { "import bespouri::{}", vec![stmt(StatementKind::Import(ImportSpecifier { id: Default::default(), @@ -1084,7 +1087,7 @@ fn imports() { }))] }; - assert_ast! { + assert_ast_comb! { "import bespouri::*", vec![stmt(StatementKind::Import(ImportSpecifier { id: Default::default(), @@ -1097,7 +1100,7 @@ fn imports() { #[test] fn if_exprs() { use ExpressionKind::*; - assert_expr_comb!( + assert_expr!( "if a() then { tuah(); }", expr(IfExpression { discriminator: Some(bx(expr(Call { f: bx(expr(Value(qn!(a)))), arguments: vec![] }))), @@ -1109,7 +1112,7 @@ fn if_exprs() { ); //TODO add tests for named expressions - assert_expr_comb!( + assert_expr!( "if a then b else c", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(a))))), @@ -1120,7 +1123,7 @@ fn if_exprs() { }) ); - assert_expr_comb!( + assert_expr!( r#"if true then { let a = 10 b @@ -1151,7 +1154,7 @@ fn pattern_matching() { use ExpressionKind::*; for item in ["if x is Some(a) then { 4 } else { 9 }", "if x is Some(a) then 4 else 9"] { - assert_expr_comb!( + assert_expr!( item, expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1164,7 +1167,7 @@ fn pattern_matching() { ); } - assert_expr_comb!( + assert_expr!( "if x is Something { a, b: x } then { 4 } else { 9 }", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1179,7 +1182,7 @@ fn pattern_matching() { }) ); - assert_expr_comb!( + assert_expr!( "if x is -1 then 1 else 2", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1191,7 +1194,7 @@ fn pattern_matching() { }) ); - assert_expr_comb!( + assert_expr!( "if x is true then 1 else 2", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1203,7 +1206,7 @@ fn pattern_matching() { }) ); - assert_expr_comb!( + assert_expr!( "if x { is 1 then 5; else 20 }", expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1225,7 +1228,7 @@ fn pattern_matching() { }) ); - assert_expr_comb!( + assert_expr!( r#"if x is "gnosticism" then 1 else 2"#, expr(IfExpression { discriminator: Some(bx(expr(Value(qn!(x))))), @@ -1237,7 +1240,7 @@ fn pattern_matching() { }) ); - assert_expr_comb! { + assert_expr! { r#" if (45, "panda", false, 2.2) { is (49, "pablo", _, 28.4) then "no" @@ -1400,7 +1403,7 @@ fn comments() { use ExpressionKind::*; let source = "1 + /* hella /* bro */ */ 2"; - assert_expr_comb!(source, binop("+", expr(NatLiteral(1)), expr(NatLiteral(2)))); + assert_expr!(source, binop("+", expr(NatLiteral(1)), expr(NatLiteral(2)))); //TODO make sure this error message makes sense let source = "1 + /* hella /* bro */ 2";