diff --git a/src/runner/json_v0_bridge/README.md b/src/runner/json_v0_bridge/README.md index bdf50903..8efc82d6 100644 --- a/src/runner/json_v0_bridge/README.md +++ b/src/runner/json_v0_bridge/README.md @@ -7,3 +7,26 @@ 3. break / continue / exit の snapshot を `LoopSnapshotMergeBox` に渡して canonical continue_merge/backedge を構築する。 LoopForm/PHI の意味論を変更したい場合は、`loopform_builder.rs` / `loop_snapshot_merge.rs` を更新すること。`loop_.rs` 内での ad-hoc な PHI 実装は禁止。 + +### Rust パーサー経路との関係 + +- 共通 SSOT: + - 制御フロー: `src/mir/ssot/cf_common.rs`(branch/jump/compare/phi 挿入) + - 算術・比較: `src/mir/ssot/binop_lower.rs`(二項演算 lowering) + - ループ形: `src/mir/ssot/loop_common.rs` + `LoopFormBuilder` +- フロントエンド(入口): + - Rust パーサー経路: `parser/*` + `mir/builder/*` が AST から MIR を構築する。 + - JSON v0 経路: このディレクトリの lowering 群が `ProgramV0` から MIR を構築する。 + - どちらも「PHI/LoopForm/CF の意味論」は mir/ssot 側に委譲し、入口側では構造準備のみに留める。 + +### Bridge 固有ロジックの箱化方針 + +- JSON v0 → MIR の際に必要な「ブリッジ固有」の処理は、入口ファイルにベタ書きしない: + - `hostbridge` / `env` / `me` ダミーなどの特別な変数解決 + - Stage‑1/Stage‑B の try-result モードに合わせた throw ルーティング +- これらは `lowering/globals.rs` / `lowering/throw_ctx.rs` などの小さなモジュールに閉じ込め、 + - JSON v0 経路 + - 将来の Rust パーサー self‑host 経路 + から同じ箱を使い回せるようにする。 + +このディレクトリでは「JSON → MIR 変換」と「最低限のブリッジ設定」だけを行い、その先の最適化や意味論変更は `mir/*`(optimizer/pass, LoopForm, VM/LLVM)側に任せる。 diff --git a/src/runner/json_v0_bridge/lowering.rs b/src/runner/json_v0_bridge/lowering.rs index 46a477ec..38cd6b0c 100644 --- a/src/runner/json_v0_bridge/lowering.rs +++ b/src/runner/json_v0_bridge/lowering.rs @@ -13,11 +13,13 @@ mod merge; use merge::{merge_var_maps, new_block}; // Feature splits (gradual extraction) pub(super) mod expr; +pub(super) mod globals; pub(super) mod if_else; pub(super) mod loop_; pub(super) mod match_expr; // placeholder (not wired) pub(super) mod ternary; // placeholder (not wired) pub(super) mod throw_ctx; +pub(super) mod throw_lower; pub(super) mod try_catch; // thread-local ctx for Result-mode throw routing #[derive(Clone, Copy)] diff --git a/src/runner/json_v0_bridge/lowering/expr.rs b/src/runner/json_v0_bridge/lowering/expr.rs index 9bd1d9c6..54403c5e 100644 --- a/src/runner/json_v0_bridge/lowering/expr.rs +++ b/src/runner/json_v0_bridge/lowering/expr.rs @@ -1,7 +1,9 @@ use super::match_expr; use super::merge::new_block; +use super::globals::resolve_bridge_global; use super::ternary; use super::BridgeEnv; +use super::throw_lower::lower_throw; use crate::mir::{BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId}; use crate::ast::Span; use std::collections::BTreeMap; @@ -50,101 +52,15 @@ impl<'a> VarScope for MapVars<'a> { if let Some(&vid) = self.vars.get(name) { return Ok(Some(vid)); } - // Phase 21.8: Check using-imported modules/boxes - if let Some(box_type) = env.imports.get(name) { - let dst = f.next_value_id(); - if let Some(bb) = f.get_block_mut(cur_bb) { - // Treat as static box reference - create a const string representing the box type - bb.add_instruction(MirInstruction::Const { - dst, - value: ConstValue::String(box_type.clone()), - }); - } - // Cache the resolution for subsequent uses - self.vars.insert(name.to_string(), dst); - return Ok(Some(dst)); - } - // Phase 25.1a: Treat `hostbridge` as a well-known global for bridge lowering. - // The actual extern dispatch is handled at runtime; here we only need a stable - // placeholder value so that Program(JSON) containing hostbridge.extern_invoke(...) - // can be lowered without "undefined variable" errors. - if name == "hostbridge" { - let dst = f.next_value_id(); - if let Some(bb) = f.get_block_mut(cur_bb) { - bb.add_instruction(MirInstruction::Const { - dst, - value: ConstValue::String("hostbridge".into()), - }); - } - self.vars.insert(name.to_string(), dst); - return Ok(Some(dst)); - } - // Phase 25.1b: Treat `env` as a well-known global for env.box_introspect.* etc. - // Similar to hostbridge, we need a placeholder value for the nested method pattern. - if name == "env" { - let dst = f.next_value_id(); - if let Some(bb) = f.get_block_mut(cur_bb) { - bb.add_instruction(MirInstruction::Const { - dst, - value: ConstValue::String("env".into()), - }); - } - self.vars.insert(name.to_string(), dst); - return Ok(Some(dst)); - } - if name == "me" { - if env.allow_me_dummy { - let dst = f.next_value_id(); - if let Some(bb) = f.get_block_mut(cur_bb) { - bb.add_instruction(MirInstruction::NewBox { - dst, - box_type: env.me_class.clone(), - args: vec![], - }); - } - self.vars.insert(name.to_string(), dst); - Ok(Some(dst)) - } else { - Err("undefined 'me' outside box context (set NYASH_BRIDGE_ME_DUMMY=1 to inject placeholder)".into()) - } - } else { - Ok(None) - } - } -} -fn lower_throw( - env: &BridgeEnv, - f: &mut MirFunction, - cur_bb: BasicBlockId, - exception_value: ValueId, -) -> (ValueId, BasicBlockId) { - // Result-mode try context active: route to current catch via Jump and record incoming - if env.try_result_mode && super::throw_ctx::is_active() { - if crate::config::env::cli_verbose() { - eprintln!("[Bridge] lower_throw: routing to catch (Result-mode)"); + // Bridge 固有のグローバル解決(imports/hostbridge/env/me dummy)は専用モジュールに委譲 + if let Some(vid) = + resolve_bridge_global(name, env, f, cur_bb, self.vars)? + { + return Ok(Some(vid)); } - let _ = super::throw_ctx::record_throw(f, cur_bb, exception_value); - return (exception_value, cur_bb); - } - // Legacy path: emit MIR Throw (if enabled) or degrade to const 0 - if env.throw_enabled { - if let Some(bb) = f.get_block_mut(cur_bb) { - bb.set_terminator(MirInstruction::Throw { - exception: exception_value, - effects: EffectMask::PANIC, - }); - } - (exception_value, cur_bb) - } else { - let dst = f.next_value_id(); - if let Some(bb) = f.get_block_mut(cur_bb) { - bb.add_instruction(MirInstruction::Const { - dst, - value: ConstValue::Integer(0), - }); - } - (dst, cur_bb) + + Ok(None) } } diff --git a/src/runner/json_v0_bridge/lowering/globals.rs b/src/runner/json_v0_bridge/lowering/globals.rs new file mode 100644 index 00000000..a325776d --- /dev/null +++ b/src/runner/json_v0_bridge/lowering/globals.rs @@ -0,0 +1,77 @@ +use super::BridgeEnv; +use crate::mir::{BasicBlockId, ConstValue, MirFunction, MirInstruction, ValueId}; +use std::collections::BTreeMap; + +/// Resolve Bridge-specific globals (imports/hostbridge/env/me dummy). +/// +/// - `vars`: current local/global value map (updated when a new value is synthesized) +/// - returns Some(ValueId) when the name is handled here, or Ok(None) to let callers +/// fallback to "undefined variable" handling. +pub(super) fn resolve_bridge_global( + name: &str, + env: &BridgeEnv, + f: &mut MirFunction, + cur_bb: BasicBlockId, + vars: &mut BTreeMap, +) -> Result, String> { + // Phase 21.8: using-imported modules/boxes + if let Some(box_type) = env.imports.get(name) { + let dst = f.next_value_id(); + if let Some(bb) = f.get_block_mut(cur_bb) { + bb.add_instruction(MirInstruction::Const { + dst, + value: ConstValue::String(box_type.clone()), + }); + } + vars.insert(name.to_string(), dst); + return Ok(Some(dst)); + } + + // Phase 25.1a: well-known bridge globals + if name == "hostbridge" { + let dst = f.next_value_id(); + if let Some(bb) = f.get_block_mut(cur_bb) { + bb.add_instruction(MirInstruction::Const { + dst, + value: ConstValue::String("hostbridge".into()), + }); + } + vars.insert(name.to_string(), dst); + return Ok(Some(dst)); + } + + if name == "env" { + let dst = f.next_value_id(); + if let Some(bb) = f.get_block_mut(cur_bb) { + bb.add_instruction(MirInstruction::Const { + dst, + value: ConstValue::String("env".into()), + }); + } + vars.insert(name.to_string(), dst); + return Ok(Some(dst)); + } + + if name == "me" { + if env.allow_me_dummy { + let dst = f.next_value_id(); + if let Some(bb) = f.get_block_mut(cur_bb) { + bb.add_instruction(MirInstruction::NewBox { + dst, + box_type: env.me_class.clone(), + args: vec![], + }); + } + vars.insert(name.to_string(), dst); + Ok(Some(dst)) + } else { + Err( + "undefined 'me' outside box context (set NYASH_BRIDGE_ME_DUMMY=1 to inject placeholder)" + .into(), + ) + } + } else { + Ok(None) + } +} + diff --git a/src/runner/json_v0_bridge/lowering/throw_lower.rs b/src/runner/json_v0_bridge/lowering/throw_lower.rs new file mode 100644 index 00000000..79321ae8 --- /dev/null +++ b/src/runner/json_v0_bridge/lowering/throw_lower.rs @@ -0,0 +1,45 @@ +use super::BridgeEnv; +use crate::mir::{BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId}; + +/// Lower a throw expression/value according to BridgeEnv and throw_ctx. +/// +/// - Result-mode try contextが有効なら、catch ブロックへ jump しつつ incoming に記録する。 +/// - それ以外では: +/// - throw_enabled=1 のとき MIR Throw を発行 +/// - そうでなければ `const 0` にフォールバック +pub(super) fn lower_throw( + env: &BridgeEnv, + f: &mut MirFunction, + cur_bb: BasicBlockId, + exception_value: ValueId, +) -> (ValueId, BasicBlockId) { + // Result-mode try context active: route to current catch via Jump and record incoming + if env.try_result_mode && super::throw_ctx::is_active() { + if crate::config::env::cli_verbose() { + eprintln!("[Bridge] lower_throw: routing to catch (Result-mode)"); + } + let _ = super::throw_ctx::record_throw(f, cur_bb, exception_value); + return (exception_value, cur_bb); + } + + // Legacy path: emit MIR Throw (if enabled) or degrade to const 0 + if env.throw_enabled { + if let Some(bb) = f.get_block_mut(cur_bb) { + bb.set_terminator(MirInstruction::Throw { + exception: exception_value, + effects: EffectMask::PANIC, + }); + } + (exception_value, cur_bb) + } else { + let dst = f.next_value_id(); + if let Some(bb) = f.get_block_mut(cur_bb) { + bb.add_instruction(MirInstruction::Const { + dst, + value: ConstValue::Integer(0), + }); + } + (dst, cur_bb) + } +} +