From a8e5d7f98e1112f5a7db104c1a2a8bc92211c13c Mon Sep 17 00:00:00 2001 From: Nilton Constantino Date: Mon, 2 Feb 2026 23:37:40 +0000 Subject: [PATCH] pr 66 --- .../src/building/orchestrator.rs | 17 +- .../prometeu-compiler/src/building/output.rs | 8 +- crates/prometeu-compiler/src/common/files.rs | 27 ++ .../prometeu-compiler/src/common/symbols.rs | 11 +- crates/prometeu-compiler/src/compiler.rs | 116 ++++++-- .../src/frontends/pbs/lowering.rs | 153 ++++++----- crates/prometeu-compiler/src/ir_core/instr.rs | 21 +- crates/prometeu-compiler/src/ir_core/mod.rs | 20 +- .../prometeu-compiler/src/ir_core/validate.rs | 72 ++--- crates/prometeu-compiler/src/ir_vm/mod.rs | 2 +- crates/prometeu-compiler/src/lib.rs | 19 +- .../src/lowering/core_to_vm.rs | 249 +++++++++--------- .../tests/export_conflicts.rs | 19 +- .../tests/hip_conformance.rs | 24 +- test-cartridges/canonical/golden/program.pbc | Bin 1087 -> 3727 bytes test-cartridges/test01/cartridge/program.pbc | Bin 1087 -> 3727 bytes 16 files changed, 463 insertions(+), 295 deletions(-) diff --git a/crates/prometeu-compiler/src/building/orchestrator.rs b/crates/prometeu-compiler/src/building/orchestrator.rs index 39d9e111..473bc772 100644 --- a/crates/prometeu-compiler/src/building/orchestrator.rs +++ b/crates/prometeu-compiler/src/building/orchestrator.rs @@ -1,6 +1,7 @@ use crate::building::linker::{LinkError, Linker}; use crate::building::output::{compile_project, CompileError}; use crate::building::plan::{BuildPlan, BuildTarget}; +use crate::common::files::FileManager; use crate::deps::resolver::ResolvedGraph; use prometeu_core::virtual_machine::ProgramImage; use std::collections::HashMap; @@ -11,6 +12,12 @@ pub enum BuildError { Link(LinkError), } +#[derive(Debug, Clone)] +pub struct BuildResult { + pub image: ProgramImage, + pub file_manager: FileManager, +} + impl std::fmt::Display for BuildError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -34,17 +41,21 @@ impl From for BuildError { } } -pub fn build_from_graph(graph: &ResolvedGraph, target: BuildTarget) -> Result { +pub fn build_from_graph(graph: &ResolvedGraph, target: BuildTarget) -> Result { let plan = BuildPlan::from_graph(graph, target); let mut compiled_modules = HashMap::new(); let mut modules_in_order = Vec::new(); + let mut file_manager = FileManager::new(); for step in &plan.steps { - let compiled = compile_project(step.clone(), &compiled_modules)?; + let compiled = compile_project(step.clone(), &compiled_modules, &mut file_manager)?; compiled_modules.insert(step.project_id.clone(), compiled.clone()); modules_in_order.push(compiled); } let program_image = Linker::link(modules_in_order, plan.steps)?; - Ok(program_image) + Ok(BuildResult { + image: program_image, + file_manager, + }) } diff --git a/crates/prometeu-compiler/src/building/output.rs b/crates/prometeu-compiler/src/building/output.rs index b45163a8..aad61606 100644 --- a/crates/prometeu-compiler/src/building/output.rs +++ b/crates/prometeu-compiler/src/building/output.rs @@ -108,10 +108,9 @@ impl ModuleProvider for ProjectModuleProvider { pub fn compile_project( step: BuildStep, - dep_modules: &HashMap + dep_modules: &HashMap, + file_manager: &mut FileManager, ) -> Result { - let mut file_manager = FileManager::new(); - // 1. Parse all files and group symbols by module let mut module_symbols_map: HashMap = HashMap::new(); let mut parsed_files: Vec<(String, FileNode)> = Vec::new(); // (module_path, ast) @@ -387,7 +386,8 @@ mod tests { deps: BTreeMap::new(), }; - let compiled = compile_project(step, &HashMap::new()).expect("Failed to compile project"); + let mut file_manager = FileManager::new(); + let compiled = compile_project(step, &HashMap::new(), &mut file_manager).expect("Failed to compile project"); assert_eq!(compiled.project_id, project_id); assert_eq!(compiled.target, BuildTarget::Main); diff --git a/crates/prometeu-compiler/src/common/files.rs b/crates/prometeu-compiler/src/common/files.rs index 7ea479a5..630293c8 100644 --- a/crates/prometeu-compiler/src/common/files.rs +++ b/crates/prometeu-compiler/src/common/files.rs @@ -1,12 +1,14 @@ use std::path::PathBuf; use std::sync::Arc; +#[derive(Debug, Clone)] pub struct SourceFile { pub id: usize, pub path: PathBuf, pub source: Arc, } +#[derive(Debug, Clone)] pub struct FileManager { files: Vec, } @@ -57,3 +59,28 @@ impl FileManager { (line, col) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_lookup_pos() { + let mut fm = FileManager::new(); + let source = "line1\nline2\n line3".to_string(); + let file_id = fm.add(PathBuf::from("test.pbs"), source); + + // "l" in line 1 + assert_eq!(fm.lookup_pos(file_id, 0), (1, 1)); + // "e" in line 1 + assert_eq!(fm.lookup_pos(file_id, 3), (1, 4)); + // "\n" after line 1 + assert_eq!(fm.lookup_pos(file_id, 5), (1, 6)); + // "l" in line 2 + assert_eq!(fm.lookup_pos(file_id, 6), (2, 1)); + // first space in line 3 + assert_eq!(fm.lookup_pos(file_id, 12), (3, 1)); + // "l" in line 3 + assert_eq!(fm.lookup_pos(file_id, 14), (3, 3)); + } +} diff --git a/crates/prometeu-compiler/src/common/symbols.rs b/crates/prometeu-compiler/src/common/symbols.rs index 42484dcd..1b024b66 100644 --- a/crates/prometeu-compiler/src/common/symbols.rs +++ b/crates/prometeu-compiler/src/common/symbols.rs @@ -1,6 +1,13 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; +use crate::common::spans::Span; -#[derive(Serialize, Debug, Clone)] +#[derive(Debug, Clone)] +pub struct RawSymbol { + pub pc: u32, + pub span: Span, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct Symbol { pub pc: u32, pub file: String, diff --git a/crates/prometeu-compiler/src/compiler.rs b/crates/prometeu-compiler/src/compiler.rs index 0aad62ac..4d2196d8 100644 --- a/crates/prometeu-compiler/src/compiler.rs +++ b/crates/prometeu-compiler/src/compiler.rs @@ -5,7 +5,9 @@ use crate::backend; use crate::common::config::ProjectConfig; -use crate::common::symbols::Symbol; +use crate::common::symbols::{Symbol, RawSymbol}; +use crate::common::files::FileManager; +use crate::common::spans::Span; use anyhow::Result; use prometeu_bytecode::BytecodeModule; use std::path::Path; @@ -20,7 +22,10 @@ pub struct CompilationUnit { /// The list of debug symbols discovered during compilation. /// These are used to map bytecode offsets back to source code locations. - pub symbols: Vec, + pub raw_symbols: Vec, + + /// The file manager containing all source files used during compilation. + pub file_manager: FileManager, } impl CompilationUnit { @@ -31,7 +36,23 @@ impl CompilationUnit { /// * `emit_disasm` - If true, a `.disasm` file will be created next to the output. /// * `emit_symbols` - If true, a `.json` symbols file will be created next to the output. pub fn export(&self, out: &Path, emit_disasm: bool, emit_symbols: bool) -> Result<()> { - let artifacts = backend::artifacts::Artifacts::new(self.rom.clone(), self.symbols.clone()); + let mut symbols = Vec::new(); + for raw in &self.raw_symbols { + let path = self.file_manager.get_path(raw.span.file_id) + .map(|p| p.to_string_lossy().to_string()) + .unwrap_or_else(|| format!("file_{}", raw.span.file_id)); + + let (line, col) = self.file_manager.lookup_pos(raw.span.file_id, raw.span.start); + + symbols.push(Symbol { + pc: raw.pc, + file: path, + line, + col, + }); + } + + let artifacts = backend::artifacts::Artifacts::new(self.rom.clone(), symbols); artifacts.export(out, emit_disasm, emit_symbols) } } @@ -67,27 +88,30 @@ pub fn compile_ext(project_dir: &Path, explain_deps: bool) -> Result = func.body.iter().map(|i| &i.kind).collect(); @@ -396,4 +419,49 @@ mod tests { assert!(result.is_ok(), "Failed to compile: {:?}", result.err()); } + + #[test] + fn test_symbols_emission_integration() { + let dir = tempdir().unwrap(); + let project_dir = dir.path(); + + fs::write( + project_dir.join("prometeu.json"), + r#"{ + "name": "symbols_test", + "version": "0.1.0", + "script_fe": "pbs", + "entry": "src/main/modules/main.pbs" + }"#, + ).unwrap(); + + let code = r#" + fn frame(): void { + let x = 10; + } + "#; + fs::create_dir_all(project_dir.join("src/main/modules")).unwrap(); + fs::write(project_dir.join("src/main/modules/main.pbs"), code).unwrap(); + + let unit = compile(project_dir).expect("Failed to compile"); + let out_pbc = project_dir.join("build/program.pbc"); + fs::create_dir_all(out_pbc.parent().unwrap()).unwrap(); + + unit.export(&out_pbc, false, true).expect("Failed to export"); + + let symbols_path = project_dir.join("build/symbols.json"); + assert!(symbols_path.exists(), "symbols.json should exist at {:?}", symbols_path); + + let symbols_content = fs::read_to_string(symbols_path).unwrap(); + let symbols: Vec = serde_json::from_str(&symbols_content).unwrap(); + + assert!(!symbols.is_empty(), "Symbols list should not be empty"); + + // Check for non-zero line/col + let main_sym = symbols.iter().find(|s| s.line > 0 && s.col > 0); + assert!(main_sym.is_some(), "Should find at least one symbol with real location"); + + let sym = main_sym.unwrap(); + assert!(sym.file.contains("main.pbs"), "Symbol file should point to main.pbs, got {}", sym.file); + } } diff --git a/crates/prometeu-compiler/src/frontends/pbs/lowering.rs b/crates/prometeu-compiler/src/frontends/pbs/lowering.rs index a1638a33..a6e1444b 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/lowering.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/lowering.rs @@ -1,11 +1,12 @@ use crate::common::diagnostics::{Diagnostic, DiagnosticBundle, DiagnosticLevel}; +use crate::common::spans::Span; use crate::frontends::pbs::ast::*; use crate::frontends::pbs::contracts::ContractRegistry; use crate::frontends::pbs::symbols::*; use crate::frontends::pbs::types::PbsType; use crate::ir_core; use crate::ir_core::ids::{FieldId, FunctionId, TypeId, ValueId}; -use crate::ir_core::{Block, Function, Instr, Module, Param, Program, Terminator, Type}; +use crate::ir_core::{Block, Function, Instr, InstrKind, Module, Param, Program, Terminator, Type}; use std::collections::HashMap; #[derive(Clone)] @@ -33,6 +34,7 @@ pub struct Lowerer<'a> { contract_registry: ContractRegistry, diagnostics: Vec, max_slots_used: u32, + current_span: Option, } impl<'a> Lowerer<'a> { @@ -70,6 +72,7 @@ impl<'a> Lowerer<'a> { contract_registry: ContractRegistry::new(), diagnostics: Vec::new(), max_slots_used: 0, + current_span: None, } } @@ -264,28 +267,31 @@ impl<'a> Lowerer<'a> { } fn lower_node(&mut self, node: &Node) -> Result<(), ()> { - match node { + let old_span = self.current_span; + self.current_span = Some(node.span()); + + let res = match node { Node::Block(n) => self.lower_block(n), Node::LetStmt(n) => self.lower_let_stmt(n), Node::ExprStmt(n) => self.lower_node(&n.expr), Node::ReturnStmt(n) => self.lower_return_stmt(n), Node::IntLit(n) => { let id = self.program.const_pool.add_int(n.value); - self.emit(Instr::PushConst(id)); + self.emit(InstrKind::PushConst(id)); Ok(()) } Node::FloatLit(n) => { let id = self.program.const_pool.add_float(n.value); - self.emit(Instr::PushConst(id)); + self.emit(InstrKind::PushConst(id)); Ok(()) } Node::StringLit(n) => { let id = self.program.const_pool.add_string(n.value.clone()); - self.emit(Instr::PushConst(id)); + self.emit(InstrKind::PushConst(id)); Ok(()) } Node::BoundedLit(n) => { - self.emit(Instr::PushBounded(n.value)); + self.emit(InstrKind::PushBounded(n.value)); Ok(()) } Node::Ident(n) => self.lower_ident(n), @@ -304,12 +310,15 @@ impl<'a> Lowerer<'a> { self.error("E_LOWER_UNSUPPORTED", format!("Lowering for node kind {:?} not supported", node), node.span()); Err(()) } - } + }; + + self.current_span = old_span; + res } fn lower_alloc(&mut self, n: &AllocNode) -> Result<(), ()> { let (ty_id, slots) = self.get_type_id_and_slots(&n.ty)?; - self.emit(Instr::Alloc { ty: ty_id, slots }); + self.emit(InstrKind::Alloc { ty: ty_id, slots }); Ok(()) } @@ -359,22 +368,22 @@ impl<'a> Lowerer<'a> { // 2. Preserve gate identity let gate_slot = self.add_local_to_scope(format!("$gate_{}", self.get_next_local_slot()), Type::Int); - self.emit(Instr::SetLocal(gate_slot)); + self.emit(InstrKind::SetLocal(gate_slot)); // 3. Begin Operation - self.emit(Instr::BeginPeek { gate: ValueId(gate_slot) }); - self.emit(Instr::GateLoadField { gate: ValueId(gate_slot), field: FieldId(0) }); + self.emit(InstrKind::BeginPeek { gate: ValueId(gate_slot) }); + self.emit(InstrKind::GateLoadField { gate: ValueId(gate_slot), field: FieldId(0) }); // 4. Bind view to local self.local_vars.push(HashMap::new()); let view_slot = self.add_local_to_scope(n.binding.to_string(), Type::Int); - self.emit(Instr::SetLocal(view_slot)); + self.emit(InstrKind::SetLocal(view_slot)); // 5. Body self.lower_node(&n.body)?; // 6. End Operation - self.emit(Instr::EndPeek); + self.emit(InstrKind::EndPeek); self.local_vars.pop(); Ok(()) @@ -386,22 +395,22 @@ impl<'a> Lowerer<'a> { // 2. Preserve gate identity let gate_slot = self.add_local_to_scope(format!("$gate_{}", self.get_next_local_slot()), Type::Int); - self.emit(Instr::SetLocal(gate_slot)); + self.emit(InstrKind::SetLocal(gate_slot)); // 3. Begin Operation - self.emit(Instr::BeginBorrow { gate: ValueId(gate_slot) }); - self.emit(Instr::GateLoadField { gate: ValueId(gate_slot), field: FieldId(0) }); + self.emit(InstrKind::BeginBorrow { gate: ValueId(gate_slot) }); + self.emit(InstrKind::GateLoadField { gate: ValueId(gate_slot), field: FieldId(0) }); // 4. Bind view to local self.local_vars.push(HashMap::new()); let view_slot = self.add_local_to_scope(n.binding.to_string(), Type::Int); - self.emit(Instr::SetLocal(view_slot)); + self.emit(InstrKind::SetLocal(view_slot)); // 5. Body self.lower_node(&n.body)?; // 6. End Operation - self.emit(Instr::EndBorrow); + self.emit(InstrKind::EndBorrow); self.local_vars.pop(); Ok(()) @@ -413,22 +422,22 @@ impl<'a> Lowerer<'a> { // 2. Preserve gate identity let gate_slot = self.add_local_to_scope(format!("$gate_{}", self.get_next_local_slot()), Type::Int); - self.emit(Instr::SetLocal(gate_slot)); + self.emit(InstrKind::SetLocal(gate_slot)); // 3. Begin Operation - self.emit(Instr::BeginMutate { gate: ValueId(gate_slot) }); - self.emit(Instr::GateLoadField { gate: ValueId(gate_slot), field: FieldId(0) }); + self.emit(InstrKind::BeginMutate { gate: ValueId(gate_slot) }); + self.emit(InstrKind::GateLoadField { gate: ValueId(gate_slot), field: FieldId(0) }); // 4. Bind view to local self.local_vars.push(HashMap::new()); let view_slot = self.add_local_to_scope(n.binding.to_string(), Type::Int); - self.emit(Instr::SetLocal(view_slot)); + self.emit(InstrKind::SetLocal(view_slot)); // 5. Body self.lower_node(&n.body)?; // 6. End Operation - self.emit(Instr::EndMutate); + self.emit(InstrKind::EndMutate); self.local_vars.pop(); Ok(()) @@ -470,7 +479,7 @@ impl<'a> Lowerer<'a> { let slot = self.add_local_to_scope(n.name.clone(), ty); for i in (0..slots).rev() { - self.emit(Instr::SetLocal(slot + i)); + self.emit(InstrKind::SetLocal(slot + i)); } Ok(()) } @@ -487,7 +496,7 @@ impl<'a> Lowerer<'a> { if let Some(info) = self.find_local(&n.name) { let slots = self.get_type_slots(&info.ty); for i in 0..slots { - self.emit(Instr::GetLocal(info.slot + i)); + self.emit(InstrKind::GetLocal(info.slot + i)); } Ok(()) } else { @@ -495,18 +504,18 @@ impl<'a> Lowerer<'a> { match n.name.as_str() { "true" => { let id = self.program.const_pool.add_int(1); - self.emit(Instr::PushConst(id)); + self.emit(InstrKind::PushConst(id)); return Ok(()); } "false" => { let id = self.program.const_pool.add_int(0); - self.emit(Instr::PushConst(id)); + self.emit(InstrKind::PushConst(id)); return Ok(()); } "none" => { // For now, treat none as 0. This should be refined when optional is fully implemented. let id = self.program.const_pool.add_int(0); - self.emit(Instr::PushConst(id)); + self.emit(InstrKind::PushConst(id)); return Ok(()); } _ => {} @@ -550,7 +559,7 @@ impl<'a> Lowerer<'a> { return Ok(()); } }; - self.emit(Instr::PushBounded(val)); + self.emit(InstrKind::PushBounded(val)); return Ok(()); } } @@ -558,7 +567,7 @@ impl<'a> Lowerer<'a> { if let Some((slot, ty)) = self.resolve_member_access(n) { let slots = self.get_type_slots(&ty); for i in 0..slots { - self.emit(Instr::GetLocal(slot + i)); + self.emit(InstrKind::GetLocal(slot + i)); } return Ok(()); } @@ -663,7 +672,7 @@ impl<'a> Lowerer<'a> { self.lower_node(arg)?; } if let Some(func_id) = self.function_ids.get(&id_node.name) { - self.emit(Instr::Call(*func_id, n.args.len() as u32)); + self.emit(InstrKind::Call(*func_id, n.args.len() as u32)); Ok(()) } else if let Some(sym) = self.imported_symbols.value_symbols.get(&id_node.name) { if let Some(origin) = &sym.origin { @@ -673,7 +682,7 @@ impl<'a> Lowerer<'a> { if parts.len() == 2 { let dep_alias = parts[0].to_string(); let module_path = parts[1].to_string(); - self.emit(Instr::ImportCall(dep_alias, module_path, sym.name.clone(), n.args.len() as u32)); + self.emit(InstrKind::ImportCall(dep_alias, module_path, sym.name.clone(), n.args.len() as u32)); return Ok(()); } } @@ -739,7 +748,7 @@ impl<'a> Lowerer<'a> { if let Some(method) = self.contract_registry.get_method(&obj_id.name, &ma.member) { let id = method.id; let return_slots = if matches!(method.return_type, PbsType::Void) { 0 } else { 1 }; - self.emit(Instr::HostCall(id, return_slots)); + self.emit(InstrKind::HostCall(id, return_slots)); return Ok(()); } } @@ -773,7 +782,7 @@ impl<'a> Lowerer<'a> { let g6 = (g & 0xFF) >> 2; let b5 = (b & 0xFF) >> 3; let rgb565 = (r5 << 11) | (g6 << 5) | b5; - self.emit(Instr::PushBounded(rgb565 as u32)); + self.emit(InstrKind::PushBounded(rgb565 as u32)); return Ok(()); } else { self.error("E_LOWER_UNSUPPORTED", "Color.rgb only supports literal arguments in this version".to_string(), n.span); @@ -799,7 +808,7 @@ impl<'a> Lowerer<'a> { if let Some(method) = self.contract_registry.get_method(&obj_id.name, &ma.member) { let ir_ty = self.convert_pbs_type(&method.return_type); let return_slots = self.get_type_slots(&ir_ty); - self.emit(Instr::HostCall(method.id, return_slots)); + self.emit(InstrKind::HostCall(method.id, return_slots)); return Ok(()); } else { self.error("E_RESOLVE_UNDEFINED", format!("Undefined contract member '{}.{}'", obj_id.name, ma.member), ma.span); @@ -874,13 +883,13 @@ impl<'a> Lowerer<'a> { fn lower_pad_any(&mut self, base_slot: u32) { for i in 0..12 { let btn_base = base_slot + (i * 4); - self.emit(Instr::GetLocal(btn_base)); // pressed - self.emit(Instr::GetLocal(btn_base + 1)); // released - self.emit(Instr::Or); - self.emit(Instr::GetLocal(btn_base + 2)); // down - self.emit(Instr::Or); + self.emit(InstrKind::GetLocal(btn_base)); // pressed + self.emit(InstrKind::GetLocal(btn_base + 1)); // released + self.emit(InstrKind::Or); + self.emit(InstrKind::GetLocal(btn_base + 2)); // down + self.emit(InstrKind::Or); if i > 0 { - self.emit(Instr::Or); + self.emit(InstrKind::Or); } } } @@ -889,18 +898,18 @@ impl<'a> Lowerer<'a> { self.lower_node(&n.left)?; self.lower_node(&n.right)?; match n.op.as_str() { - "+" => self.emit(Instr::Add), - "-" => self.emit(Instr::Sub), - "*" => self.emit(Instr::Mul), - "/" => self.emit(Instr::Div), - "==" => self.emit(Instr::Eq), - "!=" => self.emit(Instr::Neq), - "<" => self.emit(Instr::Lt), - "<=" => self.emit(Instr::Lte), - ">" => self.emit(Instr::Gt), - ">=" => self.emit(Instr::Gte), - "&&" => self.emit(Instr::And), - "||" => self.emit(Instr::Or), + "+" => self.emit(InstrKind::Add), + "-" => self.emit(InstrKind::Sub), + "*" => self.emit(InstrKind::Mul), + "/" => self.emit(InstrKind::Div), + "==" => self.emit(InstrKind::Eq), + "!=" => self.emit(InstrKind::Neq), + "<" => self.emit(InstrKind::Lt), + "<=" => self.emit(InstrKind::Lte), + ">" => self.emit(InstrKind::Gt), + ">=" => self.emit(InstrKind::Gte), + "&&" => self.emit(InstrKind::And), + "||" => self.emit(InstrKind::Or), _ => { self.error("E_LOWER_UNSUPPORTED", format!("Binary operator '{}' not supported", n.op), n.span); return Err(()); @@ -912,8 +921,8 @@ impl<'a> Lowerer<'a> { fn lower_unary(&mut self, n: &UnaryNode) -> Result<(), ()> { self.lower_node(&n.expr)?; match n.op.as_str() { - "-" => self.emit(Instr::Neg), - "!" => self.emit(Instr::Not), + "-" => self.emit(InstrKind::Neg), + "!" => self.emit(InstrKind::Not), _ => { self.error("E_LOWER_UNSUPPORTED", format!("Unary operator '{}' not supported", n.op), n.span); return Err(()); @@ -1013,9 +1022,9 @@ impl<'a> Lowerer<'a> { id } - fn emit(&mut self, instr: Instr) { + fn emit(&mut self, kind: InstrKind) { if let Some(block) = &mut self.current_block { - block.instrs.push(instr); + block.instrs.push(Instr::new(kind, self.current_span)); } } @@ -1151,7 +1160,7 @@ mod tests { assert!(add_func.blocks.len() >= 1); let first_block = &add_func.blocks[0]; // Check for Add instruction - assert!(first_block.instrs.iter().any(|i| matches!(i, ir_core::Instr::Add))); + assert!(first_block.instrs.iter().any(|i| matches!(i.kind, ir_core::InstrKind::Add))); } #[test] @@ -1203,9 +1212,9 @@ mod tests { let func = &program.modules[0].functions[0]; let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); - assert!(instrs.iter().any(|i| matches!(i, ir_core::Instr::Alloc { .. }))); - assert!(instrs.iter().any(|i| matches!(i, ir_core::Instr::BeginMutate { .. }))); - assert!(instrs.iter().any(|i| matches!(i, ir_core::Instr::EndMutate))); + assert!(instrs.iter().any(|i| matches!(i.kind, ir_core::InstrKind::Alloc { .. }))); + assert!(instrs.iter().any(|i| matches!(i.kind, ir_core::InstrKind::BeginMutate { .. }))); + assert!(instrs.iter().any(|i| matches!(i.kind, ir_core::InstrKind::EndMutate))); } #[test] @@ -1273,14 +1282,14 @@ mod tests { let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); // Assert distinct Core IR instruction sequences - assert!(instrs.iter().any(|i| matches!(i, Instr::BeginPeek { .. }))); - assert!(instrs.iter().any(|i| matches!(i, Instr::EndPeek))); + assert!(instrs.iter().any(|i| matches!(i.kind, InstrKind::BeginPeek { .. }))); + assert!(instrs.iter().any(|i| matches!(i.kind, InstrKind::EndPeek))); - assert!(instrs.iter().any(|i| matches!(i, Instr::BeginBorrow { .. }))); - assert!(instrs.iter().any(|i| matches!(i, Instr::EndBorrow))); + assert!(instrs.iter().any(|i| matches!(i.kind, InstrKind::BeginBorrow { .. }))); + assert!(instrs.iter().any(|i| matches!(i.kind, InstrKind::EndBorrow))); - assert!(instrs.iter().any(|i| matches!(i, Instr::BeginMutate { .. }))); - assert!(instrs.iter().any(|i| matches!(i, Instr::EndMutate))); + assert!(instrs.iter().any(|i| matches!(i.kind, InstrKind::BeginMutate { .. }))); + assert!(instrs.iter().any(|i| matches!(i.kind, InstrKind::EndMutate))); } #[test] @@ -1307,9 +1316,9 @@ mod tests { let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); // Gfx.clear -> 0x1010 - assert!(instrs.iter().any(|i| matches!(i, ir_core::Instr::HostCall(0x1010, 0)))); + assert!(instrs.iter().any(|i| matches!(i.kind, ir_core::InstrKind::HostCall(0x1010, 0)))); // Log.write -> 0x5001 - assert!(instrs.iter().any(|i| matches!(i, ir_core::Instr::HostCall(0x5001, 0)))); + assert!(instrs.iter().any(|i| matches!(i.kind, ir_core::InstrKind::HostCall(0x5001, 0)))); } #[test] @@ -1404,7 +1413,7 @@ mod tests { let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); let alloc = instrs.iter().find_map(|i| { - if let Instr::Alloc { ty, slots } = i { + if let InstrKind::Alloc { ty, slots } = &i.kind { Some((ty, slots)) } else { None @@ -1436,7 +1445,7 @@ mod tests { let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); let alloc = instrs.iter().find_map(|i| { - if let Instr::Alloc { ty, slots } = i { + if let InstrKind::Alloc { ty, slots } = &i.kind { Some((ty, slots)) } else { None @@ -1468,7 +1477,7 @@ mod tests { let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); let alloc = instrs.iter().find_map(|i| { - if let Instr::Alloc { ty, slots } = i { + if let InstrKind::Alloc { ty, slots } = &i.kind { Some((ty, slots)) } else { None diff --git a/crates/prometeu-compiler/src/ir_core/instr.rs b/crates/prometeu-compiler/src/ir_core/instr.rs index 07498df1..621d6411 100644 --- a/crates/prometeu-compiler/src/ir_core/instr.rs +++ b/crates/prometeu-compiler/src/ir_core/instr.rs @@ -1,9 +1,22 @@ use super::ids::{ConstId, FieldId, FunctionId, TypeId, ValueId}; +use crate::common::spans::Span; use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct Instr { + pub kind: InstrKind, + pub span: Option, +} + +impl Instr { + pub fn new(kind: InstrKind, span: Option) -> Self { + Self { kind, span } + } +} + /// Instructions within a basic block. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub enum Instr { +pub enum InstrKind { /// Placeholder for constant loading. PushConst(ConstId), /// Push a bounded value (0..0xFFFF). @@ -54,3 +67,9 @@ pub enum Instr { GateStoreIndex { gate: ValueId, index: ValueId, value: ValueId }, Free, } + +impl From for Instr { + fn from(kind: InstrKind) -> Self { + Self::new(kind, None) + } +} diff --git a/crates/prometeu-compiler/src/ir_core/mod.rs b/crates/prometeu-compiler/src/ir_core/mod.rs index 401c3067..b10e84cf 100644 --- a/crates/prometeu-compiler/src/ir_core/mod.rs +++ b/crates/prometeu-compiler/src/ir_core/mod.rs @@ -45,8 +45,8 @@ mod tests { blocks: vec![Block { id: 0, instrs: vec![ - Instr::PushConst(ConstId(0)), - Instr::Call(FunctionId(11), 0), + Instr::from(InstrKind::PushConst(ConstId(0))), + Instr::from(InstrKind::Call(FunctionId(11), 0)), ], terminator: Terminator::Return, }], @@ -81,13 +81,19 @@ mod tests { "id": 0, "instrs": [ { - "PushConst": 0 + "kind": { + "PushConst": 0 + }, + "span": null }, { - "Call": [ - 11, - 0 - ] + "kind": { + "Call": [ + 11, + 0 + ] + }, + "span": null } ], "terminator": "Return" diff --git a/crates/prometeu-compiler/src/ir_core/validate.rs b/crates/prometeu-compiler/src/ir_core/validate.rs index 8e597433..a8ca8c39 100644 --- a/crates/prometeu-compiler/src/ir_core/validate.rs +++ b/crates/prometeu-compiler/src/ir_core/validate.rs @@ -1,5 +1,5 @@ use super::ids::ValueId; -use super::instr::Instr; +use super::instr::{InstrKind}; use super::program::Program; use super::terminator::Terminator; use std::collections::{HashMap, VecDeque}; @@ -57,54 +57,54 @@ fn validate_function(func: &super::function::Function) -> Result<(), String> { visited_with_stack.insert(block_id, current_stack.clone()); for instr in &block.instrs { - match instr { - Instr::BeginPeek { gate } => { + match &instr.kind { + InstrKind::BeginPeek { gate } => { current_stack.push(HipOp { kind: HipOpKind::Peek, gate: *gate }); } - Instr::BeginBorrow { gate } => { + InstrKind::BeginBorrow { gate } => { current_stack.push(HipOp { kind: HipOpKind::Borrow, gate: *gate }); } - Instr::BeginMutate { gate } => { + InstrKind::BeginMutate { gate } => { current_stack.push(HipOp { kind: HipOpKind::Mutate, gate: *gate }); } - Instr::EndPeek => { + InstrKind::EndPeek => { match current_stack.pop() { Some(op) if op.kind == HipOpKind::Peek => {}, Some(op) => return Err(format!("EndPeek doesn't match current HIP op: {:?}", op)), None => return Err("EndPeek without matching BeginPeek".to_string()), } } - Instr::EndBorrow => { + InstrKind::EndBorrow => { match current_stack.pop() { Some(op) if op.kind == HipOpKind::Borrow => {}, Some(op) => return Err(format!("EndBorrow doesn't match current HIP op: {:?}", op)), None => return Err("EndBorrow without matching BeginBorrow".to_string()), } } - Instr::EndMutate => { + InstrKind::EndMutate => { match current_stack.pop() { Some(op) if op.kind == HipOpKind::Mutate => {}, Some(op) => return Err(format!("EndMutate doesn't match current HIP op: {:?}", op)), None => return Err("EndMutate without matching BeginMutate".to_string()), } } - Instr::GateLoadField { .. } | Instr::GateLoadIndex { .. } => { + InstrKind::GateLoadField { .. } | InstrKind::GateLoadIndex { .. } => { if current_stack.is_empty() { return Err("GateLoad outside of HIP operation".to_string()); } } - Instr::GateStoreField { .. } | Instr::GateStoreIndex { .. } => { + InstrKind::GateStoreField { .. } | InstrKind::GateStoreIndex { .. } => { match current_stack.last() { Some(op) if op.kind == HipOpKind::Mutate => {}, _ => return Err("GateStore outside of BeginMutate".to_string()), } } - Instr::Call(id, _) => { + InstrKind::Call(id, _) => { if id.0 == 0 { return Err("Call to FunctionId(0)".to_string()); } } - Instr::Alloc { ty, .. } => { + InstrKind::Alloc { ty, .. } => { if ty.0 == 0 { return Err("Alloc with TypeId(0)".to_string()); } @@ -185,12 +185,12 @@ mod tests { let block = Block { id: 0, instrs: vec![ - Instr::BeginPeek { gate: ValueId(0) }, - Instr::GateLoadField { gate: ValueId(0), field: FieldId(0) }, - Instr::BeginMutate { gate: ValueId(1) }, - Instr::GateStoreField { gate: ValueId(1), field: FieldId(0), value: ValueId(2) }, - Instr::EndMutate, - Instr::EndPeek, + Instr::from(InstrKind::BeginPeek { gate: ValueId(0) }), + Instr::from(InstrKind::GateLoadField { gate: ValueId(0), field: FieldId(0) }), + Instr::from(InstrKind::BeginMutate { gate: ValueId(1) }), + Instr::from(InstrKind::GateStoreField { gate: ValueId(1), field: FieldId(0), value: ValueId(2) }), + Instr::from(InstrKind::EndMutate), + Instr::from(InstrKind::EndPeek), ], terminator: Terminator::Return, }; @@ -203,7 +203,7 @@ mod tests { let block = Block { id: 0, instrs: vec![ - Instr::BeginPeek { gate: ValueId(0) }, + Instr::from(InstrKind::BeginPeek { gate: ValueId(0) }), ], terminator: Terminator::Return, }; @@ -218,8 +218,8 @@ mod tests { let block = Block { id: 0, instrs: vec![ - Instr::BeginPeek { gate: ValueId(0) }, - Instr::EndMutate, + Instr::from(InstrKind::BeginPeek { gate: ValueId(0) }), + Instr::from(InstrKind::EndMutate), ], terminator: Terminator::Return, }; @@ -234,9 +234,9 @@ mod tests { let block = Block { id: 0, instrs: vec![ - Instr::BeginBorrow { gate: ValueId(0) }, - Instr::GateStoreField { gate: ValueId(0), field: FieldId(0), value: ValueId(1) }, - Instr::EndBorrow, + Instr::from(InstrKind::BeginBorrow { gate: ValueId(0) }), + Instr::from(InstrKind::GateStoreField { gate: ValueId(0), field: FieldId(0), value: ValueId(1) }), + Instr::from(InstrKind::EndBorrow), ], terminator: Terminator::Return, }; @@ -251,9 +251,9 @@ mod tests { let block = Block { id: 0, instrs: vec![ - Instr::BeginMutate { gate: ValueId(0) }, - Instr::GateStoreField { gate: ValueId(0), field: FieldId(0), value: ValueId(1) }, - Instr::EndMutate, + Instr::from(InstrKind::BeginMutate { gate: ValueId(0) }), + Instr::from(InstrKind::GateStoreField { gate: ValueId(0), field: FieldId(0), value: ValueId(1) }), + Instr::from(InstrKind::EndMutate), ], terminator: Terminator::Return, }; @@ -266,7 +266,7 @@ mod tests { let block = Block { id: 0, instrs: vec![ - Instr::GateLoadField { gate: ValueId(0), field: FieldId(0) }, + Instr::from(InstrKind::GateLoadField { gate: ValueId(0), field: FieldId(0) }), ], terminator: Terminator::Return, }; @@ -281,15 +281,15 @@ mod tests { let block0 = Block { id: 0, instrs: vec![ - Instr::BeginPeek { gate: ValueId(0) }, + Instr::from(InstrKind::BeginPeek { gate: ValueId(0) }), ], terminator: Terminator::Jump(1), }; let block1 = Block { id: 1, instrs: vec![ - Instr::GateLoadField { gate: ValueId(0), field: FieldId(0) }, - Instr::EndPeek, + Instr::from(InstrKind::GateLoadField { gate: ValueId(0), field: FieldId(0) }), + Instr::from(InstrKind::EndPeek), ], terminator: Terminator::Return, }; @@ -302,14 +302,14 @@ mod tests { let block0 = Block { id: 0, instrs: vec![ - Instr::PushConst(ConstId(0)), // cond + Instr::from(InstrKind::PushConst(ConstId(0))), // cond ], terminator: Terminator::JumpIfFalse { target: 2, else_target: 1 }, }; let block1 = Block { id: 1, instrs: vec![ - Instr::BeginPeek { gate: ValueId(0) }, + Instr::from(InstrKind::BeginPeek { gate: ValueId(0) }), ], terminator: Terminator::Jump(3), }; @@ -323,7 +323,7 @@ mod tests { let block3 = Block { id: 3, instrs: vec![ - Instr::EndPeek, // ERROR: block 2 reaches here with empty stack + Instr::from(InstrKind::EndPeek), // ERROR: block 2 reaches here with empty stack ], terminator: Terminator::Return, }; @@ -338,7 +338,7 @@ mod tests { let block_func0 = Block { id: 0, instrs: vec![ - Instr::Call(FunctionId(0), 0), + Instr::from(InstrKind::Call(FunctionId(0), 0)), ], terminator: Terminator::Return, }; @@ -348,7 +348,7 @@ mod tests { let block_ty0 = Block { id: 0, instrs: vec![ - Instr::Alloc { ty: TypeId(0), slots: 1 }, + Instr::from(InstrKind::Alloc { ty: TypeId(0), slots: 1 }), ], terminator: Terminator::Return, }; diff --git a/crates/prometeu-compiler/src/ir_vm/mod.rs b/crates/prometeu-compiler/src/ir_vm/mod.rs index 125879e8..6361cd46 100644 --- a/crates/prometeu-compiler/src/ir_vm/mod.rs +++ b/crates/prometeu-compiler/src/ir_vm/mod.rs @@ -136,7 +136,7 @@ mod tests { blocks: vec![ir_core::Block { id: 0, instrs: vec![ - ir_core::Instr::PushConst(ConstId(0)), + ir_core::Instr::from(ir_core::InstrKind::PushConst(ConstId(0))), ], terminator: ir_core::Terminator::Return, }], diff --git a/crates/prometeu-compiler/src/lib.rs b/crates/prometeu-compiler/src/lib.rs index 423d6a83..c4bc559d 100644 --- a/crates/prometeu-compiler/src/lib.rs +++ b/crates/prometeu-compiler/src/lib.rs @@ -80,13 +80,21 @@ pub enum Commands { #[arg(short, long)] out: Option, + /// Whether to generate a .json symbols file for source mapping. + #[arg(long, default_value_t = true)] + emit_symbols: bool, + + /// Disable symbol generation. + #[arg(long)] + no_symbols: bool, + /// Whether to generate a .disasm file for debugging. #[arg(long, default_value_t = true)] emit_disasm: bool, - /// Whether to generate a .json symbols file for source mapping. - #[arg(long, default_value_t = true)] - emit_symbols: bool, + /// Disable disassembly generation. + #[arg(long)] + no_disasm: bool, /// Whether to explain the dependency resolution process. #[arg(long)] @@ -113,13 +121,18 @@ pub fn run() -> Result<()> { project_dir, out, emit_disasm, + no_disasm, emit_symbols, + no_symbols, explain_deps, .. } => { let build_dir = project_dir.join("build"); let out = out.unwrap_or_else(|| build_dir.join("program.pbc")); + let emit_symbols = emit_symbols && !no_symbols; + let emit_disasm = emit_disasm && !no_disasm; + if !build_dir.exists() { std::fs::create_dir_all(&build_dir)?; } diff --git a/crates/prometeu-compiler/src/lowering/core_to_vm.rs b/crates/prometeu-compiler/src/lowering/core_to_vm.rs index 058349b5..450de4d3 100644 --- a/crates/prometeu-compiler/src/lowering/core_to_vm.rs +++ b/crates/prometeu-compiler/src/lowering/core_to_vm.rs @@ -81,8 +81,9 @@ pub fn lower_function( let mut stack_types = Vec::new(); for instr in &block.instrs { - match instr { - ir_core::Instr::PushConst(id) => { + let span = instr.span; + match &instr.kind { + ir_core::InstrKind::PushConst(id) => { let ty = if let Some(val) = program.const_pool.get(ir_core::ConstId(id.0)) { match val { ir_core::ConstantValue::Int(_) => ir_core::Type::Int, @@ -93,13 +94,13 @@ pub fn lower_function( ir_core::Type::Void }; stack_types.push(ty); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::PushConst(ir_vm::ConstId(id.0)), None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::PushConst(ir_vm::ConstId(id.0)), span)); } - ir_core::Instr::PushBounded(val) => { + ir_core::InstrKind::PushBounded(val) => { stack_types.push(ir_core::Type::Bounded); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::PushBounded(*val), None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::PushBounded(*val), span)); } - ir_core::Instr::Call(func_id, arg_count) => { + ir_core::InstrKind::Call(func_id, arg_count) => { // Pop arguments from type stack for _ in 0..*arg_count { stack_types.pop(); @@ -113,7 +114,7 @@ pub fn lower_function( arg_count: *arg_count }, None)); } - ir_core::Instr::ImportCall(dep_alias, module_path, symbol_name, arg_count) => { + ir_core::InstrKind::ImportCall(dep_alias, module_path, symbol_name, arg_count) => { // Pop arguments from type stack for _ in 0..*arg_count { stack_types.pop(); @@ -128,19 +129,19 @@ pub fn lower_function( arg_count: *arg_count, }, None)); } - ir_core::Instr::HostCall(id, slots) => { + ir_core::InstrKind::HostCall(id, slots) => { // HostCall return types are not easily known without a registry, // but we now pass the number of slots. for _ in 0..*slots { stack_types.push(ir_core::Type::Int); } - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Syscall(*id), None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Syscall(*id), span)); } - ir_core::Instr::GetLocal(slot) => { + ir_core::InstrKind::GetLocal(slot) => { let ty = local_types.get(slot).cloned().unwrap_or(ir_core::Type::Void); stack_types.push(ty.clone()); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: *slot }, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: *slot }, span)); // If it's a gate, we should retain it if we just pushed it onto stack? // "on assigning a gate to a local/global" @@ -149,18 +150,18 @@ pub fn lower_function( // Wait, if I Load it, I have a new handle on the stack. I should Retain it. if is_gate_type(&ty) { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); } } - ir_core::Instr::SetLocal(slot) => { + ir_core::InstrKind::SetLocal(slot) => { let new_ty = stack_types.pop().unwrap_or(ir_core::Type::Void); let old_ty = local_types.get(slot).cloned(); // 1. Release old value if it was a gate if let Some(old_ty) = old_ty { if is_gate_type(&old_ty) { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: *slot }, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: *slot }, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span)); } } @@ -173,121 +174,121 @@ pub fn lower_function( // Actually, if we Pop it later, we Release it. local_types.insert(*slot, new_ty); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalStore { slot: *slot }, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalStore { slot: *slot }, span)); } - ir_core::Instr::Pop => { + ir_core::InstrKind::Pop => { let ty = stack_types.pop().unwrap_or(ir_core::Type::Void); if is_gate_type(&ty) { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span)); } else { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Pop, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Pop, span)); } } - ir_core::Instr::Dup => { + ir_core::InstrKind::Dup => { let ty = stack_types.last().cloned().unwrap_or(ir_core::Type::Void); stack_types.push(ty.clone()); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Dup, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Dup, span)); if is_gate_type(&ty) { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); } } - ir_core::Instr::Add | ir_core::Instr::Sub | ir_core::Instr::Mul | ir_core::Instr::Div => { + ir_core::InstrKind::Add | ir_core::InstrKind::Sub | ir_core::InstrKind::Mul | ir_core::InstrKind::Div => { stack_types.pop(); stack_types.pop(); stack_types.push(ir_core::Type::Int); // Assume Int for arithmetic - let kind = match instr { - ir_core::Instr::Add => ir_vm::InstrKind::Add, - ir_core::Instr::Sub => ir_vm::InstrKind::Sub, - ir_core::Instr::Mul => ir_vm::InstrKind::Mul, - ir_core::Instr::Div => ir_vm::InstrKind::Div, + let kind = match &instr.kind { + ir_core::InstrKind::Add => ir_vm::InstrKind::Add, + ir_core::InstrKind::Sub => ir_vm::InstrKind::Sub, + ir_core::InstrKind::Mul => ir_vm::InstrKind::Mul, + ir_core::InstrKind::Div => ir_vm::InstrKind::Div, _ => unreachable!(), }; - vm_func.body.push(ir_vm::Instruction::new(kind, None)); + vm_func.body.push(ir_vm::Instruction::new(kind, span)); } - ir_core::Instr::Neg => { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Neg, None)); + ir_core::InstrKind::Neg => { + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Neg, span)); } - ir_core::Instr::Eq | ir_core::Instr::Neq | ir_core::Instr::Lt | ir_core::Instr::Lte | ir_core::Instr::Gt | ir_core::Instr::Gte => { + ir_core::InstrKind::Eq | ir_core::InstrKind::Neq | ir_core::InstrKind::Lt | ir_core::InstrKind::Lte | ir_core::InstrKind::Gt | ir_core::InstrKind::Gte => { stack_types.pop(); stack_types.pop(); stack_types.push(ir_core::Type::Bool); - let kind = match instr { - ir_core::Instr::Eq => ir_vm::InstrKind::Eq, - ir_core::Instr::Neq => ir_vm::InstrKind::Neq, - ir_core::Instr::Lt => ir_vm::InstrKind::Lt, - ir_core::Instr::Lte => ir_vm::InstrKind::Lte, - ir_core::Instr::Gt => ir_vm::InstrKind::Gt, - ir_core::Instr::Gte => ir_vm::InstrKind::Gte, + let kind = match &instr.kind { + ir_core::InstrKind::Eq => ir_vm::InstrKind::Eq, + ir_core::InstrKind::Neq => ir_vm::InstrKind::Neq, + ir_core::InstrKind::Lt => ir_vm::InstrKind::Lt, + ir_core::InstrKind::Lte => ir_vm::InstrKind::Lte, + ir_core::InstrKind::Gt => ir_vm::InstrKind::Gt, + ir_core::InstrKind::Gte => ir_vm::InstrKind::Gte, _ => unreachable!(), }; - vm_func.body.push(ir_vm::Instruction::new(kind, None)); + vm_func.body.push(ir_vm::Instruction::new(kind, span)); } - ir_core::Instr::And | ir_core::Instr::Or => { + ir_core::InstrKind::And | ir_core::InstrKind::Or => { stack_types.pop(); stack_types.pop(); stack_types.push(ir_core::Type::Bool); - let kind = match instr { - ir_core::Instr::And => ir_vm::InstrKind::And, - ir_core::Instr::Or => ir_vm::InstrKind::Or, + let kind = match &instr.kind { + ir_core::InstrKind::And => ir_vm::InstrKind::And, + ir_core::InstrKind::Or => ir_vm::InstrKind::Or, _ => unreachable!(), }; - vm_func.body.push(ir_vm::Instruction::new(kind, None)); + vm_func.body.push(ir_vm::Instruction::new(kind, span)); } - ir_core::Instr::Not => { + ir_core::InstrKind::Not => { stack_types.pop(); stack_types.push(ir_core::Type::Bool); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Not, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Not, span)); } - ir_core::Instr::Alloc { ty, slots } => { + ir_core::InstrKind::Alloc { ty, slots } => { stack_types.push(ir_core::Type::Struct("".to_string())); // It's a gate vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Alloc { type_id: ir_vm::TypeId(ty.0), slots: *slots }, None)); } - ir_core::Instr::BeginPeek { gate } => { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginPeek, None)); + ir_core::InstrKind::BeginPeek { gate } => { + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginPeek, span)); } - ir_core::Instr::BeginBorrow { gate } => { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginBorrow, None)); + ir_core::InstrKind::BeginBorrow { gate } => { + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginBorrow, span)); } - ir_core::Instr::BeginMutate { gate } => { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginMutate, None)); + ir_core::InstrKind::BeginMutate { gate } => { + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginMutate, span)); } - ir_core::Instr::EndPeek => { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndPeek, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, None)); + ir_core::InstrKind::EndPeek => { + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndPeek, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span)); } - ir_core::Instr::EndBorrow => { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndBorrow, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, None)); + ir_core::InstrKind::EndBorrow => { + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndBorrow, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span)); } - ir_core::Instr::EndMutate => { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndMutate, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, None)); + ir_core::InstrKind::EndMutate => { + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndMutate, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span)); } - ir_core::Instr::GateLoadField { gate, field } => { + ir_core::InstrKind::GateLoadField { gate, field } => { let offset = program.field_offsets.get(field) .ok_or_else(|| anyhow::anyhow!("E_LOWER_UNRESOLVED_OFFSET: Field {:?} offset cannot be resolved", field))?; let field_ty = program.field_types.get(field).cloned().unwrap_or(ir_core::Type::Int); stack_types.push(field_ty.clone()); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateLoad { offset: *offset }, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateLoad { offset: *offset }, span)); if is_gate_type(&field_ty) { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); } } - ir_core::Instr::GateStoreField { gate, field, value } => { + ir_core::InstrKind::GateStoreField { gate, field, value } => { let offset = program.field_offsets.get(field) .ok_or_else(|| anyhow::anyhow!("E_LOWER_UNRESOLVED_OFFSET: Field {:?} offset cannot be resolved", field))?; @@ -295,32 +296,32 @@ pub fn lower_function( // 1. Release old value in HIP if it was a gate if is_gate_type(&field_ty) { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateLoad { offset: *offset }, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateLoad { offset: *offset }, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span)); } - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: value.0 }, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: value.0 }, span)); // 2. Retain new value if it's a gate if let Some(val_ty) = local_types.get(&value.0) { if is_gate_type(val_ty) { - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span)); } } - vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateStore { offset: *offset }, None)); + vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateStore { offset: *offset }, span)); } - ir_core::Instr::GateLoadIndex { .. } => { + ir_core::InstrKind::GateLoadIndex { .. } => { anyhow::bail!("E_LOWER_UNSUPPORTED: Dynamic HIP index access not supported in v0 lowering"); } - ir_core::Instr::GateStoreIndex { .. } => { + ir_core::InstrKind::GateStoreIndex { .. } => { anyhow::bail!("E_LOWER_UNSUPPORTED: Dynamic HIP index access not supported in v0 lowering"); } - ir_core::Instr::Free => anyhow::bail!("Instruction 'Free' cannot be represented in ir_vm v0"), + ir_core::InstrKind::Free => anyhow::bail!("Instruction 'Free' cannot be represented in ir_vm v0"), } } @@ -403,8 +404,8 @@ mod tests { use super::*; use crate::ir_core; use crate::ir_core::ids::{ConstId as CoreConstId, FunctionId}; - use crate::ir_core::{Block, ConstPool, ConstantValue, Instr, Program, Terminator}; - use crate::ir_vm::*; + use crate::ir_core::{Block, ConstPool, ConstantValue, Instr, InstrKind, Program, Terminator}; + use crate::ir_vm::{InstrKind as VmInstrKind, Label}; #[test] fn test_full_lowering() { @@ -424,15 +425,15 @@ mod tests { Block { id: 0, instrs: vec![ - Instr::PushConst(CoreConstId(0)), - Instr::Call(FunctionId(2), 1), + Instr::from(InstrKind::PushConst(CoreConstId(0))), + Instr::from(InstrKind::Call(FunctionId(2), 1)), ], terminator: Terminator::Jump(1), }, Block { id: 1, instrs: vec![ - Instr::HostCall(42, 1), + Instr::from(InstrKind::HostCall(42, 1)), ], terminator: Terminator::Return, }, @@ -456,34 +457,34 @@ mod tests { assert_eq!(func.body.len(), 7); match &func.body[0].kind { - InstrKind::Label(Label(l)) => assert_eq!(l, "block_0"), + VmInstrKind::Label(Label(l)) => assert_eq!(l, "block_0"), _ => panic!("Expected label block_0"), } match &func.body[1].kind { - InstrKind::PushConst(id) => assert_eq!(id.0, 0), + VmInstrKind::PushConst(id) => assert_eq!(id.0, 0), _ => panic!("Expected PushConst 0"), } match &func.body[2].kind { - InstrKind::Call { func_id, arg_count } => { + VmInstrKind::Call { func_id, arg_count } => { assert_eq!(func_id.0, 2); assert_eq!(*arg_count, 1); } _ => panic!("Expected Call"), } match &func.body[3].kind { - InstrKind::Jmp(Label(l)) => assert_eq!(l, "block_1"), + VmInstrKind::Jmp(Label(l)) => assert_eq!(l, "block_1"), _ => panic!("Expected Jmp block_1"), } match &func.body[4].kind { - InstrKind::Label(Label(l)) => assert_eq!(l, "block_1"), + VmInstrKind::Label(Label(l)) => assert_eq!(l, "block_1"), _ => panic!("Expected label block_1"), } match &func.body[5].kind { - InstrKind::Syscall(id) => assert_eq!(*id, 42), + VmInstrKind::Syscall(id) => assert_eq!(*id, 42), _ => panic!("Expected HostCall 42"), } match &func.body[6].kind { - InstrKind::Ret => (), + VmInstrKind::Ret => (), _ => panic!("Expected Ret"), } } @@ -507,8 +508,8 @@ mod tests { blocks: vec![Block { id: 0, instrs: vec![ - Instr::GateLoadField { gate: ir_core::ValueId(0), field: field_id }, - Instr::GateStoreField { gate: ir_core::ValueId(0), field: field_id, value: ir_core::ValueId(1) }, + Instr::from(InstrKind::GateLoadField { gate: ir_core::ValueId(0), field: field_id }), + Instr::from(InstrKind::GateStoreField { gate: ir_core::ValueId(0), field: field_id, value: ir_core::ValueId(1) }), ], terminator: Terminator::Return, }], @@ -536,23 +537,23 @@ mod tests { assert_eq!(func.body.len(), 9); match &func.body[1].kind { - ir_vm::InstrKind::LocalLoad { slot } => assert_eq!(*slot, 0), + VmInstrKind::LocalLoad { slot } => assert_eq!(*slot, 0), _ => panic!("Expected LocalLoad 0"), } match &func.body[2].kind { - ir_vm::InstrKind::GateRetain => (), + VmInstrKind::GateRetain => (), _ => panic!("Expected GateRetain"), } match &func.body[3].kind { - ir_vm::InstrKind::GateLoad { offset } => assert_eq!(*offset, 100), + VmInstrKind::GateLoad { offset } => assert_eq!(*offset, 100), _ => panic!("Expected GateLoad 100"), } match &func.body[7].kind { - ir_vm::InstrKind::GateStore { offset } => assert_eq!(*offset, 100), + VmInstrKind::GateStore { offset } => assert_eq!(*offset, 100), _ => panic!("Expected GateStore 100"), } match &func.body[8].kind { - ir_vm::InstrKind::Ret => (), + VmInstrKind::Ret => (), _ => panic!("Expected Ret"), } } @@ -571,7 +572,7 @@ mod tests { blocks: vec![Block { id: 0, instrs: vec![ - Instr::GateLoadField { gate: ir_core::ValueId(0), field: ir_core::FieldId(999) }, + Instr::from(InstrKind::GateLoadField { gate: ir_core::ValueId(0), field: ir_core::FieldId(999) }), ], terminator: Terminator::Return, }], @@ -610,16 +611,16 @@ mod tests { id: 0, instrs: vec![ // 1. allocates a gate - Instr::Alloc { ty: type_id, slots: 1 }, - Instr::SetLocal(0), // x = alloc + Instr::from(InstrKind::Alloc { ty: type_id, slots: 1 }), + Instr::from(InstrKind::SetLocal(0)), // x = alloc // 2. copies it - Instr::GetLocal(0), - Instr::SetLocal(1), // y = x + Instr::from(InstrKind::GetLocal(0)), + Instr::from(InstrKind::SetLocal(1)), // y = x // 3. overwrites one copy - Instr::PushConst(CoreConstId(0)), - Instr::SetLocal(0), // x = 0 (overwrites gate) + Instr::from(InstrKind::PushConst(CoreConstId(0))), + Instr::from(InstrKind::SetLocal(0)), // x = 0 (overwrites gate) ], terminator: Terminator::Return, }], @@ -638,14 +639,14 @@ mod tests { let kinds: Vec<_> = func.body.iter().map(|i| &i.kind).collect(); - assert!(kinds.contains(&&InstrKind::GateRetain)); - assert!(kinds.contains(&&InstrKind::GateRelease)); + assert!(kinds.contains(&&VmInstrKind::GateRetain)); + assert!(kinds.contains(&&VmInstrKind::GateRelease)); // Check specific sequence for overwrite: // LocalLoad 0, GateRelease, LocalStore 0 let mut found_overwrite = false; for i in 0..kinds.len() - 2 { - if let (InstrKind::LocalLoad { slot: 0 }, InstrKind::GateRelease, InstrKind::LocalStore { slot: 0 }) = (kinds[i], kinds[i+1], kinds[i+2]) { + if let (VmInstrKind::LocalLoad { slot: 0 }, VmInstrKind::GateRelease, VmInstrKind::LocalStore { slot: 0 }) = (kinds[i], kinds[i+1], kinds[i+2]) { found_overwrite = true; break; } @@ -656,7 +657,7 @@ mod tests { // LocalLoad 1, GateRelease, Ret let mut found_cleanup = false; for i in 0..kinds.len() - 2 { - if let (InstrKind::LocalLoad { slot: 1 }, InstrKind::GateRelease, InstrKind::Ret) = (kinds[i], kinds[i+1], kinds[i+2]) { + if let (VmInstrKind::LocalLoad { slot: 1 }, VmInstrKind::GateRelease, VmInstrKind::Ret) = (kinds[i], kinds[i+1], kinds[i+2]) { found_cleanup = true; break; } @@ -681,10 +682,10 @@ mod tests { blocks: vec![Block { id: 0, instrs: vec![ - Instr::PushConst(CoreConstId(0)), - Instr::SetLocal(0), // x = 42 - Instr::GetLocal(0), - Instr::Pop, + Instr::from(InstrKind::PushConst(CoreConstId(0))), + Instr::from(InstrKind::SetLocal(0)), // x = 42 + Instr::from(InstrKind::GetLocal(0)), + Instr::from(InstrKind::Pop), ], terminator: Terminator::Return, }], @@ -703,7 +704,7 @@ mod tests { for instr in &func.body { match &instr.kind { - InstrKind::GateRetain | InstrKind::GateRelease => { + VmInstrKind::GateRetain | VmInstrKind::GateRelease => { panic!("Non-gate program should not contain RC instructions: {:?}", instr); } _ => {} @@ -717,8 +718,8 @@ mod tests { // Since we are using struct variants with mandatory 'offset' field, this is // enforced by the type system, but we can also check the serialized form. let instructions = vec![ - ir_vm::InstrKind::GateLoad { offset: 123 }, - ir_vm::InstrKind::GateStore { offset: 456 }, + VmInstrKind::GateLoad { offset: 123 }, + VmInstrKind::GateStore { offset: 456 }, ]; let json = serde_json::to_string(&instructions).unwrap(); assert!(json.contains("\"GateLoad\":{\"offset\":123}")); diff --git a/crates/prometeu-compiler/tests/export_conflicts.rs b/crates/prometeu-compiler/tests/export_conflicts.rs index 61843e84..7ecd2f6b 100644 --- a/crates/prometeu-compiler/tests/export_conflicts.rs +++ b/crates/prometeu-compiler/tests/export_conflicts.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use tempfile::tempdir; use prometeu_compiler::building::output::{compile_project, CompileError, ExportKey, ExportMetadata}; use prometeu_compiler::building::plan::{BuildStep, BuildTarget}; +use prometeu_compiler::common::files::FileManager; use prometeu_compiler::deps::resolver::ProjectId; use prometeu_compiler::semantics::export_surface::ExportSurfaceKind; use prometeu_compiler::building::output::CompiledModule; @@ -58,7 +59,8 @@ fn test_local_vs_dependency_conflict() { deps, }; - let result = compile_project(step, &dep_modules); + let mut file_manager = FileManager::new(); + let result = compile_project(step, &dep_modules, &mut file_manager); match result { Err(CompileError::DuplicateExport { symbol, .. }) => { @@ -136,7 +138,8 @@ fn test_aliased_dependency_conflict() { deps, }; - let result = compile_project(step, &dep_modules); + let mut file_manager = FileManager::new(); + let result = compile_project(step, &dep_modules, &mut file_manager); match result { Err(CompileError::DuplicateExport { symbol, .. }) => { @@ -169,7 +172,8 @@ fn test_mixed_main_test_modules() { deps: BTreeMap::new(), }; - let compiled = compile_project(step, &HashMap::new()).unwrap(); + let mut file_manager = FileManager::new(); + let compiled = compile_project(step, &HashMap::new(), &mut file_manager).unwrap(); // Both should be in exports with normalized paths assert!(compiled.exports.keys().any(|k| k.module_path == "math")); @@ -197,7 +201,8 @@ fn test_module_merging_same_directory() { deps: BTreeMap::new(), }; - let compiled = compile_project(step, &HashMap::new()).unwrap(); + let mut file_manager = FileManager::new(); + let compiled = compile_project(step, &HashMap::new(), &mut file_manager).unwrap(); // Both should be in the same module "gfx" assert!(compiled.exports.keys().any(|k| k.module_path == "gfx" && k.symbol_name == "Gfx")); @@ -225,7 +230,8 @@ fn test_duplicate_symbol_in_same_module_different_files() { deps: BTreeMap::new(), }; - let result = compile_project(step, &HashMap::new()); + let mut file_manager = FileManager::new(); + let result = compile_project(step, &HashMap::new(), &mut file_manager); assert!(result.is_err()); // Should be a frontend error (duplicate symbol) } @@ -251,7 +257,8 @@ fn test_root_module_merging() { deps: BTreeMap::new(), }; - let compiled = compile_project(step, &HashMap::new()).unwrap(); + let mut file_manager = FileManager::new(); + let compiled = compile_project(step, &HashMap::new(), &mut file_manager).unwrap(); // Both should be in the root module "" assert!(compiled.exports.keys().any(|k| k.module_path == "" && k.symbol_name == "Main")); diff --git a/crates/prometeu-compiler/tests/hip_conformance.rs b/crates/prometeu-compiler/tests/hip_conformance.rs index f8daf33a..bef112ee 100644 --- a/crates/prometeu-compiler/tests/hip_conformance.rs +++ b/crates/prometeu-compiler/tests/hip_conformance.rs @@ -1,6 +1,6 @@ use prometeu_compiler::backend::emit_bytecode::emit_module; use prometeu_compiler::ir_core::ids::{ConstId as CoreConstId, FieldId, FunctionId, TypeId as CoreTypeId, ValueId}; -use prometeu_compiler::ir_core::{self, Block, ConstPool, ConstantValue, Instr, Program, Terminator}; +use prometeu_compiler::ir_core::{self, Block, ConstPool, ConstantValue, Instr, InstrKind as CoreInstrKind, Program, Terminator}; use prometeu_compiler::ir_vm::InstrKind; use prometeu_compiler::lowering::lower_program; use std::collections::HashMap; @@ -37,22 +37,22 @@ fn test_hip_conformance_core_to_vm_to_bytecode() { id: 0, instrs: vec![ // allocates a storage struct - Instr::Alloc { ty: type_id, slots: 2 }, - Instr::SetLocal(0), // x = alloc + Instr::from(CoreInstrKind::Alloc { ty: type_id, slots: 2 }), + Instr::from(CoreInstrKind::SetLocal(0)), // x = alloc // mutates a field - Instr::BeginMutate { gate: ValueId(0) }, - Instr::PushConst(CoreConstId(0)), - Instr::SetLocal(1), // v = 42 - Instr::GateStoreField { gate: ValueId(0), field: field_id, value: ValueId(1) }, - Instr::EndMutate, + Instr::from(CoreInstrKind::BeginMutate { gate: ValueId(0) }), + Instr::from(CoreInstrKind::PushConst(CoreConstId(0))), + Instr::from(CoreInstrKind::SetLocal(1)), // v = 42 + Instr::from(CoreInstrKind::GateStoreField { gate: ValueId(0), field: field_id, value: ValueId(1) }), + Instr::from(CoreInstrKind::EndMutate), // peeks value - Instr::BeginPeek { gate: ValueId(0) }, - Instr::GateLoadField { gate: ValueId(0), field: field_id }, - Instr::EndPeek, + Instr::from(CoreInstrKind::BeginPeek { gate: ValueId(0) }), + Instr::from(CoreInstrKind::GateLoadField { gate: ValueId(0), field: field_id }), + Instr::from(CoreInstrKind::EndPeek), - Instr::Pop, // clean up the peeked value + Instr::from(CoreInstrKind::Pop), // clean up the peeked value ], terminator: Terminator::Return, }], diff --git a/test-cartridges/canonical/golden/program.pbc b/test-cartridges/canonical/golden/program.pbc index 033b90ca4c445d3c04c8b7ad090cd51a231b9952..b06b91caaacaf4416129e782584fa51dc847ec21 100644 GIT binary patch literal 3727 zcmZwJ4QQ2R7zW^H$Dd569jDFzxoj;fbJIj*h>T|Av6doH1{F+4J7-^}XNu&iA|X)%j{; z8-nHfZJfp zqB!REIj-gg?HzXJ(Q~fUR$`u`nzS^VK2?*J3|+4-&DNw@PklD+V&+XNiW4g@>G2LDXF&$?;ckE2J znIWbduOzq0bej=kx=jx;-KK?@Zc{@{$Cb!!h3Pgq#B`e!V!9QFm~JnJm~OnixGzk% z2_dFiQHbd_KE(8N$MJKx4WO4|j_HOQIc<~aHa5g`D-1E+#)Oz|yyv-1rrV1lrrW3x z(+#&^T9fHEGQ{-sOmZuHHa$H}6rU;rR>y*E@m!#$FSK4=2 zKi>+mWGsr`#+Jo+Jc>ue#(A1&hHW**YfwD;)&v^ z;!^P}@oe#2aiw^nc(Hhic&T`WxK_MM{GqsB+#qfheZxU}2?-1`1?-d^qe7{PS?^y=# zDQttkZ{l%czQ+w+zgRq7Tp}(DZ^XM#7iwYnCN}yPYH@fM=DtS7?x)>uY)-!(d}VFz lY;14g9RGa`E+F^<+11%p(cbuJM@9Q*&70d=x~kIZ{{s-7BZ>e3 delta 28 icmeB|-On+>hf9Hhfq?~x1z0wQ&0=O^V3_R0=L-N-69s4h diff --git a/test-cartridges/test01/cartridge/program.pbc b/test-cartridges/test01/cartridge/program.pbc index 033b90ca4c445d3c04c8b7ad090cd51a231b9952..eafefd126fd0c9fd2c0b52ed2405b6ba44787d38 100644 GIT binary patch literal 3727 zcmZwJ4``2h90%~vew>^CKg0Z=nc2DXXFD$4EoprwNn%_{(zSK7?zD~O2AEgm zlB6XhNs^F+bY0iT2}xWUr*&PrBuTqV-tX@|)8pMe?eo09ukZKS^Lw7>`+c@woquWE zK1loj->pV>DXIXq4ONcHq1sV(ea!G<&#_xSz^pIY^+U`mk!)K5I@4A#qPI~J4W5Hr z9>q4#&vp$@XtTL9k3GjqZ5hVds!hH5^jo#5Cwp978m&#Ep7!~4jaAt5UUIew`!Uw} zA+Fi-_{f~KrXG9!eh)@Vc@48Lx)z_xbo(^KbgK$6J>55tmOpe6^58@ zSc2(Drdz)d)6+Z2v+&*Y^fpm^t30h|imyt~ljvig139a}eoUID-nBh1^>e?>j^cQ3 zIn+kfCKNx7-h$eS;vMyl(|j`YCDdgUpFVvSbp^#4rf;BbqRPU*Ab&@3rEsY9koaNgLtoazxaT-U3^S@TzpE*=g#NXdwu7`oTu#gH8JNUJKiC_ zCB7}bFMcHM6mw3qpZ84skNBmyTl}9mhdIigzfe3t%ypDKzF0h3Tp}(PSBR&JXNf-( zSBq=JE?y|+n$O-(op^qj;^jS==VxEap3wy}s?@UEH(PCNn#q{ltUBMdA_S zvEov3nRu#rrnpKxM?6Jw8BmPOe zSG-?*NZc+yCO#=XB|a;@D83}VCjL#_A-*NPC%!L!Bz`LH5zEaSUg@_A}$Z#!F&G@H7Cr!8{Me6;V!iQMe$m>q1zf7`QIabWo>F}Xj#Lt e_c{oEf!xscb!AJ#x2=^e>l!yUuh~$Y4u1hf9Hhfq?~x1z0wQ&0=O^V3_R0=L-N-69s4h