Skip to content

Commit ab1f939

Browse files
committed
AST: use simpler MemberExpr nodes
* restrict `MemberExpr` nodes to `<expr>.b` and `a.b` forms * store a single `SrcLoc` for the member name (size is always 32 bytes) * use bitfield to avoid using `strlen` for SrcLoc computations * simplify `Parser.parseCastExpr`, `p.parsePureMemberExpr` and `Parser.parseImpureMemberExpr`: no longer use `peekToken` on identifiers, remove `Parser.parseIdentifier` * store name length in `IdentifierExpr` nodes to simplify end location computation * rename `MemberExpr.getExprBase` as `MemberExpr.getBaseExpr` for consistency * merge `Generator.emitMemberExprBase` into `Generator.emitMemberExpr` * disable bogus const check in `conversion_checker.Checker.check` * improve `Analyser.analyseToContainer` for const/volatile correctness * fix `Analyser.findMemberOffset` for member expression chains should support ̀to_container(s, array[n].ptr, ptr)`? * this simplifies the code and reduces memory usage by 100KB
1 parent be626b3 commit ab1f939

21 files changed

+309
-399
lines changed

analyser/conversion_checker.c2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ public fn bool Checker.check(Checker* c, QualType lhs, QualType rhs, Expr** e_pt
147147
const Type* rcanon = t2.getTypeOrNil();
148148

149149
if (lcanon == rcanon) {
150+
#if 0 // This is bogus!
150151
//u32 lquals = lhs.getQuals();
151152
//u32 rquals = rhs.getQuals();
152153
// TODO: check constness of pointed thing instead of that of pointer
@@ -155,6 +156,7 @@ public fn bool Checker.check(Checker* c, QualType lhs, QualType rhs, Expr** e_pt
155156
c.diags.error(loc, "conversion discards const qualifier");
156157
return false;
157158
}
159+
#endif
158160
return true;
159161
}
160162

analyser/module_analyser_builtin.c2

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,8 @@ fn QualType Analyser.analyseOffsetOf(Analyser* ma, BuiltinExpr* b) {
167167
}
168168

169169
fn QualType Analyser.analyseToContainer(Analyser* ma, BuiltinExpr* b) {
170-
// syntax: Type* to_container(Type, member, member*)
171-
// const Type* to_container(Type, member, const member*)
172-
Expr* inner = b.getInner();
170+
// syntax: const? volatile? Type* to_container(Type, member, const? volatile? member*)
171+
Expr* inner = b.getInner(); // Type
173172
QualType qt = ma.analyseExpr(&inner, false, RHS);
174173
if (qt.isInvalid()) return QualType_Invalid;
175174

@@ -186,32 +185,40 @@ fn QualType Analyser.analyseToContainer(Analyser* ma, BuiltinExpr* b) {
186185
Expr* member = b.getToContainerMember();
187186
Decl* d = ma.findMemberOffset(b, std, member);
188187
if (!d) return QualType_Invalid;
189-
QualType qmem = d.getType();
190-
qmem = ma.builder.actOnPointerType(qmem);
191188

192189
// check ptr
193-
QualType qptr = ma.analyseExpr(b.getToContainerPointer2(), false, RHS);
190+
Expr** pptr = b.getToContainerPointer2();
191+
QualType qptr = ma.analyseExpr(pptr, false, RHS);
194192
if (qptr.isInvalid()) return QualType_Invalid;
195193

196-
// Note: 3rd argument may be const ptr, but result will be const ptr as well then
197-
Expr* eptr = b.getToContainerPointer();
198-
if (!ma.checker.check(qptr, qmem, b.getToContainerPointer2(), eptr.getLoc())) {
194+
// Note: 3rd argument may be const/volatile ptr: copy qualifiers to result type
195+
PointerType* pt = qptr.getPointerType();
196+
qt.copyQuals(pt.getInner());
197+
198+
// Construct expected pointer type with proper qualifiers
199+
QualType qmem = d.getType();
200+
qmem.copyQuals(pt.getInner());
201+
QualType expectedType = ma.builder.actOnPointerType(qmem);
202+
203+
if (!ma.checker.check(expectedType, qptr, pptr, (*pptr).getLoc())) {
199204
return QualType_Invalid;
200205
}
201206

202-
if (qptr.isConstPtr()) qt.setConst();
203207
return ma.builder.actOnPointerType(qt);
204208
}
205209

206-
fn Decl* Analyser.findMemberOffset(Analyser* ma, BuiltinExpr* b, StructTypeDecl* std, Expr* member) {
207-
u32 base_offset = 0;
208-
Decl* d = nil;
210+
type FindMemberOffsetContext struct {
211+
StructTypeDecl* std;
212+
u32 base_offset;
213+
}
209214

215+
fn Decl* Analyser.findMemberOffsetAux(Analyser* ma, FindMemberOffsetContext* ctx, Expr* member) {
216+
Decl* d = nil;
210217
if (member.isIdentifier()) {
211218
IdentifierExpr* i = (IdentifierExpr*)member;
212219
u32 name_idx = i.getNameIdx();
213220

214-
d = ma.findStructMemberOffset(std, name_idx, member.getLoc(), &base_offset);
221+
d = ma.findStructMemberOffset(ctx.std, name_idx, member.getLoc(), &ctx.base_offset);
215222
if (!d) return nil;
216223

217224
i.setDecl(d);
@@ -221,20 +228,33 @@ fn Decl* Analyser.findMemberOffset(Analyser* ma, BuiltinExpr* b, StructTypeDecl*
221228
} else {
222229
assert(member.isMember());
223230
MemberExpr* m = (MemberExpr*)member;
224-
for (u32 i=0; i<m.getNumRefs(); i++) {
231+
u32 start = 0;
232+
if (m.hasExpr()) {
233+
d = ma.findMemberOffsetAux(ctx, m.getBaseExpr());
234+
if (!d) return nil;
235+
if (d.isStructType()) ctx.std = (StructTypeDecl*)d;
236+
start = 1;
237+
}
238+
for (u32 i = start; i < 2; i++) {
225239
u32 name_idx = m.getNameIdx(i);
226240
SrcLoc loc = m.getLoc(i);
227-
d = ma.findStructMemberOffset(std, name_idx, loc, &base_offset);
241+
d = ma.findStructMemberOffset(ctx.std, name_idx, loc, &ctx.base_offset);
228242
if (!d) return nil;
229243

230-
if (d.isStructType()) std = (StructTypeDecl*)d;
244+
if (d.isStructType()) ctx.std = (StructTypeDecl*)d;
231245
d.setUsed();
232246
m.setDecl(d, i);
233247
}
234248
m.setKind(StructMember);
235249
}
236250
member.setType(d.getType());
237-
b.setUValue(base_offset);
251+
return d;
252+
}
253+
254+
fn Decl* Analyser.findMemberOffset(Analyser* ma, BuiltinExpr* b, StructTypeDecl* std, Expr* member) {
255+
FindMemberOffsetContext ctx = { std, 0 }
256+
Decl* d = ma.findMemberOffsetAux(&ctx, member);
257+
if (d) b.setUValue(ctx.base_offset);
238258
return d;
239259
}
240260

analyser/module_analyser_call.c2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ fn QualType Analyser.analyseCallExpr(Analyser* ma, Expr** e_ptr) {
108108
call.setCallsTypeFunc();
109109
baseType = m.getBaseType();
110110
// loc points to the last member of the function name
111-
loc = m.getLastLoc();
111+
loc = m.getMemberLoc();
112112
}
113113
break;
114114
case StaticTypeFunc:
@@ -149,7 +149,7 @@ fn QualType Analyser.analyseCallExpr(Analyser* ma, Expr** e_ptr) {
149149
if (!baseType.isPointer()) {
150150
// TODO: Check if structure is lvalue. If not, we should add a local object to
151151
// store the rvalue and use that as the lvalue
152-
Expr* base = m.getExprBase();
152+
Expr* base = m.getBaseExpr();
153153
if (base && !base.isLValue()) {
154154
ma.errorRange(m.getLoc(0), base.getRange(), "type function needs lvalue");
155155
return QualType_Invalid;

analyser/module_analyser_expr.c2

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ fn Decl* Analyser.analyseIdentifier(Analyser* ma, Expr** e_ptr, u32 side) {
167167
IdentifierKind kind = ma.setExprFlags(e_ptr, d);
168168
i.setKind(kind);
169169

170-
if (ma.usedPublic && !d.isPublic() && d.isGlobal()) {
170+
if (ma.usedPublic && !d.isPublic() && d.isGlobal() && !d.isImport()) {
171171
// Note: can also be a function or type for inline function bodies
172172
const char* kind_str = type2str(qt);
173173
if (ma.scope.inFunction()) {
@@ -400,12 +400,12 @@ fn bool Analyser.checkAssignment(Analyser* ma, Expr* assignee, QualType tleft, c
400400
case Type:
401401
break;
402402
case Var:
403-
ma.error(loc, "cannot assign to read-only variable '%s'", m.getLastMemberName());
403+
ma.error(loc, "cannot assign to read-only variable '%s'", m.getMemberName());
404404
return false;
405405
case EnumConstant:
406406
break;
407407
case StructMember:
408-
ma.error(loc, "assignment of member '%s' in read-only object", m.getLastMemberName());
408+
ma.error(loc, "assignment of member '%s' in read-only object", m.getMemberName());
409409
return false;
410410
case Label:
411411
break;

analyser/module_analyser_member.c2

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,37 @@ const char[] DiagStaticThoughVar = "cannot access static type-function through v
2424

2525
fn QualType Analyser.analyseMemberExpr(Analyser* ma, Expr** e_ptr, u32 side) {
2626
Expr* e = *e_ptr;
27-
MemberExpr* m =(MemberExpr*)e;
27+
MemberExpr* m = (MemberExpr*)e;
2828

2929
SrcLoc baseLoc = 0;
30-
ValType valtype = ValType.NValue;
30+
ValType valtype = NValue;
3131
QualType baseType = QualType_Invalid;
3232

3333
CallKind ck = Invalid;
34+
u32 start = 0;
3435

3536
if (m.hasExpr()) {
36-
Expr* exprBase = m.getExprBase();
37+
Expr* exprBase = m.getBaseExpr();
38+
baseLoc = exprBase.getLoc();
3739
// note: no ImplicitCast can be added
3840
baseType = ma.analyseExpr(&exprBase, false, side);
3941
if (baseType.isInvalid()) return QualType_Invalid;
4042

4143
valtype = exprBase.getValType();
42-
43-
//stdio.printf("EXPR BASE\n");
44-
//baseType.dump();
44+
start = 1;
4545
}
4646

4747
Decl* d = nil;
48-
u32 refcount = m.getNumRefs();
49-
bool is_substruct;
50-
for (u32 i=0; i<refcount; i++) {
48+
bool is_substruct = false;
49+
for (u32 i = start; i < 2; i++) {
5150
is_substruct = false;
5251
u32 name_idx = m.getNameIdx(i);
5352
SrcLoc loc = m.getLoc(i);
5453

5554
//stdio.printf(" [%d/%d] %s\n", i, refcount, m.getName(i));
5655

5756
if (baseType.isInvalid()) {
57+
// first member
5858
d = ma.scope.find(name_idx, loc, ma.usedPublic);
5959
if (!d) {
6060
ma.has_error = true;
@@ -121,15 +121,14 @@ fn QualType Analyser.analyseMemberExpr(Analyser* ma, Expr** e_ptr, u32 side) {
121121
//stdio.printf("ENUM BASE (type: %d)\n", valtype == ValType.NValue);
122122
EnumType* et = (EnumType*)t;
123123
EnumTypeDecl* etd = et.getDecl();
124+
d = (Decl*)etd;
124125

125126
// check if constant/enum-function (by first casing)
126-
const char* last = m.getLastMemberName();
127-
if (ctype.isupper(last[0]) || name_idx == ma.min_idx || name_idx == ma.max_idx) { // search for constants
128-
if (valtype != ValType.NValue) { // variable of Enum type (eg Enum a; a.x)
127+
const char* name = m.getMemberName();
128+
if (ctype.isupper(name[0]) || name_idx == ma.min_idx || name_idx == ma.max_idx) { // search for constants
129+
if (valtype != NValue) { // variable of Enum type (eg Enum a; a.x)
129130
// TODO reset msg to normal invalid base
130-
// TODO use range
131-
//ma.errorRange(baseLoc, m.getRange(i), "invalid member reference base (enum constant/variable)");
132-
ma.error(baseLoc, "invalid member reference base (enum constant/variable)");
131+
ma.errorRange(baseLoc, m.getBaseRange(), "invalid member reference base (enum constant/variable)");
133132
return QualType_Invalid;
134133
}
135134
EnumConstantDecl* ecd;
@@ -143,7 +142,7 @@ fn QualType Analyser.analyseMemberExpr(Analyser* ma, Expr** e_ptr, u32 side) {
143142
} else {
144143
ecd = etd.findConstant(name_idx);
145144
if (!ecd) {
146-
ma.error(loc, "enum '%s' has no constant '%s'", d.getFullName(), m.getLastMemberName());
145+
ma.error(loc, "enum '%s' has no constant '%s'", d.getFullName(), name);
147146
return QualType_Invalid;
148147
}
149148
}
@@ -154,10 +153,9 @@ fn QualType Analyser.analyseMemberExpr(Analyser* ma, Expr** e_ptr, u32 side) {
154153
}
155154
// no need to update baseType
156155
} else { // search for enum-function
157-
d = (Decl*)etd;
158156
Decl* ef = etd.findFunction(name_idx);
159157
if (!ef) {
160-
ma.error(loc, "enum '%s' has no function '%s'", d.getFullName(), m.getLastMemberName());
158+
ma.error(loc, "enum '%s' has no function '%s'", d.getFullName(), name);
161159
return QualType_Invalid;
162160
}
163161
//FunctionDecl* fd = (FunctionDecl*)ef);
@@ -167,7 +165,7 @@ fn QualType Analyser.analyseMemberExpr(Analyser* ma, Expr** e_ptr, u32 side) {
167165
baseType = ef.getType();
168166
if (!ma.scope.checkAccess(d, loc)) return QualType_Invalid;
169167
}
170-
valtype = ValType.RValue;
168+
valtype = RValue;
171169
break;
172170
case Alias:
173171
assert(0);
@@ -188,22 +186,20 @@ fn QualType Analyser.analyseMemberExpr(Analyser* ma, Expr** e_ptr, u32 side) {
188186
valtype = decl2valtype(d);
189187
break;
190188
default:
191-
ma.errorRange(loc, m.getRange(i), "invalid member reference base");
189+
ma.errorRange(loc, m.getBaseRange(), "invalid member reference base");
192190
return QualType_Invalid;
193191
}
194192
}
195193

196194
baseLoc = loc;
197195

198196
// Note: a.b.c = 1; -> b is always used, c only if in RHS
199-
if (i == refcount -1) {
197+
if (i == 1) {
200198
if (side & RHS) d.setUsed();
201199
} else {
202200
d.setUsed();
203201
}
204202
m.setDecl(d, i);
205-
206-
//baseType.dump();
207203
}
208204

209205
if (is_substruct) {
@@ -278,7 +274,7 @@ fn Decl* Analyser.analyseStructMemberAccess(Analyser* ma, StructTypeDecl* std, u
278274
// StructTypeDecl for substruct or VarDecl for normal members
279275
// TODO FIX THIS (do in outer?)
280276
#if 1
281-
if (side && valtype == ValType.NValue) {
277+
if (side && valtype == NValue) {
282278
QualType t = std.asDecl().getType();
283279
ma.error(loc, "member access needs an instantiation of type '%s'", t.diagName());
284280
return nil;
@@ -303,7 +299,7 @@ fn TypeKind Analyser.analyseBaseType(Analyser* ma, QualType baseType) {
303299
fn ValType decl2valtype(const Decl* d) {
304300
switch (d.getKind()) {
305301
case Function:
306-
return ValType.RValue;
302+
return RValue;
307303
case Import:
308304
case StructType:
309305
case EnumType:
@@ -312,8 +308,8 @@ fn ValType decl2valtype(const Decl* d) {
312308
case AliasType:
313309
break;
314310
case Variable:
315-
return ValType.LValue;
311+
return LValue;
316312
}
317-
return ValType.NValue;
313+
return NValue;
318314
}
319315

ast/identifier_expr.c2

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ module ast;
1818
import ast_context;
1919
import string_buffer;
2020
import src_loc local;
21-
import string local;
2221

2322
public type IdentifierKind enum u8 {
2423
Unresolved,
@@ -49,6 +48,7 @@ type IdentifierExprBits struct {
4948
u32 : NumExprBits;
5049
u32 has_decl : 1;
5150
u32 kind : 3; // IdentifierKind
51+
u32 name_len : 32 - 18;
5252
}
5353

5454
public type IdentifierExpr struct @(opaque) {
@@ -59,21 +59,22 @@ public type IdentifierExpr struct @(opaque) {
5959
}
6060
}
6161

62-
public fn IdentifierExpr* IdentifierExpr.create(ast_context.Context* c, SrcLoc loc, u32 name) {
62+
public fn IdentifierExpr* IdentifierExpr.create(ast_context.Context* c, SrcLoc loc, u32 name, u32 name_len) {
6363
IdentifierExpr* e = c.alloc(sizeof(IdentifierExpr));
6464
e.base.init(Identifier, loc, 0, 0, 0, ValType.NValue);
6565
e.name_idx = name;
66+
e.base.base.identifierExprBits.name_len = name_len;
6667
#if AstStatistics
6768
Stats.addExpr(Identifier, sizeof(IdentifierExpr));
6869
#endif
6970
return e;
7071
}
7172

7273
fn Expr* IdentifierExpr.instantiate(IdentifierExpr* e, Instantiator* inst) {
73-
return (Expr*)IdentifierExpr.create(inst.c, e.base.base.loc, e.name_idx);
74+
return (Expr*)IdentifierExpr.create(inst.c, e.base.base.loc, e.name_idx, e.base.base.identifierExprBits.name_len);
7475
}
7576

76-
public fn Expr* IdentifierExpr.asExpr(IdentifierExpr* e) { return &e.base; }
77+
fn Expr* IdentifierExpr.asExpr(IdentifierExpr* e) { return &e.base; }
7778

7879
public fn void IdentifierExpr.setDecl(IdentifierExpr* e, Decl* decl) {
7980
e.decl = decl;
@@ -105,7 +106,7 @@ public fn const char* IdentifierExpr.getName(const IdentifierExpr* e) {
105106
}
106107

107108
fn SrcLoc IdentifierExpr.getEndLoc(const IdentifierExpr* e) {
108-
return e.base.base.loc + (u32)strlen(e.getName());
109+
return e.base.base.loc + e.base.base.identifierExprBits.name_len;
109110
}
110111

111112
public fn u32 IdentifierExpr.getNameIdx(const IdentifierExpr* e) {

0 commit comments

Comments
 (0)