Files
hakorune/src/ast/utils.rs
nyash-codex f9d100ce01 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>
2025-11-21 06:25:17 +09:00

402 lines
15 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.

//! Utility helpers for Nyash AST nodes extracted from `ast.rs`.
use super::{ASTNode, ASTNodeType, Span};
use std::fmt;
impl ASTNode {
/// AST nodeの種類を文字列で取得 (デバッグ用)
pub fn node_type(&self) -> &'static str {
match self {
ASTNode::Program { .. } => "Program",
ASTNode::Assignment { .. } => "Assignment",
ASTNode::Print { .. } => "Print",
ASTNode::If { .. } => "If",
ASTNode::Loop { .. } => "Loop",
ASTNode::While { .. } => "While",
ASTNode::ForRange { .. } => "ForRange",
ASTNode::Return { .. } => "Return",
ASTNode::Break { .. } => "Break",
ASTNode::Continue { .. } => "Continue",
ASTNode::UsingStatement { .. } => "UsingStatement",
ASTNode::ImportStatement { .. } => "ImportStatement",
ASTNode::BoxDeclaration { .. } => "BoxDeclaration",
ASTNode::FunctionDeclaration { .. } => "FunctionDeclaration",
ASTNode::GlobalVar { .. } => "GlobalVar",
ASTNode::Literal { .. } => "Literal",
ASTNode::Variable { .. } => "Variable",
ASTNode::UnaryOp { .. } => "UnaryOp",
ASTNode::BinaryOp { .. } => "BinaryOp",
ASTNode::MethodCall { .. } => "MethodCall",
ASTNode::FieldAccess { .. } => "FieldAccess",
ASTNode::Index { .. } => "Index",
ASTNode::New { .. } => "New",
ASTNode::This { .. } => "This",
ASTNode::Me { .. } => "Me",
ASTNode::FromCall { .. } => "FromCall",
ASTNode::ThisField { .. } => "ThisField",
ASTNode::MeField { .. } => "MeField",
ASTNode::Local { .. } => "Local",
ASTNode::Outbox { .. } => "Outbox",
ASTNode::FunctionCall { .. } => "FunctionCall",
ASTNode::Call { .. } => "Call",
ASTNode::Nowait { .. } => "Nowait",
ASTNode::Arrow { .. } => "Arrow",
ASTNode::TryCatch { .. } => "TryCatch",
ASTNode::Throw { .. } => "Throw",
ASTNode::AwaitExpression { .. } => "AwaitExpression",
ASTNode::QMarkPropagate { .. } => "QMarkPropagate",
ASTNode::MatchExpr { .. } => "MatchExpr",
ASTNode::Lambda { .. } => "Lambda",
ASTNode::ArrayLiteral { .. } => "ArrayLiteral",
ASTNode::MapLiteral { .. } => "MapLiteral",
// Optional diagnostic-only wrapper
ASTNode::ScopeBox { .. } => "ScopeBox",
}
}
/// Structure/Expression/Statement の分類
pub fn classify(&self) -> ASTNodeType {
use ASTNodeType::{Expression as E, Statement as S, Structure as St};
match self {
// Structure nodes - 言語の基本構造
ASTNode::BoxDeclaration { .. } => St,
ASTNode::FunctionDeclaration { .. } => St,
ASTNode::If { .. } => St,
ASTNode::Loop { .. } => St,
ASTNode::While { .. } => St,
ASTNode::ForRange { .. } => St,
ASTNode::TryCatch { .. } => St,
ASTNode::ScopeBox { .. } => St, // diagnostic wrapper
// Expression nodes - 値を生成する表現
ASTNode::Literal { .. } => E,
ASTNode::Variable { .. } => E,
ASTNode::BinaryOp { .. } => E,
ASTNode::UnaryOp { .. } => E,
ASTNode::FunctionCall { .. } => E,
ASTNode::Call { .. } => E,
ASTNode::MethodCall { .. } => E,
ASTNode::FieldAccess { .. } => E,
ASTNode::New { .. } => E,
ASTNode::This { .. } => E,
ASTNode::Me { .. } => E,
ASTNode::FromCall { .. } => E,
ASTNode::ThisField { .. } => E,
ASTNode::MeField { .. } => E,
ASTNode::Index { .. } => E,
ASTNode::MatchExpr { .. } => E,
ASTNode::QMarkPropagate { .. } => E,
ASTNode::Lambda { .. } => E,
ASTNode::ArrayLiteral { .. } => E,
ASTNode::MapLiteral { .. } => E,
ASTNode::AwaitExpression { .. } => E,
// Statement nodes - 実行可能なアクション
ASTNode::Program { .. } => S,
ASTNode::Assignment { .. } => S,
ASTNode::Print { .. } => S,
ASTNode::Return { .. } => S,
ASTNode::Break { .. } => S,
ASTNode::Continue { .. } => S,
ASTNode::UsingStatement { .. } => S,
ASTNode::ImportStatement { .. } => S,
ASTNode::GlobalVar { .. } => S,
ASTNode::Local { .. } => S,
ASTNode::Outbox { .. } => S,
ASTNode::Nowait { .. } => S,
ASTNode::Arrow { .. } => S,
ASTNode::Throw { .. } => S,
}
}
pub fn is_structure(&self) -> bool {
matches!(self.classify(), ASTNodeType::Structure)
}
pub fn is_expression(&self) -> bool {
matches!(self.classify(), ASTNodeType::Expression)
}
pub fn is_statement(&self) -> bool {
matches!(self.classify(), ASTNodeType::Statement)
}
/// AST nodeの詳細情報を取得 (デバッグ用)
pub fn info(&self) -> String {
match self {
ASTNode::Program { statements, .. } => {
format!("Program({} statements)", statements.len())
}
ASTNode::Assignment { target, .. } => {
format!("Assignment(target: {})", target.info())
}
ASTNode::Print { .. } => "Print".to_string(),
ASTNode::If { .. } => "If".to_string(),
ASTNode::Loop {
condition: _, body, ..
} => {
format!("Loop({} statements)", body.len())
}
ASTNode::While {
condition: _, body, ..
} => {
format!("While({} statements)", body.len())
}
ASTNode::ForRange {
var_name,
start: _,
end: _,
body,
..
} => {
format!("ForRange(var={}, {} statements)", var_name, body.len())
}
ASTNode::Return { value, .. } => {
if value.is_some() {
"Return(with value)".to_string()
} else {
"Return(void)".to_string()
}
}
ASTNode::Break { .. } => "Break".to_string(),
ASTNode::Continue { .. } => "Continue".to_string(),
ASTNode::UsingStatement { namespace_name, .. } => {
format!("UsingStatement({})", namespace_name)
}
ASTNode::ImportStatement { path, alias, .. } => {
if let Some(a) = alias {
format!("ImportStatement({}, as {})", path, a)
} else {
format!("ImportStatement({})", path)
}
}
ASTNode::BoxDeclaration {
name,
fields,
methods,
constructors,
is_interface,
extends,
implements,
..
} => {
let mut desc = if *is_interface {
format!("InterfaceBox({}, {} methods", name, methods.len())
} else {
format!(
"BoxDeclaration({}, {} fields, {} methods, {} constructors",
name,
fields.len(),
methods.len(),
constructors.len()
)
};
if !extends.is_empty() {
desc.push_str(&format!(", extends [{}]", extends.join(", ")));
}
if !implements.is_empty() {
desc.push_str(&format!(", implements [{}]", implements.join(", ")));
}
desc.push(')');
desc
}
ASTNode::FunctionDeclaration {
name,
params,
body,
is_static,
is_override,
..
} => {
let static_str = if *is_static { "static " } else { "" };
let override_str = if *is_override { "override " } else { "" };
format!(
"FunctionDeclaration({}{}{}({}), {} statements)",
override_str,
static_str,
name,
params.join(", "),
body.len()
)
}
ASTNode::GlobalVar { name, .. } => {
format!("GlobalVar({})", name)
}
ASTNode::Literal { .. } => "Literal".to_string(),
ASTNode::Variable { name, .. } => {
format!("Variable({})", name)
}
ASTNode::UnaryOp { operator, .. } => {
format!("UnaryOp({})", operator)
}
ASTNode::BinaryOp { operator, .. } => {
format!("BinaryOp({})", operator)
}
ASTNode::MethodCall {
method, arguments, ..
} => {
format!("MethodCall({}, {} args)", method, arguments.len())
}
ASTNode::FieldAccess { field, .. } => {
format!("FieldAccess({})", field)
}
ASTNode::New {
class,
arguments,
type_arguments,
..
} => {
if type_arguments.is_empty() {
format!("New({}, {} args)", class, arguments.len())
} else {
format!(
"New({}<{}>, {} args)",
class,
type_arguments.join(", "),
arguments.len()
)
}
}
ASTNode::This { .. } => "This".to_string(),
ASTNode::Me { .. } => "Me".to_string(),
ASTNode::FromCall {
parent,
method,
arguments,
..
} => {
format!("FromCall({}.{}, {} args)", parent, method, arguments.len())
}
ASTNode::ThisField { field, .. } => {
format!("ThisField({})", field)
}
ASTNode::MeField { field, .. } => {
format!("MeField({})", field)
}
ASTNode::Local { variables, .. } => {
format!("Local({})", variables.join(", "))
}
ASTNode::Outbox { variables, .. } => {
format!("Outbox({})", variables.join(", "))
}
ASTNode::FunctionCall {
name, arguments, ..
} => {
format!("FunctionCall({}, {} args)", name, arguments.len())
}
ASTNode::Call { .. } => "Call".to_string(),
ASTNode::Nowait { variable, .. } => {
format!("Nowait({})", variable)
}
ASTNode::Arrow { .. } => "Arrow(>>)".to_string(),
ASTNode::TryCatch {
try_body,
catch_clauses,
finally_body,
..
} => {
let mut desc = format!(
"TryCatch({} try statements, {} catch clauses",
try_body.len(),
catch_clauses.len()
);
if finally_body.is_some() {
desc.push_str(", has finally");
}
desc.push(')');
desc
}
ASTNode::Throw { .. } => "Throw".to_string(),
ASTNode::AwaitExpression { expression, .. } => {
format!("Await({:?})", expression)
}
ASTNode::MatchExpr { .. } => "MatchExpr".to_string(),
ASTNode::QMarkPropagate { .. } => "QMarkPropagate".to_string(),
ASTNode::Lambda { params, body, .. } => {
format!("Lambda({} params, {} statements)", params.len(), body.len())
}
ASTNode::ArrayLiteral { elements, .. } => {
format!("ArrayLiteral({} elements)", elements.len())
}
ASTNode::MapLiteral { entries, .. } => {
format!("MapLiteral({} entries)", entries.len())
}
ASTNode::Index { target, index, .. } => {
format!("Index(target={:?}, index={:?})", target, index)
}
ASTNode::ScopeBox { .. } => "ScopeBox".to_string(),
}
}
/// ASTードからSpan情報を取得
pub fn span(&self) -> Span {
match self {
ASTNode::Program { span, .. } => *span,
ASTNode::Assignment { span, .. } => *span,
ASTNode::Print { span, .. } => *span,
ASTNode::If { span, .. } => *span,
ASTNode::Loop { span, .. } => *span,
ASTNode::While { span, .. } => *span,
ASTNode::ForRange { span, .. } => *span,
ASTNode::Return { span, .. } => *span,
ASTNode::Break { span, .. } => *span,
ASTNode::Continue { span, .. } => *span,
ASTNode::UsingStatement { span, .. } => *span,
ASTNode::ImportStatement { span, .. } => *span,
ASTNode::Nowait { span, .. } => *span,
ASTNode::Arrow { span, .. } => *span,
ASTNode::TryCatch { span, .. } => *span,
ASTNode::Throw { span, .. } => *span,
ASTNode::BoxDeclaration { span, .. } => *span,
ASTNode::FunctionDeclaration { span, .. } => *span,
ASTNode::GlobalVar { span, .. } => *span,
ASTNode::Literal { span, .. } => *span,
ASTNode::Variable { span, .. } => *span,
ASTNode::UnaryOp { span, .. } => *span,
ASTNode::BinaryOp { span, .. } => *span,
ASTNode::MethodCall { span, .. } => *span,
ASTNode::FieldAccess { span, .. } => *span,
ASTNode::Index { span, .. } => *span,
ASTNode::New { span, .. } => *span,
ASTNode::This { span, .. } => *span,
ASTNode::Me { span, .. } => *span,
ASTNode::FromCall { span, .. } => *span,
ASTNode::ThisField { span, .. } => *span,
ASTNode::MeField { span, .. } => *span,
ASTNode::Local { span, .. } => *span,
ASTNode::Outbox { span, .. } => *span,
ASTNode::FunctionCall { span, .. } => *span,
ASTNode::Call { span, .. } => *span,
ASTNode::AwaitExpression { span, .. } => *span,
ASTNode::MatchExpr { span, .. } => *span,
ASTNode::QMarkPropagate { span, .. } => *span,
ASTNode::Lambda { span, .. } => *span,
ASTNode::ArrayLiteral { span, .. } => *span,
ASTNode::MapLiteral { span, .. } => *span,
ASTNode::ScopeBox { span, .. } => *span,
}
}
}
impl fmt::Display for ASTNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.info())
}
}
impl ASTNode {
/// FunctionDeclarationのパラメータ数を取得
pub fn get_param_count(&self) -> usize {
match self {
ASTNode::FunctionDeclaration { params, .. } => params.len(),
_ => 0,
}
}
}