Skip to content

Commit

Permalink
feat(rivet/parser+rivetc.parser): allow adding fields to struct from …
Browse files Browse the repository at this point in the history
…`extend`
  • Loading branch information
StunxFS committed Dec 25, 2023
1 parent 4f1a69a commit 6f5d79b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 22 deletions.
22 changes: 15 additions & 7 deletions lib/rivet/src/parser/decls.ri
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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,
Expand All @@ -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();
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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,
Expand Down
8 changes: 5 additions & 3 deletions lib/rivet/src/parser/mod.ri
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down
32 changes: 20 additions & 12 deletions rivetc/src/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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()
Expand All @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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 = []
Expand All @@ -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(
Expand Down Expand Up @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
10 changes: 10 additions & 0 deletions tests/valid/src/extend.ri
Original file line number Diff line number Diff line change
@@ -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");
}

0 comments on commit 6f5d79b

Please sign in to comment.