Skip to content

Commit

Permalink
Allow member/member_frame also in freestanding methods with ::
Browse files Browse the repository at this point in the history
This is currently limited to classes without subclasses
  • Loading branch information
aardappel committed Nov 1, 2024
1 parent 582dbc0 commit 7ec00e4
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 4 deletions.
3 changes: 2 additions & 1 deletion dev/src/lobster/idents.h
Original file line number Diff line number Diff line change
Expand Up @@ -1275,7 +1275,8 @@ struct SymbolTable {
udt.ssuperclass = supertype->udt;
}
PushSuperGenerics(udt.ssuperclass);
for (auto &field : udt.g.fields) {
for (size_t i = udt.sfields.size(); i < udt.g.fields.size(); i++) {
auto &field = udt.g.fields[i];
udt.sfields.push_back({ ResolveTypeVars(field.giventype, errl) });
}
PopSuperGenerics(udt.ssuperclass);
Expand Down
16 changes: 14 additions & 2 deletions dev/src/lobster/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,11 @@ struct Parser {
// This is an arbitrary restriction that we could lift, just doesn't seem
// great to have invisble extra members in structs.
if (gudt->is_struct) Error("member declaration only allowed in classes");
// TODO: This is not great: when "member" is used in an inline method decl, this should
// never happen, and it can later still be subclassed, but when it is used outside
// in a free-standing method we can't allow new fields to be added when a subclass
// has already copied them. We can maybe lift this restriction.
if (gudt->has_subclasses) Error("member cannot be added in freestanding method to class that has been subclassed");
st.bound_typevars_stack.push_back(gudt->generics);
auto field_idx = gudt->fields.size();
ParseField(gudt, true, true);
Expand All @@ -411,6 +416,10 @@ struct Parser {
member->field_idx = field_idx;
member->frame = frame;
member->this_sid = this_sid;
for (UDT *udt = gudt->first; udt; udt = udt->next) {
// New fields have been added possibly non-inline, run this again to be sure.
st.ResolveFields(*udt, lex);
}
list->Add(member);
break;
}
Expand Down Expand Up @@ -531,7 +540,6 @@ struct Parser {
GUDT *gudt = st.LookupStruct(sname);
bool was_predeclaration = gudt && gudt->predeclaration;
gudt = &st.StructDecl(sname, is_struct, lex);
gudtstack.push_back(gudt);
UDT *udt = nullptr;
if (Either(T_COLON, T_LT)) {
// A regular struct declaration
Expand Down Expand Up @@ -675,7 +683,6 @@ struct Parser {
parent_list->Add(new UDTRef(line, udt));
}
parent_list->Add(new GUDTRef(line, gudt, gudt->predeclaration));
gudtstack.pop_back();
}

FunRef *ParseNamedFunctionDefinition(bool is_constructor, bool isprivate, GUDT *self) {
Expand Down Expand Up @@ -761,8 +768,10 @@ struct Parser {
st.bound_typevars_stack.push_back(sf->generics);
if (parens) Expect(T_LEFTPAREN);
size_t nargs = 0;
bool self_withtype = false;
if (self) {
nargs++;
self_withtype = true;
auto id = st.LookupDef("this", false, true);
auto &arg = sf->args.back();
arg.type = &self->unspecialized_type;
Expand All @@ -787,6 +796,7 @@ struct Parser {
if (nargs == 1 && (arg.type->t == V_UUDT || IsUDT(arg.type->t))) {
non_inline_method = true;
self = GetGUDTAny(arg.type);
self_withtype = withtype;
st.bound_typevars_stack.push_back(self->generics);
}
sf->giventypes.push_back({ arg.type });
Expand Down Expand Up @@ -885,6 +895,7 @@ struct Parser {
} else {
f.anonymous = true;
}
if (self_withtype) gudtstack.push_back(self);
// Parse the body.
Line line = lex;
if (!f.istype) {
Expand All @@ -893,6 +904,7 @@ struct Parser {
ParseBody(block, -1);
ImplicitReturn(*ov);
}
if (self_withtype) gudtstack.pop_back();
if (name) functionstack.pop_back();
if (non_inline_method) st.bound_typevars_stack.pop_back();
st.bound_typevars_stack.pop_back();
Expand Down
10 changes: 9 additions & 1 deletion tests/misc/frame.lobster
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ class C:
member_frame a = 1
member_frame b = float2_1
member_frame s = "s"
member_frame r = D {}
def nested():
member_frame rf = D {}
return rf
let r = nested()
print "c: {a++} {b} {s} {r}"
b += 1.0
s += "s"
r.i++

def freestanding(c::C):
member_frame a2 = 1
print "a2: {a2++}"

def aa():
static_frame a = 1
static_frame b = float2_1
Expand All @@ -46,5 +53,6 @@ while gl.frame():
if count % 4:
aa()
c.f()
c.freestanding()
if count++ == 10:
return

0 comments on commit 7ec00e4

Please sign in to comment.