Files
hakorune/src/mir/builder/utils.rs
Selfhosting Dev 73b90a7c28 feat: スモークテストv2実装&Phase 15.5後のプラグイン対応
Phase 15.5 Core Box削除後の新テストシステム構築:

## 実装内容
- スモークテストv2システム完全実装(3段階プロファイル)
- 共通ライブラリ(test_runner/plugin_manager/result_checker/preflight)
- インタープリター層完全削除(約350行)
- PyVM重要インフラ特化保持戦略(JSON v0ブリッジ専用)
- nyash.tomlパス修正(13箇所、プラグイン正常ロード確認)

## 動作確認済み
- 基本算術演算(+, -, *, /)
- 制御構文(if, loop, break, continue)
- 変数代入とスコープ
- プラグインロード(20個の.soファイル)

## 既知の問題
- StringBox/IntegerBoxメソッドが動作しない
  - オブジェクト生成は成功するがメソッド呼び出しでエラー
  - Phase 15.5影響でプラグイン実装が不完全な可能性

## ドキュメント
- docs/development/testing/smoke-tests-v2.md 作成
- docs/reference/pyvm-usage-guidelines.md 作成
- CODEX_QUESTION.md(Codex相談用)作成

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-24 09:30:42 +09:00

225 lines
7.5 KiB
Rust

