change ir to ir_vm and make it feature frozen
This commit is contained in:
parent
4174d01a43
commit
c34166435f
@ -4,13 +4,13 @@
|
|||||||
//! converting the Intermediate Representation (IR) into the binary Prometeu ByteCode (PBC) format.
|
//! converting the Intermediate Representation (IR) into the binary Prometeu ByteCode (PBC) format.
|
||||||
//!
|
//!
|
||||||
//! It performs two main tasks:
|
//! It performs two main tasks:
|
||||||
//! 1. **Instruction Lowering**: Translates `ir::Instruction` into `prometeu_bytecode::asm::Asm` ops.
|
//! 1. **Instruction Lowering**: Translates `ir_vm::Instruction` into `prometeu_bytecode::asm::Asm` ops.
|
||||||
//! 2. **Symbol Mapping**: Associates bytecode offsets (Program Counter) with source code locations.
|
//! 2. **Symbol Mapping**: Associates bytecode offsets (Program Counter) with source code locations.
|
||||||
|
|
||||||
use crate::common::files::FileManager;
|
use crate::common::files::FileManager;
|
||||||
use crate::common::symbols::Symbol;
|
use crate::common::symbols::Symbol;
|
||||||
use crate::ir;
|
use crate::ir_vm;
|
||||||
use crate::ir::instr::InstrKind;
|
use crate::ir_vm::instr::InstrKind;
|
||||||
use crate::ir_core::ConstantValue;
|
use crate::ir_core::ConstantValue;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use prometeu_bytecode::asm::{assemble, update_pc_by_operand, Asm, Operand};
|
use prometeu_bytecode::asm::{assemble, update_pc_by_operand, Asm, Operand};
|
||||||
@ -26,7 +26,7 @@ pub struct EmitResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Entry point for emitting a bytecode module from the IR.
|
/// Entry point for emitting a bytecode module from the IR.
|
||||||
pub fn emit_module(module: &ir::Module, file_manager: &FileManager) -> Result<EmitResult> {
|
pub fn emit_module(module: &ir_vm::Module, file_manager: &FileManager) -> Result<EmitResult> {
|
||||||
let mut emitter = BytecodeEmitter::new(file_manager);
|
let mut emitter = BytecodeEmitter::new(file_manager);
|
||||||
emitter.emit(module)
|
emitter.emit(module)
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ impl<'a> BytecodeEmitter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Transforms an IR module into a binary PBC file.
|
/// Transforms an IR module into a binary PBC file.
|
||||||
fn emit(&mut self, module: &ir::Module) -> Result<EmitResult> {
|
fn emit(&mut self, module: &ir_vm::Module) -> Result<EmitResult> {
|
||||||
let mut asm_instrs = Vec::new();
|
let mut asm_instrs = Vec::new();
|
||||||
let mut ir_instr_map = Vec::new(); // Maps Asm index to IR instruction (for symbols)
|
let mut ir_instr_map = Vec::new(); // Maps Asm index to IR instruction (for symbols)
|
||||||
|
|
||||||
@ -232,9 +232,9 @@ impl<'a> BytecodeEmitter<'a> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ir::module::{Module, Function};
|
use crate::ir_vm::module::{Module, Function};
|
||||||
use crate::ir::instr::{Instruction, InstrKind};
|
use crate::ir_vm::instr::{Instruction, InstrKind};
|
||||||
use crate::ir::types::Type;
|
use crate::ir_vm::types::Type;
|
||||||
use crate::ir_core::ids::FunctionId;
|
use crate::ir_core::ids::FunctionId;
|
||||||
use crate::ir_core::const_pool::ConstantValue;
|
use crate::ir_core::const_pool::ConstantValue;
|
||||||
use crate::common::files::FileManager;
|
use crate::common::files::FileManager;
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use crate::common::config::ProjectConfig;
|
|||||||
use crate::common::files::FileManager;
|
use crate::common::files::FileManager;
|
||||||
use crate::common::symbols::Symbol;
|
use crate::common::symbols::Symbol;
|
||||||
use crate::frontends::Frontend;
|
use crate::frontends::Frontend;
|
||||||
use crate::ir;
|
use crate::ir_vm;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ pub fn compile(project_dir: &Path) -> Result<CompilationUnit> {
|
|||||||
// 3. IR Validation
|
// 3. IR Validation
|
||||||
// Ensures the generated IR is sound and doesn't violate any VM constraints
|
// Ensures the generated IR is sound and doesn't violate any VM constraints
|
||||||
// before we spend time generating bytecode.
|
// before we spend time generating bytecode.
|
||||||
ir::validate::validate_module(&ir_module)
|
ir_vm::validate::validate_module(&ir_module)
|
||||||
.map_err(|bundle| anyhow::anyhow!("IR Validation failed: {:?}", bundle))?;
|
.map_err(|bundle| anyhow::anyhow!("IR Validation failed: {:?}", bundle))?;
|
||||||
|
|
||||||
// 4. Emit Bytecode
|
// 4. Emit Bytecode
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::common::diagnostics::DiagnosticBundle;
|
use crate::common::diagnostics::DiagnosticBundle;
|
||||||
use crate::ir;
|
use crate::ir_vm;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::common::files::FileManager;
|
use crate::common::files::FileManager;
|
||||||
@ -13,5 +13,5 @@ pub trait Frontend {
|
|||||||
&self,
|
&self,
|
||||||
entry: &Path,
|
entry: &Path,
|
||||||
file_manager: &mut FileManager,
|
file_manager: &mut FileManager,
|
||||||
) -> Result<ir::Module, DiagnosticBundle>;
|
) -> Result<ir_vm::Module, DiagnosticBundle>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ pub use lowering::Lowerer;
|
|||||||
use crate::common::diagnostics::DiagnosticBundle;
|
use crate::common::diagnostics::DiagnosticBundle;
|
||||||
use crate::common::files::FileManager;
|
use crate::common::files::FileManager;
|
||||||
use crate::frontends::Frontend;
|
use crate::frontends::Frontend;
|
||||||
use crate::ir;
|
use crate::ir_vm;
|
||||||
use crate::lowering::core_to_vm;
|
use crate::lowering::core_to_vm;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ impl Frontend for PbsFrontend {
|
|||||||
&self,
|
&self,
|
||||||
entry: &Path,
|
entry: &Path,
|
||||||
file_manager: &mut FileManager,
|
file_manager: &mut FileManager,
|
||||||
) -> Result<ir::Module, DiagnosticBundle> {
|
) -> Result<ir_vm::Module, DiagnosticBundle> {
|
||||||
let source = std::fs::read_to_string(entry).map_err(|e| {
|
let source = std::fs::read_to_string(entry).map_err(|e| {
|
||||||
DiagnosticBundle::error(format!("Failed to read file: {}", e), None)
|
DiagnosticBundle::error(format!("Failed to read file: {}", e), None)
|
||||||
})?;
|
})?;
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
//! The IR is a higher-level representation of the program than bytecode, but lower
|
//! The IR is a higher-level representation of the program than bytecode, but lower
|
||||||
//! than the source code AST. It is organized into Modules, Functions, and Globals.
|
//! than the source code AST. It is organized into Modules, Functions, and Globals.
|
||||||
|
|
||||||
use crate::ir::instr::Instruction;
|
use crate::ir_vm::instr::Instruction;
|
||||||
use crate::ir::types::Type;
|
use crate::ir_vm::types::Type;
|
||||||
use crate::ir_core::const_pool::ConstPool;
|
use crate::ir_core::const_pool::ConstPool;
|
||||||
use crate::ir_core::ids::FunctionId;
|
use crate::ir_core::ids::FunctionId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::common::diagnostics::DiagnosticBundle;
|
use crate::common::diagnostics::DiagnosticBundle;
|
||||||
use crate::ir::module::Module;
|
use crate::ir_vm::module::Module;
|
||||||
|
|
||||||
pub fn validate_module(_module: &Module) -> Result<(), DiagnosticBundle> {
|
pub fn validate_module(_module: &Module) -> Result<(), DiagnosticBundle> {
|
||||||
// TODO: Implement common IR validations:
|
// TODO: Implement common IR validations:
|
||||||
@ -38,7 +38,7 @@
|
|||||||
//! See the [`compiler`] module for the main entry point to trigger a compilation programmatically.
|
//! See the [`compiler`] module for the main entry point to trigger a compilation programmatically.
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod ir;
|
pub mod ir_vm;
|
||||||
pub mod ir_core;
|
pub mod ir_core;
|
||||||
pub mod lowering;
|
pub mod lowering;
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
use crate::ir;
|
use crate::ir_vm;
|
||||||
use crate::ir_core;
|
use crate::ir_core;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
/// Lowers a Core IR program into a VM IR module.
|
/// Lowers a Core IR program into a VM IR module.
|
||||||
pub fn lower_program(program: &ir_core::Program) -> Result<ir::Module> {
|
pub fn lower_program(program: &ir_core::Program) -> Result<ir_vm::Module> {
|
||||||
// For now, we assume a single module program or lower the first one.
|
// For now, we assume a single module program or lower the first one.
|
||||||
// In the future, we might want to lower all modules and link them.
|
// In the future, we might want to lower all modules and link them.
|
||||||
if let Some(core_module) = program.modules.first() {
|
if let Some(core_module) = program.modules.first() {
|
||||||
@ -14,8 +14,8 @@ pub fn lower_program(program: &ir_core::Program) -> Result<ir::Module> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lowers a single Core IR module into a VM IR module.
|
/// Lowers a single Core IR module into a VM IR module.
|
||||||
pub fn lower_module(core_module: &ir_core::Module, const_pool: &ir_core::ConstPool) -> Result<ir::Module> {
|
pub fn lower_module(core_module: &ir_core::Module, const_pool: &ir_core::ConstPool) -> Result<ir_vm::Module> {
|
||||||
let mut vm_module = ir::Module::new(core_module.name.clone());
|
let mut vm_module = ir_vm::Module::new(core_module.name.clone());
|
||||||
vm_module.const_pool = const_pool.clone();
|
vm_module.const_pool = const_pool.clone();
|
||||||
|
|
||||||
for core_func in &core_module.functions {
|
for core_func in &core_module.functions {
|
||||||
@ -26,11 +26,11 @@ pub fn lower_module(core_module: &ir_core::Module, const_pool: &ir_core::ConstPo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lowers a Core IR function into a VM IR function.
|
/// Lowers a Core IR function into a VM IR function.
|
||||||
pub fn lower_function(core_func: &ir_core::Function) -> Result<ir::Function> {
|
pub fn lower_function(core_func: &ir_core::Function) -> Result<ir_vm::Function> {
|
||||||
let mut vm_func = ir::Function {
|
let mut vm_func = ir_vm::Function {
|
||||||
id: core_func.id,
|
id: core_func.id,
|
||||||
name: core_func.name.clone(),
|
name: core_func.name.clone(),
|
||||||
params: core_func.params.iter().map(|p| ir::Param {
|
params: core_func.params.iter().map(|p| ir_vm::Param {
|
||||||
name: p.name.clone(),
|
name: p.name.clone(),
|
||||||
r#type: lower_type(&p.ty),
|
r#type: lower_type(&p.ty),
|
||||||
}).collect(),
|
}).collect(),
|
||||||
@ -40,62 +40,62 @@ pub fn lower_function(core_func: &ir_core::Function) -> Result<ir::Function> {
|
|||||||
|
|
||||||
for block in &core_func.blocks {
|
for block in &core_func.blocks {
|
||||||
// Core blocks map to labels in the flat VM IR instruction list.
|
// Core blocks map to labels in the flat VM IR instruction list.
|
||||||
vm_func.body.push(ir::Instruction::new(
|
vm_func.body.push(ir_vm::Instruction::new(
|
||||||
ir::InstrKind::Label(ir::Label(format!("block_{}", block.id))),
|
ir_vm::InstrKind::Label(ir_vm::Label(format!("block_{}", block.id))),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
|
|
||||||
for instr in &block.instrs {
|
for instr in &block.instrs {
|
||||||
let kind = match instr {
|
let kind = match instr {
|
||||||
ir_core::Instr::PushConst(id) => ir::InstrKind::PushConst(*id),
|
ir_core::Instr::PushConst(id) => ir_vm::InstrKind::PushConst(*id),
|
||||||
ir_core::Instr::Call(func_id, arg_count) => ir::InstrKind::Call {
|
ir_core::Instr::Call(func_id, arg_count) => ir_vm::InstrKind::Call {
|
||||||
func_id: *func_id,
|
func_id: *func_id,
|
||||||
arg_count: *arg_count
|
arg_count: *arg_count
|
||||||
},
|
},
|
||||||
ir_core::Instr::Syscall(id) => ir::InstrKind::Syscall(*id),
|
ir_core::Instr::Syscall(id) => ir_vm::InstrKind::Syscall(*id),
|
||||||
ir_core::Instr::GetLocal(slot) => ir::InstrKind::GetLocal(*slot),
|
ir_core::Instr::GetLocal(slot) => ir_vm::InstrKind::GetLocal(*slot),
|
||||||
ir_core::Instr::SetLocal(slot) => ir::InstrKind::SetLocal(*slot),
|
ir_core::Instr::SetLocal(slot) => ir_vm::InstrKind::SetLocal(*slot),
|
||||||
ir_core::Instr::Pop => ir::InstrKind::Pop,
|
ir_core::Instr::Pop => ir_vm::InstrKind::Pop,
|
||||||
ir_core::Instr::Dup => ir::InstrKind::Dup,
|
ir_core::Instr::Dup => ir_vm::InstrKind::Dup,
|
||||||
ir_core::Instr::Add => ir::InstrKind::Add,
|
ir_core::Instr::Add => ir_vm::InstrKind::Add,
|
||||||
ir_core::Instr::Sub => ir::InstrKind::Sub,
|
ir_core::Instr::Sub => ir_vm::InstrKind::Sub,
|
||||||
ir_core::Instr::Mul => ir::InstrKind::Mul,
|
ir_core::Instr::Mul => ir_vm::InstrKind::Mul,
|
||||||
ir_core::Instr::Div => ir::InstrKind::Div,
|
ir_core::Instr::Div => ir_vm::InstrKind::Div,
|
||||||
ir_core::Instr::Neg => ir::InstrKind::Neg,
|
ir_core::Instr::Neg => ir_vm::InstrKind::Neg,
|
||||||
ir_core::Instr::Eq => ir::InstrKind::Eq,
|
ir_core::Instr::Eq => ir_vm::InstrKind::Eq,
|
||||||
ir_core::Instr::Neq => ir::InstrKind::Neq,
|
ir_core::Instr::Neq => ir_vm::InstrKind::Neq,
|
||||||
ir_core::Instr::Lt => ir::InstrKind::Lt,
|
ir_core::Instr::Lt => ir_vm::InstrKind::Lt,
|
||||||
ir_core::Instr::Lte => ir::InstrKind::Lte,
|
ir_core::Instr::Lte => ir_vm::InstrKind::Lte,
|
||||||
ir_core::Instr::Gt => ir::InstrKind::Gt,
|
ir_core::Instr::Gt => ir_vm::InstrKind::Gt,
|
||||||
ir_core::Instr::Gte => ir::InstrKind::Gte,
|
ir_core::Instr::Gte => ir_vm::InstrKind::Gte,
|
||||||
ir_core::Instr::And => ir::InstrKind::And,
|
ir_core::Instr::And => ir_vm::InstrKind::And,
|
||||||
ir_core::Instr::Or => ir::InstrKind::Or,
|
ir_core::Instr::Or => ir_vm::InstrKind::Or,
|
||||||
ir_core::Instr::Not => ir::InstrKind::Not,
|
ir_core::Instr::Not => ir_vm::InstrKind::Not,
|
||||||
ir_core::Instr::Alloc => ir::InstrKind::Alloc,
|
ir_core::Instr::Alloc => ir_vm::InstrKind::Alloc,
|
||||||
ir_core::Instr::ReadGate => ir::InstrKind::LoadRef(0),
|
ir_core::Instr::ReadGate => ir_vm::InstrKind::LoadRef(0),
|
||||||
ir_core::Instr::WriteGate => ir::InstrKind::StoreRef(0),
|
ir_core::Instr::WriteGate => ir_vm::InstrKind::StoreRef(0),
|
||||||
ir_core::Instr::Free => ir::InstrKind::Nop,
|
ir_core::Instr::Free => ir_vm::InstrKind::Nop,
|
||||||
};
|
};
|
||||||
vm_func.body.push(ir::Instruction::new(kind, None));
|
vm_func.body.push(ir_vm::Instruction::new(kind, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
match &block.terminator {
|
match &block.terminator {
|
||||||
ir_core::Terminator::Return => {
|
ir_core::Terminator::Return => {
|
||||||
vm_func.body.push(ir::Instruction::new(ir::InstrKind::Ret, None));
|
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Ret, None));
|
||||||
}
|
}
|
||||||
ir_core::Terminator::Jump(target) => {
|
ir_core::Terminator::Jump(target) => {
|
||||||
vm_func.body.push(ir::Instruction::new(
|
vm_func.body.push(ir_vm::Instruction::new(
|
||||||
ir::InstrKind::Jmp(ir::Label(format!("block_{}", target))),
|
ir_vm::InstrKind::Jmp(ir_vm::Label(format!("block_{}", target))),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ir_core::Terminator::JumpIfFalse { target, else_target } => {
|
ir_core::Terminator::JumpIfFalse { target, else_target } => {
|
||||||
vm_func.body.push(ir::Instruction::new(
|
vm_func.body.push(ir_vm::Instruction::new(
|
||||||
ir::InstrKind::JmpIfFalse(ir::Label(format!("block_{}", target))),
|
ir_vm::InstrKind::JmpIfFalse(ir_vm::Label(format!("block_{}", target))),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
vm_func.body.push(ir::Instruction::new(
|
vm_func.body.push(ir_vm::Instruction::new(
|
||||||
ir::InstrKind::Jmp(ir::Label(format!("block_{}", else_target))),
|
ir_vm::InstrKind::Jmp(ir_vm::Label(format!("block_{}", else_target))),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -105,20 +105,20 @@ pub fn lower_function(core_func: &ir_core::Function) -> Result<ir::Function> {
|
|||||||
Ok(vm_func)
|
Ok(vm_func)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_type(ty: &ir_core::Type) -> ir::Type {
|
fn lower_type(ty: &ir_core::Type) -> ir_vm::Type {
|
||||||
match ty {
|
match ty {
|
||||||
ir_core::Type::Void => ir::Type::Void,
|
ir_core::Type::Void => ir_vm::Type::Void,
|
||||||
ir_core::Type::Int => ir::Type::Int,
|
ir_core::Type::Int => ir_vm::Type::Int,
|
||||||
ir_core::Type::Float => ir::Type::Float,
|
ir_core::Type::Float => ir_vm::Type::Float,
|
||||||
ir_core::Type::Bool => ir::Type::Bool,
|
ir_core::Type::Bool => ir_vm::Type::Bool,
|
||||||
ir_core::Type::String => ir::Type::String,
|
ir_core::Type::String => ir_vm::Type::String,
|
||||||
ir_core::Type::Optional(inner) => ir::Type::Array(Box::new(lower_type(inner))), // Approximation
|
ir_core::Type::Optional(inner) => ir_vm::Type::Array(Box::new(lower_type(inner))), // Approximation
|
||||||
ir_core::Type::Result(ok, _) => lower_type(ok), // Approximation
|
ir_core::Type::Result(ok, _) => lower_type(ok), // Approximation
|
||||||
ir_core::Type::Struct(_) => ir::Type::Object,
|
ir_core::Type::Struct(_) => ir_vm::Type::Object,
|
||||||
ir_core::Type::Service(_) => ir::Type::Object,
|
ir_core::Type::Service(_) => ir_vm::Type::Object,
|
||||||
ir_core::Type::Contract(_) => ir::Type::Object,
|
ir_core::Type::Contract(_) => ir_vm::Type::Object,
|
||||||
ir_core::Type::ErrorType(_) => ir::Type::Object,
|
ir_core::Type::ErrorType(_) => ir_vm::Type::Object,
|
||||||
ir_core::Type::Function { .. } => ir::Type::Function,
|
ir_core::Type::Function { .. } => ir_vm::Type::Function,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::ir_core;
|
use crate::ir_core;
|
||||||
use crate::ir_core::*;
|
use crate::ir_core::*;
|
||||||
use crate::ir::*;
|
use crate::ir_vm::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_full_lowering() {
|
fn test_full_lowering() {
|
||||||
|
|||||||
@ -1,357 +1,223 @@
|
|||||||
# PBS Compiler — Junie PR Plan
|
# PBS ⇄ VM Alignment — Junie PRs (HIP Semantics Hardening)
|
||||||
|
|
||||||
> **Purpose:** this document defines a sequence of small, focused Pull Requests to be implemented by *Junie*, one at a time.
|
> **Purpose:** fix semantic mismatches between the PBS frontend (Core IR) and the VM **before** any VM heap/gate implementation.
|
||||||
>
|
>
|
||||||
> **Audience:** compiler implementer (AI or human).
|
> These PRs are **surgical**, **mandatory**, and **non-creative**.
|
||||||
|
> Junie must follow them **exactly**.
|
||||||
|
|
||||||
|
> **Context:**
|
||||||
>
|
>
|
||||||
> **Scope:** PBS-first compiler architecture. TS and Lua frontends are assumed **removed**.
|
> * PBS frontend is implemented and produces Core IR.
|
||||||
>
|
> * Bytecode stability is a hard requirement.
|
||||||
> **Hard rules:**
|
> * VM currently has stack + const pool; heap exists but is unused.
|
||||||
>
|
> * HIP semantics (gates/storage) are currently **incorrectly lowered**.
|
||||||
> * Each PR must compile and pass tests.
|
> * `ir_vm` is feature-frozen at the moment. we are going to validate only `ir_core`
|
||||||
> * Each PR must include tests.
|
> * Lowering is the only place `ir_core` and `ir_vm` touch each other.
|
||||||
> * No speculative features.
|
> - VM IR is never imported from Core IR.
|
||||||
> * Follow the `Prometeu Base Script (PBS) - Implementation Spec`.
|
> - Core IR never imports VM IR.
|
||||||
> * VM IR is frozen: new opcodes are forbidden unless explicitly planned in a PR titled “VM Instruction Set Change” with a full rationale + golden bytecode tests.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Global Architectural Direction (Non-negotiable)
|
## Global Rules (Read Before Any PR)
|
||||||
|
|
||||||
* PBS is the **primary language**.
|
1. **No new features.** Only semantic correction.
|
||||||
* Frontend is implemented **before** runtime integration.
|
2. **No new VM opcodes yet.** VM changes come later.
|
||||||
* Architecture uses **two IR layers**:
|
3. **No fallback values** (e.g. `FunctionId(0)`). Fail with diagnostics.
|
||||||
* **Core IR** (PBS-semantic, typed, resolved)
|
4. **Every PR must include tests** (golden or unit).
|
||||||
* **VM IR** (stack-based, backend-friendly)
|
5. **Core IR is the source of semantic truth.**
|
||||||
* VM IR remains simple and stable.
|
|
||||||
* Lowering is explicit and testable.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PR-01 — ProjectConfig and Frontend Selection
|
# PR-20 — Core IR: Make HIP Semantics Explicit (No Handle Loss)
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Introduce a project-level configuration that selects the frontend and entry file explicitly.
|
Fix the Core IR so HIP operations never lose the destination gate.
|
||||||
|
|
||||||
### Motivation
|
### Problem (Current Bug)
|
||||||
|
|
||||||
The compiler must not hardcode entry points or languages. PBS will be the first frontend, others may return later.
|
Current lowering evaluates a gate, reads storage, stores the result in a local, and later attempts to write back **without having the gate anymore**.
|
||||||
|
|
||||||
### Scope
|
This violates PBS semantics: storage access must always be mediated by the **original gate**.
|
||||||
|
|
||||||
* Add `ProjectConfig` (serde-deserializable) loaded from `prometeu.json`
|
### Required Changes
|
||||||
* Fields (v0):
|
|
||||||
|
|
||||||
* `script_fe: "pbs"`
|
#### 1. Extend Core IR instructions
|
||||||
* `entry: "main.pbs"`
|
|
||||||
* Refactor compiler entry point to:
|
|
||||||
|
|
||||||
* load config
|
Add explicit HIP instructions:
|
||||||
* select frontend by `script_fe`
|
|
||||||
* resolve entry path relative to project root
|
|
||||||
|
|
||||||
### Files Likely Touched
|
```rust
|
||||||
|
enum CoreInstr {
|
||||||
|
// existing …
|
||||||
|
|
||||||
* `compiler/mod.rs`
|
Alloc { ty: TypeId, slots: u32 },
|
||||||
* `compiler/driver.rs`
|
|
||||||
* `common/config.rs` (new)
|
|
||||||
|
|
||||||
### Tests (mandatory)
|
BeginPeek { gate: ValueId },
|
||||||
|
BeginBorrow { gate: ValueId },
|
||||||
|
BeginMutate { gate: ValueId },
|
||||||
|
|
||||||
* unit test: load valid `prometeu.json`
|
EndPeek,
|
||||||
* unit test: invalid frontend → diagnostic
|
EndBorrow,
|
||||||
* integration test: project root + entry resolution
|
EndMutate,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Notes to Junie
|
Rules:
|
||||||
|
|
||||||
Do **not** add PBS parsing yet. This PR is infrastructure only.
|
* `Begin*` instructions **do not consume** the gate.
|
||||||
|
* Gate identity must remain available until the matching `End*`.
|
||||||
|
|
||||||
|
#### 2. Remove any lowering that copies HIP storage into locals
|
||||||
|
|
||||||
|
* No `ReadGate → SetLocal` pattern.
|
||||||
|
* Storage views are **not locals**.
|
||||||
|
|
||||||
|
### Tests (Mandatory)
|
||||||
|
|
||||||
|
* Golden Core IR test showing `BeginMutate(gate)` … `EndMutate` wrapping body
|
||||||
|
* Test asserting gate is still live at `EndMutate`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PR-02 — Core IR Skeleton (PBS-first)
|
# PR-21 — Distinguish `peek`, `borrow`, and `mutate` in Core IR
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Introduce a **Core IR** layer independent from the VM IR.
|
Restore the semantic distinction mandated by PBS.
|
||||||
|
|
||||||
### Motivation
|
### Required Semantics
|
||||||
|
|
||||||
PBS semantics must be represented before lowering to VM instructions.
|
| Operation | Effect |
|
||||||
|
| --------- | ------------------------------- |
|
||||||
|
| `peek` | Copy storage → stack value |
|
||||||
|
| `borrow` | Temporary read-only view |
|
||||||
|
| `mutate` | Temporary mutable view + commit |
|
||||||
|
|
||||||
### Scope
|
### Required Changes
|
||||||
|
|
||||||
* Add new module: `ir_core`
|
* Lower PBS `peek` → `BeginPeek` / `EndPeek`
|
||||||
* Define minimal structures:
|
* Lower PBS `borrow` → `BeginBorrow` / `EndBorrow`
|
||||||
|
* Lower PBS `mutate` → `BeginMutate` / `EndMutate`
|
||||||
|
|
||||||
* `Program`
|
These **must not** share the same lowering path.
|
||||||
* `Module`
|
|
||||||
* `Function`
|
|
||||||
* `Block`
|
|
||||||
* `Instr`
|
|
||||||
* `Terminator`
|
|
||||||
* IDs only (no string-based calls):
|
|
||||||
|
|
||||||
* `FunctionId`
|
|
||||||
* `ConstId`
|
|
||||||
* `TypeId`
|
|
||||||
|
|
||||||
### Constraints
|
|
||||||
|
|
||||||
* Core IR must NOT reference VM opcodes
|
|
||||||
* No lowering yet
|
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
* construct Core IR manually in tests
|
* PBS snippet with all three operations
|
||||||
* snapshot test (JSON) for deterministic shape
|
* Assert distinct Core IR instruction sequences
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PR-03 — Constant Pool and IDs
|
# PR-22 — Make Allocation Shape Explicit in Core IR
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Introduce a stable constant pool shared by Core IR and VM IR.
|
Stop implicit / guessed heap layouts.
|
||||||
|
|
||||||
### Scope
|
### Required Changes
|
||||||
|
|
||||||
* Add `ConstPool`:
|
* Replace any shape-less `Alloc` with:
|
||||||
|
|
||||||
* strings
|
```rust
|
||||||
* numbers
|
Alloc { ty: TypeId, slots: u32 }
|
||||||
* Replace inline literals in VM IR with `ConstId`
|
```
|
||||||
* Update existing VM IR to accept `PushConst(ConstId)`
|
|
||||||
|
Rules:
|
||||||
|
|
||||||
|
* `TypeId` comes from frontend type checking
|
||||||
|
* `slots` is derived deterministically (struct fields / array size)
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
* const pool deduplication
|
* Allocating storage struct emits correct `slots`
|
||||||
* deterministic ConstId assignment
|
* Allocating array emits correct `slots`
|
||||||
* IR snapshot stability
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PR-04 — VM IR Cleanup (Stabilization)
|
# PR-23 — Eliminate Invalid Call Fallbacks
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Stabilize VM IR as a **lowering target**, not a language IR.
|
Prevent invalid bytecode generation.
|
||||||
|
|
||||||
### Scope
|
### Required Changes
|
||||||
|
|
||||||
* Replace string-based calls with `FunctionId`
|
* Remove **all** fallbacks to `FunctionId(0)` or equivalent
|
||||||
* Ensure locals are accessed via slots
|
* On unresolved symbols during lowering:
|
||||||
* Remove or internalize `PushScope` / `PopScope`
|
|
||||||
|
* Emit canonical diagnostic (`E_RESOLVE_UNDEFINED` or `E_LOWER_UNSUPPORTED`)
|
||||||
|
* Abort lowering
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
* golden VM IR tests
|
* PBS program calling missing function → compile error
|
||||||
* lowering smoke test (Core IR → VM IR)
|
* No Core IR or VM IR emitted
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PR-05 — Core IR → VM IR Lowering Pass
|
# PR-24 — Validate Contract Calls in Frontend (Arity + Types)
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Implement the lowering pass from Core IR to VM IR.
|
Move contract validation to compile time.
|
||||||
|
|
||||||
### Scope
|
### Required Changes
|
||||||
|
|
||||||
* New module: `lowering/core_to_vm.rs`
|
* During PBS type checking:
|
||||||
* Lowering rules:
|
|
||||||
|
|
||||||
* Core blocks → labels
|
* Validate argument count against contract signature
|
||||||
* Core calls → VM calls
|
* Validate argument types
|
||||||
* Host calls preserved
|
|
||||||
* No PBS frontend yet
|
* Lower only validated calls to `HostCall`
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
* lowering correctness
|
* Wrong arity → `E_TYPE_MISMATCH`
|
||||||
* instruction ordering
|
* Correct call lowers to Core IR `HostCall`
|
||||||
* label resolution
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PR-06 — PBS Frontend: Lexer
|
# PR-25 — Core IR Invariants Test Suite
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
Implement PBS lexer according to the spec.
|
Lock in correct semantics before touching the VM.
|
||||||
|
|
||||||
### Scope
|
### Required Invariants
|
||||||
|
|
||||||
* Token kinds
|
* Every `Begin*` has a matching `End*`
|
||||||
* Keyword table
|
* Gate passed to `Begin*` is available at `End*`
|
||||||
* Span tracking
|
* No storage writes without `BeginMutate`
|
||||||
|
* No silent fallbacks
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
* tokenization tests
|
* Property-style tests or golden IR assertions
|
||||||
* keyword vs identifier tests
|
|
||||||
* bounded literals
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PR-07 — PBS Frontend: Parser (Raw AST)
|
## STOP POINT
|
||||||
|
|
||||||
### Goal
|
After PR-25:
|
||||||
|
|
||||||
Parse PBS source into a raw AST.
|
* Core IR correctly represents PBS HIP semantics
|
||||||
|
* Lowering is deterministic and safe
|
||||||
|
* VM is still unchanged
|
||||||
|
|
||||||
### Scope
|
**Only after this point may VM PRs begin.**
|
||||||
|
|
||||||
* Imports
|
Any VM work before this is a hard rejection.
|
||||||
* Top-level declarations
|
|
||||||
* Blocks
|
|
||||||
* Expressions (calls, literals, control flow)
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* valid programs
|
|
||||||
* syntax error recovery
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PR-08 — PBS Frontend: Symbol Collection and Resolver
|
## Instruction to Junie
|
||||||
|
|
||||||
### Goal
|
If any rule in this document is unclear:
|
||||||
|
|
||||||
Resolve names, modules, and visibility.
|
* Stop
|
||||||
|
* Add a failing test
|
||||||
|
* Document the ambiguity
|
||||||
|
|
||||||
### Scope
|
Do not invent behavior.
|
||||||
|
|
||||||
* Type namespace vs value namespace
|
This document is binding.
|
||||||
* Visibility rules
|
|
||||||
* Import resolution
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* duplicate symbols
|
|
||||||
* invalid imports
|
|
||||||
* visibility errors
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# PR-09 — PBS Frontend: Type Checking
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
|
|
||||||
Validate PBS semantics.
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
* Primitive types
|
|
||||||
* Structs
|
|
||||||
* `optional<T>` and `result<T, E>`
|
|
||||||
* Mutability rules
|
|
||||||
* Return path validation
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* type mismatch
|
|
||||||
* mutability violations
|
|
||||||
* implicit `none` behavior
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# PR-10 — PBS Frontend: Semantic Lowering to Core IR
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
|
|
||||||
Lower typed PBS AST into Core IR.
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
* ID-based calls
|
|
||||||
* ConstPool usage
|
|
||||||
* Control flow lowering
|
|
||||||
* SAFE vs HIP effects represented explicitly
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* PBS → Core IR snapshots
|
|
||||||
* semantic correctness
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# PR-11 — Host-bound Contracts and Syscall Mapping
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
|
|
||||||
Connect PBS host-bound contracts to runtime syscalls (without executing them).
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
* Contract registry
|
|
||||||
* Mapping: contract.method → syscall id
|
|
||||||
* Core IR host call nodes
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* invalid contract calls
|
|
||||||
* correct syscall mapping
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# PR-12 — Diagnostics Canonicalization
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
|
|
||||||
Standardize diagnostics output.
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
* Error codes (`E_*`, `W_*`)
|
|
||||||
* Stable messages
|
|
||||||
* Span accuracy
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* golden diagnostics
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# PR-13 — Backend Integration (VM IR → Bytecode)
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
|
|
||||||
Reconnect the pipeline to the Prometeu runtime backend.
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
* VM IR → bytecode emission
|
|
||||||
* No PBS semantics here
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* bytecode emission smoke test
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# PR-14 — End-to-End PBS Compile Test
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
|
|
||||||
Prove the full pipeline works.
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
|
|
||||||
* Sample PBS project
|
|
||||||
* Compile → bytecode
|
|
||||||
* Diagnostics only (no execution)
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
* golden bytecode snapshot
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Final Note to Junie
|
|
||||||
|
|
||||||
Do **not** skip PRs.
|
|
||||||
Do **not** merge multiple PRs together.
|
|
||||||
If the spec is unclear, create a failing test and document the ambiguity.
|
|
||||||
|
|
||||||
This plan is the authoritative roadmap for PBS frontend implementation.
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user