import {
convertTargetName,
stripOuterParens,
wrapExpression,
} from "./high-level-stack-shared.js";
import { warnStackUnderflow } from "./high-level-state.js";
export function tryUnaryExpression(state, instruction) {
const mnemonic = instruction.opcode.mnemonic;
switch (mnemonic) {
case "SQRT": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`sqrt(${value})`);
return true;
}
case "NOT": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`!${wrapExpression(value)}`);
return true;
}
case "INC": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`${wrapExpression(value)} + 1`);
return true;
}
case "DEC": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`${wrapExpression(value)} - 1`);
return true;
}
case "SUBSTR": {
if (!ensureStack(state, instruction, 3)) return true;
const count = stripOuterParens(state.stack.pop());
const index = stripOuterParens(state.stack.pop());
const value = stripOuterParens(state.stack.pop());
state.stack.push(`substr(${value}, ${index}, ${count})`);
return true;
}
case "CONVERT": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
const targetName = convertTargetName(instruction.operand);
state.stack.push(
targetName !== null ? `convert_to_${targetName}(${value})` : `convert(${value})`,
);
return true;
}
case "NEWBUFFER": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
const temp = `t${state.nextTempId}`;
state.nextTempId += 1;
state.statements.push(`let ${temp} = new_buffer(${value});`);
state.stack.push(temp);
return true;
}
case "NEWARRAY": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
const temp = `t${state.nextTempId}`;
state.nextTempId += 1;
state.statements.push(`let ${temp} = new_array(${value});`);
state.stack.push(temp);
return true;
}
case "NEGATE": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`-${wrapExpression(value)}`);
return true;
}
case "ABS": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`abs(${value})`);
return true;
}
case "SIGN": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`sign(${value})`);
return true;
}
case "INVERT": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`~${wrapExpression(value)}`);
return true;
}
case "ISNULL": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`is_null(${value})`);
return true;
}
case "NZ": {
if (!ensureStack(state, instruction, 1)) return true;
const value = stripOuterParens(state.stack.pop());
state.stack.push(`${wrapExpression(value)} != 0`);
return true;
}
default:
return false;
}
}
function ensureStack(state, instruction, needed) {
if (state.stack.length >= needed) return true;
warnStackUnderflow(state, instruction, needed);
return false;
}