use super::{BasicBlock, BasicBlockId};
use crate::mir::{BarrierOp, TypeOpKind, WeakRefOp};
use std::fs;
// Resolve include path using nyash.toml include.roots if present
pub(super) fn resolve_include_path_builder(filename: &str) -> String {
if filename.starts_with("./") || filename.starts_with("../") {
return filename.to_string();
}
let parts: Vec<&str> = filename.splitn(2, '/').collect();
if parts.len() == 2 {
let root = parts[0];
let rest = parts[1];
let cfg_path = "nyash.toml";
if let Ok(toml_str) = fs::read_to_string(cfg_path) {
if let Ok(toml_val) = toml::from_str::<toml::Value>(&toml_str) {
if let Some(include) = toml_val.get("include") {
if let Some(roots) = include.get("roots").and_then(|v| v.as_table()) {
if let Some(root_path) = roots.get(root).and_then(|v| v.as_str()) {
let mut base = root_path.to_string();
if !base.ends_with('/') && !base.ends_with('\\') {
base.push('/');
}
return format!("{}{}", base, rest);
}
}
}
}
}
}
format!("./{}", filename)
}
// Optional builder debug logging
pub(super) fn builder_debug_enabled() -> bool {
std::env::var("NYASH_BUILDER_DEBUG").is_ok()
}
pub(super) fn builder_debug_log(msg: &str) {
if builder_debug_enabled() {
eprintln!("[BUILDER] {}", msg);
}
}
impl super::MirBuilder {
/// Ensure a basic block exists in the current function
pub(crate) fn ensure_block_exists(&mut self, block_id: BasicBlockId) -> Result<(), String> {
if let Some(ref mut function) = self.current_function {
if !function.blocks.contains_key(&block_id) {
let block = BasicBlock::new(block_id);
function.add_block(block);
}
Ok(())
} else {
Err("No current function".to_string())
}
}
/// Start a new basic block and set as current
pub(crate) fn start_new_block(&mut self, block_id: BasicBlockId) -> Result<(), String> {
if let Some(ref mut function) = self.current_function {
function.add_block(BasicBlock::new(block_id));
self.current_block = Some(block_id);
Ok(())
} else {
Err("No current function".to_string())
}
}
}
impl super::MirBuilder {
/// Emit a Box method call or plugin call (unified BoxCall)
pub(super) fn emit_box_or_plugin_call(
&mut self,
dst: Option<super::ValueId>,
box_val: super::ValueId,
method: String,
method_id: Option<u16>,
args: Vec<super::ValueId>,
effects: super::EffectMask,
) -> Result<(), String> {
// Check environment variable for unified call usage
let use_unified = std::env::var("NYASH_MIR_UNIFIED_CALL")
.unwrap_or_else(|_| "0".to_string()) != "0";
if use_unified {
// Use unified call emission for BoxCall
// First, try to determine the box type
let mut box_type: Option<String> = self.value_origin_newbox.get(&box_val).cloned();
if box_type.is_none() {
if let Some(t) = self.value_types.get(&box_val) {
match t {
super::MirType::String => box_type = Some("StringBox".to_string()),
super::MirType::Box(name) => box_type = Some(name.clone()),
_ => {}
}
}
}
// Use emit_unified_call with Method target
let target = super::builder_calls::CallTarget::Method {
box_type,
method: method.clone(),
receiver: box_val,
};
return self.emit_unified_call(dst, target, args);
}
// Legacy implementation
self.emit_instruction(super::MirInstruction::BoxCall {
dst,
box_val,
method: method.clone(),
method_id,
args,
effects,
})?;
if let Some(d) = dst {
let mut recv_box: Option<String> = self.value_origin_newbox.get(&box_val).cloned();
if recv_box.is_none() {
if let Some(t) = self.value_types.get(&box_val) {
match t {
super::MirType::String => recv_box = Some("StringBox".to_string()),
super::MirType::Box(name) => recv_box = Some(name.clone()),
_ => {}
}
}
}
if let Some(bt) = recv_box {
if let Some(mt) = self.plugin_method_sigs.get(&(bt.clone(), method.clone())) {
self.value_types.insert(d, mt.clone());
} else {
// Phase 15.5: Unified plugin-based type resolution
// Former core boxes (StringBox, ArrayBox, MapBox) now use plugin_method_sigs only
// No special hardcoded inference - all boxes treated uniformly
}
}
}
Ok(())
}
#[allow(dead_code)]
pub(super) fn emit_type_check(
&mut self,
value: super::ValueId,
expected_type: String,
) -> Result<super::ValueId, String> {
let dst = self.value_gen.next();
self.emit_instruction(super::MirInstruction::TypeOp {
dst,
op: TypeOpKind::Check,
value,
ty: super::MirType::Box(expected_type),
})?;
Ok(dst)
}
#[allow(dead_code)]
pub(super) fn emit_cast(
&mut self,
value: super::ValueId,
target_type: super::MirType,
) -> Result<super::ValueId, String> {
let dst = self.value_gen.next();
self.emit_instruction(super::MirInstruction::TypeOp {
dst,
op: TypeOpKind::Cast,
value,
ty: target_type.clone(),
})?;
Ok(dst)
}
#[allow(dead_code)]
pub(super) fn emit_weak_new(
&mut self,
box_val: super::ValueId,
) -> Result<super::ValueId, String> {
if crate::config::env::mir_core13_pure() {
return Ok(box_val);
}
let dst = self.value_gen.next();
self.emit_instruction(super::MirInstruction::WeakRef {
dst,
op: WeakRefOp::New,
value: box_val,
})?;
Ok(dst)
}
#[allow(dead_code)]
pub(super) fn emit_weak_load(
&mut self,
weak_ref: super::ValueId,
) -> Result<super::ValueId, String> {
if crate::config::env::mir_core13_pure() {
return Ok(weak_ref);
}
let dst = self.value_gen.next();
self.emit_instruction(super::MirInstruction::WeakRef {
dst,
op: WeakRefOp::Load,
value: weak_ref,
})?;
Ok(dst)
}
#[allow(dead_code)]
pub(super) fn emit_barrier_read(&mut self, ptr: super::ValueId) -> Result<(), String> {
self.emit_instruction(super::MirInstruction::Barrier {
op: BarrierOp::Read,
ptr,
})
}
#[allow(dead_code)]
pub(super) fn emit_barrier_write(&mut self, ptr: super::ValueId) -> Result<(), String> {
self.emit_instruction(super::MirInstruction::Barrier {
op: BarrierOp::Write,
ptr,
})
}
}