import {
containsIdentifier,
isTempIdent,
leadingWhitespace,
nextCodeLine,
parseAssignment,
replaceIdentifier,
TEMP_TOKEN_RE,
} from "./postprocess-shared.js";
export function stripStackComments(statements) {
for (let i = 0; i < statements.length; i++) {
const trimmed = statements[i].trim();
if (
trimmed.startsWith("// drop ") ||
trimmed.startsWith("// remove second") ||
trimmed.startsWith("// xdrop stack") ||
trimmed.startsWith("// rotate top") ||
trimmed.startsWith("// tuck top") ||
trimmed.startsWith("// reverse top") ||
trimmed === "// clear stack"
) {
statements[i] = "";
continue;
}
for (const suffix of [" // duplicate top of stack", " // copy second stack value"]) {
const pos = statements[i].indexOf(suffix);
if (pos >= 0) {
statements[i] = statements[i].slice(0, pos);
}
}
}
}
export function eliminateIdentityTemps(statements) {
const firstSeen = new Map(); const lastSeen = new Map(); for (let i = 0; i < statements.length; i++) {
const t = statements[i].trim();
if (t === "") continue;
const matches = t.match(TEMP_TOKEN_RE);
if (matches) {
for (const m of matches) {
if (!firstSeen.has(m)) firstSeen.set(m, i);
lastSeen.set(m, i);
}
}
}
let index = 0;
while (index < statements.length) {
const trimmed = statements[index].trim();
if (!trimmed.startsWith("let ")) {
index++;
continue;
}
const assign = parseAssignment(trimmed);
if (!assign || !isTempIdent(assign.lhs) || !isTempIdent(assign.rhs)) {
index++;
continue;
}
if (assign.lhs === assign.rhs) {
statements[index] = "";
index++;
continue;
}
const first = firstSeen.get(assign.lhs);
if (first !== undefined && first < index) {
index++;
continue;
}
for (let j = index + 1; j < statements.length; j++) {
if (containsIdentifier(statements[j], assign.lhs)) {
statements[j] = replaceIdentifier(statements[j], assign.lhs, assign.rhs);
}
}
statements[index] = "";
index++;
}
}
export function collapseTempIntoStore(statements) {
const tempLineCounts = new Map();
for (let i = 0; i < statements.length; i++) {
const t = statements[i].trim();
if (t === "") continue;
const matches = t.match(TEMP_TOKEN_RE);
if (matches) {
const seen = new Set(matches); for (const m of seen) {
tempLineCounts.set(m, (tempLineCounts.get(m) || 0) + 1);
}
}
}
let index = 0;
while (index + 1 < statements.length) {
const trimmed = statements[index].trim();
if (!trimmed.startsWith("let ")) {
index++;
continue;
}
const a1 = parseAssignment(trimmed);
if (!a1 || !isTempIdent(a1.lhs)) {
index++;
continue;
}
const next = nextCodeLine(statements, index + 1);
if (next < 0) {
index++;
continue;
}
const temp = a1.lhs;
const trimmedNext = statements[next].trim();
const a2 = parseAssignment(trimmedNext);
if (a2 && a2.rhs === temp) {
const usedLater = (tempLineCounts.get(temp) || 0) > 2;
if (!usedLater) {
const indent = leadingWhitespace(statements[next]);
const prefix = a2.hasLet ? "let " : "";
statements[next] = `${indent}${prefix}${a2.lhs} = ${a1.rhs};`;
statements[index] = "";
index = next + 1;
continue;
}
}
if (trimmedNext === `return ${temp};`) {
const usedLater = (tempLineCounts.get(temp) || 0) > 2;
if (!usedLater) {
const indent = leadingWhitespace(statements[next]);
statements[next] = `${indent}return ${a1.rhs};`;
statements[index] = "";
index = next + 1;
continue;
}
}
index++;
}
}
export function eliminateBareTempUses(statements) {
for (let index = 0; index + 1 < statements.length; index++) {
const assign = parseAssignment(statements[index]);
if (!assign || !isTempIdent(assign.lhs)) {
continue;
}
const next = nextCodeLine(statements, index + 1);
if (next < 0 || statements[next].trim() !== `${assign.lhs};`) {
continue;
}
statements[next] = "";
}
}