mir: read plugin method signatures from nyash_box (#134)
* mir: load plugin method signatures * llvm: read box type ids from nyash_box * mir: show value types in MIR printer
This commit is contained in:
34
nyash_box.toml
Normal file
34
nyash_box.toml
Normal file
@ -0,0 +1,34 @@
|
||||
# Central plugin type definitions
|
||||
|
||||
[CounterBox]
|
||||
type_id = 7
|
||||
|
||||
[CounterBox.methods.inc]
|
||||
returns = { type = "i64" }
|
||||
|
||||
[CounterBox.methods.get]
|
||||
returns = { type = "i64" }
|
||||
|
||||
[MathBox]
|
||||
type_id = 50
|
||||
|
||||
[MathBox.methods.sqrt]
|
||||
returns = { type = "f64" }
|
||||
|
||||
[MathBox.methods.sin]
|
||||
returns = { type = "f64" }
|
||||
|
||||
[MathBox.methods.cos]
|
||||
returns = { type = "f64" }
|
||||
|
||||
[MathBox.methods.round]
|
||||
returns = { type = "f64" }
|
||||
|
||||
[FileBox]
|
||||
type_id = 6
|
||||
|
||||
[FileBox.methods.read]
|
||||
returns = { type = "string" }
|
||||
|
||||
[FileBox.methods.exists]
|
||||
returns = { type = "bool" }
|
||||
@ -269,13 +269,27 @@ impl LLVMCompiler {
|
||||
})
|
||||
}
|
||||
|
||||
// Load box type-id mapping from nyash.toml (for NewBox lowering)
|
||||
// Load box type-id mapping from nyash_box.toml (central plugin registry)
|
||||
let mut box_type_ids: StdHashMap<String, i64> = StdHashMap::new();
|
||||
if let Ok(cfg) = std::fs::read_to_string("nyash_box.toml") {
|
||||
if let Ok(doc) = toml::from_str::<toml::Value>(&cfg) {
|
||||
if let Some(table) = doc.as_table() {
|
||||
for (box_name, box_val) in table {
|
||||
if let Some(id) = box_val.get("type_id").and_then(|v| v.as_integer()) {
|
||||
box_type_ids.insert(box_name.clone(), id as i64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback: legacy box_types table in nyash.toml
|
||||
if let Ok(cfg) = std::fs::read_to_string("nyash.toml") {
|
||||
if let Ok(doc) = toml::from_str::<toml::Value>(&cfg) {
|
||||
if let Some(bt) = doc.get("box_types").and_then(|v| v.as_table()) {
|
||||
for (k, v) in bt {
|
||||
if let Some(id) = v.as_integer() { box_type_ids.insert(k.clone(), id as i64); }
|
||||
if let Some(id) = v.as_integer() {
|
||||
box_type_ids.entry(k.clone()).or_insert(id as i64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -545,7 +559,7 @@ impl LLVMCompiler {
|
||||
_ => return Err("box receiver must be pointer or i64 handle".to_string()),
|
||||
};
|
||||
let recv_h = codegen.builder.build_ptr_to_int(recv_p, i64t, "recv_p2i").map_err(|e| e.to_string())?;
|
||||
// Resolve type_id from metadata (Box("Type")) via nyash.toml
|
||||
// Resolve type_id from metadata (Box("Type")) using box_type_ids
|
||||
let type_id: i64 = if let Some(crate::mir::MirType::Box(bname)) = func.metadata.value_types.get(box_val) {
|
||||
*box_type_ids.get(bname).unwrap_or(&0)
|
||||
} else if let Some(crate::mir::MirType::String) = func.metadata.value_types.get(box_val) {
|
||||
|
||||
@ -69,6 +69,9 @@ pub struct MirBuilder {
|
||||
|
||||
/// Optional per-value type annotations (MIR-level): ValueId -> MirType
|
||||
pub(super) value_types: HashMap<ValueId, super::MirType>,
|
||||
|
||||
/// Plugin method return type signatures loaded from nyash_box.toml
|
||||
plugin_method_sigs: HashMap<(String, String), super::MirType>,
|
||||
/// Current static box name when lowering a static box body (e.g., "Main")
|
||||
current_static_box: Option<String>,
|
||||
|
||||
@ -105,22 +108,20 @@ impl MirBuilder {
|
||||
}
|
||||
}
|
||||
if let Some(bt) = recv_box {
|
||||
let inferred: Option<super::MirType> = match (bt.as_str(), method.as_str()) {
|
||||
// Built-in box methods
|
||||
("StringBox", "length") | ("StringBox", "len") => Some(super::MirType::Integer),
|
||||
("StringBox", "is_empty") => Some(super::MirType::Bool),
|
||||
("StringBox", "charCodeAt") => Some(super::MirType::Integer),
|
||||
("ArrayBox", "length") => Some(super::MirType::Integer),
|
||||
|
||||
// Plugin box methods
|
||||
("CounterBox", "get") => Some(super::MirType::Integer),
|
||||
("MathBox", "sqrt") => Some(super::MirType::Float),
|
||||
("FileBox", "read") => Some(super::MirType::String),
|
||||
("FileBox", "exists") => Some(super::MirType::Bool),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(mt) = inferred {
|
||||
self.value_types.insert(d, mt);
|
||||
if let Some(mt) = self.plugin_method_sigs.get(&(bt.clone(), method.clone())) {
|
||||
self.value_types.insert(d, mt.clone());
|
||||
} else {
|
||||
let inferred: Option<super::MirType> = match (bt.as_str(), method.as_str()) {
|
||||
// Built-in box methods
|
||||
("StringBox", "length") | ("StringBox", "len") => Some(super::MirType::Integer),
|
||||
("StringBox", "is_empty") => Some(super::MirType::Bool),
|
||||
("StringBox", "charCodeAt") => Some(super::MirType::Integer),
|
||||
("ArrayBox", "length") => Some(super::MirType::Integer),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(mt) = inferred {
|
||||
self.value_types.insert(d, mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,6 +129,37 @@ impl MirBuilder {
|
||||
}
|
||||
/// Create a new MIR builder
|
||||
pub fn new() -> Self {
|
||||
// Load plugin method signatures from nyash_box.toml if available
|
||||
let mut plugin_method_sigs: HashMap<(String, String), super::MirType> = HashMap::new();
|
||||
if let Ok(content) = fs::read_to_string("nyash_box.toml") {
|
||||
if let Ok(root) = toml::from_str::<toml::Value>(&content) {
|
||||
if let Some(table) = root.as_table() {
|
||||
for (box_name, box_val) in table {
|
||||
if let Some(methods) = box_val.get("methods").and_then(|v| v.as_table()) {
|
||||
for (mname, mval) in methods {
|
||||
if let Some(ret) = mval.get("returns") {
|
||||
let ty_str = ret
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
.or_else(|| ret.get("type").and_then(|t| t.as_str()).map(|s| s.to_string()));
|
||||
if let Some(ts) = ty_str {
|
||||
let mir_ty = match ts.to_lowercase().as_str() {
|
||||
"i64" | "int" | "integer" => super::MirType::Integer,
|
||||
"f64" | "float" => super::MirType::Float,
|
||||
"bool" | "boolean" => super::MirType::Bool,
|
||||
"string" => super::MirType::String,
|
||||
"void" | "unit" => super::MirType::Void,
|
||||
other => super::MirType::Box(other.to_string()),
|
||||
};
|
||||
plugin_method_sigs.insert((box_name.clone(), mname.clone()), mir_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Self {
|
||||
current_module: None,
|
||||
current_function: None,
|
||||
@ -141,6 +173,7 @@ impl MirBuilder {
|
||||
weak_fields_by_box: HashMap::new(),
|
||||
field_origin_class: HashMap::new(),
|
||||
value_types: HashMap::new(),
|
||||
plugin_method_sigs,
|
||||
current_static_box: None,
|
||||
include_loading: HashSet::new(),
|
||||
include_box_map: HashMap::new(),
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
* Implements pretty-printing for MIR modules and functions
|
||||
*/
|
||||
|
||||
use super::{MirModule, MirFunction, BasicBlock, MirInstruction};
|
||||
use super::{MirModule, MirFunction, BasicBlock, MirInstruction, ValueId, MirType};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
use crate::debug::log as dlog;
|
||||
|
||||
@ -219,7 +220,7 @@ impl MirPrinter {
|
||||
if i > 0 {
|
||||
writeln!(output).unwrap();
|
||||
}
|
||||
output.push_str(&self.print_basic_block(block));
|
||||
output.push_str(&self.print_basic_block(block, &function.metadata.value_types));
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +230,7 @@ impl MirPrinter {
|
||||
}
|
||||
|
||||
/// Print a basic block
|
||||
pub fn print_basic_block(&self, block: &BasicBlock) -> String {
|
||||
pub fn print_basic_block(&self, block: &BasicBlock, types: &HashMap<ValueId, MirType>) -> String {
|
||||
let mut output = String::new();
|
||||
|
||||
// Block header
|
||||
@ -254,7 +255,7 @@ impl MirPrinter {
|
||||
write!(output, " ").unwrap();
|
||||
}
|
||||
|
||||
let mut line = self.format_instruction(instruction);
|
||||
let mut line = self.format_instruction(instruction, types);
|
||||
if self.show_effects_inline {
|
||||
let eff = instruction.effects();
|
||||
let cat = if eff.is_pure() { "pure" } else if eff.is_read_only() { "readonly" } else { "side" };
|
||||
@ -272,27 +273,35 @@ impl MirPrinter {
|
||||
output
|
||||
}
|
||||
|
||||
fn format_dst(&self, dst: &ValueId, types: &HashMap<ValueId, MirType>) -> String {
|
||||
if let Some(ty) = types.get(dst) {
|
||||
format!("{}: {:?} =", dst, ty)
|
||||
} else {
|
||||
format!("{} =", dst)
|
||||
}
|
||||
}
|
||||
|
||||
/// Format a single instruction
|
||||
fn format_instruction(&self, instruction: &MirInstruction) -> String {
|
||||
fn format_instruction(&self, instruction: &MirInstruction, types: &HashMap<ValueId, MirType>) -> String {
|
||||
match instruction {
|
||||
MirInstruction::Const { dst, value } => {
|
||||
format!("{} = const {}", dst, value)
|
||||
format!("{} const {}", self.format_dst(dst, types), value)
|
||||
},
|
||||
|
||||
MirInstruction::BinOp { dst, op, lhs, rhs } => {
|
||||
format!("{} = {} {:?} {}", dst, lhs, op, rhs)
|
||||
format!("{} {} {:?} {}", self.format_dst(dst, types), lhs, op, rhs)
|
||||
},
|
||||
|
||||
MirInstruction::UnaryOp { dst, op, operand } => {
|
||||
format!("{} = {:?} {}", dst, op, operand)
|
||||
format!("{} {:?} {}", self.format_dst(dst, types), op, operand)
|
||||
},
|
||||
|
||||
MirInstruction::Compare { dst, op, lhs, rhs } => {
|
||||
format!("{} = icmp {:?} {}, {}", dst, op, lhs, rhs)
|
||||
format!("{} icmp {:?} {}, {}", self.format_dst(dst, types), op, lhs, rhs)
|
||||
},
|
||||
|
||||
MirInstruction::Load { dst, ptr } => {
|
||||
format!("{} = load {}", dst, ptr)
|
||||
format!("{} load {}", self.format_dst(dst, types), ptr)
|
||||
},
|
||||
|
||||
MirInstruction::Store { value, ptr } => {
|
||||
@ -306,7 +315,7 @@ impl MirPrinter {
|
||||
.join(", ");
|
||||
|
||||
if let Some(dst) = dst {
|
||||
format!("{} = call {}({})", dst, func, args_str)
|
||||
format!("{} call {}({})", self.format_dst(dst, types), func, args_str)
|
||||
} else {
|
||||
format!("call {}({})", func, args_str)
|
||||
}
|
||||
@ -316,7 +325,7 @@ impl MirPrinter {
|
||||
let c = captures.iter().map(|(n, v)| format!("{}={}", n, v)).collect::<Vec<_>>().join(", ");
|
||||
let me_s = me.map(|m| format!(" me={}", m)).unwrap_or_default();
|
||||
let cap_s = if c.is_empty() { String::new() } else { format!(" [{}]", c) };
|
||||
format!("{} = function_new ({}) {{...{}}}{}{}", dst, p, body.len(), cap_s, me_s)
|
||||
format!("{} function_new ({}) {{...{}}}{}{}", self.format_dst(dst, types), p, body.len(), cap_s, me_s)
|
||||
},
|
||||
|
||||
MirInstruction::BoxCall { dst, box_val, method, method_id, args, effects: _ } => {
|
||||
@ -326,7 +335,7 @@ impl MirPrinter {
|
||||
.join(", ");
|
||||
let id_suffix = method_id.map(|id| format!("[#{}]", id)).unwrap_or_default();
|
||||
if let Some(dst) = dst {
|
||||
format!("{} = call {}.{}{}({})", dst, box_val, method, id_suffix, args_str)
|
||||
format!("{} call {}.{}{}({})", self.format_dst(dst, types), box_val, method, id_suffix, args_str)
|
||||
} else {
|
||||
format!("call {}.{}{}({})", box_val, method, id_suffix, args_str)
|
||||
}
|
||||
@ -337,7 +346,7 @@ impl MirPrinter {
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
if let Some(dst) = dst {
|
||||
format!("{} = plugin_invoke {}.{}({})", dst, box_val, method, args_str)
|
||||
format!("{} plugin_invoke {}.{}({})", self.format_dst(dst, types), box_val, method, args_str)
|
||||
} else {
|
||||
format!("plugin_invoke {}.{}({})", box_val, method, args_str)
|
||||
}
|
||||
@ -364,7 +373,7 @@ impl MirPrinter {
|
||||
.map(|(bb, val)| format!("[{}, {}]", val, bb))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{} = phi {}", dst, inputs_str)
|
||||
format!("{} phi {}", self.format_dst(dst, types), inputs_str)
|
||||
},
|
||||
|
||||
MirInstruction::NewBox { dst, box_type, args } => {
|
||||
@ -372,26 +381,26 @@ impl MirPrinter {
|
||||
.map(|v| format!("{}", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{} = new {}({})", dst, box_type, args_str)
|
||||
format!("{} new {}({})", self.format_dst(dst, types), box_type, args_str)
|
||||
},
|
||||
|
||||
// Legacy -> Unified print: TypeCheck as TypeOp(check)
|
||||
MirInstruction::TypeCheck { dst, value, expected_type } => {
|
||||
// Print using unified TypeOp style to avoid naming divergence
|
||||
format!("{} = typeop check {} {}", dst, value, expected_type)
|
||||
format!("{} typeop check {} {}", self.format_dst(dst, types), value, expected_type)
|
||||
},
|
||||
|
||||
MirInstruction::Cast { dst, value, target_type } => {
|
||||
format!("{} = cast {} to {:?}", dst, value, target_type)
|
||||
format!("{} cast {} to {:?}", self.format_dst(dst, types), value, target_type)
|
||||
},
|
||||
|
||||
MirInstruction::TypeOp { dst, op, value, ty } => {
|
||||
let op_str = match op { super::TypeOpKind::Check => "check", super::TypeOpKind::Cast => "cast" };
|
||||
format!("{} = typeop {} {} {:?}", dst, op_str, value, ty)
|
||||
format!("{} typeop {} {} {:?}", self.format_dst(dst, types), op_str, value, ty)
|
||||
},
|
||||
|
||||
MirInstruction::ArrayGet { dst, array, index } => {
|
||||
format!("{} = {}[{}]", dst, array, index)
|
||||
format!("{} {}[{}]", self.format_dst(dst, types), array, index)
|
||||
},
|
||||
|
||||
MirInstruction::ArraySet { array, index, value } => {
|
||||
@ -399,7 +408,7 @@ impl MirPrinter {
|
||||
},
|
||||
|
||||
MirInstruction::Copy { dst, src } => {
|
||||
format!("{} = copy {}", dst, src)
|
||||
format!("{} copy {}", self.format_dst(dst, types), src)
|
||||
},
|
||||
|
||||
MirInstruction::Debug { value, message } => {
|
||||
@ -433,11 +442,11 @@ impl MirPrinter {
|
||||
|
||||
// Phase 6: Box reference operations
|
||||
MirInstruction::RefNew { dst, box_val } => {
|
||||
format!("{} = ref_new {}", dst, box_val)
|
||||
format!("{} ref_new {}", self.format_dst(dst, types), box_val)
|
||||
},
|
||||
|
||||
MirInstruction::RefGet { dst, reference, field } => {
|
||||
format!("{} = ref_get {}.{}", dst, reference, field)
|
||||
format!("{} ref_get {}.{}", self.format_dst(dst, types), reference, field)
|
||||
},
|
||||
|
||||
MirInstruction::RefSet { reference, field, value } => {
|
||||
@ -446,12 +455,12 @@ impl MirPrinter {
|
||||
|
||||
// Legacy -> Unified print: WeakNew as weakref new
|
||||
MirInstruction::WeakNew { dst, box_val } => {
|
||||
format!("{} = weakref new {}", dst, box_val)
|
||||
format!("{} weakref new {}", self.format_dst(dst, types), box_val)
|
||||
},
|
||||
|
||||
// Legacy -> Unified print: WeakLoad as weakref load
|
||||
MirInstruction::WeakLoad { dst, weak_ref } => {
|
||||
format!("{} = weakref load {}", dst, weak_ref)
|
||||
format!("{} weakref load {}", self.format_dst(dst, types), weak_ref)
|
||||
},
|
||||
|
||||
// Legacy -> Unified print: BarrierRead as barrier read
|
||||
@ -466,7 +475,7 @@ impl MirPrinter {
|
||||
|
||||
MirInstruction::WeakRef { dst, op, value } => {
|
||||
let op_str = match op { super::WeakRefOp::New => "new", super::WeakRefOp::Load => "load" };
|
||||
format!("{} = weakref {} {}", dst, op_str, value)
|
||||
format!("{} weakref {} {}", self.format_dst(dst, types), op_str, value)
|
||||
},
|
||||
|
||||
MirInstruction::Barrier { op, ptr } => {
|
||||
@ -476,7 +485,7 @@ impl MirPrinter {
|
||||
|
||||
// Phase 7: Async/Future Operations
|
||||
MirInstruction::FutureNew { dst, value } => {
|
||||
format!("{} = future_new {}", dst, value)
|
||||
format!("{} future_new {}", self.format_dst(dst, types), value)
|
||||
},
|
||||
|
||||
MirInstruction::FutureSet { future, value } => {
|
||||
@ -484,14 +493,14 @@ impl MirPrinter {
|
||||
},
|
||||
|
||||
MirInstruction::Await { dst, future } => {
|
||||
format!("{} = await {}", dst, future)
|
||||
format!("{} await {}", self.format_dst(dst, types), future)
|
||||
},
|
||||
|
||||
// Phase 9.7: External Function Calls
|
||||
MirInstruction::ExternCall { dst, iface_name, method_name, args, effects } => {
|
||||
let args_str = args.iter().map(|v| format!("{}", v)).collect::<Vec<_>>().join(", ");
|
||||
if let Some(dst) = dst {
|
||||
format!("{} = extern_call {}.{}({}) [effects: {}]", dst, iface_name, method_name, args_str, effects)
|
||||
format!("{} extern_call {}.{}({}) [effects: {}]", self.format_dst(dst, types), iface_name, method_name, args_str, effects)
|
||||
} else {
|
||||
format!("extern_call {}.{}({}) [effects: {}]", iface_name, method_name, args_str, effects)
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
; MIR Module: main
|
||||
|
||||
define void @main() {
|
||||
define i64 @main() {
|
||||
bb0:
|
||||
0: %0 = const 42
|
||||
1: %1 = const 10
|
||||
2: %2 = %0 Add %1
|
||||
3: print %2
|
||||
0: %0: Integer = const 42
|
||||
1: %1: Integer = const 10
|
||||
2: %2: Integer = %0 Add %1
|
||||
3: extern_call env.console.log(%2) [effects: pure|io]
|
||||
4: ret %2
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
; MIR Module: main
|
||||
|
||||
define void @main() {
|
||||
define i1 @main() {
|
||||
bb0:
|
||||
0: %0 = const 42
|
||||
1: %1 = const 42
|
||||
2: %2 = icmp Eq %0, %1
|
||||
3: print %2
|
||||
0: %0: Integer = const 42
|
||||
1: %1: Integer = const 42
|
||||
2: %2: Bool = icmp Eq %0, %1
|
||||
3: extern_call env.console.log(%2) [effects: pure|io]
|
||||
4: ret %2
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
; MIR Module: main
|
||||
|
||||
define void @main() {
|
||||
define i64 @main() {
|
||||
bb0:
|
||||
0: %0 = const "Hello"
|
||||
1: %1 = const "World"
|
||||
2: %2 = %0 Add %1
|
||||
3: print %2
|
||||
0: %0: String = const "Hello"
|
||||
1: %1: String = const "World"
|
||||
2: %2: Integer = %0 Add %1
|
||||
3: extern_call env.console.log(%2) [effects: pure|io]
|
||||
4: ret %2
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user