diff --git a/schala-lang/language/src/parsing/mod.rs b/schala-lang/language/src/parsing/mod.rs index f5787ce..02b554d 100644 --- a/schala-lang/language/src/parsing/mod.rs +++ b/schala-lang/language/src/parsing/mod.rs @@ -168,7 +168,7 @@ //! //! module := 'module' IDENTIFIER '{' statement* '}' //! ``` -mod new; +pub mod new; mod test; use std::rc::Rc; diff --git a/schala-lang/language/src/parsing/new.rs b/schala-lang/language/src/parsing/new.rs index c9f63f6..c5b60d2 100644 --- a/schala-lang/language/src/parsing/new.rs +++ b/schala-lang/language/src/parsing/new.rs @@ -66,17 +66,18 @@ peg::parser! { pub rule program(parser: &mut Parser) -> AST = - __ statements:(statement(parser) ** delimiter() ) __ { AST { id: Default::default(), statements: statements.into() } } + __ statements:(statement(parser) ** (delimiter()+) ) __ { AST { id: parser.fresh(), statements: statements.into() } } rule delimiter() = (";" / "\n")+ //Note - this is a hack, ideally the rule `rule block() -> Block = "{" _ items:(statement() ** //delimiter()) _ "}" { items.into() }` would've worked, but it doesn't. - pub rule block(parser: &mut Parser) -> Block = "{" __ items:block_item(parser)* __ "}" { items.into() } / - "{" __ stmt:statement(parser) __ "}" { vec![stmt].into() } + pub rule block(parser: &mut Parser) -> Block = + "{" __ items:block_item(parser)* __ "}" { items.into() } / + "{" __ stmt:statement(parser) __ "}" { vec![stmt].into() } rule block_item(parser: &mut Parser) -> Statement = - stmt:statement(parser) delimiter()+ { stmt } + _ stmt:statement(parser) _ delimiter()+ { stmt } rule statement(parser: &mut Parser) -> Statement = _ pos:position!() kind:statement_kind(parser) _ { Statement { id: parser.fresh(), location: pos.into(), kind } } @@ -116,7 +117,7 @@ peg::parser! { rule declaration(parser: &mut Parser) -> Declaration = - binding(parser) / type_decl() / annotation(parser) / func(parser) / interface(parser) / + binding(parser) / type_decl(parser) / annotation(parser) / func(parser) / interface(parser) / implementation(parser) / module(parser) rule module(parser: &mut Parser) -> Declaration = @@ -180,14 +181,16 @@ peg::parser! { } - rule type_decl() -> Declaration = + rule type_decl(parser: &mut Parser) -> Declaration = "type" _ "alias" _ alias:type_alias() { alias } / - "type" _ mutable:"mut"? _ name:type_singleton_name() _ "=" _ body:type_body() { + "type" _ mutable:"mut"? _ name:type_singleton_name() _ "=" _ body:type_body(parser) { Declaration::TypeDecl { name, body, mutable: mutable.is_some() } } rule type_singleton_name() -> TypeSingletonName = - name:identifier() params:type_params()? { TypeSingletonName { name: rc_string(name), params: if let Some(params) = params { params } else { vec![] } } } + name:identifier() params:type_params()? { TypeSingletonName { + name: rc_string(name), params: if let Some(params) = params { params } else { vec![] } + } } rule type_params() -> Vec = "<" _ idents:(type_identifier() ** (_ "," _)) _ ">" { idents } @@ -196,17 +199,17 @@ peg::parser! { "(" _ items:(type_identifier() ** (_ "," _)) _ ")" { TypeIdentifier::Tuple(items) } / singleton:type_singleton_name() { TypeIdentifier::Singleton(singleton) } - rule type_body() -> TypeBody = - "{" _ items:(record_variant_item() ++ (_ "," _)) _ "}" { TypeBody::ImmediateRecord(Default::default(), items) } / - variants:(variant_spec() ** (_ "|" _)) { TypeBody::Variants(variants) } + rule type_body(parser: &mut Parser) -> TypeBody = + "{" _ items:(record_variant_item() ** (__ "," __)) __ "}" { TypeBody::ImmediateRecord(parser.fresh(), items) } / + variants:(variant_spec(parser) ** (__ "|" __)) { TypeBody::Variants(variants) } - rule variant_spec() -> Variant = - name:identifier() _ "{" _ typed_identifier_list:(record_variant_item() ++ (_ "," _)) _ "}" { Variant { - id: Default::default(), name: rc_string(name), kind: VariantKind::Record(typed_identifier_list) + rule variant_spec(parser: &mut Parser) -> Variant = + name:identifier() __ "{" __ typed_identifier_list:(record_variant_item() ** (__ "," __)) __ ","? __ "}" { Variant { + id: parser.fresh(), name: rc_string(name), kind: VariantKind::Record(typed_identifier_list) } } / - name:identifier() "(" tuple_members:(type_identifier() ++ (_ "," _)) ")" { Variant { - id: Default::default(), name: rc_string(name), kind: VariantKind::TupleStruct(tuple_members) } } / - name:identifier() { Variant { id: Default::default(), name: rc_string(name), kind: VariantKind::UnitStruct } } + name:identifier() "(" tuple_members:(type_identifier() ++ (__ "," __)) ")" { Variant { + id: parser.fresh(), name: rc_string(name), kind: VariantKind::TupleStruct(tuple_members) } } / + name:identifier() { Variant { id: parser.fresh(), name: rc_string(name), kind: VariantKind::UnitStruct } } rule record_variant_item() -> (Rc, TypeIdentifier) = name:identifier() _ ":" _ ty:type_identifier() { (rc_string(name), ty) } @@ -221,7 +224,7 @@ peg::parser! { __ kind:expression_kind(true, parser) _ type_anno:type_anno()? { Expression { id: parser.fresh(), type_anno, kind } } rule expression_no_struct(parser: &mut Parser) -> Expression = - __ kind:expression_kind(false, parser) { Expression { id: Default::default(), type_anno: None, kind: kind } } + __ kind:expression_kind(false, parser) { Expression { id: parser.fresh(), type_anno: None, kind: kind } } rule expression_kind(struct_ok: bool, parser: &mut Parser) -> ExpressionKind = precedence_expr(struct_ok, parser) @@ -229,7 +232,7 @@ peg::parser! { rule precedence_expr(struct_ok: bool, parser: &mut Parser) -> ExpressionKind = first:prefix_expr(struct_ok, parser) _ next:(precedence_continuation(struct_ok, parser))* { let next = next.into_iter().map(|(sigil, expr)| (BinOp::from_sigil(sigil), expr)).collect(); - BinopSequence { first, next }.do_precedence() + BinopSequence { first, next }.do_precedence(parser) } rule precedence_continuation(struct_ok: bool, parser: &mut Parser) -> (&'input str, ExpressionKind) = @@ -257,7 +260,7 @@ peg::parser! { rule extended_expr(struct_ok: bool, parser: &mut Parser) -> ExpressionKind = primary:primary(struct_ok, parser) parts:(extended_expr_part(parser)*) { - let mut expression = Expression::new(Default::default(), primary); + let mut expression = Expression::new(parser.fresh(), primary); for part in parts.into_iter() { let kind = match part { ExtendedPart::Index(indexers) => { @@ -340,7 +343,7 @@ peg::parser! { rule while_expr(parser: &mut Parser) -> ExpressionKind = "while" _ cond:expression_kind(false, parser)? _ body:block(parser) { ExpressionKind::WhileExpression { - condition: cond.map(|kind| Box::new(Expression::new(Default::default(), kind))), + condition: cond.map(|kind| Box::new(Expression::new(parser.fresh(), kind))), body, } } @@ -370,7 +373,10 @@ peg::parser! { //TODO improve the definition of identifiers rule identifier() -> &'input str = - !reserved() text:$(['a'..='z' | 'A'..='Z' | '_'] ['a'..='z' | 'A'..='Z' | '0'..='9' | '_']*) { text } + !(reserved() !(ident_continuation())) text:$(['a'..='z' | 'A'..='Z' | '_'] ident_continuation()*) { text } + + rule ident_continuation() -> &'input str = + text:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_']) rule reserved() = "if" / "then" / "else" / "is" / "fn" / "for" / "while" / "let" / "in" / "mut" / "return" / "break" / "alias" / "type" / "self" / "Self" / "interface" / "impl" / "true" / "false" / "module" / "import" @@ -441,7 +447,7 @@ peg::parser! { _ name:identifier() _ ":" _ pat:pattern(parser) _ { (name, pat) } / _ name:identifier() _ { let qn = QualifiedName { - id: Default::default(), + id: parser.fresh(), components: vec![Rc::new(name.to_string())], }; (name, Pattern::VarOrName(qn)) @@ -561,13 +567,14 @@ struct BinopSequence { } impl BinopSequence { - fn do_precedence(self) -> ExpressionKind { + fn do_precedence(self, parser: &mut Parser) -> ExpressionKind { fn helper( precedence: i32, lhs: ExpressionKind, rest: &mut Vec<(BinOp, ExpressionKind)>, + parser: &mut Parser, ) -> Expression { - let mut lhs = Expression::new(Default::default(), lhs); + let mut lhs = Expression::new(parser.fresh(), lhs); loop { let (next_op, next_rhs) = match rest.pop() { Some((a, b)) => (a, b), @@ -578,15 +585,15 @@ impl BinopSequence { rest.push((next_op, next_rhs)); break; } - let rhs = helper(new_precedence, next_rhs, rest); + let rhs = helper(new_precedence, next_rhs, rest, parser); lhs = Expression::new( - Default::default(), + parser.fresh(), ExpressionKind::BinExp(next_op, Box::new(lhs), Box::new(rhs)), ); } lhs } let mut as_stack = self.next.into_iter().rev().collect(); - helper(BinOp::min_precedence(), self.first, &mut as_stack).kind + helper(BinOp::min_precedence(), self.first, &mut as_stack, parser).kind } } diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index a61e949..8bfd0af 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -1305,6 +1305,25 @@ fn blocks() { let block = schala_parser::block(case, &mut parser); assert_eq!(block.unwrap(), vec![exst(Value(qn!(a)))].into()); } + + let source = r#"{ + fn quah() { + fn foo() { } + } + }"#; + let block = schala_parser::block(source, &mut parser); + assert_eq!( + block.unwrap(), + vec![decl(Declaration::FuncDecl( + Signature { name: rc("quah"), operator: false, params: vec![], type_anno: None }, + vec![decl(Declaration::FuncDecl( + Signature { name: rc("foo"), operator: false, params: vec![], type_anno: None }, + vec![].into(), + ))] + .into() + ))] + .into() + ); } #[test] diff --git a/schala-lang/language/src/schala.rs b/schala-lang/language/src/schala.rs index 141df1a..4a6fb6f 100644 --- a/schala-lang/language/src/schala.rs +++ b/schala-lang/language/src/schala.rs @@ -128,11 +128,11 @@ pub(crate) struct SourceReference { } impl SourceReference { - fn new() -> SourceReference { + pub(crate) fn new() -> SourceReference { SourceReference { last_source: None, newline_offsets: vec![] } } - fn load_new_source(&mut self, source: &str) { + pub(crate) fn load_new_source(&mut self, source: &str) { for (offset, ch) in source.as_bytes().iter().enumerate() { if *ch == ('\n' as u8) { self.newline_offsets.push(offset); diff --git a/schala-lang/language/src/symbol_table/test.rs b/schala-lang/language/src/symbol_table/test.rs index e76d5f0..29587ef 100644 --- a/schala-lang/language/src/symbol_table/test.rs +++ b/schala-lang/language/src/symbol_table/test.rs @@ -137,7 +137,7 @@ fn dont_falsely_detect_duplicates() { let a = 40; 77 } - let q = 39; + let q = 39 "#; let (symbols, _) = add_symbols(source); @@ -173,7 +173,8 @@ fn second_inner_func() { } inner_func(x) -}"#; +} +"#; let (symbols, _) = add_symbols(source); assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func"])).is_some()); assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func", "inner_func"])).is_some()); @@ -189,7 +190,8 @@ inner_func(x) fn enclosing_scopes_3() { let source = r#" fn outer_func(x) { -fn inner_func(arg) { + + fn inner_func(arg) { arg } diff --git a/schala-lang/language/src/tree_walk_eval/test.rs b/schala-lang/language/src/tree_walk_eval/test.rs index 5f42f81..8d2aed7 100644 --- a/schala-lang/language/src/tree_walk_eval/test.rs +++ b/schala-lang/language/src/tree_walk_eval/test.rs @@ -43,7 +43,7 @@ fn test_basic_eval() { #[test] fn op_eval() { - eval_assert("- 13", "-13"); + eval_assert("-13", "-13"); eval_assert("10 - 2", "8"); } @@ -96,7 +96,7 @@ trad()"#, ); let err = - "No symbol found for name: QualifiedName { id: Id { idx: 4, t: PhantomData }, components: [\"a\"] }"; + "No symbol found for name: QualifiedName { id: Id { idx: 9, t: PhantomData }, components: [\"a\"] }"; eval_assert_failure( r#" @@ -271,26 +271,26 @@ fn full_if_matching() { let source = r#" type Option = Some(T) | None let a = Option::None -if a { is Option::None then 4, is Option::Some(x) then x } +if a { is Option::None then 4; is Option::Some(x) then x } "#; eval_assert(source, "4"); let source = r#" type Option = Some(T) | None let sara = Option::Some(99) -if sara { is Option::None then 1 + 3, is Option::Some(x) then x } +if sara { is Option::None then 1 + 3; is Option::Some(x) then x } "#; eval_assert(source, "99"); let source = r#" let a = 10 -if a { is 10 then "x", is 4 then "y" } +if a { is 10 then "x"; is 4 then "y" } "#; eval_assert(source, "\"x\""); let source = r#" let a = 10 -if a { is 15 then "x", is 10 then "y" } +if a { is 15 then "x"; is 10 then "y" } "#; eval_assert(source, "\"y\""); } @@ -300,7 +300,7 @@ if a { is 15 then "x", is 10 then "y" } fn string_pattern() { let source = r#" let a = "foo" -if a { is "foo" then "x", is _ then "y" } +if a { is "foo" then "x"; is _ then "y" } "#; eval_assert(source, "\"x\""); } @@ -310,7 +310,7 @@ fn boolean_pattern() { let source = r#" let a = true if a { - is true then "x", + is true then "x" is false then "y" } "#; @@ -321,7 +321,7 @@ if a { fn boolean_pattern_2() { let source = r#" let a = false -if a { is true then "x", is false then "y" } +if a { is true then "x"; is false then "y" } "#; eval_assert(source, "\"y\""); } @@ -341,7 +341,7 @@ if Option::Some(10) { fn tuple_pattern() { let source = r#" if (1, 2) { - is (1, x) then x, + is (1, x) then x; is _ then 99 } "#; @@ -352,7 +352,7 @@ if (1, 2) { fn tuple_pattern_2() { let source = r#" if (1, 2) { - is (10, x) then x, + is (10, x) then x is (y, x) then x + y } "#; @@ -363,7 +363,7 @@ if (1, 2) { fn tuple_pattern_3() { let source = r#" if (1, 5) { - is (10, x) then x, + is (10, x) then x is (1, x) then x } "#; @@ -374,8 +374,8 @@ if (1, 5) { fn tuple_pattern_4() { let source = r#" if (1, 5) { - is (10, x) then x, - is (1, x) then x, + is (10, x) then x + is (1, x) then x } "#; eval_assert(source, "5"); @@ -390,21 +390,21 @@ let b = Stuff::Jugs(1, "haha") let c = Stuff::Mardok let x = if a { - is Stuff::Mulch(20) then "x", + is Stuff::Mulch(20) then "x" is _ then "ERR" } let y = if b { - is Stuff::Mulch(n) then "ERR", - is Stuff::Jugs(2, _) then "ERR", - is Stuff::Jugs(1, s) then s, - is _ then "ERR", + is Stuff::Mulch(n) then "ERR" + is Stuff::Jugs(2, _) then "ERR" + is Stuff::Jugs(1, s) then s + is _ then "ERR" } let z = if c { - is Stuff::Jugs(_, _) then "ERR", - is Stuff::Mardok then "NIGH", - is _ then "ERR", + is Stuff::Jugs(_, _) then "ERR" + is Stuff::Mardok then "NIGH" + is _ then "ERR" } (x, y, z) diff --git a/schala-lang/language/src/util.rs b/schala-lang/language/src/util.rs index 4856f7d..fd5b4a9 100644 --- a/schala-lang/language/src/util.rs +++ b/schala-lang/language/src/util.rs @@ -52,10 +52,10 @@ where T: Hash + Eq /// Quickly create an AST from a string, with no error checking. For test use only #[cfg(test)] pub fn quick_ast(input: &str) -> crate::ast::AST { - let tokens = crate::tokenizing::tokenize(input); - let mut parser = crate::parsing::Parser::new(); - parser.add_new_tokens(tokens); - let output = parser.parse(); + let mut source_reference = crate::schala::SourceReference::new(); + let mut parser = crate::parsing::new::Parser::new(); + source_reference.load_new_source(input); + let output = parser.parse(input, &source_reference); output.unwrap() }