const PUSH_LIT_RE = /^PUSH(\d+|M1)$/u;
const PUSHINT_RE = /^PUSHINT(?:8|16|32|64)$/u;
export function popValue(valueStack) {
if (valueStack.length === 0) {
return null;
}
return valueStack.pop();
}
export function popMany(valueStack, count) {
for (let index = 0; index < count; index += 1) {
if (valueStack.length === 0) {
break;
}
valueStack.pop();
}
}
export function ensureArgValueArray(methodArgValues, methodOffset, size) {
const current = methodArgValues.get(methodOffset) ?? [];
while (current.length < size) {
current.push(null);
}
methodArgValues.set(methodOffset, current);
return current;
}
export function propagateCallArguments(
methodArgValues,
methodArgCountsByOffset,
targetOffset,
valueStack,
) {
const argCount = methodArgCountsByOffset.get(targetOffset) ?? 0;
if (argCount === 0) {
return;
}
const args = [];
const start = Math.max(0, valueStack.length - argCount);
for (let index = valueStack.length - 1; index >= start; index -= 1) {
args.push(valueStack[index] ?? null);
}
const values = ensureArgValueArray(methodArgValues, targetOffset, argCount);
for (let index = 0; index < argCount; index += 1) {
values[index] = mergeValues(values[index], args[index] ?? null);
}
popMany(valueStack, argCount);
}
export function pointerValue(target) {
return { kind: "pointer", target };
}
export function valueToPointer(value) {
return value?.kind === "pointer" ? value.target : null;
}
export function mergeValues(existing, next) {
if (next === null || next === undefined) {
return existing ?? null;
}
if (existing === undefined || existing === null) {
return next;
}
if (existing?.kind === "pointer" && next?.kind === "pointer") {
return existing.target === next.target ? existing : null;
}
return existing === next ? existing : null;
}
export function isImmediateInteger(mnemonic) {
return PUSH_LIT_RE.test(mnemonic) || PUSHINT_RE.test(mnemonic);
}
export function integerValue(mnemonic, instruction) {
const match = PUSH_LIT_RE.exec(mnemonic);
if (match) {
return { kind: "int", value: match[1] === "M1" ? -1 : Number(match[1]) };
}
const raw = instruction.operand?.value;
return { kind: "int", value: Number(raw) };
}