Factor JSON v0 bridge globals/throw into small helpers

This commit is contained in:
nyash-codex
2025-11-24 15:21:49 +09:00
parent da1a5558e5
commit 6885235145
5 changed files with 156 additions and 93 deletions

View File

@ -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` ダミーなどの特別な変数解決
- Stage1/StageB の try-result モードに合わせた throw ルーティング
- これらは `lowering/globals.rs` / `lowering/throw_ctx.rs` などの小さなモジュールに閉じ込め、
- JSON v0 経路
- 将来の Rust パーサー selfhost 経路
から同じ箱を使い回せるようにする。
このディレクトリでは「JSON → MIR 変換」と「最低限のブリッジ設定」だけを行い、その先の最適化や意味論変更は `mir/*`optimizer/pass, LoopForm, VM/LLVM側に任せる。

View File

@ -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)]

View File

@ -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)
}
}

View File

@ -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<String, ValueId>,
) -> Result<Option<ValueId>, 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)
}
}

View File

@ -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)
}
}