// ── Pure C code generation — no DOM dependencies ───────────────────────── // // These functions operate on generic block objects with the interface: // { generateOwnCode(): string, // generateCode(visited: Set): string, // wcNextFlow?: [{ toElement: block }], // nextFlow?: [{ toElement: block }] } // // Browser DOM blocks use wcNextFlow; test/mock blocks use nextFlow. // Decision blocks must expose isDecision = true. (function () { "use strict"; var CodeGen = {}; /** * Collects all blocks reachable from the given roots via nextFlow, * excluding the interior of decision blocks (they handle their own * branching). Returns a Set of block references. * @param {Array} roots * @param {function(block): boolean} [isDecision] * @returns {Set} */ CodeGen.branchDescendants = function (roots, isDecision) { isDecision = isDecision || function (b) { return b.isDecision; }; var d = new Set(), q = roots.slice(); for (var i = 0; i < q.length; i++) { var el = q[i]; if (d.has(el)) continue; d.add(el); if (isDecision(el)) continue; var flow = el.wcNextFlow || el.nextFlow || []; for (var j = 0; j < flow.length; j++) { var target = flow[j].toElement; if (target && !d.has(target)) q.push(target); } } return d; }; /** * 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. * @param {Array} roots * @param {Set} stop blocks to exclude (shared between branches) * @param {Set} visited blocks already emitted * @param {function(block): boolean} [isDecision] * @returns {string} */ CodeGen.emitBranch = function (roots, stop, visited, isDecision) { isDecision = isDecision || 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); } } } for (var i = 0; i < roots.length; i++) walk(roots[i]); return parts.join(""); }; /** * Generates the error-path branch for a proc call: computes shared blocks * between error and success paths, emits error-exclusive code inside `if`, * then success-exclusive and shared code after it (no else). * @param {string} ifHeader e.g. 'if (func() != 0)' or 'if ((r=f()) != 0)' * @param {Array} errTargets root blocks reachable from the error hook * @param {Array} okTargets root blocks reachable from the success hook * @param {function(block): boolean} [isDecision] * @returns {string} */ CodeGen.generateCallWithError = function ( ifHeader, errTargets, okTargets, isDecision ) { var errAll = CodeGen.branchDescendants(errTargets, isDecision); var okAll = CodeGen.branchDescendants(okTargets, isDecision); var shared = new Set(); errAll.forEach(function (b) { 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); var sharedCode = CodeGen.emitBranch( Array.from(shared), new Set(), new Set(), isDecision ); var out = ifHeader + " {\n" + errCode + "}\n"; if (okCode) out += okCode; if (sharedCode) out += sharedCode; return out; }; /** * Assembles a complete C source file from a program's entry block, * include directives, and variable declarations. * @param {Object} entryBlock the first block in the flow (e.g. START) * @param {string[]} includes #include directives * @param {string} declarations variable declarations (already indented) * @returns {string} */ CodeGen.generateCFile = function (entryBlock, includes, declarations) { var lines = ["// --- WiseCode\u00ae ---"]; for (var i = 0; i < includes.length; i++) lines.push(includes[i]); lines.push(""); lines.push("int main() {"); if (declarations) lines.push(declarations); var body = entryBlock.generateCode(new Set()); lines.push(body); lines.push("}"); lines.push("// --- END ---"); return lines.join("\n"); }; // ── Export ────────────────────────────────────────────────────────── if (typeof module !== "undefined" && module.exports) { module.exports = CodeGen; } if (typeof window !== "undefined") { window.CodeGen = CodeGen; } })();