chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更

Phase 25.1 完了成果:
-  LoopForm v2 テスト・ドキュメント・コメント完備
  - 4ケース(A/B/C/D)完全テストカバレッジ
  - 最小再現ケース作成(SSAバグ調査用)
  - SSOT文書作成(loopform_ssot.md)
  - 全ソースに [LoopForm] コメントタグ追加

-  Stage-1 CLI デバッグ環境構築
  - stage1_cli.hako 実装
  - stage1_bridge.rs ブリッジ実装
  - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh)
  - アーキテクチャ改善提案文書

-  環境変数削減計画策定
  - 25変数の完全調査・分類
  - 6段階削減ロードマップ(25→5、80%削減)
  - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG)

Phase 26-D からの累積変更:
- PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等)
- MIRビルダーリファクタリング
- 型伝播・最適化パス改善
- その他約300ファイルの累積変更

🎯 技術的成果:
- SSAバグ根本原因特定(条件分岐内loop変数変更)
- Region+next_iパターン適用完了(UsingCollectorBox等)
- LoopFormパターン文書化・テスト化完了
- セルフホスティング基盤強化

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: ChatGPT <noreply@openai.com>
Co-Authored-By: Task Assistant <task@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-21 06:25:17 +09:00
parent baf028a94f
commit f9d100ce01
366 changed files with 14322 additions and 5236 deletions

View File

