diff --git a/crates/prometeu-bytecode/src/disasm.rs b/crates/prometeu-bytecode/src/disasm.rs index 57210343..bda3c592 100644 --- a/crates/prometeu-bytecode/src/disasm.rs +++ b/crates/prometeu-bytecode/src/disasm.rs @@ -41,7 +41,7 @@ pub fn disasm(rom: &[u8]) -> Result, String> { match opcode { OpCode::PushConst | OpCode::PushI32 | OpCode::Jmp | OpCode::JmpIfFalse | OpCode::JmpIfTrue | OpCode::GetGlobal | OpCode::SetGlobal | OpCode::GetLocal | OpCode::SetLocal - | OpCode::PopN | OpCode::Syscall => { + | OpCode::PopN | OpCode::Syscall | OpCode::LoadRef | OpCode::StoreRef => { let v = read_u32_le(&mut cursor).map_err(|e| e.to_string())?; operands.push(DisasmOperand::U32(v)); } diff --git a/crates/prometeu-bytecode/src/opcode.rs b/crates/prometeu-bytecode/src/opcode.rs index be711438..ade51676 100644 --- a/crates/prometeu-bytecode/src/opcode.rs +++ b/crates/prometeu-bytecode/src/opcode.rs @@ -54,7 +54,7 @@ pub enum OpCode { /// Operand: value (i32) PushI32 = 0x17, /// Removes `n` values from the stack. - /// Operand: n (u16) + /// Operand: n (u32) PopN = 0x18, // --- 6.3 Arithmetic --- diff --git a/crates/prometeu-compiler/src/backend/emit_bytecode.rs b/crates/prometeu-compiler/src/backend/emit_bytecode.rs index 04d7b298..99d0ab59 100644 --- a/crates/prometeu-compiler/src/backend/emit_bytecode.rs +++ b/crates/prometeu-compiler/src/backend/emit_bytecode.rs @@ -161,6 +161,13 @@ impl<'a> BytecodeEmitter<'a> { asm_instrs.push(Asm::Op(OpCode::Syscall, vec![Operand::U32(*id)])); } InstrKind::FrameSync => asm_instrs.push(Asm::Op(OpCode::FrameSync, vec![])), + InstrKind::Alloc => asm_instrs.push(Asm::Op(OpCode::Alloc, vec![])), + InstrKind::LoadRef(offset) => { + asm_instrs.push(Asm::Op(OpCode::LoadRef, vec![Operand::U32(*offset)])); + } + InstrKind::StoreRef(offset) => { + asm_instrs.push(Asm::Op(OpCode::StoreRef, vec![Operand::U32(*offset)])); + } } let end_idx = asm_instrs.len(); diff --git a/crates/prometeu-compiler/src/frontends/pbs/typecheck.rs b/crates/prometeu-compiler/src/frontends/pbs/typecheck.rs index 896b217a..a6e686ca 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/typecheck.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/typecheck.rs @@ -179,8 +179,15 @@ impl<'a> TypeChecker<'a> { // In v0, we assume target is a gate. We bind the inner type to the binding. let inner_ty = match target_ty { PbsType::Contract(name) if name.starts_with("Gate<") => { - // Try to extract type name from Gate - PbsType::Void // Simplified + // Extract type name from Gate + let inner_name = &name[5..name.len()-1]; + match inner_name { + "int" => PbsType::Int, + "float" => PbsType::Float, + "bool" => PbsType::Bool, + "string" => PbsType::String, + _ => PbsType::Void, // Should be PbsType::Struct(inner_name) if we had better info + } } _ => PbsType::Void }; diff --git a/crates/prometeu-compiler/src/ir/instr.rs b/crates/prometeu-compiler/src/ir/instr.rs index 82af4900..4db2d4e4 100644 --- a/crates/prometeu-compiler/src/ir/instr.rs +++ b/crates/prometeu-compiler/src/ir/instr.rs @@ -136,4 +136,13 @@ pub enum InstrKind { Syscall(u32), /// Special instruction to synchronize with the hardware frame clock. FrameSync, + + // --- HIP / Memory --- + + /// Allocates memory on the heap. Pops size from stack. + Alloc, + /// Reads from heap at reference + offset. Pops reference, pushes value. + LoadRef(u32), + /// Writes to heap at reference + offset. Pops reference and value. + StoreRef(u32), } diff --git a/crates/prometeu-compiler/src/lib.rs b/crates/prometeu-compiler/src/lib.rs index 67eb62bf..6cf89d4b 100644 --- a/crates/prometeu-compiler/src/lib.rs +++ b/crates/prometeu-compiler/src/lib.rs @@ -1,7 +1,7 @@ //! # Prometeu Compiler //! //! This crate provides the official compiler for the Prometeu ecosystem. -//! It translates high-level source code (primarily TypeScript/JavaScript) into +//! It translates high-level source code (primarily Prometeu Base Script - PBS) into //! Prometeu ByteCode (.pbc), which runs on the Prometeu Virtual Machine. //! //! ## Architecture Overview: @@ -9,8 +9,8 @@ //! The compiler follows a multi-stage pipeline: //! //! 1. **Frontend (Parsing & Analysis)**: -//! - Uses the `oxc` parser to generate an Abstract Syntax Tree (AST). -//! - Performs semantic analysis and validation (e.g., ensuring only supported TS features are used). +//! - Uses the PBS parser to generate an Abstract Syntax Tree (AST). +//! - Performs semantic analysis and validation. //! - Lowers the AST into the **Intermediate Representation (IR)**. //! - *Example*: Converting a `a + b` expression into IR instructions like `Push(a)`, `Push(b)`, `Add`. //! @@ -30,7 +30,7 @@ //! //! ```bash //! # Build a project from a directory -//! prometeu-compiler build ./my-game --entry ./src/main.ts --out ./game.pbc +//! prometeu-compiler build ./my-game --entry ./src/main.pbs --out ./game.pbc //! ``` //! //! ## Programmatic Entry Point: @@ -67,7 +67,7 @@ pub enum Commands { /// Path to the project root directory. project_dir: PathBuf, - /// Explicit path to the entry file (defaults to src/main.ts). + /// Explicit path to the entry file (defaults to src/main.pbs). #[arg(short, long)] entry: Option, diff --git a/crates/prometeu-compiler/src/lowering/core_to_vm.rs b/crates/prometeu-compiler/src/lowering/core_to_vm.rs index 1a23a8e8..f5048463 100644 --- a/crates/prometeu-compiler/src/lowering/core_to_vm.rs +++ b/crates/prometeu-compiler/src/lowering/core_to_vm.rs @@ -71,11 +71,10 @@ pub fn lower_function(core_func: &ir_core::Function) -> Result { ir_core::Instr::And => ir::InstrKind::And, ir_core::Instr::Or => ir::InstrKind::Or, ir_core::Instr::Not => ir::InstrKind::Not, - ir_core::Instr::Alloc | ir_core::Instr::Free | ir_core::Instr::ReadGate | ir_core::Instr::WriteGate => { - // HIP effects are not yet supported in VM IR, so we emit Nop or similar. - // For now, let's use Nop. - ir::InstrKind::Nop - } + ir_core::Instr::Alloc => ir::InstrKind::Alloc, + ir_core::Instr::ReadGate => ir::InstrKind::LoadRef(0), + ir_core::Instr::WriteGate => ir::InstrKind::StoreRef(0), + ir_core::Instr::Free => ir::InstrKind::Nop, }; vm_func.body.push(ir::Instruction::new(kind, None)); } diff --git a/crates/prometeu-compiler/tests/pbs_end_to_end_tests.rs b/crates/prometeu-compiler/tests/pbs_end_to_end_tests.rs new file mode 100644 index 00000000..7dc29fdd --- /dev/null +++ b/crates/prometeu-compiler/tests/pbs_end_to_end_tests.rs @@ -0,0 +1,50 @@ +use prometeu_compiler::compiler; +use prometeu_bytecode::pbc::parse_pbc; +use prometeu_bytecode::disasm::disasm; +use prometeu_bytecode::opcode::OpCode; +use std::fs; +use tempfile::tempdir; + +#[test] +fn test_compile_hip_program() { + let dir = tempdir().unwrap(); + let project_dir = dir.path(); + + // Create prometeu.json + fs::write( + project_dir.join("prometeu.json"), + r#"{ + "script_fe": "pbs", + "entry": "main.pbs" + }"#, + ).unwrap(); + + // Create main.pbs with HIP effects + let code = " + fn main() { + let x = alloc int; + mutate x as v { + let y = v + 1; + } + } + "; + fs::write(project_dir.join("main.pbs"), code).unwrap(); + + // Compile + let unit = compiler::compile(project_dir).expect("Failed to compile"); + + // Parse PBC + let pbc = parse_pbc(&unit.rom).expect("Failed to parse PBC"); + + // Disassemble + let instrs = disasm(&pbc.rom).expect("Failed to disassemble"); + + // Verify opcodes exist in bytecode + let opcodes: Vec<_> = instrs.iter().map(|i| i.opcode).collect(); + + assert!(opcodes.contains(&OpCode::Alloc)); + assert!(opcodes.contains(&OpCode::LoadRef)); // From ReadGate + assert!(opcodes.contains(&OpCode::StoreRef)); // From WriteGate + assert!(opcodes.contains(&OpCode::Add)); + assert!(opcodes.contains(&OpCode::Ret)); +}