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,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|