Phase 12: 統一TypeBox ABI実装開始 - ChatGPT5による極小コアABI基盤構築

- TypeBox ABI雛形: メソッドスロット管理システム追加
- Type Registry: Array/Map/StringBoxの基本メソッド定義
- Host API: C ABI逆呼び出しシステム実装
- Phase 12ドキュメント整理: 設計文書統合・アーカイブ化
- MIR Builder: クリーンアップと分離実装完了

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-09-03 05:04:56 +09:00
parent e2e25f6615
commit 53d88157aa
84 changed files with 4739 additions and 2750 deletions

View File

@ -1,39 +1,301 @@
use super::{MirInstruction, EffectMask, Effect, ConstValue, ValueId};
use crate::mir::TypeOpKind;
use crate::mir::loop_builder::LoopBuilder;
use crate::ast::ASTNode;
impl super::MirBuilder {
// Print statement: env.console.log(value) with early TypeOp handling
pub(super) fn build_print_statement(&mut self, expression: ASTNode) -> Result<ValueId, String> {
self.build_print_statement_legacy(expression)
super::utils::builder_debug_log("enter build_print_statement");
match &expression {
// print(isType(val, "Type")) / print(asType(...))
ASTNode::FunctionCall { name, arguments, .. }
if (name == "isType" || name == "asType") && arguments.len() == 2 =>
{
super::utils::builder_debug_log("pattern: print(FunctionCall isType|asType)");
if let Some(type_name) = super::MirBuilder::extract_string_literal(&arguments[1]) {
super::utils::builder_debug_log(&format!("extract_string_literal OK: {}", type_name));
let val = self.build_expression(arguments[0].clone())?;
let ty = super::MirBuilder::parse_type_name_to_mir(&type_name);
let dst = self.value_gen.next();
let op = if name == "isType" { TypeOpKind::Check } else { TypeOpKind::Cast };
super::utils::builder_debug_log(&format!("emit TypeOp {:?} value={} dst= {}", op, val, dst));
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: val, ty })?;
self.emit_instruction(MirInstruction::ExternCall {
dst: None,
iface_name: "env.console".to_string(),
method_name: "log".to_string(),
args: vec![dst],
effects: EffectMask::PURE.add(Effect::Io),
})?;
return Ok(dst);
} else {
super::utils::builder_debug_log("extract_string_literal FAIL");
}
}
// print(obj.is("Type")) / print(obj.as("Type"))
ASTNode::MethodCall { object, method, arguments, .. }
if (method == "is" || method == "as") && arguments.len() == 1 =>
{
super::utils::builder_debug_log("pattern: print(MethodCall is|as)");
if let Some(type_name) = super::MirBuilder::extract_string_literal(&arguments[0]) {
super::utils::builder_debug_log(&format!("extract_string_literal OK: {}", type_name));
let obj_val = self.build_expression(*object.clone())?;
let ty = super::MirBuilder::parse_type_name_to_mir(&type_name);
let dst = self.value_gen.next();
let op = if method == "is" { TypeOpKind::Check } else { TypeOpKind::Cast };
super::utils::builder_debug_log(&format!("emit TypeOp {:?} obj={} dst= {}", op, obj_val, dst));
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: obj_val, ty })?;
self.emit_instruction(MirInstruction::ExternCall {
dst: None,
iface_name: "env.console".to_string(),
method_name: "log".to_string(),
args: vec![dst],
effects: EffectMask::PURE.add(Effect::Io),
})?;
return Ok(dst);
} else {
super::utils::builder_debug_log("extract_string_literal FAIL");
}
}
_ => {}
}
let value = self.build_expression(expression)?;
super::utils::builder_debug_log(&format!("fallback print value={}", value));
self.emit_instruction(MirInstruction::ExternCall {
dst: None,
iface_name: "env.console".to_string(),
method_name: "log".to_string(),
args: vec![value],
effects: EffectMask::PURE.add(Effect::Io),
})?;
Ok(value)
}
// Block: sequentially build statements and return last value or Void
pub(super) fn build_block(&mut self, statements: Vec<ASTNode>) -> Result<ValueId, String> {
self.build_block_legacy(statements)
let mut last_value = None;
for statement in statements { last_value = Some(self.build_expression(statement)?); }
Ok(last_value.unwrap_or_else(|| {
let void_val = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: void_val, value: ConstValue::Void }).unwrap();
void_val
}))
}
pub(super) fn build_if_statement(&mut self, condition: ASTNode, then_branch: ASTNode, else_branch: Option<ASTNode>) -> Result<ValueId, String> {
self.build_if_statement_legacy(condition, then_branch, else_branch)
// If: lower to Branch + Phi, bind reassigned var name if identical
pub(super) fn build_if_statement(
&mut self,
condition: ASTNode,
then_branch: ASTNode,
else_branch: Option<ASTNode>,
) -> Result<ValueId, String> {
let condition_val = self.build_expression(condition)?;
let then_block = self.block_gen.next();
let else_block = self.block_gen.next();
let merge_block = self.block_gen.next();
self.emit_instruction(MirInstruction::Branch { condition: condition_val, then_bb: then_block, else_bb: else_block })?;
// then
self.current_block = Some(then_block);
self.ensure_block_exists(then_block)?;
let then_ast_for_analysis = then_branch.clone();
let then_value = self.build_expression(then_branch)?;
if !self.is_current_block_terminated() { self.emit_instruction(MirInstruction::Jump { target: merge_block })?; }
// else
self.current_block = Some(else_block);
self.ensure_block_exists(else_block)?;
let (else_value, else_ast_for_analysis) = if let Some(else_ast) = else_branch {
let val = self.build_expression(else_ast.clone())?;
(val, Some(else_ast))
} else {
let void_val = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: void_val, value: ConstValue::Void })?;
(void_val, None)
};
if !self.is_current_block_terminated() { self.emit_instruction(MirInstruction::Jump { target: merge_block })?; }
// merge + phi
self.current_block = Some(merge_block);
self.ensure_block_exists(merge_block)?;
let result_val = self.value_gen.next();
self.emit_instruction(MirInstruction::Phi { dst: result_val, inputs: vec![(then_block, then_value), (else_block, else_value)] })?;
// heuristic: bind same var name to phi result
let assigned_var_then = extract_assigned_var(&then_ast_for_analysis);
let assigned_var_else = else_ast_for_analysis.as_ref().and_then(|a| extract_assigned_var(a));
if let (Some(a), Some(b)) = (assigned_var_then, assigned_var_else) { if a == b { self.variable_map.insert(a, result_val); } }
Ok(result_val)
}
// Loop: delegate to LoopBuilder
pub(super) fn build_loop_statement(&mut self, condition: ASTNode, body: Vec<ASTNode>) -> Result<ValueId, String> {
self.build_loop_statement_legacy(condition, body)
let mut loop_builder = LoopBuilder::new(self);
loop_builder.build_loop(condition, body)
}
pub(super) fn build_try_catch_statement(&mut self, try_body: Vec<ASTNode>, catch_clauses: Vec<crate::ast::CatchClause>, finally_body: Option<Vec<ASTNode>>) -> Result<ValueId, String> {
self.build_try_catch_statement_legacy(try_body, catch_clauses, finally_body)
// Try/Catch/Finally lowering with basic Extern semantics when disabled
pub(super) fn build_try_catch_statement(
&mut self,
try_body: Vec<ASTNode>,
catch_clauses: Vec<crate::ast::CatchClause>,
finally_body: Option<Vec<ASTNode>>,
) -> Result<ValueId, String> {
if std::env::var("NYASH_BUILDER_DISABLE_TRYCATCH").ok().as_deref() == Some("1") {
let try_ast = ASTNode::Program { statements: try_body, span: crate::ast::Span::unknown() };
let result = self.build_expression(try_ast)?;
return Ok(result);
}
let try_block = self.block_gen.next();
let catch_block = self.block_gen.next();
let finally_block = if finally_body.is_some() { Some(self.block_gen.next()) } else { None };
let exit_block = self.block_gen.next();
if let Some(catch_clause) = catch_clauses.first() {
if std::env::var("NYASH_DEBUG_TRYCATCH").ok().as_deref() == Some("1") {
eprintln!("[BUILDER] Emitting catch handler for {:?}", catch_clause.exception_type);
}
let exception_value = self.value_gen.next();
self.emit_instruction(MirInstruction::Catch { exception_type: catch_clause.exception_type.clone(), exception_value, handler_bb: catch_block })?;
}
self.emit_instruction(MirInstruction::Jump { target: try_block })?;
self.start_new_block(try_block)?;
let try_ast = ASTNode::Program { statements: try_body, span: crate::ast::Span::unknown() };
let _try_result = self.build_expression(try_ast)?;
if !self.is_current_block_terminated() { let next_target = finally_block.unwrap_or(exit_block); self.emit_instruction(MirInstruction::Jump { target: next_target })?; }
self.start_new_block(catch_block)?;
if std::env::var("NYASH_DEBUG_TRYCATCH").ok().as_deref() == Some("1") { eprintln!("[BUILDER] Enter catch block {:?}", catch_block); }
if let Some(catch_clause) = catch_clauses.first() {
if std::env::var("NYASH_DEBUG_TRYCATCH").ok().as_deref() == Some("1") { eprintln!("[BUILDER] Emitting catch handler for {:?}", catch_clause.exception_type); }
let catch_ast = ASTNode::Program { statements: catch_clause.body.clone(), span: crate::ast::Span::unknown() };
self.build_expression(catch_ast)?;
}
if !self.is_current_block_terminated() { let next_target = finally_block.unwrap_or(exit_block); self.emit_instruction(MirInstruction::Jump { target: next_target })?; }
if let (Some(finally_block_id), Some(finally_statements)) = (finally_block, finally_body) {
self.start_new_block(finally_block_id)?;
let finally_ast = ASTNode::Program { statements: finally_statements, span: crate::ast::Span::unknown() };
self.build_expression(finally_ast)?;
self.emit_instruction(MirInstruction::Jump { target: exit_block })?;
}
self.start_new_block(exit_block)?;
let result = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: result, value: ConstValue::Void })?;
Ok(result)
}
// Throw: emit Throw or fallback to env.debug.trace when disabled
pub(super) fn build_throw_statement(&mut self, expression: ASTNode) -> Result<ValueId, String> {
self.build_throw_statement_legacy(expression)
if std::env::var("NYASH_BUILDER_DISABLE_THROW").ok().as_deref() == Some("1") {
let v = self.build_expression(expression)?;
self.emit_instruction(MirInstruction::ExternCall {
dst: None,
iface_name: "env.debug".to_string(),
method_name: "trace".to_string(),
args: vec![v],
effects: EffectMask::PURE.add(Effect::Debug),
})?;
return Ok(v);
}
let exception_value = self.build_expression(expression)?;
self.emit_instruction(MirInstruction::Throw { exception: exception_value, effects: EffectMask::PANIC })?;
Ok(exception_value)
}
pub(super) fn build_local_statement(&mut self, variables: Vec<String>, initial_values: Vec<Option<Box<ASTNode>>>) -> Result<ValueId, String> {
self.build_local_statement_legacy(variables, initial_values)
// Local declarations with optional initializers
pub(super) fn build_local_statement(
&mut self,
variables: Vec<String>,
initial_values: Vec<Option<Box<ASTNode>>>,
) -> Result<ValueId, String> {
let mut last_value = None;
for (i, var_name) in variables.iter().enumerate() {
let value_id = if i < initial_values.len() && initial_values[i].is_some() {
let init_expr = initial_values[i].as_ref().unwrap();
self.build_expression(*init_expr.clone())?
} else {
self.value_gen.next()
};
self.variable_map.insert(var_name.clone(), value_id);
last_value = Some(value_id);
}
Ok(last_value.unwrap_or_else(|| self.value_gen.next()))
}
// Return statement
pub(super) fn build_return_statement(&mut self, value: Option<Box<ASTNode>>) -> Result<ValueId, String> {
self.build_return_statement_legacy(value)
let return_value = if let Some(expr) = value {
self.build_expression(*expr)?
} else {
let void_dst = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: void_dst, value: ConstValue::Void })?;
void_dst
};
self.emit_instruction(MirInstruction::Return { value: Some(return_value) })?;
Ok(return_value)
}
// Nowait: prefer env.future.spawn_instance if method call; else FutureNew
pub(super) fn build_nowait_statement(&mut self, variable: String, expression: ASTNode) -> Result<ValueId, String> {
self.build_nowait_statement_legacy(variable, expression)
if let ASTNode::MethodCall { object, method, arguments, .. } = expression.clone() {
let recv_val = self.build_expression(*object)?;
let mname_id = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: mname_id, value: super::ConstValue::String(method.clone()) })?;
let mut arg_vals: Vec<ValueId> = Vec::with_capacity(2 + arguments.len());
arg_vals.push(recv_val);
arg_vals.push(mname_id);
for a in arguments.into_iter() { arg_vals.push(self.build_expression(a)?); }
let future_id = self.value_gen.next();
self.emit_instruction(MirInstruction::ExternCall {
dst: Some(future_id),
iface_name: "env.future".to_string(),
method_name: "spawn_instance".to_string(),
args: arg_vals,
effects: crate::mir::effect::EffectMask::PURE.add(crate::mir::effect::Effect::Io),
})?;
self.variable_map.insert(variable.clone(), future_id);
return Ok(future_id);
}
let expression_value = self.build_expression(expression)?;
let future_id = self.value_gen.next();
self.emit_instruction(MirInstruction::FutureNew { dst: future_id, value: expression_value })?;
self.variable_map.insert(variable.clone(), future_id);
Ok(future_id)
}
// Await: insert Safepoint before/after and emit Await
pub(super) fn build_await_expression(&mut self, expression: ASTNode) -> Result<ValueId, String> {
self.build_await_expression_legacy(expression)
let future_value = self.build_expression(expression)?;
self.emit_instruction(MirInstruction::Safepoint)?;
let result_id = self.value_gen.next();
self.emit_instruction(MirInstruction::Await { dst: result_id, future: future_value })?;
self.emit_instruction(MirInstruction::Safepoint)?;
Ok(result_id)
}
// me: resolve to param if present; else symbolic const (stable mapping)
pub(super) fn build_me_expression(&mut self) -> Result<ValueId, String> {
self.build_me_expression_legacy()
if let Some(id) = self.variable_map.get("me").cloned() { return Ok(id); }
let me_value = self.value_gen.next();
let me_tag = if let Some(ref cls) = self.current_static_box { cls.clone() } else { "__me__".to_string() };
self.emit_instruction(MirInstruction::Const { dst: me_value, value: ConstValue::String(me_tag) })?;
self.variable_map.insert("me".to_string(), me_value);
Ok(me_value)
}
}
// Local helper for if-statement analysis
fn extract_assigned_var(ast: &ASTNode) -> Option<String> {
match ast {
ASTNode::Assignment { target, .. } => {
if let ASTNode::Variable { name, .. } = target.as_ref() { Some(name.clone()) } else { None }
}
ASTNode::Program { statements, .. } => statements.last().and_then(|st| extract_assigned_var(st)),
_ => None,
}
}