feat: defer statement support in both compilers
- Add statement for function-level deferred execution - Deferred expressions run in LIFO order on function exit (return or implicit) - Bootstrap: desugar defers in hir_lower.nim (inject before return + end of func) - Selfhost: emit defers in c_backend.bux via CEmitter defer stack - Both: add tkDefer token, skDefer AST node, hDefer HIR node - Parser, lexer, sema, token files updated in both bootstrap/ and src/
This commit is contained in:
@@ -157,6 +157,7 @@ const skReturn: int = 8;
|
||||
const skBreak: int = 9;
|
||||
const skContinue: int = 10;
|
||||
const skDecl: int = 11;
|
||||
const skDefer: int = 12;
|
||||
|
||||
struct ElseIf {
|
||||
line: uint32;
|
||||
|
||||
+74
-1
@@ -66,6 +66,15 @@ struct CEmitter {
|
||||
sb: StringBuilder,
|
||||
indent: int,
|
||||
mod: *HirModule,
|
||||
deferCount: int,
|
||||
defer0: *HirNode,
|
||||
defer1: *HirNode,
|
||||
defer2: *HirNode,
|
||||
defer3: *HirNode,
|
||||
defer4: *HirNode,
|
||||
defer5: *HirNode,
|
||||
defer6: *HirNode,
|
||||
defer7: *HirNode,
|
||||
}
|
||||
|
||||
func CBE_Init() -> CEmitter {
|
||||
@@ -73,6 +82,49 @@ func CBE_Init() -> CEmitter {
|
||||
return CEmitter { sb: sb, indent: 0, mod: null as *HirModule };
|
||||
}
|
||||
|
||||
func CBE_PushDefer(cbe: *CEmitter, node: *HirNode) {
|
||||
if cbe.deferCount == 0 { cbe.defer0 = node; }
|
||||
if cbe.deferCount == 1 { cbe.defer1 = node; }
|
||||
if cbe.deferCount == 2 { cbe.defer2 = node; }
|
||||
if cbe.deferCount == 3 { cbe.defer3 = node; }
|
||||
if cbe.deferCount == 4 { cbe.defer4 = node; }
|
||||
if cbe.deferCount == 5 { cbe.defer5 = node; }
|
||||
if cbe.deferCount == 6 { cbe.defer6 = node; }
|
||||
if cbe.deferCount == 7 { cbe.defer7 = node; }
|
||||
cbe.deferCount = cbe.deferCount + 1;
|
||||
}
|
||||
|
||||
func CBE_EmitDefers(cbe: *CEmitter) -> int {
|
||||
if cbe.deferCount == 0 { return 0; }
|
||||
var i: int = cbe.deferCount - 1;
|
||||
while i >= 0 {
|
||||
StringBuilder_Append(&cbe.sb, "\n");
|
||||
var sp: int = 0;
|
||||
while sp < cbe.indent {
|
||||
StringBuilder_Append(&cbe.sb, " ");
|
||||
sp = sp + 1;
|
||||
}
|
||||
var dn: *HirNode = null as *HirNode;
|
||||
if i == 0 { dn = cbe.defer0; }
|
||||
if i == 1 { dn = cbe.defer1; }
|
||||
if i == 2 { dn = cbe.defer2; }
|
||||
if i == 3 { dn = cbe.defer3; }
|
||||
if i == 4 { dn = cbe.defer4; }
|
||||
if i == 5 { dn = cbe.defer5; }
|
||||
if i == 6 { dn = cbe.defer6; }
|
||||
if i == 7 { dn = cbe.defer7; }
|
||||
CBE_EmitExpr(cbe, dn);
|
||||
StringBuilder_Append(&cbe.sb, ";");
|
||||
i = i - 1;
|
||||
}
|
||||
cbe.deferCount = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
func CBE_ClearDefers(cbe: *CEmitter) {
|
||||
cbe.deferCount = 0;
|
||||
}
|
||||
|
||||
func CBE_Emit(cbe: *CEmitter, text: String) {
|
||||
var i: int = 0;
|
||||
while i < cbe.indent {
|
||||
@@ -231,8 +283,23 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Defer
|
||||
if kind == hDefer {
|
||||
CBE_PushDefer(cbe, node.child1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Return
|
||||
if kind == hReturn {
|
||||
let hadDefers: int = CBE_EmitDefers(cbe);
|
||||
if hadDefers != 0 {
|
||||
StringBuilder_Append(&cbe.sb, "\n");
|
||||
var sp: int = 0;
|
||||
while sp < cbe.indent {
|
||||
StringBuilder_Append(&cbe.sb, " ");
|
||||
sp = sp + 1;
|
||||
}
|
||||
}
|
||||
StringBuilder_Append(&cbe.sb, "return");
|
||||
if node.child1 != null as *HirNode {
|
||||
StringBuilder_Append(&cbe.sb, " ");
|
||||
@@ -500,6 +567,11 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
|
||||
if kind == hBlock {
|
||||
var child: *HirNode = node.child1;
|
||||
while child != null as *HirNode {
|
||||
if child.kind == hDefer {
|
||||
CBE_EmitExpr(cbe, child);
|
||||
child = child.child3;
|
||||
continue;
|
||||
}
|
||||
// Indent
|
||||
var sp: int = 0;
|
||||
while sp < cbe.indent {
|
||||
@@ -971,6 +1043,7 @@ func CBackend_Generate(mod: *HirModule) -> String {
|
||||
var hasReturn: bool = false;
|
||||
cbe.indent = 1;
|
||||
CBE_EmitExpr(cbe, body);
|
||||
CBE_EmitDefers(cbe);
|
||||
cbe.indent = 0;
|
||||
// Check if body has a return statement
|
||||
var stmt: *HirNode = body.child1;
|
||||
@@ -982,7 +1055,7 @@ func CBackend_Generate(mod: *HirModule) -> String {
|
||||
if String_Eq(mod.funcs[i].retTypeName, "int") && !hasReturn {
|
||||
StringBuilder_Append(&cbe.sb, " return 0;\n");
|
||||
}
|
||||
StringBuilder_Append(&cbe.sb, "}\n\n");
|
||||
StringBuilder_Append(&cbe.sb, "\n}\n\n");
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ const hTupleInit: int = 27;
|
||||
const hMatch: int = 28;
|
||||
const hSpawn: int = 29;
|
||||
const hAwait: int = 30;
|
||||
const hDefer: int = 31;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HirArgList — linked list for call arguments beyond 2
|
||||
|
||||
@@ -482,6 +482,15 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
||||
return n;
|
||||
}
|
||||
|
||||
// Defer
|
||||
if kind == skDefer {
|
||||
n.kind = hDefer;
|
||||
if stmt.child1 != null as *Expr {
|
||||
n.child1 = Lcx_LowerExpr(ctx, stmt.child1);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
@@ -301,6 +301,7 @@ func lexKeywordKind(text: String) -> int {
|
||||
if String_Eq(text, "super") { return tkSuper; }
|
||||
if String_Eq(text, "sizeof") { return tkSizeOf; }
|
||||
if String_Eq(text, "discard") { return tkDiscard; }
|
||||
if String_Eq(text, "defer") { return tkDefer; }
|
||||
if String_Eq(text, "async") { return tkAsync; }
|
||||
if String_Eq(text, "await") { return tkAwait; }
|
||||
if String_Eq(text, "spawn") { return tkSpawn; }
|
||||
|
||||
@@ -704,6 +704,19 @@ func parserParseStmt(p: *Parser) -> *Stmt {
|
||||
return s;
|
||||
}
|
||||
|
||||
// defer expr
|
||||
if kind == tkDefer {
|
||||
discard parserAdvance(p);
|
||||
let val: *Expr = parserParseExpr(p);
|
||||
parserMatch(p, tkSemicolon);
|
||||
let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt;
|
||||
s.kind = skDefer;
|
||||
s.line = line;
|
||||
s.column = col;
|
||||
s.child1 = val;
|
||||
return s;
|
||||
}
|
||||
|
||||
// if
|
||||
if kind == tkIf {
|
||||
discard parserAdvance(p);
|
||||
|
||||
@@ -138,6 +138,7 @@ const tkAsync: int = 102;
|
||||
const tkAwait: int = 103;
|
||||
const tkSpawn: int = 104;
|
||||
const tkDiscard: int = 105;
|
||||
const tkDefer: int = 106;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Token struct
|
||||
|
||||
Reference in New Issue
Block a user