Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion analyser/module_analyser_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,19 @@ fn QualType Analyser.convertRvalue(Analyser* ma, Expr** e_ptr, QualType result)
fn QualType Analyser.analyseExprInner(Analyser* ma, Expr** e_ptr, u32 side) {
Expr* e = *e_ptr;

// prevent multiple analysis and handle literals faster
QualType qt0 = e.getType();
if (!qt0.isInvalid()) return qt0;

switch (e.getKind()) {
case IntegerLiteral:
case FloatLiteral:
case BooleanLiteral:
case CharLiteral:
case StringLiteral:
case Nil:
return e.getType(); // already set in creator
//return e.getType(); // already set in creator and handled above
break;
case Identifier:
Decl* d = ma.analyseIdentifier(e_ptr, side);
if (!d) break;
Expand Down
104 changes: 86 additions & 18 deletions analyser/module_analyser_switch.c2
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,19 @@ import string_buffer;
import string;
import value_type local;

fn QualType Analyser.analyseSwitchExpr(Analyser* ma, Stmt** s_ptr) {
fn QualType Analyser.analyseSwitchDecl(Analyser* ma, Stmt** s_ptr) {
Stmt* s = *s_ptr;
if (s.isDecl()) {
QualType qt = ma.analyseDeclStmt(s);
if (qt.isValid()) {
DeclStmt* ds = (DeclStmt*)s;
VarDecl* vd = ds.getDecl(0);
if (!vd.getInit()) {
ma.error(vd.asDecl().getLoc(), "variable declaration in switch expression must have an initializer");
return QualType_Invalid;
}
assert(s.isDecl());
QualType qt = ma.analyseDeclStmt(s);
if (qt.isValid()) {
DeclStmt* ds = (DeclStmt*)s;
VarDecl* vd = ds.getDecl(0);
if (!vd.getInit()) {
ma.error(vd.asDecl().getLoc(), "variable declaration in switch expression must have an initializer");
return QualType_Invalid;
}
return qt;
}

assert(s.isExpr());
return ma.analyseExpr((Expr**)s_ptr, true, RHS);
return qt;
}

fn FlowBits Analyser.analyseSwitchStmt(Analyser* ma, Stmt* s) {
Expand All @@ -52,20 +48,33 @@ fn FlowBits Analyser.analyseSwitchStmt(Analyser* ma, Stmt* s) {

EnumTypeDecl* etd = nil;

QualType ct = ma.analyseSwitchExpr(sw.getCond2());
if (sw.hasDecl()) {
Stmt** declp = sw.getDecl2();
QualType ct = ma.analyseSwitchDecl(declp);
if (ct.isInvalid()) {
ma.scope.exit(ma.has_error);
return FlowNext | FlowError;
}
}
Expr** condp = sw.getCond2();
if (!*condp) {
DeclStmt* ds = (DeclStmt*)sw.getDecl();
assert(ds);
VarDecl* vd = ds.getDecl(0);
*condp = ma.builder.actOnIdentifier(0, vd.asDecl().getNameIdx(), 0);
}
QualType ct = ma.analyseExpr(condp, true, RHS);
if (ct.isInvalid()) {
ma.scope.exit(ma.has_error);
return FlowNext | FlowError;
}

bool isCharPtr = ct.isCharPointer();

// TODO check type (must be number-ish)

if (isCharPtr) {
is_string = true;
sw.setString();
} else {
// TODO check type (must be number-ish)
EnumType* et = ct.getEnumTypeOrNil();
if (et) etd = et.getDecl();
}
Expand Down Expand Up @@ -147,6 +156,65 @@ fn FlowBits Analyser.analyseSwitchStmt(Analyser* ma, Stmt* s) {
// TODO: handle complete coverage
if (!defaultCase) flow |= FlowNext;

if (!(flow & FlowError) && is_string) {
// Create alternate expression for c2_strswitch(s)
// create call expression `c2_helper.c2_strswitch("expression", "case string")
// TODO: handle declaration expressions
string_buffer.Buf* casestr = string_buffer.create(128, false, 0);

for (u32 i = 0; i < numCases; i++) {
SwitchCase* c = cases[i];
if (c.isDefault())
continue;
Expr* e = c.getCond(0);
if (e.isImplicitCast()) {
const ImplicitCastExpr* ic = (ImplicitCastExpr*)e;
e = ic.getInner();
}
if (e.isNil())
continue;
if (e.isStringLiteral()) {
StringLiteral* lit = (StringLiteral*)e;
const char *str = lit.getText();
u8 slen = (lit.getSize() - 1) & 0xFF;
if (slen) {
// only encode non emty strings, empty string has index 1
casestr.add1(slen);
casestr.add2(str, slen);
}
} else {
e.dump();
assert(0);
}
}

u32 casestr_len = casestr.size();
u32 casestr_idx = ma.astPool.add(casestr.data(), casestr_len, false);
casestr.free();
Expr* casestr_expr = ma.builder.actOnStringLiteral(0, 0, casestr_idx, casestr_len);

u32 c2_strswitch_idx = ma.astPool.addStr("c2_strswitch", true);
u32 c2_helper_idx = ma.astPool.addStr("c2_helper", true);
Expr* func = ma.builder.actOnMemberExpr(nil, c2_helper_idx, 0, 0, c2_strswitch_idx);
Expr* cond = *condp;
Expr*[2] args;
args[0] = cond;
args[1] = casestr_expr;
Expr* call = ma.builder.actOnCallExpr(cond.getStartLoc(), cond.getEndLoc(), func, args, 2);
ct = ma.analyseExpr(&call, true, RHS);
if (ct.isInvalid()) flow |= FlowError;
else {
if (sw.hasCond()) {
Expr* alt = ma.builder.actOnAlternate(cond, call);
// set alternate type to that of generated branch
alt.setType(call.getType());
alt.copyFlags(call);
call = alt;
}
*condp = call;
}
}

ma.putInitChecker(checker);
return flow;
}
Expand Down
2 changes: 2 additions & 0 deletions analyser/module_sorter.c2
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public fn void sort(component.Component* c, diagnostics.Diags* diags) {
if (count <= 1) return;

ModuleSorter s;
s.diags = diags;
s.num_mods = count;
s.cur_mod_idx = 0;
s.comp = c;
Expand Down Expand Up @@ -64,6 +65,7 @@ public fn void sort(component.Component* c, diagnostics.Diags* diags) {
}

type ModuleSorter struct {
diagnostics.Diags* diags;
component.Component* comp;
u32 num_mods;
ast.Module** modules;
Expand Down
62 changes: 48 additions & 14 deletions ast/switch_stmt.c2
Original file line number Diff line number Diff line change
Expand Up @@ -24,56 +24,88 @@ type SwitchStmtBits struct {
u32 : NumStmtBits;
u32 is_string : 1;
u32 has_default : 1;
u32 num_cases : 32 - NumStmtBits - 2;
u32 has_decl : 1;
u32 has_cond : 1;
u32 num_cases : 32 - NumStmtBits - 4;
}

public type SwitchStmt struct @(opaque) {
Stmt base;
Stmt* cond;
SwitchCase*[0] cases; // tail-allocated
Expr* cond;
Stmt*[0] decl; // tail allocated, optional
//SwitchCase*[0] cases; // tail-allocated
}

public fn SwitchStmt* SwitchStmt.create(ast_context.Context* c,
SrcLoc loc,
Stmt* cond,
Stmt* decl,
Expr* cond,
SwitchCase** cases,
u32 numCases,
bool has_default)
{
u32 size = sizeof(SwitchStmt) + numCases * sizeof(Stmt*);
bool has_decl = (decl != nil);
u32 size = sizeof(SwitchStmt) + has_decl * sizeof(Stmt*) + numCases * sizeof(SwitchCase*);
SwitchStmt* s = c.alloc(size);
s.base.init(Switch, loc);
s.base.switchStmtBits.has_default = has_default;
s.base.switchStmtBits.num_cases = numCases;
s.base.switchStmtBits.has_decl = has_decl;
s.base.switchStmtBits.has_cond = cond != nil;
s.cond = cond;
string.memcpy(s.cases, cases, numCases * sizeof(SwitchCase*));
if (has_decl) s.decl[0] = decl;
SwitchCase** cases_dest = (void*)(s.decl + has_decl);
string.memcpy(cases_dest, cases, numCases * sizeof(SwitchCase*));
#if AstStatistics
Stats.addStmt(Switch, size);
#endif
return s;
}

fn Stmt* SwitchStmt.instantiate(SwitchStmt* s, Instantiator* inst) {
bool has_decl = s.base.switchStmtBits.has_decl;
u32 numCases = s.getNumCases();
u32 size = sizeof(SwitchStmt) + numCases * sizeof(SwitchCase*);
u32 size = sizeof(SwitchStmt) + has_decl * sizeof(Stmt*) + numCases * sizeof(SwitchCase*);
SwitchStmt* s2 = inst.c.alloc(size);
s2.base = s.base;
s2.cond = s.cond.instantiate(inst);
if (has_decl) s2.decl[0] = s.decl[0].instantiate(inst);
SwitchCase** cases_from = (void*)(s.decl + has_decl);
SwitchCase** cases_dest = (void*)(s2.decl + has_decl);
for (u32 i=0; i<numCases; i++) {
s2.cases[i] = s.cases[i].instantiate(inst);
cases_dest[i] = cases_from[i].instantiate(inst);
}
#if AstStatistics
Stats.addStmt(Switch, size);
#endif
return (Stmt*)s2;
}

public fn Stmt* SwitchStmt.getCond(const SwitchStmt* s) {
public fn bool SwitchStmt.hasDecl(const SwitchStmt* s) {
return s.base.switchStmtBits.has_decl;
}

public fn Stmt* SwitchStmt.getDecl(const SwitchStmt* s) {
if (!s.base.switchStmtBits.has_decl) return nil;
return s.decl[0];
}

public fn Stmt** SwitchStmt.getDecl2(SwitchStmt* s) {
if (!s.base.switchStmtBits.has_decl) return nil;
return s.decl;
}

// does the original code have a condition expression
public fn bool SwitchStmt.hasCond(const SwitchStmt* s) {
return s.base.switchStmtBits.has_cond;
}

public fn Expr* SwitchStmt.getCond(const SwitchStmt* s) {
return s.cond;
}

public fn Stmt** SwitchStmt.getCond2(SwitchStmt* s) {
return s.cond ? &s.cond : nil;
public fn Expr** SwitchStmt.getCond2(SwitchStmt* s) {
return &s.cond;
}

public fn bool SwitchStmt.isString(const SwitchStmt* s) {
Expand All @@ -93,7 +125,7 @@ public fn u32 SwitchStmt.getNumCases(const SwitchStmt* s) {
}

public fn SwitchCase** SwitchStmt.getCases(SwitchStmt* s) {
return s.cases;
return (SwitchCase**)&s.decl[s.base.switchStmtBits.has_decl];
}

fn void SwitchStmt.print(const SwitchStmt* s, string_buffer.Buf* out, u32 indent) {
Expand All @@ -108,9 +140,11 @@ fn void SwitchStmt.print(const SwitchStmt* s, string_buffer.Buf* out, u32 indent
}
out.newline();

s.cond.print(out, indent + 1);
if (s.hasDecl()) s.decl[0].print(out, indent + 1);
if (s.cond) s.cond.print(out, indent + 1);
SwitchCase** cases_from = (void*)(s.decl + s.hasDecl());
for (u32 i=0; i<s.base.switchStmtBits.num_cases; i++) {
s.cases[i].print(out, indent + 1);
cases_from[i].print(out, indent + 1);
}
}

14 changes: 8 additions & 6 deletions common/ast_builder.c2
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public fn void Builder.actOnModule(Builder* b,
b.ast.addImport(i);
}

public fn void Builder.actOnImport(Builder* b,
public fn Decl* Builder.actOnImport(Builder* b,
u32 mod_name,
SrcLoc mod_loc,
u32 alias_name,
Expand All @@ -122,7 +122,7 @@ public fn void Builder.actOnImport(Builder* b,
// reject self imports, no error for implicit imports (eg: varargs)
b.diags.error(mod_loc, "cannot import own module '%s'", idx2name(mod_name));
}
return;
return nil;
}

ImportDecl* old = b.ast.findImport(mod_name);
Expand All @@ -132,13 +132,13 @@ public fn void Builder.actOnImport(Builder* b,
b.diags.error(mod_loc, "duplicate import of module '%s'", idx2name(mod_name));
b.diags.note(old.asDecl().getLoc(), "previous import is here");
}
return;
return (Decl*)old;
}

if (alias_name) {
if (alias_name == mod_name) {
b.diags.error(alias_loc, "alias name is same as module name");
return;
return nil;
}
// Note: other clashes are done by Scope later
}
Expand All @@ -151,6 +151,7 @@ public fn void Builder.actOnImport(Builder* b,
b.ast_idx,
islocal);
b.ast.addImport(d);
return (Decl*)d;
}

public fn Decl* Builder.actOnAliasType(Builder* b,
Expand Down Expand Up @@ -872,10 +873,11 @@ public fn Stmt* Builder.actOnForStmt(Builder* b,

public fn Stmt* Builder.actOnSwitchStmt(Builder* b,
SrcLoc loc,
Stmt* cond,
Stmt* decl,
Expr* cond,
SwitchCase** cases, u32 num_cases,
bool has_default) {
return (Stmt*)SwitchStmt.create(b.context, loc, cond, cases, num_cases, has_default);
return (Stmt*)SwitchStmt.create(b.context, loc, decl, cond, cases, num_cases, has_default);
}

public fn SwitchCase* Builder.actOnCase(Builder* b,
Expand Down
9 changes: 7 additions & 2 deletions generator/ast_visitor.c2
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ public type OnRef fn void (void* arg, const Ref* ref);
public type Visitor struct @(opaque) {
void* arg;
OnRef on_ref;
bool use_generated; // use generated branch in AlternateExpr nodes
}

public fn Visitor* create(void* arg, OnRef on_ref) {
public fn Visitor* create(void* arg, OnRef on_ref, bool use_generated = false) {
Visitor* v = stdlib.calloc(1, sizeof(Visitor));
v.arg = arg;
v.on_ref = on_ref;
v.use_generated = use_generated;
return v;
}

Expand Down Expand Up @@ -172,7 +174,10 @@ fn void Visitor.handleStmt(Visitor* v, Stmt* s) {
break;
case Switch:
SwitchStmt* sw = (SwitchStmt*)s;
v.handleStmt(sw.getCond());
Stmt* decl = sw.getDecl();
if (decl) v.handleStmt(decl);
Expr* cond = sw.getCond();
if (cond) v.handleExpr(cond);
const u32 numcases = sw.getNumCases();
SwitchCase** cases = sw.getCases();
for (u32 i=0; i<numcases; i++) {
Expand Down
6 changes: 5 additions & 1 deletion generator/ast_visitor_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ fn void Visitor.handleExpr(Visitor* v, Expr* e) {
break;
case Alternate:
AlternateExpr* n = (AlternateExpr*)e;
v.handleExpr(n.getOriginal());
if (v.use_generated) {
v.handleExpr(n.getGenerated());
} else {
v.handleExpr(n.getOriginal());
}
break;
}
}
Expand Down
Loading
Loading