@ -1,5 +1,5 @@
use nyash_rust::ast::{ASTNode, BinaryOperator, LiteralValue, Span, UnaryOperator};
use serde_json::{json, Value};
use nyash_rust::ast::{ASTNode, LiteralValue, BinaryOperator, UnaryOperator, Span};
pub fn ast_to_json(ast: &ASTNode) -> Value {
match ast.clone() {
@ -7,7 +7,9 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
"kind": "Program",
"statements": statements.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>()
}),
ASTNode::Loop { condition, body, .. } => json!({
ASTNode::Loop {
condition, body, ..
} => json!({
"kind": "Loop",
"condition": ast_to_json(&condition),
"body": body.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>()
@ -27,18 +29,32 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
"target": ast_to_json(&target),
"value": ast_to_json(&value),
}),
ASTNode::Local { variables, initial_values, .. } => json!({
ASTNode::Local {
variables,
initial_values,
..
} => json!({
"kind": "Local",
"variables": variables,
"inits": initial_values.into_iter().map(|opt| opt.map(|v| ast_to_json(&v))).collect::<Vec<_>>()
}),
ASTNode::If { condition, then_body, else_body, .. } => json!({
ASTNode::If {
condition,
then_body,
else_body,
..
} => json!({
"kind": "If",
"condition": ast_to_json(&condition),
"then": then_body.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>(),
"else": else_body.map(|v| v.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>()),
}),
ASTNode::TryCatch { try_body, catch_clauses, finally_body, .. } => json!({
ASTNode::TryCatch {
try_body,
catch_clauses,
finally_body,
..
} => json!({
"kind": "TryCatch",
"try": try_body.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>(),
"catch": catch_clauses.into_iter().map(|cc| json!({
@ -48,7 +64,14 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
})).collect::<Vec<_>>(),
"cleanup": finally_body.map(|v| v.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>())
}),
ASTNode::FunctionDeclaration { name, params, body, is_static, is_override, .. } => json!({
ASTNode::FunctionDeclaration {
name,
params,
body,
is_static,
is_override,
..
} => json!({
"kind": "FunctionDeclaration",
"name": name,
"params": params,
@ -58,24 +81,38 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
}),
ASTNode::Variable { name, .. } => json!({"kind":"Variable","name":name}),
ASTNode::Literal { value, .. } => json!({"kind":"Literal","value": lit_to_json(&value)}),
ASTNode::BinaryOp { operator, left, right, .. } => json!({
ASTNode::BinaryOp {
operator,
left,
right,
..
} => json!({
"kind":"BinaryOp",
"op": bin_to_str(&operator),
"left": ast_to_json(&left),
"right": ast_to_json(&right),
}),
ASTNode::UnaryOp { operator, operand, .. } => json!({
ASTNode::UnaryOp {
operator, operand, ..
} => json!({
"kind":"UnaryOp",
"op": un_to_str(&operator),
"operand": ast_to_json(&operand),
}),
ASTNode::MethodCall { object, method, arguments, .. } => json!({
ASTNode::MethodCall {
object,
method,
arguments,
..
} => json!({
"kind":"MethodCall",
"object": ast_to_json(&object),
"method": method,
"arguments": arguments.into_iter().map(|a| ast_to_json(&a)).collect::<Vec<_>>()
}),
ASTNode::FunctionCall { name, arguments, .. } => json!({
ASTNode::FunctionCall {
name, arguments, ..
} => json!({
"kind":"FunctionCall",
"name": name,
"arguments": arguments.into_iter().map(|a| ast_to_json(&a)).collect::<Vec<_>>()
@ -88,7 +125,12 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
"kind":"Map",
"entries": entries.into_iter().map(|(k,v)| json!({"k":k,"v":ast_to_json(&v)})).collect::<Vec<_>>()
}),
ASTNode::MatchExpr { scrutinee, arms, else_expr, .. } => json!({
ASTNode::MatchExpr {
scrutinee,
arms,
else_expr,
..
} => json!({
"kind":"MatchExpr",
"scrutinee": ast_to_json(&scrutinee),
"arms": arms.into_iter().map(|(lit, body)| json!({
@ -108,45 +150,163 @@ pub fn json_to_ast(v: &Value) -> Option<ASTNode> {
let k = v.get("kind")?.as_str()?;
Some(match k {
"Program" => {
let stmts = v.get("statements")?.as_array()?.iter().filter_map(json_to_ast).collect::<Vec<_>>();
ASTNode::Program { statements: stmts, span: Span::unknown() }
let stmts = v
.get("statements")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect::<Vec<_>>();
ASTNode::Program {
statements: stmts,
span: Span::unknown(),
}
}
"Loop" => ASTNode::Loop {
condition: Box::new(json_to_ast(v.get("condition")?)?),
body: v.get("body")?.as_array()?.iter().filter_map(json_to_ast).collect::<Vec<_>>(),
body: v
.get("body")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect::<Vec<_>>(),
span: Span::unknown(),
},
"Print" => ASTNode::Print { expression: Box::new(json_to_ast(v.get("expression")?)?), span: Span::unknown() },
"Return" => ASTNode::Return { value: v.get("value").and_then(json_to_ast).map(Box::new), span: Span::unknown() },
"Break" => ASTNode::Break { span: Span::unknown() },
"Continue" => ASTNode::Continue { span: Span::unknown() },
"Assignment" => ASTNode::Assignment { target: Box::new(json_to_ast(v.get("target")?)?), value: Box::new(json_to_ast(v.get("value")?)?), span: Span::unknown() },
"Local" => {
let vars = v.get("variables")?.as_array()?.iter().filter_map(|s| s.as_str().map(|x| x.to_string())).collect();
let inits = v.get("inits")?.as_array()?.iter().map(|initv| {
if initv.is_null() { None } else { json_to_ast(initv).map(Box::new) }
}).collect();
ASTNode::Local { variables: vars, initial_values: inits, span: Span::unknown() }
"Print" => ASTNode::Print {
expression: Box::new(json_to_ast(v.get("expression")?)?),
span: Span::unknown(),
},
"Return" => ASTNode::Return {
value: v.get("value").and_then(json_to_ast).map(Box::new),
span: Span::unknown(),
},
"Break" => ASTNode::Break {
span: Span::unknown(),
},
"Continue" => ASTNode::Continue {
span: Span::unknown(),
},
"Assignment" => ASTNode::Assignment {
target: Box::new(json_to_ast(v.get("target")?)?),
value: Box::new(json_to_ast(v.get("value")?)?),
span: Span::unknown(),
},
"Local" => {
let vars = v
.get("variables")?
.as_array()?
.iter()
.filter_map(|s| s.as_str().map(|x| x.to_string()))
.collect();
let inits = v
.get("inits")?
.as_array()?
.iter()
.map(|initv| {
if initv.is_null() {
None
} else {
json_to_ast(initv).map(Box::new)
}
})
.collect();
ASTNode::Local {
variables: vars,
initial_values: inits,
span: Span::unknown(),
}
}
"If" => ASTNode::If {
condition: Box::new(json_to_ast(v.get("condition")?)?),
then_body: v
.get("then")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect::<Vec<_>>(),
else_body: v.get("else").and_then(|a| {
a.as_array()
.map(|arr| arr.iter().filter_map(json_to_ast).collect::<Vec<_>>())
}),
span: Span::unknown(),
},
"If" => ASTNode::If { condition: Box::new(json_to_ast(v.get("condition")?)?), then_body: v.get("then")?.as_array()?.iter().filter_map(json_to_ast).collect::<Vec<_>>(), else_body: v.get("else").and_then(|a| a.as_array().map(|arr| arr.iter().filter_map(json_to_ast).collect::<Vec<_>>())), span: Span::unknown() },
"FunctionDeclaration" => ASTNode::FunctionDeclaration {
name: v.get("name")?.as_str()?.to_string(),
params: v.get("params")?.as_array()?.iter().filter_map(|s| s.as_str().map(|x| x.to_string())).collect(),
body: v.get("body")?.as_array()?.iter().filter_map(json_to_ast).collect(),
params: v
.get("params")?
.as_array()?
.iter()
.filter_map(|s| s.as_str().map(|x| x.to_string()))
.collect(),
body: v
.get("body")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect(),
is_static: v.get("static").and_then(|b| b.as_bool()).unwrap_or(false),
is_override: v.get("override").and_then(|b| b.as_bool()).unwrap_or(false),
span: Span::unknown(),
},
"Variable" => ASTNode::Variable { name: v.get("name")?.as_str()?.to_string(), span: Span::unknown() },
"Literal" => ASTNode::Literal { value: json_to_lit(v.get("value")?)?, span: Span::unknown() },
"BinaryOp" => ASTNode::BinaryOp { operator: str_to_bin(v.get("op")?.as_str()?)?, left: Box::new(json_to_ast(v.get("left")?)?), right: Box::new(json_to_ast(v.get("right")?)?), span: Span::unknown() },
"UnaryOp" => ASTNode::UnaryOp { operator: str_to_un(v.get("op")?.as_str()?)?, operand: Box::new(json_to_ast(v.get("operand")?)?), span: Span::unknown() },
"MethodCall" => ASTNode::MethodCall { object: Box::new(json_to_ast(v.get("object")?)?), method: v.get("method")?.as_str()?.to_string(), arguments: v.get("arguments")?.as_array()?.iter().filter_map(json_to_ast).collect(), span: Span::unknown() },
"FunctionCall" => ASTNode::FunctionCall { name: v.get("name")?.as_str()?.to_string(), arguments: v.get("arguments")?.as_array()?.iter().filter_map(json_to_ast).collect(), span: Span::unknown() },
"Array" => ASTNode::ArrayLiteral { elements: v.get("elements")?.as_array()?.iter().filter_map(json_to_ast).collect(), span: Span::unknown() },
"Map" => ASTNode::MapLiteral { entries: v.get("entries")?.as_array()?.iter().filter_map(|e| {
Some((e.get("k")?.as_str()?.to_string(), json_to_ast(e.get("v")?)?))
}).collect(), span: Span::unknown() },
"Variable" => ASTNode::Variable {
name: v.get("name")?.as_str()?.to_string(),
span: Span::unknown(),
},
"Literal" => ASTNode::Literal {
value: json_to_lit(v.get("value")?)?,
span: Span::unknown(),
},
"BinaryOp" => ASTNode::BinaryOp {
operator: str_to_bin(v.get("op")?.as_str()?)?,
left: Box::new(json_to_ast(v.get("left")?)?),
right: Box::new(json_to_ast(v.get("right")?)?),
span: Span::unknown(),
},
"UnaryOp" => ASTNode::UnaryOp {
operator: str_to_un(v.get("op")?.as_str()?)?,
operand: Box::new(json_to_ast(v.get("operand")?)?),
span: Span::unknown(),
},
"MethodCall" => ASTNode::MethodCall {
object: Box::new(json_to_ast(v.get("object")?)?),
method: v.get("method")?.as_str()?.to_string(),
arguments: v
.get("arguments")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect(),
span: Span::unknown(),
},
"FunctionCall" => ASTNode::FunctionCall {
name: v.get("name")?.as_str()?.to_string(),
arguments: v
.get("arguments")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect(),
span: Span::unknown(),
},
"Array" => ASTNode::ArrayLiteral {
elements: v
.get("elements")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect(),
span: Span::unknown(),
},
"Map" => ASTNode::MapLiteral {
entries: v
.get("entries")?
.as_array()?
.iter()
.filter_map(|e| {
Some((e.get("k")?.as_str()?.to_string(), json_to_ast(e.get("v")?)?))
})
.collect(),
span: Span::unknown(),
},
"MatchExpr" => {
let scr = json_to_ast(v.get("scrutinee")?)?;
let arms_json = v.get("arms")?.as_array()?.iter();
@ -166,18 +326,47 @@ pub fn json_to_ast(v: &Value) -> Option<ASTNode> {
}
}
"TryCatch" => {
let try_b = v.get("try")?.as_array()?.iter().filter_map(json_to_ast).collect::<Vec<_>>();
let try_b = v
.get("try")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect::<Vec<_>>();
let mut catches = Vec::new();
if let Some(arr) = v.get("catch").and_then(|x| x.as_array()) {
for c in arr.iter() {
let exc_t = match c.get("type") { Some(t) if !t.is_null() => t.as_str().map(|s| s.to_string()), _ => None };
let var = match c.get("var") { Some(vv) if !vv.is_null() => vv.as_str().map(|s| s.to_string()), _ => None };
let body = c.get("body")?.as_array()?.iter().filter_map(json_to_ast).collect::<Vec<_>>();
catches.push(nyash_rust::ast::CatchClause { exception_type: exc_t, variable_name: var, body, span: Span::unknown() });
let exc_t = match c.get("type") {
Some(t) if !t.is_null() => t.as_str().map(|s| s.to_string()),
_ => None,
};
let var = match c.get("var") {
Some(vv) if !vv.is_null() => vv.as_str().map(|s| s.to_string()),
_ => None,
};
let body = c
.get("body")?
.as_array()?
.iter()
.filter_map(json_to_ast)
.collect::<Vec<_>>();
catches.push(nyash_rust::ast::CatchClause {
exception_type: exc_t,
variable_name: var,
body,
span: Span::unknown(),
});
}
}
let cleanup = v.get("cleanup").and_then(|cl| cl.as_array().map(|arr| arr.iter().filter_map(json_to_ast).collect::<Vec<_>>()));
ASTNode::TryCatch { try_body: try_b, catch_clauses: catches, finally_body: cleanup, span: Span::unknown() }
let cleanup = v.get("cleanup").and_then(|cl| {
cl.as_array()
.map(|arr| arr.iter().filter_map(json_to_ast).collect::<Vec<_>>())
});
ASTNode::TryCatch {
try_body: try_b,
catch_clauses: catches,
finally_body: cleanup,
span: Span::unknown(),
}
}
_ => return None,
})