neo-decompiler 0.10.1

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 { scanSlotCounts, scanStaticSlotCount } from "./util.js";
import { buildDirectCallEffectsByOffset } from "./type-call-effects.js";
import { inferInSlice } from "./type-simulation.js";
import { joinType, manifestType } from "./type-support.js";

// Best-effort type recovery via a per-method stack simulation, mirroring the
// Rust core (src/decompiler/analysis/types/simulation.rs) so the `analysis.types`
// output matches across the two ports. Conservative: falls back to
// "unknown"/"any" rather than guessing.

export function inferTypes(instructions, methodGroups, manifest = null, methodTokens = []) {
  const staticCount = scanStaticSlotCount(instructions);
  const statics = Array.from({ length: staticCount }, () => "unknown");
  const directCallEffects = buildDirectCallEffectsByOffset(methodGroups, methodTokens);

  const methods = methodGroups.map((group) => {
    const [localCount, argCount] = scanSlotCounts(group.instructions);
    const locals = Array.from({ length: localCount }, () => "unknown");
    const argumentsTypes = Array.from({ length: argCount }, () => "unknown");

    const params = group.source?.parameters;
    if (params) {
      while (argumentsTypes.length < params.length) argumentsTypes.push("unknown");
      for (let index = 0; index < params.length; index += 1) {
        argumentsTypes[index] = joinType(argumentsTypes[index], manifestType(params[index].kind));
      }
    }

    inferInSlice(group.instructions, locals, argumentsTypes, statics, methodTokens, directCallEffects);

    return {
      method: { offset: group.start, name: group.name },
      arguments: argumentsTypes,
      locals,
    };
  });

  return { methods, statics };
}