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
80 changes: 58 additions & 22 deletions analyser/module_analyser_stmt.c2
Original file line number Diff line number Diff line change
Expand Up @@ -251,27 +251,37 @@ fn FlowBits Analyser.analyseCompoundStmt(Analyser* ma, CompoundStmt* c) {
return flow | flow2; // return FlowNext if last statement has FlowNext or empty block
}

fn QualType Analyser.analyseCondition(Analyser* ma, Stmt** s_ptr, bool check_assign) {
fn QualType Analyser.analyseConditionDecl(Analyser* ma, Stmt** s_ptr, const char* context) {
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 condition 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.hasInitCall()) {
ma.error(vd.asDecl().getLoc(), "variable declaration in %s cannot have an init call", context);
return QualType_Invalid;
}
if (!vd.hasInit()) {
ma.error(vd.asDecl().getLoc(), "variable declaration in %s must have an initializer", context);
return QualType_Invalid;
}
return qt;
}
return qt;
}

fn QualType Analyser.analyseCondition(Analyser* ma, Stmt** s_ptr, const char* context, bool check_assign, bool check_bool) {
Stmt* s = *s_ptr;
if (s.isDecl()) {
return ma.analyseConditionDecl(s_ptr, context);
}
assert(s.isExpr());
QualType qt = ma.analyseExpr((Expr**)s_ptr, true, RHS);
Expr* e = (Expr*)*s_ptr;
if (qt.isValid()) ma.checker.check(getBuiltinQT(Bool), qt, (Expr**)s_ptr, e.getLoc());
e = (Expr*)*s_ptr; // re-read in case of ImplicitCast insertions

if (check_bool) {
if (qt.isValid()) ma.checker.check(getBuiltinQT(Bool), qt, (Expr**)s_ptr, e.getLoc());
e = (Expr*)*s_ptr; // re-read in case of ImplicitCast insertions
}
if (check_assign && e.isAssignment()) {
ma.warn(e.getLoc(), "using the result of an assignment as a condition without parentheses");
}
Expand All @@ -284,19 +294,45 @@ fn FlowBits Analyser.analyseIfStmt(Analyser* ma, Stmt* s) {
IfStmt* i = (IfStmt*)s;
ma.scope.enter(scope.Decl);

ma.analyseCondition(i.getCond2(), true);
if (ma.has_error) goto done;
if (i.hasDecl()) {
QualType ct = ma.analyseConditionDecl(i.getDecl2(), "'if' condition");
if (ct.isInvalid()) {
ma.scope.exit(ma.has_error);
return FlowNext | FlowError;
}
}
VarDecl* vd = nil;
Expr** condp = i.getCond2();
if (!*condp) {
// Use declared variable as condition
DeclStmt* ds = (DeclStmt*)i.getDecl();
assert(ds);
vd = ds.getDecl(0);
*condp = ma.builder.actOnIdentifier(0, vd.asDecl().getNameIdx(), 0);
}
QualType qt = ma.analyseExpr(condp, true, RHS);
if (qt.isInvalid()) goto done;
// reset the used bit so warning is emitted if variable is not used in the 'if' scope
if (vd) vd.asDecl().clearUsed();

Expr* e = *condp;
bool ok = ma.checker.check(getBuiltinQT(Bool), qt, condp, e.getLoc());
e = *condp; // re-read in case of ImplicitCast insertions
if (e.isAssignment()) {
ma.warn(e.getLoc(), "using the result of an assignment as a condition without parentheses");
}
if (!ok) goto done;
// TODO: handle constant conditions

ma.scope.enter(scope.Decl);
flow = ma.analyseStmt(i.getThen2(), true);
ma.scope.exit(ma.has_error);

FlowBits flow2 = FlowNext;
Stmt** else_ = i.getElse2();
if (else_) {
Stmt** else_stmt = i.getElse2();
if (else_stmt) {
ma.scope.enter(scope.Decl);
flow2 = ma.analyseStmt(else_, true);
flow2 = ma.analyseStmt(else_stmt, true);
ma.scope.exit(ma.has_error);
}
flow |= flow2;
Expand All @@ -312,7 +348,7 @@ fn FlowBits Analyser.analyseForStmt(Analyser* ma, Stmt* s) {
ma.scope.enter(scope.Break | scope.Continue | scope.Decl | scope.Control);
Stmt** init = f.getInit2();
if (init) {
QualType ct = ma.analyseCondition(init, false);
QualType ct = ma.analyseCondition(init, "'for' init clause", false, false);
if (ct.isInvalid()) goto done;
}

Expand Down Expand Up @@ -352,8 +388,8 @@ fn FlowBits Analyser.analyseWhileStmt(Analyser* ma, Stmt* s) {
WhileStmt* w = (WhileStmt*)s;

ma.scope.enter(scope.Decl);
ma.analyseCondition(w.getCond2(), true);
if (ma.has_error) goto done;
QualType ct = ma.analyseCondition(w.getCond2(), "'while' condition", true, true);
if (ct.isInvalid()) goto done;

Expr* cond = getCondExpr(w.getCond());
if (cond.isCtv()) {
Expand Down
20 changes: 3 additions & 17 deletions analyser/module_analyser_switch.c2
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,6 @@ import string_buffer;
import string;
import value_type local;

fn QualType Analyser.analyseSwitchDecl(Analyser* ma, Stmt** s_ptr) {
Stmt* s = *s_ptr;
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;
}

fn FlowBits Analyser.analyseSwitchStmt(Analyser* ma, Stmt* s) {
FlowBits flow = 0;
SwitchStmt* sw = (SwitchStmt*)s;
Expand All @@ -50,7 +35,7 @@ fn FlowBits Analyser.analyseSwitchStmt(Analyser* ma, Stmt* s) {

if (sw.hasDecl()) {
Stmt** declp = sw.getDecl2();
QualType ct = ma.analyseSwitchDecl(declp);
QualType ct = ma.analyseConditionDecl(declp, "'switch' expression");
if (ct.isInvalid()) {
ma.scope.exit(ma.has_error);
return FlowNext | FlowError;
Expand Down Expand Up @@ -216,7 +201,8 @@ fn FlowBits Analyser.analyseSwitchStmt(Analyser* ma, Stmt* s) {
ct = ma.analyseExpr(&call, true, RHS);
if (ct.isInvalid()) flow |= FlowError;
else {
if (sw.hasCond()) {
if (sw.hasSourceCond()) {
// create alternate node for c2i generator
Expr* alt = ma.builder.actOnAlternate(cond, call);
// set alternate type to that of generated branch
alt.setType(call.getType());
Expand Down
4 changes: 4 additions & 0 deletions ast/ast_evaluator.c2
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,10 @@ fn Cont Expr.eval(Expr* e, Evaluator* sf) {
}

fn Cont IfStmt.eval(IfStmt* s, Evaluator* sf) {
if (s.hasDecl()) {
Cont cont = s.getDecl().eval(sf);
if (cont != Normal) return cont;
}
Cont cont = s.getCond().eval(sf);
if (cont != Normal) return cont;
if (!sf.result.isZero()) {
Expand Down
69 changes: 53 additions & 16 deletions ast/if_stmt.c2
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,41 @@ import string_buffer;

type IfStmtBits struct {
u32 : NumStmtBits;
u32 has_decl : 1;
u32 has_source_cond : 1;
u32 has_else : 1;
}

public type IfStmt struct @(opaque) {
Stmt base;
Stmt* cond;
Expr* cond;
Stmt* then;
Stmt*[0] else_stmt; // tail-allocated
Stmt*[0] tail; // tail-allocated: else/decl
}

public fn IfStmt* IfStmt.create(ast_context.Context* c, SrcLoc loc, Stmt* cond, Stmt* then, Stmt* else_stmt) {
u32 size = sizeof(IfStmt);
if (else_stmt) size += sizeof(Stmt*);

public fn IfStmt* IfStmt.create(ast_context.Context* c,
SrcLoc loc,
Stmt* decl,
Expr* cond,
Stmt* then,
Stmt* else_stmt)
{
u32 has_decl = (decl != nil);
u32 has_else = (else_stmt != nil);
u32 size = sizeof(IfStmt) + (has_decl + has_else) * sizeof(Stmt*);
IfStmt* s = c.alloc(size);
s.base.init(If, loc);
s.base.ifStmtBits.has_source_cond = (cond != nil);
s.cond = cond;
s.then = then;

if (else_stmt) {
if (has_else) {
s.base.ifStmtBits.has_else = 1;
s.else_stmt[0] = else_stmt;
s.tail[0] = else_stmt;
}
if (has_decl) {
s.base.ifStmtBits.has_decl = 1;
s.tail[has_else] = decl;
}
#if AstStatistics
Stats.addStmt(If, size);
Expand All @@ -51,36 +64,60 @@ public fn IfStmt* IfStmt.create(ast_context.Context* c, SrcLoc loc, Stmt* cond,
}

fn Stmt* IfStmt.instantiate(IfStmt* s, Instantiator* inst) {
Stmt* cond2 = s.cond.instantiate(inst);
Expr* cond2 = nil;
if (s.base.ifStmtBits.has_source_cond) cond2 = s.cond.instantiate(inst);
Stmt* then2 = s.then.instantiate(inst);
Stmt* else2 = nil;
if (s.base.ifStmtBits.has_else) else2 = s.else_stmt[0].instantiate(inst);
if (s.base.ifStmtBits.has_else) else2 = s.getElse().instantiate(inst);
Stmt* decl2 = nil;
if (s.base.ifStmtBits.has_decl) else2 = s.getDecl().instantiate(inst);

return (Stmt*)IfStmt.create(inst.c, s.base.loc, cond2, then2, else2);
return (Stmt*)IfStmt.create(inst.c, s.base.loc, decl2, cond2, then2, else2);
}

public fn Stmt* IfStmt.getCond(const IfStmt* s) { return s.cond; }
public fn Stmt** IfStmt.getCond2(IfStmt* s) { return &s.cond; }
public fn bool IfStmt.hasDecl(const IfStmt* s) { return s.base.ifStmtBits.has_decl; }

public fn Stmt* IfStmt.getDecl(const IfStmt* s) {
if (!s.base.ifStmtBits.has_decl) return nil;
return s.tail[s.base.ifStmtBits.has_else];
}

public fn Stmt** IfStmt.getDecl2(IfStmt* s) {
if (!s.base.ifStmtBits.has_decl) return nil;
return &s.tail[s.base.ifStmtBits.has_else];
}

public fn bool IfStmt.hasSourceCond(const IfStmt* s) { return s.base.ifStmtBits.has_source_cond; }

public fn Expr* IfStmt.getCond(const IfStmt* s) { return s.cond; }
public fn Expr** IfStmt.getCond2(IfStmt* s) { return &s.cond; }

public fn Stmt* IfStmt.getThen(const IfStmt* s) { return s.then; }
public fn Stmt** IfStmt.getThen2(IfStmt* s) { return &s.then; }

public fn bool IfStmt.hasElse(const IfStmt* s) { return s.base.ifStmtBits.has_else; }
public fn Stmt* IfStmt.getElse(const IfStmt* s) {
if (s.base.ifStmtBits.has_else) return s.else_stmt[0];
if (s.base.ifStmtBits.has_else) return s.tail[0];
return nil;
}

public fn Stmt** IfStmt.getElse2(IfStmt* s) {
if (s.base.ifStmtBits.has_else) return &s.else_stmt[0];
if (s.base.ifStmtBits.has_else) return &s.tail[0];
return nil;
}

fn void IfStmt.print(const IfStmt* s, string_buffer.Buf* out, u32 indent) {
s.base.printKind(out, indent);
out.color(col_Attr);
if (s.hasDecl()) {
out.add(" decl");
if (s.hasSourceCond()) out.add(" ; cond");
}
out.newline();

if (s.hasDecl()) s.getDecl().print(out, indent + 1);
s.cond.print(out, indent + 1);
s.then.print(out, indent + 1);
if (s.base.ifStmtBits.has_else) s.else_stmt[0].print(out, indent + 1);
if (s.hasElse()) s.getElse().print(out, indent + 1);
}

9 changes: 4 additions & 5 deletions ast/switch_stmt.c2
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type SwitchStmtBits struct {
u32 is_string : 1;
u32 has_default : 1;
u32 has_decl : 1;
u32 has_cond : 1;
u32 has_source_cond : 1;
u32 num_cases : 32 - NumStmtBits - 4;
}

Expand All @@ -51,7 +51,7 @@ public fn SwitchStmt* SwitchStmt.create(ast_context.Context* c,
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.base.switchStmtBits.has_source_cond = cond != nil;
s.cond = cond;
if (has_decl) s.decl[0] = decl;
SwitchCase** cases_dest = (void*)(s.decl + has_decl);
Expand Down Expand Up @@ -95,9 +95,8 @@ public fn Stmt** SwitchStmt.getDecl2(SwitchStmt* s) {
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 bool SwitchStmt.hasSourceCond(const SwitchStmt* s) {
return s.base.switchStmtBits.has_source_cond;
}

public fn Expr* SwitchStmt.getCond(const SwitchStmt* s) {
Expand Down
4 changes: 2 additions & 2 deletions common/ast_builder.c2
Original file line number Diff line number Diff line change
Expand Up @@ -995,8 +995,8 @@ public fn Stmt* Builder.actOnReturnStmt(Builder* b, SrcLoc loc, Expr* ret) {
return (Stmt*)ReturnStmt.create(b.context, loc, ret);
}

public fn Stmt* Builder.actOnIfStmt(Builder* b, SrcLoc loc, Stmt* cond, Stmt* then, Stmt* else_stmt) {
return (Stmt*)IfStmt.create(b.context, loc, cond, then, else_stmt);
public fn Stmt* Builder.actOnIfStmt(Builder* b, SrcLoc loc, Stmt* decl, Expr* cond, Stmt* then, Stmt* else_stmt) {
return (Stmt*)IfStmt.create(b.context, loc, decl, cond, then, else_stmt);
}

public fn Stmt* Builder.actOnWhileStmt(Builder* b, SrcLoc loc, Stmt* cond, Stmt* then) {
Expand Down
6 changes: 3 additions & 3 deletions generator/ast_visitor.c2
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,10 @@ fn void Visitor.handleStmt(Visitor* v, Stmt* s) {
break;
case If:
IfStmt* i = (IfStmt*)s;
v.handleStmt(i.getCond());
if (i.hasDecl()) v.handleStmt(i.getDecl());
if (i.getCond()) v.handleExpr(i.getCond());
v.handleStmt(i.getThen());
Stmt* e = i.getElse();
if (e) v.handleStmt(e);
if (i.hasElse()) v.handleStmt(i.getElse());
break;
case While:
WhileStmt* w = (WhileStmt*)s;
Expand Down
15 changes: 4 additions & 11 deletions generator/c/c_generator_stmt.c2
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,15 @@ fn void Generator.emitStmt(Generator* gen, string_buffer.Buf* out, Stmt* s, u32
break;
case If:
IfStmt* i = (IfStmt*)s;
Stmt* cond = i.getCond();
bool is_decl = cond.isDecl();
bool is_decl = i.hasDecl();
if (is_decl) {
out.add("{\n");
indent++;
gen.emitStmt(out, cond, indent, true);
gen.emitStmt(out, i.getDecl(), indent, true);
out.indent(indent);
out.add("if (");
DeclStmt* ds = (DeclStmt*)cond;
VarDecl* vd = ds.getDecl(0);
gen.emitName(out, vd.asDecl());
} else {
assert(cond.isExpr());
out.add("if (");
gen.emitExpr(out, (Expr*)cond);
}
out.add("if (");
gen.emitExpr(out, i.getCond());
out.add(") ");
Stmt* thenStmt = i.getThen();
gen.emitStmt(out, thenStmt, indent, true);
Expand Down
Loading
Loading