feat(mir): Phase 25.1f完了 - Conservative PHI + ControlForm観測レイヤー
🎉 Conservative PHI Box理論による完全SSA構築 **Phase 7-B: Conservative PHI実装** - 片方branchのみ定義変数に対応(emit_void使用) - 全変数にPHI生成(Conservative Box理論) - Stage-1 resolver全テスト緑化(3/3 PASS) **Phase 25.1f: ControlForm観測レイヤー** - LoopShape/IfShape/ControlForm構造定義 - Loop/If統一インターフェース実装 - debug_dump/debug_validate機能追加 - NYASH_CONTROL_FORM_TRACE環境変数対応 **主な変更**: - src/mir/builder/phi.rs: Conservative PHI実装 - src/mir/control_form.rs: ControlForm構造(NEW) - src/mir/loop_builder.rs: LoopForm v2デフォルト化 **テスト結果**: ✅ mir_stage1_using_resolver_min_fragment_verifies ✅ mir_stage1_using_resolver_full_collect_entries_verifies ✅ mir_parserbox_parse_program2_harness_parses_minimal_source 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <chatgpt@openai.com>
This commit is contained in:
@ -8,6 +8,7 @@ pub fn pre_run_reset_oob_if_strict() {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn post_run_exit_if_oob_strict_triggered() -> ! {
|
||||
if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() {
|
||||
eprintln!("[gate-c][oob-strict] Out-of-bounds observed → exit(1)");
|
||||
|
||||
@ -90,6 +90,7 @@ pub(super) fn demo_parser_system() {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn demo_interpreter_system() {
|
||||
println!("\n🎭 7. Interpreter System:");
|
||||
println!(" ⚠️ Legacy interpreter removed - use VM or LLVM backends instead");
|
||||
|
||||
@ -129,18 +129,17 @@ pub fn run_json_v1_inline(json: &str) -> i32 {
|
||||
|
||||
let sval = regs.get(&src).cloned();
|
||||
let is_integer = sval.is_some(); // hv1 inline stores i64 only → integer
|
||||
let mut out = 0i64;
|
||||
if operation == "check" || operation == "is" {
|
||||
if target == "i64" || target == "int" || target == "integer" {
|
||||
out = if is_integer { 1 } else { 0 };
|
||||
let out: i64 = if target == "i64" || target == "int" || target == "integer" {
|
||||
if is_integer { 1 } else { 0 }
|
||||
} else if target == "bool" {
|
||||
// Inline model uses integer registers; treat 0/1 as bool when present
|
||||
out = if let Some(v) = sval { if v == 0 || v == 1 { 1 } else { 0 } } else { 0 };
|
||||
if let Some(v) = sval { if v == 0 || v == 1 { 1 } else { 0 } } else { 0 }
|
||||
} else if target == "string" {
|
||||
out = 0; // no string registers in inline model
|
||||
0 // no string registers in inline model
|
||||
} else {
|
||||
out = 0;
|
||||
}
|
||||
0
|
||||
};
|
||||
regs.insert(dst, out);
|
||||
} else {
|
||||
// cast/as: pass-through (MVP)
|
||||
|
||||
@ -2,7 +2,7 @@ use super::ast::{ProgramV0, StmtV0, ExprV0};
|
||||
use crate::mir::Callee;
|
||||
use crate::mir::{
|
||||
BasicBlockId, ConstValue, EffectMask, FunctionSignature, MirFunction, MirInstruction, MirModule,
|
||||
MirPrinter, MirType, ValueId, BinaryOp,
|
||||
MirPrinter, MirType, ValueId,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::cell::RefCell;
|
||||
@ -103,6 +103,7 @@ pub(super) struct BridgeEnv {
|
||||
}
|
||||
|
||||
impl BridgeEnv {
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn load() -> Self {
|
||||
Self::with_imports(HashMap::new())
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use super::BridgeEnv;
|
||||
use super::ternary;
|
||||
use super::match_expr;
|
||||
use crate::mir::{
|
||||
BasicBlockId, BinaryOp, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId,
|
||||
BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use super::{lower_stmt_list_with_vars, merge_var_maps, new_block, BridgeEnv, LoopContext};
|
||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||
use crate::mir::{BasicBlockId, MirFunction, ValueId};
|
||||
use std::collections::HashMap;
|
||||
use super::super::ast::StmtV0;
|
||||
use super::super::ast::ExprV0;
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
use super::merge::new_block;
|
||||
use super::BridgeEnv;
|
||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||
use crate::mir::{BasicBlockId, MirFunction, ValueId};
|
||||
use super::super::ast::ExprV0;
|
||||
|
||||
use super::expr::{lower_expr_with_scope, VarScope};
|
||||
@ -35,7 +35,7 @@ pub(super) fn lower_ternary_expr_with_scope<S: VarScope>(
|
||||
}
|
||||
let out = f.next_value_id();
|
||||
// フェーズM.2: PHI統一処理(no_phi分岐削除)
|
||||
let mut inputs = vec![(tend, tval), (eend, eval)];
|
||||
let inputs = vec![(tend, tval), (eend, eval)];
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs);
|
||||
Ok((out, merge_bb))
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||
use crate::mir::{BasicBlockId, MirFunction, ValueId};
|
||||
use std::cell::RefCell;
|
||||
|
||||
thread_local! {
|
||||
|
||||
@ -511,27 +511,6 @@ pub fn try_parse_v1_to_module(json: &str) -> Result<Option<MirModule>, String> {
|
||||
if let Some(d) = dst_opt { max_value_id = max_value_id.max(d.as_u32() + 1); }
|
||||
}
|
||||
}
|
||||
"Constructor" => {
|
||||
// box_type: string, dst: required
|
||||
let dst = dst_opt.ok_or_else(|| format!(
|
||||
"mir_call Constructor requires dst in function '{}'",
|
||||
func_name
|
||||
))?;
|
||||
let bt = callee_obj
|
||||
.get("box_type")
|
||||
.and_then(Value::as_str)
|
||||
.ok_or_else(|| format!(
|
||||
"mir_call Constructor missing box_type in function '{}'",
|
||||
func_name
|
||||
))?
|
||||
.to_string();
|
||||
block_ref.add_instruction(MirInstruction::NewBox {
|
||||
dst,
|
||||
box_type: bt,
|
||||
args: argv.clone(),
|
||||
});
|
||||
max_value_id = max_value_id.max(dst.as_u32() + 1);
|
||||
}
|
||||
"Extern" => {
|
||||
let name = callee_obj
|
||||
.get("name")
|
||||
|
||||
@ -31,6 +31,7 @@ fn create_json_v1_root(functions: serde_json::Value) -> serde_json::Value {
|
||||
/// Helper: detect residual numeric-core boxcalls that should have been lowered by AotPrepNumericCoreBox.
|
||||
/// Currently we only check for `boxcall` with `method:"mul_naive"` which should become
|
||||
/// `call("NyNumericMatI64.mul_naive", ...)` when NYASH_AOT_NUMERIC_CORE=1 is effective.
|
||||
#[allow(dead_code)]
|
||||
fn has_numeric_core_boxcall(root: &serde_json::Value) -> bool {
|
||||
let funs = match root.get("functions") {
|
||||
Some(v) => v.as_array().cloned().unwrap_or_default(),
|
||||
@ -61,6 +62,7 @@ fn has_numeric_core_boxcall(root: &serde_json::Value) -> bool {
|
||||
/// Helper: enforce numeric_core invariants when NYASH_AOT_NUMERIC_CORE=1 is set.
|
||||
/// - Default: emit a warning if mul_naive boxcalls are still present.
|
||||
/// - Strict: if NYASH_AOT_NUMERIC_CORE_STRICT=1, return Err to fail fast.
|
||||
#[allow(dead_code)]
|
||||
fn check_numeric_core_invariants(root: &serde_json::Value) -> Result<(), String> {
|
||||
let numeric_on = matches!(std::env::var("NYASH_AOT_NUMERIC_CORE").ok().as_deref(), Some("1"));
|
||||
if !numeric_on {
|
||||
|
||||
@ -22,7 +22,7 @@ pub fn gather_required_providers() -> Vec<String> {
|
||||
return v;
|
||||
}
|
||||
// Default conservative set
|
||||
let mut v = vec![
|
||||
let v = vec![
|
||||
"FileBox".to_string(),
|
||||
"ConsoleBox".to_string(),
|
||||
"ArrayBox".to_string(),
|
||||
@ -86,4 +86,3 @@ pub fn check_and_report(strict: bool, quiet_pipe: bool, label: &str) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -111,7 +111,7 @@ impl<'a> PreludeManagerBox<'a> {
|
||||
fn build_text_merged(
|
||||
&self,
|
||||
source: &str,
|
||||
filename: &str,
|
||||
_filename: &str,
|
||||
prelude_paths: &[String],
|
||||
trace: bool,
|
||||
) -> Result<String, String> {
|
||||
@ -123,7 +123,7 @@ impl<'a> PreludeManagerBox<'a> {
|
||||
.map_err(|e| format!("using: failed to read '{}': {}", path, e))?;
|
||||
|
||||
// using行を除去して正規化
|
||||
let using_resolver = UsingResolutionBox::new(&self.runner, path)?;
|
||||
let _using_resolver = UsingResolutionBox::new(&self.runner, path)?;
|
||||
let (cleaned_raw, _nested) = self.collect_using_and_strip_internal(&content, path)?;
|
||||
let cleaned = self.normalize_text_for_inline(&cleaned_raw);
|
||||
|
||||
|
||||
@ -129,7 +129,7 @@ impl<'a> SelfhostPipelineBox<'a> {
|
||||
&self,
|
||||
error: &str,
|
||||
original_code: &str,
|
||||
filename: &str,
|
||||
_filename: &str,
|
||||
) -> CompilationResult {
|
||||
eprintln!("[selfhost-pipeline] ⚠️ Error: {}", error);
|
||||
eprintln!("[selfhost-pipeline] 🔄 Falling back to original code");
|
||||
@ -179,8 +179,8 @@ impl<'a> SelfhostPipelineBox<'a> {
|
||||
/// 📊 パフォーマンスプロファイリングするにゃ!
|
||||
pub fn profile_pipeline(
|
||||
&mut self,
|
||||
code: &str,
|
||||
filename: &str,
|
||||
_code: &str,
|
||||
_filename: &str,
|
||||
) -> Result<String, String> {
|
||||
// プロファイル機能を実装(別途)
|
||||
// TODO: プロファイル機能を追加
|
||||
|
||||
@ -448,7 +448,7 @@ pub fn resolve_prelude_paths_profiled(
|
||||
// must be discovered so that their definitions are present at runtime
|
||||
// (e.g., runner_min -> lower_* boxes). Previously this only ran when
|
||||
// NYASH_USING_AST=1, which caused unresolved calls in inline flows.
|
||||
let ast_on = crate::config::env::env_bool("NYASH_USING_AST");
|
||||
let _ast_on = crate::config::env::env_bool("NYASH_USING_AST");
|
||||
let mut out: Vec<String> = Vec::new();
|
||||
let mut seen: std::collections::HashSet<String> = std::collections::HashSet::new();
|
||||
fn normalize_path(path: &str) -> (String, String) {
|
||||
|
||||
@ -14,6 +14,7 @@ pub struct UsingResolutionBox<'a> {
|
||||
runner: &'a NyashRunner,
|
||||
config: UsingConfig,
|
||||
ctx_dir: Option<PathBuf>,
|
||||
#[allow(dead_code)]
|
||||
filename_canon: Option<PathBuf>,
|
||||
inside_pkg: bool,
|
||||
seen_paths: HashMap<String, (String, usize)>, // canon_path -> (alias/label, first_line)
|
||||
|
||||
@ -476,7 +476,7 @@ impl NyashRunner {
|
||||
|
||||
match vm.execute_module(&module_vm) {
|
||||
Ok(ret) => {
|
||||
use crate::box_trait::{NyashBox, IntegerBox, BoolBox};
|
||||
use crate::box_trait::{IntegerBox, BoolBox};
|
||||
|
||||
// Extract exit code from return value
|
||||
let exit_code = if let Some(ib) = ret.as_any().downcast_ref::<IntegerBox>() {
|
||||
|
||||
@ -321,7 +321,7 @@ impl NyashRunner {
|
||||
}
|
||||
match vm.execute_module(&module_vm) {
|
||||
Ok(ret) => {
|
||||
use crate::box_trait::{NyashBox, IntegerBox, BoolBox};
|
||||
use crate::box_trait::{IntegerBox, BoolBox};
|
||||
|
||||
// Extract exit code from return value
|
||||
let exit_code = if let Some(ib) = ret.as_any().downcast_ref::<IntegerBox>() {
|
||||
@ -346,7 +346,8 @@ impl NyashRunner {
|
||||
|
||||
impl NyashRunner {
|
||||
/// Small helper to continue fallback execution once AST is prepared
|
||||
fn execute_vm_fallback_from_ast(&self, filename: &str, ast: nyash_rust::ast::ASTNode) {
|
||||
#[allow(dead_code)]
|
||||
fn execute_vm_fallback_from_ast(&self, _filename: &str, ast: nyash_rust::ast::ASTNode) {
|
||||
use crate::{
|
||||
backend::MirInterpreter,
|
||||
box_factory::{BoxFactory, RuntimeError},
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
*/
|
||||
|
||||
use super::*;
|
||||
use crate::runner::child_env;
|
||||
|
||||
impl NyashRunner {
|
||||
/// Try to handle `--ny-parser-pipe` / `--json-file` flow.
|
||||
@ -20,7 +19,7 @@ impl NyashRunner {
|
||||
if !(groups.parser.ny_parser_pipe || groups.parser.json_file.is_some()) {
|
||||
return false;
|
||||
}
|
||||
let mut json = if let Some(path) = &groups.parser.json_file {
|
||||
let json = if let Some(path) = &groups.parser.json_file {
|
||||
match std::fs::read_to_string(path) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
|
||||
@ -84,6 +84,7 @@ impl NyashRunner {
|
||||
}
|
||||
|
||||
/// Suggest candidate files by leaf name within limited bases (apps/lib/.)
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn suggest_in_base(base: &str, leaf: &str, out: &mut Vec<String>) {
|
||||
use std::fs;
|
||||
fn walk(dir: &std::path::Path, leaf: &str, out: &mut Vec<String>, depth: usize) {
|
||||
|
||||
@ -58,7 +58,7 @@ impl NyashRunner {
|
||||
for p in list {
|
||||
if list_only { println!(" • {}", p); continue; }
|
||||
match std::fs::read_to_string(&p) {
|
||||
Ok(code) => {
|
||||
Ok(_code) => {
|
||||
// Legacy interpreter removed - ny_plugins execution disabled
|
||||
println!("[ny_plugins] {}: SKIP (legacy interpreter removed)", p);
|
||||
}
|
||||
|
||||
@ -403,21 +403,22 @@ impl NyashRunner {
|
||||
// パイプライン(tools/ny_selfhost_inline.sh など)を使う想定とし、ここでは常に Rust 既定
|
||||
// パスへフォールバックする。
|
||||
crate::cli_v!("[ny-compiler] inline selfhost pipeline disabled (Phase 25.1b); falling back to default path");
|
||||
return false;
|
||||
|
||||
match super::json_v0_bridge::parse_json_v0_to_module("") {
|
||||
Ok(module) => {
|
||||
if crate::config::env::cli_verbose() {
|
||||
// Dev-only escape hatch: allow forcing the old inline path when explicitly requested.
|
||||
if std::env::var("NYASH_SELFHOST_INLINE_FORCE").ok().as_deref() == Some("1") {
|
||||
match super::json_v0_bridge::parse_json_v0_to_module("") {
|
||||
Ok(module) => {
|
||||
if crate::config::env::cli_verbose() {
|
||||
super::json_v0_bridge::maybe_dump_mir(&module);
|
||||
if crate::config::env::cli_verbose() {
|
||||
super::json_v0_bridge::maybe_dump_mir(&module);
|
||||
}
|
||||
}
|
||||
let emit_only = std::env::var("NYASH_NY_COMPILER_EMIT_ONLY")
|
||||
.unwrap_or_else(|_| "1".to_string())
|
||||
== "1";
|
||||
if emit_only {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let emit_only = std::env::var("NYASH_NY_COMPILER_EMIT_ONLY")
|
||||
.unwrap_or_else(|_| "1".to_string())
|
||||
== "1";
|
||||
if emit_only {
|
||||
return false;
|
||||
}
|
||||
// Phase-15 policy: when NYASH_VM_USE_PY=1, prefer PyVM as reference executor
|
||||
// regardless of BoxCall presence to ensure semantics parity (e.g., PHI merges).
|
||||
let prefer_pyvm = std::env::var("NYASH_VM_USE_PY").ok().as_deref() == Some("1");
|
||||
@ -430,25 +431,29 @@ impl NyashRunner {
|
||||
})
|
||||
})
|
||||
});
|
||||
if prefer_pyvm || needs_pyvm {
|
||||
let label = if prefer_pyvm { "selfhost" } else { "selfhost-fallback" };
|
||||
if let Some(code) = crate::runner::modes::common_util::selfhost::json::run_pyvm_module(&module, label) {
|
||||
println!("Result: {}", code);
|
||||
std::process::exit(code);
|
||||
if prefer_pyvm || needs_pyvm {
|
||||
let label = if prefer_pyvm { "selfhost" } else { "selfhost-fallback" };
|
||||
if let Some(code) = crate::runner::modes::common_util::selfhost::json::run_pyvm_module(&module, label) {
|
||||
println!("Result: {}", code);
|
||||
std::process::exit(code);
|
||||
}
|
||||
}
|
||||
crate::runner::child_env::pre_run_reset_oob_if_strict();
|
||||
self.execute_mir_module(&module);
|
||||
if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() {
|
||||
eprintln!("[selfhost][oob-strict] Out-of-bounds observed → exit(1)");
|
||||
std::process::exit(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
crate::runner::child_env::pre_run_reset_oob_if_strict();
|
||||
self.execute_mir_module(&module);
|
||||
if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() {
|
||||
eprintln!("[selfhost][oob-strict] Out-of-bounds observed → exit(1)");
|
||||
std::process::exit(1);
|
||||
Err(e) => {
|
||||
eprintln!("❌ JSON v0 bridge error: {}", e);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("❌ JSON v0 bridge error: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Default path: always fall back to existing Rust runner.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user