377 lines
15 KiB
Rust
377 lines
15 KiB
Rust
//! 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::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::New { .. } => "New",
|
||
ASTNode::This { .. } => "This",
|
||
ASTNode::Me { .. } => "Me",
|
||
ASTNode::FromCall { .. } => "FromCall",
|
||
ASTNode::ThisField { .. } => "ThisField",
|
||
ASTNode::MeField { .. } => "MeField",
|
||
ASTNode::Include { .. } => "Include",
|
||
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::PeekExpr { .. } => "PeekExpr",
|
||
ASTNode::Lambda { .. } => "Lambda",
|
||
ASTNode::ArrayLiteral { .. } => "ArrayLiteral",
|
||
ASTNode::MapLiteral { .. } => "MapLiteral",
|
||
}
|
||
}
|
||
|
||
/// 🌟 AST分類 - ChatGPTアドバイス統合による革新的分類システム
|
||
/// Structure/Expression/Statement の明確な分離
|
||
pub fn classify(&self) -> ASTNodeType {
|
||
match self {
|
||
// Structure nodes - 言語の基本構造
|
||
ASTNode::BoxDeclaration { .. } => ASTNodeType::Structure,
|
||
ASTNode::FunctionDeclaration { .. } => ASTNodeType::Structure,
|
||
ASTNode::If { .. } => ASTNodeType::Structure,
|
||
ASTNode::Loop { .. } => ASTNodeType::Structure,
|
||
ASTNode::TryCatch { .. } => ASTNodeType::Structure,
|
||
|
||
// Expression nodes - 値を生成する表現
|
||
ASTNode::Literal { .. } => ASTNodeType::Expression,
|
||
ASTNode::Variable { .. } => ASTNodeType::Expression,
|
||
ASTNode::BinaryOp { .. } => ASTNodeType::Expression,
|
||
ASTNode::UnaryOp { .. } => ASTNodeType::Expression,
|
||
ASTNode::FunctionCall { .. } => ASTNodeType::Expression,
|
||
ASTNode::Call { .. } => ASTNodeType::Expression,
|
||
ASTNode::MethodCall { .. } => ASTNodeType::Expression,
|
||
ASTNode::FieldAccess { .. } => ASTNodeType::Expression,
|
||
ASTNode::New { .. } => ASTNodeType::Expression,
|
||
ASTNode::This { .. } => ASTNodeType::Expression,
|
||
ASTNode::Me { .. } => ASTNodeType::Expression,
|
||
ASTNode::FromCall { .. } => ASTNodeType::Expression,
|
||
ASTNode::ThisField { .. } => ASTNodeType::Expression,
|
||
ASTNode::MeField { .. } => ASTNodeType::Expression,
|
||
ASTNode::PeekExpr { .. } => ASTNodeType::Expression,
|
||
ASTNode::QMarkPropagate { .. } => ASTNodeType::Expression,
|
||
ASTNode::Lambda { .. } => ASTNodeType::Expression,
|
||
ASTNode::ArrayLiteral { .. } => ASTNodeType::Expression,
|
||
ASTNode::MapLiteral { .. } => ASTNodeType::Expression,
|
||
|
||
// Statement nodes - 実行可能なアクション
|
||
ASTNode::Program { .. } => ASTNodeType::Statement, // プログラム全体
|
||
ASTNode::Assignment { .. } => ASTNodeType::Statement,
|
||
ASTNode::Print { .. } => ASTNodeType::Statement,
|
||
ASTNode::Return { .. } => ASTNodeType::Statement,
|
||
ASTNode::Break { .. } => ASTNodeType::Statement,
|
||
ASTNode::Continue { .. } => ASTNodeType::Statement,
|
||
ASTNode::UsingStatement { .. } => ASTNodeType::Statement,
|
||
ASTNode::ImportStatement { .. } => ASTNodeType::Statement,
|
||
ASTNode::GlobalVar { .. } => ASTNodeType::Statement,
|
||
ASTNode::Include { .. } => ASTNodeType::Statement,
|
||
ASTNode::Local { .. } => ASTNodeType::Statement,
|
||
ASTNode::Outbox { .. } => ASTNodeType::Statement,
|
||
ASTNode::Nowait { .. } => ASTNodeType::Statement,
|
||
ASTNode::Arrow { .. } => ASTNodeType::Statement,
|
||
ASTNode::Throw { .. } => ASTNodeType::Statement,
|
||
ASTNode::AwaitExpression { .. } => ASTNodeType::Expression,
|
||
}
|
||
}
|
||
|
||
/// 🎯 構造パターンチェック - 2段階パーサー用
|
||
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::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::Include { filename, .. } => {
|
||
format!("Include({})", filename)
|
||
}
|
||
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::PeekExpr { .. } => "PeekExpr".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())
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 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::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::New { span, .. } => *span,
|
||
ASTNode::This { span, .. } => *span,
|
||
ASTNode::Me { span, .. } => *span,
|
||
ASTNode::FromCall { span, .. } => *span,
|
||
ASTNode::ThisField { span, .. } => *span,
|
||
ASTNode::MeField { span, .. } => *span,
|
||
ASTNode::Include { span, .. } => *span,
|
||
ASTNode::Local { span, .. } => *span,
|
||
ASTNode::Outbox { span, .. } => *span,
|
||
ASTNode::FunctionCall { span, .. } => *span,
|
||
ASTNode::Call { span, .. } => *span,
|
||
ASTNode::AwaitExpression { span, .. } => *span,
|
||
ASTNode::PeekExpr { span, .. } => *span,
|
||
ASTNode::QMarkPropagate { span, .. } => *span,
|
||
ASTNode::Lambda { span, .. } => *span,
|
||
ASTNode::ArrayLiteral { span, .. } => *span,
|
||
ASTNode::MapLiteral { 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,
|
||
}
|
||
}
|
||
}
|