From a5daebd8498d516793c44c668d05f2e406e5b079 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Wed, 18 Feb 2026 15:19:07 +0000 Subject: [PATCH] pr1.7 --- .../prometeu-bytecode/tests/roundtrip.rs | 127 ++++++++ files/TODOs.md | 301 +++++++++++++++++- 2 files changed, 413 insertions(+), 15 deletions(-) create mode 100644 crates/console/prometeu-bytecode/tests/roundtrip.rs diff --git a/crates/console/prometeu-bytecode/tests/roundtrip.rs b/crates/console/prometeu-bytecode/tests/roundtrip.rs new file mode 100644 index 00000000..231dae96 --- /dev/null +++ b/crates/console/prometeu-bytecode/tests/roundtrip.rs @@ -0,0 +1,127 @@ +use prometeu_bytecode::decode_next; +use prometeu_bytecode::isa::core::{CoreOpCode, CoreOpCodeSpecExt}; + +fn encode_instr(op: CoreOpCode, imm: Option<&[u8]>) -> Vec { + let mut out = Vec::new(); + let code = op as u16; + out.extend_from_slice(&code.to_le_bytes()); + let spec = op.spec(); + let need = spec.imm_bytes as usize; + match (need, imm) { + (0, None) => {} + (n, Some(bytes)) if bytes.len() == n => out.extend_from_slice(bytes), + (n, Some(bytes)) => panic!("immediate size mismatch for {:?}: expected {}, got {}", op, n, bytes.len()), + (n, None) => panic!("missing immediate for {:?}: need {} bytes", op, n), + } + out +} + +fn disasm(bytes: &[u8]) -> String { + // Minimal test-only disasm: NAME [operands] + let mut pc = 0usize; + let mut lines = Vec::new(); + while pc < bytes.len() { + match decode_next(pc, bytes) { + Ok(instr) => { + let name = instr.opcode.spec().name; + let mut line = String::from(name); + let imm_len = instr.opcode.spec().imm_bytes as usize; + if imm_len > 0 { + // Heuristic formatting based on known op immediates + line.push(' '); + let s = match instr.opcode { + CoreOpCode::Jmp | CoreOpCode::JmpIfFalse | CoreOpCode::JmpIfTrue => { + format!("{}", instr.imm_u32().unwrap()) + } + CoreOpCode::PushI64 => format!("{}", instr.imm_i64().unwrap()), + CoreOpCode::PushF64 => format!("{}", instr.imm_f64().unwrap()), + CoreOpCode::PushBool => format!("{}", instr.imm_u8().unwrap()), + CoreOpCode::PushI32 => format!("{}", instr.imm_i32().unwrap()), + CoreOpCode::PopN | CoreOpCode::PushConst | CoreOpCode::PushBounded => { + format!("{}", instr.imm_u32().unwrap()) + } + _ => format!("0x{}", hex::encode(instr.imm)), + }; + line.push_str(&s); + } + lines.push(line); + pc = instr.next_pc; + } + Err(_) => break, + } + } + lines.join("\n") +} + +#[test] +fn encode_decode_roundtrip_preserves_structure() { + // Program: PUSH_I32 42; PUSH_I32 100; ADD; PUSH_BOOL 1; JMP 12; NOP; HALT + let mut prog = Vec::new(); + prog.extend(encode_instr(CoreOpCode::PushI32, Some(&42i32.to_le_bytes()))); + prog.extend(encode_instr(CoreOpCode::PushI32, Some(&100i32.to_le_bytes()))); + prog.extend(encode_instr(CoreOpCode::Add, None)); + prog.extend(encode_instr(CoreOpCode::PushBool, Some(&[1u8]))); + // Jump to the HALT (compute absolute PC within this byte slice) + // Current pc after previous: 2+4 + 2+4 + 2 + 2+1 = 17 bytes + // Next we place: JMP (2+4), NOP (2), HALT (2) + // We want JMP target to land at the HALT's pc + let jmp_target: u32 = 17 + 2 + 4 + 2; // pc where HALT starts + prog.extend(encode_instr(CoreOpCode::Jmp, Some(&jmp_target.to_le_bytes()))); + prog.extend(encode_instr(CoreOpCode::Nop, None)); + prog.extend(encode_instr(CoreOpCode::Halt, None)); + + // Decode sequentially and check opcodes and immediates + let mut pc = 0usize; + let mut seen = Vec::new(); + while pc < prog.len() { + let instr = decode_next(pc, &prog).expect("decode ok"); + seen.push(instr); + pc = instr.next_pc; + } + + assert_eq!(seen.len(), 7); + assert_eq!(seen[0].opcode, CoreOpCode::PushI32); + assert_eq!(seen[0].imm_i32().unwrap(), 42); + assert_eq!(seen[1].opcode, CoreOpCode::PushI32); + assert_eq!(seen[1].imm_i32().unwrap(), 100); + assert_eq!(seen[2].opcode, CoreOpCode::Add); + assert_eq!(seen[3].opcode, CoreOpCode::PushBool); + assert_eq!(seen[3].imm_u8().unwrap(), 1); + assert_eq!(seen[4].opcode, CoreOpCode::Jmp); + assert_eq!(seen[4].imm_u32().unwrap(), jmp_target); + assert_eq!(seen[5].opcode, CoreOpCode::Nop); + assert_eq!(seen[6].opcode, CoreOpCode::Halt); +} + +#[test] +fn disasm_contains_expected_mnemonics_and_operands() { + // Tiny deterministic sample: NOP; PUSH_I32 -7; PUSH_BOOL 0; ADD; HALT + let mut prog = Vec::new(); + prog.extend(encode_instr(CoreOpCode::Nop, None)); + prog.extend(encode_instr(CoreOpCode::PushI32, Some(&(-7i32).to_le_bytes()))); + prog.extend(encode_instr(CoreOpCode::PushBool, Some(&[0u8]))); + prog.extend(encode_instr(CoreOpCode::Add, None)); + prog.extend(encode_instr(CoreOpCode::Halt, None)); + + let text = disasm(&prog); + + // Must contain stable opcode names and operand text + assert!(text.contains("NOP")); + assert!(text.contains("PUSH_I32 -7")); + assert!(text.contains("PUSH_BOOL 0")); + assert!(text.contains("ADD")); + assert!(text.contains("HALT")); +} + +// Minimal hex helper to avoid extra deps in tests +mod hex { + pub fn encode(bytes: &[u8]) -> String { + let mut s = String::with_capacity(bytes.len() * 2); + const HEX: &[u8; 16] = b"0123456789abcdef"; + for &b in bytes { + s.push(HEX[(b >> 4) as usize] as char); + s.push(HEX[(b & 0x0f) as usize] as char); + } + s + } +} diff --git a/files/TODOs.md b/files/TODOs.md index b7ad64a6..bbfe4c24 100644 --- a/files/TODOs.md +++ b/files/TODOs.md @@ -1,31 +1,302 @@ -# PR-1.7 — Bytecode Roundtrip Tests (Encode/Decode/Disasm Sanity) +# PR-2.1 — Remove ScopeFrame and HIP Runtime Structures ### Briefing -Before touching VM behavior, we want confidence that the bytecode toolchain is coherent after the ISA reset. +The new architecture removes HIP, borrow/mutate/peek semantics, and any gate-based lifetime tracking. The VM must no longer depend on `ScopeFrame` or related structures. ### Target -* Add roundtrip tests that validate: - - * Encode → decode preserves structure. - * Disasm prints stable, readable output. +* Remove `ScopeFrame` and any HIP-related runtime data structures. +* Ensure the VM compiles and runs without any scope/gate logic. ### Work items -* Add a small set of “known-good” bytecode samples built using the new minimal ISA. -* Implement tests: - - * Encode then decode equals original structure. - * Disasm output contains expected instruction names and operands. -* Keep samples intentionally tiny and deterministic. +* Delete `scope_frame.rs` and any modules dedicated to HIP or gate lifetimes. +* Remove fields in VM state that track scope frames, gates, or borrow state. +* Update the main VM execution loop to no longer push/pop scope frames. +* Remove any trap logic that references scope or gate violations. ### Acceptance checklist -* [ ] Roundtrip tests exist and pass. -* [ ] Samples do not depend on legacy semantics. +* [ ] `ScopeFrame` and related modules are fully removed. +* [ ] VM compiles without scope/gate concepts. +* [ ] No HIP-related symbols remain in the VM crate. * [ ] `cargo test` passes. ### Tests -* New unit tests for encode/decode/disasm roundtrip. +* Existing tests only. + +### Junie instructions + +**You MAY:** + +* Delete scope/gate-related modules and fields. +* Update code to remove references to them. + +**You MUST NOT:** + +* Introduce new lifetime or ownership systems. +* Replace scope frames with another architecture. +* Add compatibility layers. + +**If unclear:** + +* Ask for clarification instead of inventing new runtime concepts. + +--- + +# PR-2.2 — Simplify VM Execution Loop (Pure Stack Machine) + +### Briefing + +The VM should operate as a simple stack-based interpreter with a clear fetch–decode–execute loop, without hidden side channels or legacy behaviors. + +### Target + +* Normalize the VM main loop to a clean stack-machine structure. +* Remove any legacy control paths tied to HIP/RC behavior. + +### Work items + +* Refactor the main interpreter loop to: + + * Fetch instruction at PC. + * Decode opcode. + * Execute operation on stack/frames. +* Remove any conditional logic that depends on HIP/RC state. +* Ensure PC advancement is canonical and centralized. + +### Acceptance checklist + +* [ ] VM loop is structurally simple and readable. +* [ ] No HIP/RC conditionals remain. +* [ ] VM compiles and runs basic programs. +* [ ] `cargo test` passes. + +### Tests + +* Existing tests only. + +### Junie instructions + +**You MAY:** + +* Refactor the interpreter loop for clarity. +* Remove legacy conditionals. + +**You MUST NOT:** + +* Change opcode semantics. +* Introduce GC, closures, or coroutines here. +* Redesign the instruction set. + +**If unclear:** + +* Ask before modifying control flow assumptions. + +--- + +# PR-2.3 — Normalize Value Model (Stack vs Heap References) + +### Briefing + +The VM must use a clear value model: primitives and tuples on the stack, heap objects referenced through opaque handles. This PR prepares the VM for the GC-based heap. + +### Target + +* Define a single `Value` representation that distinguishes: + + * Immediate primitives. + * Heap references (opaque handles). +* Remove any gate-based or borrow-based value types. + +### Work items + +* Review the `Value` or equivalent enum/struct. +* Remove variants related to gates, borrows, or HIP. +* Ensure only the following categories remain: + + * Primitives (int, bool, etc.). + * Tuples or small aggregates. + * Heap reference handle (placeholder for future GC objects). +* Update stack operations accordingly. + +### Acceptance checklist + +* [ ] `Value` type has no HIP/gate-related variants. +* [ ] All stack operations compile with the new value model. +* [ ] No borrow/mutate semantics remain. +* [ ] `cargo test` passes. + +### Tests + +* Existing tests only. + +### Junie instructions + +**You MAY:** + +* Simplify the `Value` enum/struct. +* Remove legacy variants and adjust matches. + +**You MUST NOT:** + +* Design the GC handle layout. +* Introduce new object systems. +* Change instruction semantics beyond type cleanup. + +**If unclear:** + +* Ask what the intended value shape should be. + +--- + +# PR-2.4 — Consolidate Trap and Error Surface + +### Briefing + +With HIP removed, the runtime trap surface must be simplified and aligned with the new stack+heap model. + +### Target + +* Define a minimal, coherent set of runtime traps. +* Remove traps that only existed for HIP/RC semantics. + +### Work items + +* Audit the VM’s trap/error enums. +* Remove HIP/RC-related traps. +* Keep only traps that remain meaningful, such as: + + * Illegal instruction. + * Stack underflow/overflow. + * Invalid jump target. + * Out-of-bounds memory access. +* Ensure trap handling paths are consistent and deterministic. + +### Acceptance checklist + +* [ ] Trap enum contains only relevant traps. +* [ ] No HIP/RC trap names remain. +* [ ] VM compiles and tests pass. + +### Tests + +* Adjust any tests expecting removed trap codes. + +### Junie instructions + +**You MAY:** + +* Delete unused trap variants. +* Refactor match statements accordingly. + +**You MUST NOT:** + +* Add new trap categories without approval. +* Change the meaning of existing non-legacy traps. + +**If unclear:** + +* Ask before modifying trap semantics. + +--- + +# PR-2.5 — Prepare Call Frame Structure for Closures and Coroutines + +### Briefing + +Before introducing closures and coroutines, the call frame structure must be neutral and future-proof, without HIP-specific fields. + +### Target + +* Simplify the call frame to a minimal, generic structure. +* Remove any HIP/borrow/gate-related fields. + +### Work items + +* Review the call frame struct. +* Remove fields tied to scope frames, borrow state, or gates. +* Ensure the frame contains only: + + * Function identifier. + * Program counter. + * Base stack pointer. + * Locals or register area (if applicable). +* Keep the structure simple and extensible. + +### Acceptance checklist + +* [ ] Call frame struct has no HIP-related fields. +* [ ] VM call/return paths compile and work. +* [ ] `cargo test` passes. + +### Tests + +* Existing call-related tests must still pass. + +### Junie instructions + +**You MAY:** + +* Remove unused fields from the frame. +* Refactor call/return code to match the new structure. + +**You MUST NOT:** + +* Introduce closure or coroutine logic yet. +* Redesign the call stack architecture. + +**If unclear:** + +* Ask before changing frame responsibilities. + +--- + +# PR-2.6 — Remove Dead Runtime Modules and Symbols + +### Briefing + +After the VM reset, there will be leftover modules, helpers, or symbols that are no longer referenced. This PR performs a final cleanup pass. + +### Target + +* Remove dead or unreachable runtime code. +* Ensure the VM crate has a minimal, clean surface. + +### Work items + +* Use compiler warnings and search tools to find: + + * Unused modules. + * Unused structs/enums/functions. + * Legacy HIP/RC terminology. +* Remove dead code. +* Update module trees and public exports. + +### Acceptance checklist + +* [ ] No dead modules remain. +* [ ] No HIP/RC terminology found in the VM crate. +* [ ] `cargo test` passes. + +### Tests + +* Existing tests only. + +### Junie instructions + +**You MAY:** + +* Remove unused code and modules. +* Update `mod.rs` and exports. + +**You MUST NOT:** + +* Remove code that is still referenced. +* Replace deleted modules with new experimental ones. + +**If unclear:** + +* Ask before deleting anything that looks structurally important.