dev/pbs #8

Merged
bquarkz merged 74 commits from dev/pbs into master 2026-02-03 15:28:31 +00:00
8 changed files with 86 additions and 14 deletions
Showing only changes of commit 127ec789bc - Show all commits

View File

@ -41,7 +41,7 @@ pub fn disasm(rom: &[u8]) -> Result<Vec<Instr>, 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));
}

View File

@ -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 ---

View File

@ -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();

View File

@ -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<TypeName>
PbsType::Void // Simplified
// Extract type name from Gate<TypeName>
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
};

View File

@ -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),
}

View File

@ -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<PathBuf>,

View File

@ -71,11 +71,10 @@ pub fn lower_function(core_func: &ir_core::Function) -> Result<ir::Function> {
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));
}

View File

@ -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));
}