Files
hakorune/src/runner/json_v0_bridge/lowering/try_catch.rs
nyash-codex 447bbec998 refactor(joinir): Split ast_lowerer and join_ir_vm_bridge into modules
ast_lowerer.rs → ast_lowerer/ (10 files):
- mod.rs: public surface + entry dispatch
- context.rs: ExtractCtx helpers
- expr.rs: expression-to-JoinIR extraction
- if_return.rs: simple if→Select lowering
- loop_patterns.rs: loop variants (simple/break/continue)
- read_quoted.rs: read_quoted_from lowering (Phase 45-46)
- nested_if.rs: NestedIfMerge lowering
- analysis.rs: loop if-var analysis + metadata helpers
- tests.rs: frontend lowering tests
- README.md: module documentation

join_ir_vm_bridge.rs → join_ir_vm_bridge/ (5 files):
- mod.rs: public surface + shared helpers
- convert.rs: JoinIR→MIR lowering
- runner.rs: VM execution entry (run_joinir_via_vm)
- meta.rs: experimental metadata-aware hooks
- tests.rs: bridge-specific unit tests
- README.md: module documentation

Benefits:
- Clear separation of concerns per pattern
- Easier navigation and maintenance
- Each file has single responsibility
- README documents module boundaries

Co-authored-by: ChatGPT <noreply@openai.com>

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 17:42:19 +09:00

