feat: loop support via goto labels on each block
- Every block now emits a C label (its id) before its code - generateNextCode emits goto label; for back-edges (visited targets) - _emitBranch delegates to generateCode (not generateOwnCode), so labels are emitted consistently in both main and branch traversals - generateCallWithError threads a shared visited set across all three emitBranch calls, preventing duplicate label emission for shared blocks - emitBranch skips roots already visited by previous roots in the same branch (prevents spurious gotos from shared-block traversal)
This commit is contained in:
+17
-17
@@ -46,8 +46,9 @@
|
||||
|
||||
/**
|
||||
* Emits C code for a branch by walking from root blocks, stopping at
|
||||
* blocks in the stop set and at decision boundaries. Each visited block
|
||||
* is added to the visited set to prevent double-emission.
|
||||
* blocks in the stop set and at decision boundaries. When a loop
|
||||
* back-edge encounters an already-visited block, a `goto label;` is
|
||||
* emitted instead of silently dropping the edge.
|
||||
* @param {Array} roots
|
||||
* @param {Set} stop blocks to exclude (shared between branches)
|
||||
* @param {Set} visited blocks already emitted
|
||||
@@ -60,24 +61,20 @@
|
||||
function (b) {
|
||||
return b.isDecision;
|
||||
};
|
||||
var v = new Set(visited);
|
||||
var parts = [];
|
||||
|
||||
function walk(el) {
|
||||
if (v.has(el) || (stop && stop.has(el))) return;
|
||||
v.add(el);
|
||||
if (isDecision(el)) {
|
||||
parts.push(el.generateCode(v));
|
||||
} else {
|
||||
parts.push(el.generateOwnCode());
|
||||
var flow = el.wcNextFlow || el.nextFlow || [];
|
||||
for (var j = 0; j < flow.length; j++) {
|
||||
walk(flow[j].toElement);
|
||||
}
|
||||
if (stop && stop.has(el)) return;
|
||||
if (visited.has(el)) {
|
||||
parts.push("\n goto " + (el.id || "block") + ";\n");
|
||||
return;
|
||||
}
|
||||
parts.push(el.generateCode(visited));
|
||||
}
|
||||
|
||||
for (var i = 0; i < roots.length; i++) walk(roots[i]);
|
||||
for (var i = 0; i < roots.length; i++) {
|
||||
if (!visited.has(roots[i])) walk(roots[i]);
|
||||
}
|
||||
return parts.join("");
|
||||
};
|
||||
|
||||
@@ -104,12 +101,15 @@
|
||||
if (okAll.has(b)) shared.add(b);
|
||||
});
|
||||
|
||||
var errCode = CodeGen.emitBranch(errTargets, shared, new Set(), isDecision);
|
||||
var okCode = CodeGen.emitBranch(okTargets, shared, new Set(), isDecision);
|
||||
// Thread a shared visited set through all three emitBranch calls
|
||||
// so shared blocks are not re-emitted with duplicate labels.
|
||||
var visited = new Set();
|
||||
var errCode = CodeGen.emitBranch(errTargets, shared, visited, isDecision);
|
||||
var okCode = CodeGen.emitBranch(okTargets, shared, visited, isDecision);
|
||||
var sharedCode = CodeGen.emitBranch(
|
||||
Array.from(shared),
|
||||
new Set(),
|
||||
new Set(),
|
||||
visited,
|
||||
isDecision
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user