Add VSMX bytecode interpreter

- VsmxInterpreter: stack machine executing all 74 VSMX opcodes
  (arithmetic, comparisons, bitwise, jumps, calls, arrays, objects).
- Object model: VsmxBaseObject/Undefined/Null/Boolean/Number/String/
  Object/Array/Function/Reference/LocalVarReference/Method/CallState/
  NativeObject, plus BaseNativeObject for future native objects.
- CLI 'rco' now runs the menu script headlessly and prints the 172
  resulting global variables (state, chapter/language config, focus).
- Validated against Batman Begins: script runs with zero unimplemented-
  opcode warnings and defines all menu functions (on_cancel, mm_on_push,
  trans_to_play, play_movie_beginning, ...).
This commit is contained in:
2026-09-15 22:39:36 -04:00
parent d3e3cbd017
commit d56f6f12b0
17 changed files with 1627 additions and 6 deletions
+19 -6
View File
@@ -11,6 +11,9 @@ import dev.quoije.umd.player.PlaybackEngine;
import dev.quoije.umd.playlist.Playlist;
import dev.quoije.umd.rco.RcoFile;
import dev.quoije.umd.rco.vsmx.Vsmx;
import dev.quoije.umd.rco.vsmx.interpreter.VsmxBaseObject;
import dev.quoije.umd.rco.vsmx.interpreter.VsmxInterpreter;
import dev.quoije.umd.rco.vsmx.interpreter.VsmxObject;
import dev.quoije.umd.sfo.Sfo;
import java.io.ByteArrayOutputStream;
@@ -414,13 +417,23 @@ public final class Main {
Vsmx vsmx = new Vsmx(vsmxData, "menu");
System.out.printf("vsmx: %d code groups, %d texts, %d props, %d names%n",
vsmx.codes().length, vsmx.texts().length, vsmx.properties().length, vsmx.names().length);
List<String> lines = vsmx.disassemble();
int shown = Math.min(lines.size(), 100);
for (int i = 0; i < shown; i++) {
System.out.println(" " + lines.get(i));
VsmxInterpreter interpreter = new VsmxInterpreter();
interpreter.setVsmx(vsmx);
VsmxObject globals = new VsmxObject(interpreter, null);
interpreter.run(globals);
System.out.printf("global variables (%d):%n", globals.getPropertyNames().size());
for (String varName : globals.getPropertyNames()) {
VsmxBaseObject value = globals.getPropertyValue(varName);
System.out.printf(" %s = %s%n", varName, value);
}
if (lines.size() > shown) {
System.out.printf(" ... (%d more lines)%n", lines.size() - shown);
if (!interpreter.getWarnings().isEmpty()) {
System.out.printf("warnings (%d):%n", interpreter.getWarnings().size());
for (String warning : interpreter.getWarnings()) {
System.out.println(" " + warning);
}
}
}
}