Extract VM value handler
This commit is contained in:
@@ -211,6 +211,9 @@ ADV coroutine handler save/yield/resume, and bounded labeled-yield dispatch; pro
|
||||
lifecycle are routed separately. `engine/Age.Engine/Vm/VirtualMachine.ScriptLifecycle.cs` owns process/frame/root
|
||||
exit, ordinary cross-script calls, mounted append autoruns, and preloaded script-slot load/call dispatch; frame
|
||||
execution, script-provider access, and shared lifecycle state remain in `VirtualMachine.cs`.
|
||||
`engine/Age.Engine/Vm/VirtualMachine.Values.cs` owns integer arithmetic, bitwise and comparison operations,
|
||||
string comparison/concatenation/conversion/move, native byte-length and CP932 operations, and the host-backed
|
||||
fullwidth string editor; shared operand storage, addressing, and native-string encoding remain in the coordinator.
|
||||
|
||||
The disposable `build/page-map-<SCENE>.jsonl` files are produced by editor/development Godot runs and map
|
||||
runtime ADV page ordinals to their authoritative script offsets for `tools/locate_page.py`. Packaged exports
|
||||
|
||||
@@ -721,6 +721,13 @@ do not mix mechanical moves with semantic changes.
|
||||
provider access, call-depth enforcement, and shared lifecycle state remain in the coordinator. Runtime
|
||||
validation remains green.
|
||||
|
||||
The sixteenth bounded `VirtualMachine.Step` extraction moved integer arithmetic, bitwise and comparison
|
||||
operations, string comparison/concatenation/conversion/move, native byte-length and CP932 operations, and
|
||||
the host-backed fullwidth string editor into `engine/Age.Engine/Vm/VirtualMachine.Values.cs`. The top-level
|
||||
dispatcher retains all labels at their existing positions and routes the two groups around the timing query
|
||||
through guarded `StepValue`; shared operand storage, addressing, and native-string encoding remain in the
|
||||
coordinator. Runtime validation remains green.
|
||||
|
||||
**Gate:** no externally visible behavior or command changes; generated artifacts are byte-identical where
|
||||
deterministic, and the corresponding engine, Python, Godot, and corpus validations remain green after
|
||||
each domain move.
|
||||
@@ -1094,8 +1101,8 @@ Continue step 2 of the **codebase consolidation** maintenance slice: behavior-ne
|
||||
by the tracked launcher and layered validation driver. With the planned `Main`, `GodotAdvHost`, and `GfxState`
|
||||
domains isolated and the audio, movie, surface/texture, retained-object, animation, presentation, ADV-text,
|
||||
text-history, ADV-service, input, timing, persistence, and memory/collection `VirtualMachine.Step` families routed
|
||||
through domain handlers, with control-flow/coroutine and process/root-exit/cross-script lifecycle dispatch now
|
||||
isolated as well, extract scalar arithmetic and string-value dispatch next without replacing the proven
|
||||
dispatcher or changing public types, commands, and generated output.
|
||||
through domain handlers, with control-flow/coroutine, process/root-exit/cross-script lifecycle, and scalar and
|
||||
string-value dispatch now isolated as well, extract diagnostic accumulation and prompt dispatch next without
|
||||
replacing the proven dispatcher or changing public types, commands, and generated output.
|
||||
Concrete playthrough blockers may still preempt this bounded maintenance work; the consolidation effort does
|
||||
not replace Phase B gameplay validation or the open cross-platform gates.
|
||||
|
||||
82
engine/Age.Engine/Vm/VirtualMachine.Values.cs
Normal file
82
engine/Age.Engine/Vm/VirtualMachine.Values.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using Age.Engine.Hosting;
|
||||
using Age.Engine.Model;
|
||||
using Age.Engine.Sys4;
|
||||
|
||||
namespace Age.Engine.Vm;
|
||||
|
||||
public sealed partial class VirtualMachine
|
||||
{
|
||||
private int StepValue(string label, IReadOnlyList<Operand> a, int pc)
|
||||
{
|
||||
switch (label)
|
||||
{
|
||||
case "add": Write(a[0], Read(a[1]) + Read(a[2])); return pc + 1;
|
||||
case "sub": Write(a[0], Read(a[1]) - Read(a[2])); return pc + 1;
|
||||
case "mul": Write(a[0], Read(a[1]) * Read(a[2])); return pc + 1;
|
||||
case "div": Write(a[0], PyDiv(Read(a[1]), Read(a[2]))); return pc + 1;
|
||||
case "mod": Write(a[0], PyMod(Read(a[1]), Read(a[2]))); return pc + 1;
|
||||
case "and": Write(a[0], Read(a[1]) & Read(a[2])); return pc + 1;
|
||||
case "or": Write(a[0], Read(a[1]) | Read(a[2])); return pc + 1;
|
||||
case "sar": Write(a[0], Read(a[1]) >> (int)(Read(a[2]) & 31)); return pc + 1;
|
||||
case "shl": Write(a[0], Read(a[1]) << (int)(Read(a[2]) & 31)); return pc + 1;
|
||||
case "eq": Write(a[0], Read(a[1]) == Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "ne": Write(a[0], Read(a[1]) != Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "string-equals":
|
||||
Write(a[0], string.Equals(ReadStr(a[1]), ReadStr(a[2]), StringComparison.Ordinal) ? 1 : 0);
|
||||
return pc + 1;
|
||||
case "string-not-equals":
|
||||
Write(a[0], string.Equals(ReadStr(a[1]), ReadStr(a[2]), StringComparison.Ordinal) ? 0 : 1);
|
||||
return pc + 1;
|
||||
case "concat":
|
||||
{
|
||||
string left = ReadStr(a[1]);
|
||||
string right = ReadStr(a[2]);
|
||||
WriteStr(a[0], left + right);
|
||||
return pc + 1;
|
||||
}
|
||||
case "toString":
|
||||
WriteStr(a[0], unchecked((int)Read(a[1])).ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
return pc + 1;
|
||||
case "absolute-value":
|
||||
{
|
||||
int value = unchecked((int)Read(a[1]));
|
||||
int sign = value >> 31;
|
||||
Write(a[0], unchecked((value ^ sign) - sign));
|
||||
return pc + 1;
|
||||
}
|
||||
case "lt": Write(a[0], Read(a[1]) < Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "lte": Write(a[0], Read(a[1]) <= Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "gr": Write(a[0], Read(a[1]) > Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "gre": Write(a[0], Read(a[1]) >= Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "mov":
|
||||
case "set-string":
|
||||
if (IsStr(a[0]) || IsStr(a[1])) WriteStr(a[0], ReadStr(a[1]));
|
||||
else Write(a[0], Read(a[1]));
|
||||
return pc + 1;
|
||||
case "halve-strlen": // 0x1a6: strlen(native encoded bytes) >> 1
|
||||
Write(a[0], NativeStringByteLength(ReadStr(a[1])) >> 1);
|
||||
return pc + 1;
|
||||
case "edit-fullwidth-string-dialog": // 0x144: blocking AGERc command-10 editor
|
||||
{
|
||||
string current = ReadStr(a[0]);
|
||||
string initial = ReadStr(a[1]);
|
||||
FullwidthTextEditResult result =
|
||||
_host.EditFullwidthString(new(current, initial));
|
||||
if (result.Accepted) WriteStr(a[0], result.Text);
|
||||
return pc + 1;
|
||||
}
|
||||
case "cp932-character-length": // 0x2c6: Japanese-locale _mbstrlen
|
||||
Write(a[0], Cp932Text.CharacterLength(ReadStr(a[1]), _nativeStringEncoding));
|
||||
return pc + 1;
|
||||
case "cp932-substring": // 0x2c8: multibyte-character interval [start,start+count)
|
||||
WriteStr(a[0], Cp932Text.Substring(
|
||||
ReadStr(a[1]),
|
||||
unchecked((int)Read(a[2])),
|
||||
unchecked((int)Read(a[3])),
|
||||
_nativeStringEncoding));
|
||||
return pc + 1;
|
||||
default:
|
||||
throw new InvalidOperationException($"Non-value opcode routed to value handler: {label}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1212,73 +1212,36 @@ public sealed partial class VirtualMachine
|
||||
case "set-surface-persistence-flags": // 0x258 (slot)(flags): bit 0 = numbered-load reload
|
||||
Gfx.SetSurfaceReloadOnRestore(unchecked((int)Read(a[0])), (Read(a[1]) & 1) != 0);
|
||||
return pc + 1;
|
||||
case "add": Write(a[0], Read(a[1]) + Read(a[2])); return pc + 1;
|
||||
case "sub": Write(a[0], Read(a[1]) - Read(a[2])); return pc + 1;
|
||||
case "mul": Write(a[0], Read(a[1]) * Read(a[2])); return pc + 1;
|
||||
case "div": Write(a[0], PyDiv(Read(a[1]), Read(a[2]))); return pc + 1;
|
||||
case "mod": Write(a[0], PyMod(Read(a[1]), Read(a[2]))); return pc + 1;
|
||||
case "and": Write(a[0], Read(a[1]) & Read(a[2])); return pc + 1;
|
||||
case "or": Write(a[0], Read(a[1]) | Read(a[2])); return pc + 1;
|
||||
case "sar": Write(a[0], Read(a[1]) >> (int)(Read(a[2]) & 31)); return pc + 1;
|
||||
case "shl": Write(a[0], Read(a[1]) << (int)(Read(a[2]) & 31)); return pc + 1;
|
||||
case "eq": Write(a[0], Read(a[1]) == Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "ne": Write(a[0], Read(a[1]) != Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "add":
|
||||
case "sub":
|
||||
case "mul":
|
||||
case "div":
|
||||
case "mod":
|
||||
case "and":
|
||||
case "or":
|
||||
case "sar":
|
||||
case "shl":
|
||||
case "eq":
|
||||
case "ne":
|
||||
case "string-equals":
|
||||
Write(a[0], string.Equals(ReadStr(a[1]), ReadStr(a[2]), StringComparison.Ordinal) ? 1 : 0);
|
||||
return pc + 1;
|
||||
case "string-not-equals":
|
||||
Write(a[0], string.Equals(ReadStr(a[1]), ReadStr(a[2]), StringComparison.Ordinal) ? 0 : 1);
|
||||
return pc + 1;
|
||||
case "concat":
|
||||
{
|
||||
string left = ReadStr(a[1]);
|
||||
string right = ReadStr(a[2]);
|
||||
WriteStr(a[0], left + right);
|
||||
return pc + 1;
|
||||
}
|
||||
case "toString":
|
||||
WriteStr(a[0], unchecked((int)Read(a[1])).ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
return pc + 1;
|
||||
case "absolute-value":
|
||||
{
|
||||
int value = unchecked((int)Read(a[1]));
|
||||
int sign = value >> 31;
|
||||
Write(a[0], unchecked((value ^ sign) - sign));
|
||||
return pc + 1;
|
||||
}
|
||||
return StepValue(label, a, pc);
|
||||
case "get-monotonic-time-ms":
|
||||
return StepTiming(label, a, pc);
|
||||
case "lt": Write(a[0], Read(a[1]) < Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "lte": Write(a[0], Read(a[1]) <= Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "gr": Write(a[0], Read(a[1]) > Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "gre": Write(a[0], Read(a[1]) >= Read(a[2]) ? 1 : 0); return pc + 1;
|
||||
case "lt":
|
||||
case "lte":
|
||||
case "gr":
|
||||
case "gre":
|
||||
case "mov":
|
||||
case "set-string":
|
||||
if (IsStr(a[0]) || IsStr(a[1])) WriteStr(a[0], ReadStr(a[1]));
|
||||
else Write(a[0], Read(a[1]));
|
||||
return pc + 1;
|
||||
case "halve-strlen": // 0x1a6: strlen(native encoded bytes) >> 1
|
||||
Write(a[0], NativeStringByteLength(ReadStr(a[1])) >> 1);
|
||||
return pc + 1;
|
||||
case "edit-fullwidth-string-dialog": // 0x144: blocking AGERc command-10 editor
|
||||
{
|
||||
string current = ReadStr(a[0]);
|
||||
string initial = ReadStr(a[1]);
|
||||
FullwidthTextEditResult result =
|
||||
_host.EditFullwidthString(new(current, initial));
|
||||
if (result.Accepted) WriteStr(a[0], result.Text);
|
||||
return pc + 1;
|
||||
}
|
||||
case "cp932-character-length": // 0x2c6: Japanese-locale _mbstrlen
|
||||
Write(a[0], Cp932Text.CharacterLength(ReadStr(a[1]), _nativeStringEncoding));
|
||||
return pc + 1;
|
||||
case "cp932-substring": // 0x2c8: multibyte-character interval [start,start+count)
|
||||
WriteStr(a[0], Cp932Text.Substring(
|
||||
ReadStr(a[1]),
|
||||
unchecked((int)Read(a[2])),
|
||||
unchecked((int)Read(a[3])),
|
||||
_nativeStringEncoding));
|
||||
return pc + 1;
|
||||
return StepValue(label, a, pc);
|
||||
case "u00425790": // upstream ABI label
|
||||
case "append-diagnostic-value": // 0x1b2: generic operand text -> EngineCtx accumulator
|
||||
_diagnosticOutput.Append(FormatDiagnosticOperand(a[0]));
|
||||
|
||||
Reference in New Issue
Block a user