import {
braceDelta,
containsIdentifier,
extractWhileCondition,
findBlockEnd,
isBlank,
nextCodeLine,
parseAssignment,
parseForParts,
prevCodeLine,
replaceIdentifier,
} from "./postprocess-shared.js";
export function rewriteForLoops(statements) {
let index = 0;
while (index < statements.length) {
const condition = extractWhileCondition(statements[index]);
if (condition === null) {
index++;
continue;
}
const end = findBlockEnd(statements, index);
if (end < 0) {
index++;
continue;
}
const initIdx = findInitializerIndex(statements, index);
if (initIdx < 0) {
index++;
continue;
}
const initAssign = parseAssignment(statements[initIdx]);
if (!initAssign) {
index++;
continue;
}
const increment = findIncrementAssignment(statements, index, end, initAssign.lhs);
if (!increment) {
index++;
continue;
}
statements[index] = `for (${initAssign.full}; ${condition}; ${increment.expr}) {`;
statements[initIdx] = "";
statements[increment.incrementIdx] = "";
if (increment.tempIdx !== null) {
statements[increment.tempIdx] = "";
}
index++;
}
}
function findInitializerIndex(statements, start) {
let index = start;
while (index > 0) {
index--;
const line = statements[index].trim();
if (isBlank(line)) continue;
if (line === "}" || line.endsWith("{")) break;
if (line.includes("=") && line.endsWith(";")) {
const a = parseAssignment(line);
if (a && (a.lhs.startsWith("loc") || a.lhs.startsWith("arg") || a.lhs.startsWith("static"))) {
return index;
}
}
}
return -1;
}
function findIncrementAssignment(statements, start, end, varName) {
let index = end;
while (index > start) {
index--;
const line = statements[index].trim();
if (isBlank(line) || line === "}") continue;
const assign = parseAssignment(line);
if (!assign || assign.lhs !== varName) return null;
if (assign.rhs.startsWith(varName)) {
return { incrementIdx: index, tempIdx: null, expr: assign.full };
}
const prevIdx = prevCodeLine(statements, index);
if (prevIdx < 0) return null;
const prevAssign = parseAssignment(statements[prevIdx]);
if (!prevAssign) return null;
if (prevAssign.lhs === assign.rhs) {
return {
incrementIdx: index,
tempIdx: prevIdx,
expr: `${varName} = ${prevAssign.rhs}`,
};
}
if (containsIdentifier(assign.rhs, prevAssign.lhs)) {
const replaced = replaceIdentifier(assign.rhs, prevAssign.lhs, prevAssign.rhs);
return {
incrementIdx: index,
tempIdx: prevIdx,
expr: `${varName} = ${replaced}`,
};
}
return null;
}
return null;
}
function inlinedCondition(condition, assign) {
if (assign.lhs === condition) {
return assign.rhs;
}
if (condition.startsWith("!") && condition.slice(1).trim() === assign.lhs) {
return `!(${assign.rhs})`;
}
return null;
}
export function inlineConditionTemps(statements) {
let index = 0;
while (index < statements.length) {
const trimmed = statements[index].trim();
let cond = null;
let forParts = null;
let kind = null;
if (trimmed.endsWith(" {")) {
if (trimmed.startsWith("while ")) {
cond = trimmed.slice(6, -2).trim();
kind = "while";
} else if (trimmed.startsWith("for (")) {
let inner = trimmed.slice(5, -2).trim();
if (inner.endsWith(")")) inner = inner.slice(0, -1).trim();
const parts = inner.split(";");
if (parts.length === 3) {
forParts = {
init: parts[0].trim(),
condition: parts[1].trim(),
increment: parts[2].trim(),
};
kind = "for";
}
} else if (trimmed.startsWith("if ")) {
cond = trimmed.slice(3, -2).trim();
kind = "if";
}
}
if (kind !== null) {
const idx = prevCodeLine(statements, index);
if (idx >= 0) {
const assign = parseAssignment(statements[idx]);
if (assign && shouldInlineCondition(assign.rhs)) {
if (kind === "while") {
const inlined = inlinedCondition(cond, assign);
if (inlined !== null) {
statements[index] = `while ${inlined} {`;
statements[idx] = "";
}
} else if (kind === "for") {
const inlined = inlinedCondition(forParts.condition, assign);
if (inlined !== null) {
statements[index] = `for (${forParts.init}; ${inlined}; ${forParts.increment}) {`;
statements[idx] = "";
}
} else if (kind === "if") {
const inlined = inlinedCondition(cond, assign);
if (inlined !== null) {
statements[index] = `if ${inlined} {`;
statements[idx] = "";
}
}
}
}
}
index++;
}
}
function shouldInlineCondition(rhs) {
if (rhs === "true" || rhs === "false") return true;
if (rhs.includes(" ")) return true;
return /[<>!=+\-*\/&|]/.test(rhs);
}
export function inlineForIncrementTemps(statements) {
let index = 0;
while (index < statements.length) {
const forParts = parseForParts(statements[index]);
if (forParts === null) {
index++;
continue;
}
let depth = 1;
let cursor = index + 1;
while (cursor < statements.length && depth > 0) {
depth += braceDelta(statements[cursor]);
if (depth <= 0) break;
const line = statements[cursor].trim();
if (line.startsWith("let ")) {
const assign = parseAssignment(line);
if (assign && containsIdentifier(forParts.increment, assign.lhs)) {
const usedElsewhere = statements.some(
(stmt, i) => i !== cursor && i !== index && containsIdentifier(stmt, assign.lhs),
);
if (usedElsewhere || assign.rhs.includes("(")) {
cursor++;
continue;
}
const replaced = replaceIdentifier(forParts.increment, assign.lhs, assign.rhs);
statements[index] = `for (${forParts.init}; ${forParts.condition}; ${replaced}) {`;
statements[cursor] = "";
break;
}
}
cursor++;
}
index++;
}
}