ast: extract utility helpers
This commit is contained in:
314
src/ast.rs
314
src/ast.rs
@ -10,6 +10,7 @@ use std::collections::HashMap;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
mod span;
|
mod span;
|
||||||
pub use span::Span;
|
pub use span::Span;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
// Span は src/ast/span.rs へ分離(re-export で後方互換維持)
|
// Span は src/ast/span.rs へ分離(re-export で後方互換維持)
|
||||||
|
|
||||||
@ -606,317 +607,4 @@ pub enum ASTNode {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests moved to integration tests to keep this file lean
|
// Tests moved to integration tests to keep this file lean
|
||||||
|
|||||||
376
src/ast/utils.rs
Normal file
376
src/ast/utils.rs
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
//! 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user