neo-decompiler 0.11.0

Neo N3 NEF decompiler: parse, disassemble, lift bytecode to high-level pseudocode and C# skeletons, with a CLI, JSON reports, and optional WebAssembly bindings.
Documentation
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;
}