/ day8.js
const Lexer = require('./lexer');
const Parser = require('./parser');
const Compiler = require('./compiler');
const LPCVirtualMachine = require('./LPCVirtualMachine');
const GlobalHandleLedger = require('./GlobalHandleLedger');
const StringManager = require('./stringManager');
const CTX = require('./ctx');
const Scheduler = require('./scheduler');
/ 1. Source & Compile
const sourceCode = `
void main() {
write("Hello HAUKI!");
}
`;
const lexer = new Lexer(sourceCode);
const parser = new Parser(lexer.tokenize());
const compiler = new Compiler();
const blueprint = compiler.compile(parser.parseProgram());
/ 2. Booting the VM with StringManager
const ghl = new GlobalHandleLedger(100);
const sm = new StringManager(100, 1024 * 1024); // Shared GHL? Actually
StringManager creates its own in your code.
/ Note: Based on your stringManager.js, it instantiates its own GHL.
/ For a unified system, we should pass the same GHL instance to it, but for
this test we will use sm's GHL for the VM.
const vm = new LPCVirtualMachine(sm.ghl, sm);
/ Register the write syscall (ID 1)
vm.ivt[1] = function efun_write(arg1_tagged, engine, ctx) {
// arg1_tagged is now a Tagged Pointer! We decode it via StringManager.
const str = engine.stringManager.getString(arg1_tagged);
console.log(`[LPC Output] : ${str}`);
return 0; // Return success to R0
};
/ 3. Execution
vm.registerBlueprint('test_program', blueprint);
const oid = vm.clone_object('test_program');
const ctx = new CTX(blueprint.bytecode, blueprint.constantPool, oid);
const scheduler = new Scheduler(vm);
scheduler.add(ctx);
console.log("=== Booting VM ===");
scheduler.runOnce();
console.log("
=== Memory Diagnostics ===");
console.log('Active GHL Handles :', sm.ghl.getActiveCount());
console.log('DataArena Used Bytes:', sm.arena.used);
==
Erase is delete.
Interrupt is control-C (^C).
user@elli:~/GD$ node day8.js
=== Booting VM ===
[LPC Output] : Hello HAUKI!
=== Memory Diagnostics ===
Active GHL Handles : 1
DataArena Used Bytes: 12
user@elli:~/GD$
That 12-byte DataArena footprint perfectly matches the length of "Hello
HAUKI!". The engine now successfully translates string constants from abstract
logic into isolated, Ring-0 memory allocations on the fly!
To achieve full Turing completeness, we need to conquer State Mutation
(variables and math). We want to natively compile code like this:
C
int hp;
void take_damage(int amount) {
hp = hp - amount;
}
To do this, the Compiler must learn how to dynamically assign CPU registers as
it walks the tree, allowing it to hold values temporarily while it performs
math. We also need a new instruction to move values between registers so we
can safely respect our ABI calling conventions (which expects arguments in
R1).