From 6f5d79b98b2d4c9c37f1989ace3beeff8dc671d7 Mon Sep 17 00:00:00 2001 From: StunxFS Date: Mon, 25 Dec 2023 08:22:16 -0400 Subject: [PATCH] feat(rivet/parser+rivetc.parser): allow adding fields to struct from `extend` --- lib/rivet/src/parser/decls.ri | 22 +++++++++++++++------- lib/rivet/src/parser/mod.ri | 8 +++++--- rivetc/src/parser.py | 32 ++++++++++++++++++++------------ tests/valid/src/extend.ri | 10 ++++++++++ 4 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 tests/valid/src/extend.ri diff --git a/lib/rivet/src/parser/decls.ri b/lib/rivet/src/parser/decls.ri index 23dd3a547..0e5a1e72e 100644 --- a/lib/rivet/src/parser/decls.ri +++ b/lib/rivet/src/parser/decls.ri @@ -308,8 +308,9 @@ extend Parser { ); }, self.accept(.KwTrait) -> { - old_inside_trait := self.inside_trait; + prev_inside_trait := self.inside_trait; self.inside_trait = true; + name := self.parse_name(); mut bases := []mut ast.Type(); if self.accept(.Lt) { @@ -325,8 +326,8 @@ extend Parser { while !self.accept(.Rbrace) { decls.push(self.parse_decl()); } - self.inside_trait = old_inside_trait; pos += self.prev_tok.pos; + self.inside_trait = prev_inside_trait; return .Trait( doc_comment, attributes, @@ -338,8 +339,9 @@ extend Parser { ); }, self.accept(.KwStruct) -> { - old_inside_struct := self.inside_struct; + prev_inside_struct := self.inside_struct; self.inside_struct = true; + name := self.parse_name(); is_opaque := self.accept(.Semicolon); mut bases := []mut ast.Type(); @@ -358,8 +360,8 @@ extend Parser { decls.push(self.parse_decl()); } } - self.inside_struct = old_inside_struct; pos += self.prev_tok.pos; + self.inside_struct = prev_inside_struct; return .Struct( doc_comment, attributes, @@ -401,12 +403,12 @@ extend Parser { if self.accept(.Lbrace) { has_type = true; is_tagged = true; - old_inside_enum_variant_with_fields := self.inside_enum_variant_with_fields; + prev_inside_enum_variant_with_fields := self.inside_enum_variant_with_fields; self.inside_enum_variant_with_fields = true; while !self.accept(.Rbrace) { variant_decls.push(self.parse_decl()); } - self.inside_enum_variant_with_fields = old_inside_enum_variant_with_fields; + self.inside_enum_variant_with_fields = prev_inside_enum_variant_with_fields; } else if self.accept(.Lparen) { has_type = true; is_tagged = true; @@ -442,7 +444,7 @@ extend Parser { bases, variants, is_tagged, decls, pos ); }, - (self.inside_struct || self.inside_trait + (self.inside_struct || self.inside_trait || self.inside_extend || self.inside_enum_variant_with_fields) && self.tok.kind in [.KwMut, .Name] -> { // fields @@ -471,6 +473,9 @@ extend Parser { ); }, self.accept(.KwExtend) -> { + prev_inside_extend := self.inside_extend; + self.inside_extend = true; + type := self.parse_type(); mut bases := []mut ast.Type(); if self.accept(.Lt) { @@ -481,12 +486,15 @@ extend Parser { } } } + self.expect(.Lbrace); mut decls := []ast.Decl(); while !self.accept(.Rbrace) { decls.push(self.parse_decl()); } pos += self.prev_tok.pos; + + self.inside_extend = prev_inside_extend; return .Extend( attributes, type, diff --git a/lib/rivet/src/parser/mod.ri b/lib/rivet/src/parser/mod.ri index 15094a454..951d31080 100644 --- a/lib/rivet/src/parser/mod.ri +++ b/lib/rivet/src/parser/mod.ri @@ -1,5 +1,5 @@ -// Copyright (C) 2023-present Jose Mendoza - All rights reserved. Use of this -// source code is governed by an MIT license that can be found in the LICENSE +// Copyright (C) 2023-present Jose Mendoza - All rights reserved. Use of this +// source code is governed by an MIT license that can be found in the LICENSE // file. import std/fs.Path; @@ -24,12 +24,14 @@ pub struct Parser { mut file_dir: string; mut scope: ast.Scope; - mut inside_extern: bool; mut extern_abi: ast.ABI; + + mut inside_extern: bool; mut inside_mod: bool; mut inside_struct: bool; mut inside_trait: bool; mut inside_enum_variant_with_fields: bool; + mut inside_extend: bool; mut inside_func: bool; mut inside_match_header: bool; mut inside_block: bool; diff --git a/rivetc/src/parser.py b/rivetc/src/parser.py index 6ab2aaf81..360b0426f 100644 --- a/rivetc/src/parser.py +++ b/rivetc/src/parser.py @@ -24,12 +24,14 @@ def __init__(self, comp): self.scope = None - self.inside_extern = False self.extern_abi = sym.ABI.Rivet + + self.inside_extern = False self.inside_mod = False self.inside_struct = False self.inside_trait = False self.inside_enum_variant_with_fields = False + self.inside_extend = False self.inside_match_header = False self.inside_block = False @@ -307,17 +309,17 @@ def parse_decl(self): if not self.accept(Kind.Comma): break decls = [] - old_inside_trait = self.inside_trait + prev_inside_trait = self.inside_trait self.inside_trait = True self.expect(Kind.Lbrace) while not self.accept(Kind.Rbrace): decls.append(self.parse_decl()) - self.inside_trait = old_inside_trait + self.inside_trait = prev_inside_trait return ast.TraitDecl( doc_comment, attributes, is_public, name, bases, decls, pos ) elif self.accept(Kind.KwStruct): - old_inside_struct = self.inside_struct + prev_inside_struct = self.inside_struct self.inside_struct = True pos = self.tok.pos name = self.parse_name() @@ -334,14 +336,14 @@ def parse_decl(self): while self.tok.kind != Kind.Rbrace: decls.append(self.parse_decl()) self.expect(Kind.Rbrace) - self.inside_struct = old_inside_struct + self.inside_struct = prev_inside_struct return ast.StructDecl( doc_comment, attributes, is_public, name, bases, decls, is_opaque, pos ) elif ( self.inside_struct or self.inside_trait - or self.inside_enum_variant_with_fields + or self.inside_enum_variant_with_fields or self.inside_extend ) and self.tok.kind in (Kind.KwMut, Kind.Name): return self.parse_field_decl(attributes, doc_comment, is_public) elif self.accept(Kind.KwEnum): @@ -369,11 +371,11 @@ def parse_decl(self): if self.accept(Kind.Lbrace): has_typ = True is_tagged = True - old_inside_enum_variant_with_fields = self.inside_enum_variant_with_fields + prev_inside_enum_variant_with_fields = self.inside_enum_variant_with_fields self.inside_enum_variant_with_fields = True while not self.accept(Kind.Rbrace): variant_decls.append(self.parse_decl()) - self.inside_enum_variant_with_fields = old_inside_enum_variant_with_fields + self.inside_enum_variant_with_fields = prev_inside_enum_variant_with_fields elif self.accept(Kind.Lparen): has_typ = True is_tagged = True @@ -397,6 +399,9 @@ def parse_decl(self): variants, is_tagged, decls, pos ) elif self.accept(Kind.KwExtend): + prev_inside_extend = self.inside_extend + self.inside_extend = True + pos = self.prev_tok.pos typ = self.parse_type() bases = [] @@ -405,10 +410,13 @@ def parse_decl(self): bases.append(self.parse_type()) if not self.accept(Kind.Comma): break + decls = [] self.expect(Kind.Lbrace) while not self.accept(Kind.Rbrace): decls.append(self.parse_decl()) + + self.inside_extend = prev_inside_extend return ast.ExtendDecl(attributes, typ, bases, decls, pos) elif self.accept(Kind.KwFunc): return self.parse_func_decl( @@ -1108,7 +1116,7 @@ def parse_block_expr(self): pos = self.tok.pos is_unsafe = self.accept(Kind.KwUnsafe) self.expect(Kind.Lbrace) - old_inside_block = self.inside_block + prev_inside_block = self.inside_block self.inside_block = True stmts = [] has_expr = False @@ -1125,7 +1133,7 @@ def parse_block_expr(self): else: stmts.append(stmt) self.close_scope() - self.inside_block = old_inside_block + self.inside_block = prev_inside_block return ast.Block(sc, is_unsafe, stmts, expr, has_expr, pos) def parse_if_expr(self): @@ -1161,7 +1169,7 @@ def parse_match_expr(self): branches = [] pos = self.prev_tok.pos is_typematch = False - old_inside_match_header = self.inside_match_header + prev_inside_match_header = self.inside_match_header self.inside_match_header = True if self.tok.kind == Kind.Lbrace: expr = ast.BoolLiteral(True, pos) @@ -1173,7 +1181,7 @@ def parse_match_expr(self): expr = self.parse_expr() is_typematch = self.accept(Kind.KwIs) self.expect(Kind.Lbrace) - self.inside_match_header = old_inside_match_header + self.inside_match_header = prev_inside_match_header while True: pats = [] has_var = False diff --git a/tests/valid/src/extend.ri b/tests/valid/src/extend.ri new file mode 100644 index 000000000..33128fa68 --- /dev/null +++ b/tests/valid/src/extend.ri @@ -0,0 +1,10 @@ +struct Package {} + +extend Package { + name: string; +} + +test "add fields to struct from `extend`" { + pkg := Package(name: "extended"); + @assert(pkg.name == "extended"); +}