416 lines
16 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use super::super::ast::{CatchV0, StmtV0};
use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext};
use crate::ast::Span;
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
use std::collections::BTreeMap;
pub(super) fn lower_try_stmt(
f: &mut MirFunction,
cur_bb: BasicBlockId,
try_body: &[StmtV0],
catches: &[CatchV0],
finally: &[StmtV0],
vars: &mut BTreeMap<String, ValueId>,
loop_stack: &mut Vec<LoopContext>,
env: &BridgeEnv,
) -> Result<BasicBlockId, String> {
let try_enabled = std::env::var("NYASH_BRIDGE_TRY_ENABLE").ok().as_deref() == Some("1");
// Result-mode lowering: structured blocks without MIR Throw/Catch
if env.try_result_mode {
// Only support 0 or 1 catch for MVP
let has_catch = !catches.is_empty();
if catches.len() > 1 {
// Fallback to safe lowering (ignore catches) for multi-catch
let mut tmp_vars = vars.clone();
let mut next_bb = super::lower_stmt_list_with_vars(
f,
cur_bb,
try_body,
&mut tmp_vars,
loop_stack,
env,
)?;
if !finally.is_empty() {
next_bb = super::lower_stmt_list_with_vars(
f,
next_bb,
finally,
&mut tmp_vars,
loop_stack,
env,
)?;
}
*vars = tmp_vars;
return Ok(next_bb);
}
let base_vars = vars.clone();
let try_bb = new_block(f);
let catch_bb_opt = if has_catch { Some(new_block(f)) } else { None };
let finally_bb = if !finally.is_empty() {
Some(new_block(f))
} else {
None
};
let exit_bb = new_block(f);
f.set_jump_terminator(cur_bb, try_bb)?;
if let Some(succ) = f.get_block_mut(try_bb) {
succ.add_predecessor(cur_bb);
}
// Install thread-local throw context so nested throw expressions jump to catch_bb
if has_catch {
let catch_bb = catch_bb_opt.expect("catch_bb must exist when has_catch");
if crate::config::env::cli_verbose() {
eprintln!(
"[Bridge] try_result_mode: set ThrowCtx (catch_bb={:?})",
catch_bb
);
}
super::throw_ctx::set(catch_bb);
} else if crate::config::env::cli_verbose() {
eprintln!("[Bridge] try_result_mode: no catch present; ThrowCtx not set");
}
let mut try_vars = base_vars.clone();
let try_end =
super::lower_stmt_list_with_vars(f, try_bb, try_body, &mut try_vars, loop_stack, env)?;
// Take recorded incoming exceptions
let incoming_exc = if has_catch {
super::throw_ctx::take()
.map(|c| c.incoming)
.unwrap_or_default()
} else {
Vec::new()
};
let target = finally_bb.unwrap_or(exit_bb);
f.set_jump_terminator(try_end, target)?;
if let Some(succ) = f.get_block_mut(target) {
succ.add_predecessor(try_end);
}
let try_branch_vars = try_vars.clone();
// Lower catch block if present and reachable
let (catch_end, catch_branch_vars) = if has_catch {
let catch_bb = catch_bb_opt.expect("catch_bb must exist when has_catch");
// Prepare catch var mapping; optionally bind param via PHI from incoming throw sites.
let catch_clause = &catches[0];
let mut catch_vars = base_vars.clone();
if let Some(param) = &catch_clause.param {
// フェーズM.2: PHI統一処理no_phi条件削除
if !incoming_exc.is_empty() {
let phi_dst = f.next_value_id();
if let Some(_bb) = f.get_block_mut(catch_bb) {
let mut inputs = incoming_exc.clone();
inputs.sort_by_key(|(bbid, _)| bbid.0);
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
f,
catch_bb,
phi_dst,
inputs,
Span::unknown(),
);
}
catch_vars.insert(param.clone(), phi_dst);
}
}
let end = super::lower_stmt_list_with_vars(
f,
catch_bb,
&catch_clause.body,
&mut catch_vars,
loop_stack,
env,
)?;
let target = finally_bb.unwrap_or(exit_bb);
f.set_jump_terminator(end, target)?;
if let Some(succ) = f.get_block_mut(target) {
succ.add_predecessor(end);
}
(end, catch_vars)
} else {
(try_end, base_vars.clone())
};
// Finally or direct exit; merge variables across branches
use std::collections::HashSet;
if let Some(finally_block) = finally_bb {
// Compute merged var map from try_end + catch_end (if has_catch)
let branch_vars: Vec<(BasicBlockId, BTreeMap<String, ValueId>)> = if has_catch {
vec![
(try_end, try_branch_vars.clone()),
(catch_end, catch_branch_vars.clone()),
]
} else {
vec![(try_end, try_branch_vars.clone())]
};
let mut names: HashSet<String> = base_vars.keys().cloned().collect();
for (_, map) in &branch_vars {
names.extend(map.keys().cloned());
}
let mut merged_vars = base_vars.clone();
let mut phi_entries: Vec<(ValueId, Vec<(BasicBlockId, ValueId)>)> = Vec::new();
for name in names {
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (bbid, map) in &branch_vars {
if let Some(&v) = map.get(&name) {
inputs.push((*bbid, v));
}
}
if inputs.is_empty() {
if let Some(&b) = base_vars.get(&name) {
merged_vars.insert(name.clone(), b);
}
continue;
}
let uniq: HashSet<ValueId> = inputs.iter().map(|(_, v)| *v).collect();
if uniq.len() == 1 {
merged_vars.insert(name.clone(), inputs[0].1);
continue;
}
let dst = f.next_value_id();
inputs.sort_by_key(|(bbid, _)| bbid.0);
phi_entries.push((dst, inputs));
merged_vars.insert(name.clone(), dst);
}
if let Some(_bb) = f.get_block_mut(finally_block) {
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
f,
finally_block,
dst,
inputs,
Span::unknown(),
);
}
}
let mut finally_vars = merged_vars.clone();
let final_end = super::lower_stmt_list_with_vars(
f,
finally_block,
finally,
&mut finally_vars,
loop_stack,
env,
)?;
f.set_jump_terminator(final_end, exit_bb)?;
if let Some(succ) = f.get_block_mut(exit_bb) {
succ.add_predecessor(final_end);
}
*vars = finally_vars;
return Ok(exit_bb);
} else {
// Merge at exit_bb
let branch_vars: Vec<(BasicBlockId, BTreeMap<String, ValueId>)> = if has_catch {
vec![(try_end, try_branch_vars), (catch_end, catch_branch_vars)]
} else {
vec![(try_end, try_branch_vars)]
};
let mut names: HashSet<String> = base_vars.keys().cloned().collect();
for (_, map) in &branch_vars {
names.extend(map.keys().cloned());
}
let mut merged_vars = base_vars.clone();
let mut phi_entries: Vec<(ValueId, Vec<(BasicBlockId, ValueId)>)> = Vec::new();
for name in names {
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (bbid, map) in &branch_vars {
if let Some(&v) = map.get(&name) {
inputs.push((*bbid, v));
}
}
if inputs.is_empty() {
if let Some(&b) = base_vars.get(&name) {
merged_vars.insert(name.clone(), b);
}
continue;
}
let uniq: HashSet<ValueId> = inputs.iter().map(|(_, v)| *v).collect();
if uniq.len() == 1 {
merged_vars.insert(name.clone(), inputs[0].1);
continue;
}
let dst = f.next_value_id();
inputs.sort_by_key(|(bbid, _)| bbid.0);
phi_entries.push((dst, inputs));
merged_vars.insert(name.clone(), dst);
}
if let Some(_bb) = f.get_block_mut(exit_bb) {
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
f,
exit_bb,
dst,
inputs,
Span::unknown(),
);
}
}
*vars = merged_vars;
return Ok(exit_bb);
}
} else if !try_enabled || catches.is_empty() || catches.len() > 1 {
let mut tmp_vars = vars.clone();
let mut next_bb =
lower_stmt_list_with_vars(f, cur_bb, try_body, &mut tmp_vars, loop_stack, env)?;
if !finally.is_empty() {
next_bb =
lower_stmt_list_with_vars(f, next_bb, finally, &mut tmp_vars, loop_stack, env)?;
}
*vars = tmp_vars;
return Ok(next_bb);
}
let base_vars = vars.clone();
let try_bb = new_block(f);
let catch_clause = &catches[0];
let catch_bb = new_block(f);
let finally_bb = if !finally.is_empty() {
let id = new_block(f);
Some(id)
} else {
None
};
let exit_bb = new_block(f);
let handler_target = finally_bb.unwrap_or(exit_bb);
let exception_value = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::Catch {
exception_type: catch_clause.type_hint.clone(),
exception_value,
handler_bb: catch_bb,
});
}
f.set_jump_terminator(cur_bb, try_bb)?;
let mut try_vars = vars.clone();
let try_end = lower_stmt_list_with_vars(f, try_bb, try_body, &mut try_vars, loop_stack, env)?;
f.set_jump_terminator(try_end, handler_target)?;
let try_branch_vars = try_vars.clone();
let mut catch_vars = base_vars.clone();
if let Some(param) = &catch_clause.param {
catch_vars.insert(param.clone(), exception_value);
}
let catch_end = lower_stmt_list_with_vars(
f,
catch_bb,
&catch_clause.body,
&mut catch_vars,
loop_stack,
env,
)?;
if let Some(param) = &catch_clause.param {
catch_vars.remove(param);
}
f.set_jump_terminator(catch_end, handler_target)?;
let catch_branch_vars = catch_vars.clone();
use std::collections::HashSet;
let branch_vars = vec![(try_end, try_branch_vars), (catch_end, catch_branch_vars)];
if let Some(finally_block) = finally_bb {
let names: HashSet<String> = {
let mut set: HashSet<String> = base_vars.keys().cloned().collect();
for (_, map) in &branch_vars {
set.extend(map.keys().cloned());
}
set
};
let mut merged_vars = base_vars.clone();
let mut phi_entries: Vec<(ValueId, Vec<(BasicBlockId, ValueId)>)> = Vec::new();
for name in names {
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (bbid, map) in &branch_vars {
if let Some(&val) = map.get(&name) {
inputs.push((*bbid, val));
}
}
if inputs.is_empty() {
if let Some(&base_val) = base_vars.get(&name) {
merged_vars.insert(name.clone(), base_val);
}
continue;
}
let unique: HashSet<ValueId> = inputs.iter().map(|(_, v)| *v).collect();
if unique.len() == 1 {
merged_vars.insert(name.clone(), inputs[0].1);
continue;
}
let dst = f.next_value_id();
inputs.sort_by_key(|(bbid, _)| bbid.0);
phi_entries.push((dst, inputs));
merged_vars.insert(name.clone(), dst);
}
// フェーズM.2: PHI統一処理no_phi分岐削除
if let Some(_bb) = f.get_block_mut(finally_block) {
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
f,
finally_block,
dst,
inputs,
Span::unknown(),
);
}
}
let mut finally_vars = merged_vars.clone();
let final_end = lower_stmt_list_with_vars(
f,
finally_block,
finally,
&mut finally_vars,
loop_stack,
env,
)?;
f.set_jump_terminator(final_end, exit_bb)?;
*vars = finally_vars;
Ok(exit_bb)
} else {
let names: HashSet<String> = {
let mut set: HashSet<String> = base_vars.keys().cloned().collect();
for (_, map) in &branch_vars {
set.extend(map.keys().cloned());
}
set
};
let mut merged_vars = base_vars.clone();
let mut phi_entries: Vec<(ValueId, Vec<(BasicBlockId, ValueId)>)> = Vec::new();
for name in names {
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (bbid, map) in &branch_vars {
if let Some(&val) = map.get(&name) {
inputs.push((*bbid, val));
}
}
if inputs.is_empty() {
if let Some(&base_val) = base_vars.get(&name) {
merged_vars.insert(name.clone(), base_val);
}
continue;
}
let unique: HashSet<ValueId> = inputs.iter().map(|(_, v)| *v).collect();
if unique.len() == 1 {
merged_vars.insert(name.clone(), inputs[0].1);
continue;
}
let dst = f.next_value_id();
inputs.sort_by_key(|(bbid, _)| bbid.0);
phi_entries.push((dst, inputs));
merged_vars.insert(name.clone(), dst);
}
// フェーズM.2: PHI統一処理no_phi分岐削除
if let Some(_bb) = f.get_block_mut(exit_bb) {
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
f,
exit_bb,
dst,
inputs,
Span::unknown(),
);
}
}
*vars = merged_vars;
Ok(exit_bb)
}
}