2025-08-09 15:14:44 +09:00
|
|
|
|
/*!
|
|
|
|
|
|
* Nyash AST (Abstract Syntax Tree) - Rust Implementation
|
|
|
|
|
|
*
|
|
|
|
|
|
* Python版nyashc_v4.pyのAST構造をRustで完全再実装
|
|
|
|
|
|
* Everything is Box哲学に基づく型安全なAST設計
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
use crate::box_trait::NyashBox;
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
|
|
|
/// ソースコード位置情報 - エラー報告とデバッグの革命
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
|
pub struct Span {
|
|
|
|
|
|
pub start: usize, // 開始位置(バイトオフセット)
|
|
|
|
|
|
pub end: usize, // 終了位置(バイトオフセット)
|
|
|
|
|
|
pub line: usize, // 行番号(1から開始)
|
|
|
|
|
|
pub column: usize, // 列番号(1から開始)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Span {
|
|
|
|
|
|
/// 新しいSpanを作成
|
|
|
|
|
|
pub fn new(start: usize, end: usize, line: usize, column: usize) -> Self {
|
|
|
|
|
|
Self { start, end, line, column }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// デフォルトのSpan(不明な位置)
|
|
|
|
|
|
pub fn unknown() -> Self {
|
|
|
|
|
|
Self { start: 0, end: 0, line: 1, column: 1 }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 2つのSpanを結合(開始位置から終了位置まで)
|
|
|
|
|
|
pub fn merge(&self, other: Span) -> Span {
|
|
|
|
|
|
Span {
|
|
|
|
|
|
start: self.start.min(other.start),
|
|
|
|
|
|
end: self.end.max(other.end),
|
|
|
|
|
|
line: self.line,
|
|
|
|
|
|
column: self.column,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// ソースコードから該当箇所を抽出してエラー表示用文字列を生成
|
|
|
|
|
|
pub fn error_context(&self, source: &str) -> String {
|
|
|
|
|
|
let lines: Vec<&str> = source.lines().collect();
|
|
|
|
|
|
if self.line == 0 || self.line > lines.len() {
|
|
|
|
|
|
return format!("line {}, column {}", self.line, self.column);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let line_content = lines[self.line - 1];
|
|
|
|
|
|
let mut context = String::new();
|
|
|
|
|
|
|
|
|
|
|
|
// 行番号とソース行を表示
|
|
|
|
|
|
context.push_str(&format!(" |\n{:3} | {}\n", self.line, line_content));
|
|
|
|
|
|
|
|
|
|
|
|
// カーソル位置を表示(簡易版)
|
|
|
|
|
|
if self.column > 0 && self.column <= line_content.len() + 1 {
|
|
|
|
|
|
context.push_str(" | ");
|
|
|
|
|
|
for _ in 1..self.column {
|
|
|
|
|
|
context.push(' ');
|
|
|
|
|
|
}
|
|
|
|
|
|
let span_length = if self.end > self.start {
|
|
|
|
|
|
(self.end - self.start).min(line_content.len() - self.column + 1)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
1
|
|
|
|
|
|
};
|
|
|
|
|
|
for _ in 0..span_length.max(1) {
|
|
|
|
|
|
context.push('^');
|
|
|
|
|
|
}
|
|
|
|
|
|
context.push('\n');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
context
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 位置情報の文字列表現
|
|
|
|
|
|
pub fn location_string(&self) -> String {
|
|
|
|
|
|
format!("line {}, column {}", self.line, self.column)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Span {
|
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
|
write!(f, "line {}, column {}", self.line, self.column)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 🌟 AST分類システム - ChatGPTアドバイス統合による3層アーキテクチャ
|
|
|
|
|
|
/// Structure/Expression/Statement の明確な分離による型安全性向上
|
|
|
|
|
|
|
|
|
|
|
|
/// ASTノードの種類分類
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
|
pub enum ASTNodeType {
|
|
|
|
|
|
Structure, // 構造定義: box, function, if, loop, try/catch
|
|
|
|
|
|
Expression, // 式: リテラル, 変数, 演算, 呼び出し
|
|
|
|
|
|
Statement, // 文: 代入, return, break, include
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 構造ノード - 言語の基本構造を定義
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum StructureNode {
|
|
|
|
|
|
BoxDeclaration {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
fields: Vec<String>,
|
|
|
|
|
|
methods: Vec<ASTNode>,
|
|
|
|
|
|
constructors: Vec<ASTNode>,
|
|
|
|
|
|
init_fields: Vec<String>,
|
|
|
|
|
|
is_interface: bool,
|
|
|
|
|
|
extends: Option<String>,
|
|
|
|
|
|
implements: Vec<String>,
|
|
|
|
|
|
/// 🔥 ジェネリクス型パラメータ (例: ["T", "U"])
|
|
|
|
|
|
type_parameters: Vec<String>,
|
|
|
|
|
|
/// 🔥 Static boxかどうかのフラグ
|
|
|
|
|
|
is_static: bool,
|
|
|
|
|
|
/// 🔥 Static初期化ブロック (static { ... })
|
|
|
|
|
|
static_init: Option<Vec<ASTNode>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
FunctionDeclaration {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
params: Vec<String>,
|
|
|
|
|
|
body: Vec<ASTNode>,
|
|
|
|
|
|
is_static: bool, // 🔥 静的メソッドフラグ
|
2025-08-11 07:55:41 +09:00
|
|
|
|
is_override: bool, // 🔥 オーバーライドフラグ
|
2025-08-09 15:14:44 +09:00
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
IfStructure {
|
|
|
|
|
|
condition: Box<ASTNode>,
|
|
|
|
|
|
then_body: Vec<ASTNode>,
|
|
|
|
|
|
else_body: Option<Vec<ASTNode>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
LoopStructure {
|
|
|
|
|
|
condition: Box<ASTNode>,
|
|
|
|
|
|
body: Vec<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
TryCatchStructure {
|
|
|
|
|
|
try_body: Vec<ASTNode>,
|
|
|
|
|
|
catch_clauses: Vec<CatchClause>,
|
|
|
|
|
|
finally_body: Option<Vec<ASTNode>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 式ノード - 値を生成する表現
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum ExpressionNode {
|
|
|
|
|
|
Literal {
|
|
|
|
|
|
value: LiteralValue,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
Variable {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
BinaryOperation {
|
|
|
|
|
|
operator: BinaryOperator,
|
|
|
|
|
|
left: Box<ASTNode>,
|
|
|
|
|
|
right: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
UnaryOperation {
|
|
|
|
|
|
operator: UnaryOperator,
|
|
|
|
|
|
operand: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
FunctionCall {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
arguments: Vec<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
MethodCall {
|
|
|
|
|
|
object: Box<ASTNode>,
|
|
|
|
|
|
method: String,
|
|
|
|
|
|
arguments: Vec<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
FieldAccess {
|
|
|
|
|
|
object: Box<ASTNode>,
|
|
|
|
|
|
field: String,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
NewExpression {
|
|
|
|
|
|
class: String,
|
|
|
|
|
|
arguments: Vec<ASTNode>,
|
|
|
|
|
|
/// 🔥 ジェネリクス型引数 (例: ["IntegerBox", "StringBox"])
|
|
|
|
|
|
type_arguments: Vec<String>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
ThisExpression {
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
MeExpression {
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 文ノード - 実行可能なアクション
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum StatementNode {
|
|
|
|
|
|
Assignment {
|
|
|
|
|
|
target: Box<ASTNode>,
|
|
|
|
|
|
value: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
Print {
|
|
|
|
|
|
expression: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
Return {
|
|
|
|
|
|
value: Option<Box<ASTNode>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
Break {
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
Include {
|
|
|
|
|
|
filename: String,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
Local {
|
|
|
|
|
|
variables: Vec<String>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
Throw {
|
|
|
|
|
|
exception_type: String,
|
|
|
|
|
|
message: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
Expression {
|
|
|
|
|
|
expr: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Catch節の構造体
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub struct CatchClause {
|
|
|
|
|
|
pub exception_type: Option<String>, // None = catch-all
|
|
|
|
|
|
pub variable_name: Option<String>, // 例外を受け取る変数名
|
|
|
|
|
|
pub body: Vec<ASTNode>, // catch本体
|
|
|
|
|
|
pub span: Span, // ソースコード位置
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// リテラル値の型 (Clone可能)
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum LiteralValue {
|
|
|
|
|
|
String(String),
|
|
|
|
|
|
Integer(i64),
|
|
|
|
|
|
Float(f64), // 浮動小数点数サポート追加
|
|
|
|
|
|
Bool(bool),
|
|
|
|
|
|
Void,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl LiteralValue {
|
|
|
|
|
|
/// LiteralValueをNyashBoxに変換
|
|
|
|
|
|
pub fn to_nyash_box(&self) -> Box<dyn NyashBox> {
|
|
|
|
|
|
use crate::box_trait::{StringBox, IntegerBox, BoolBox, VoidBox};
|
|
|
|
|
|
use crate::boxes::math_box::FloatBox;
|
|
|
|
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
|
LiteralValue::String(s) => Box::new(StringBox::new(s)),
|
|
|
|
|
|
LiteralValue::Integer(i) => Box::new(IntegerBox::new(*i)),
|
|
|
|
|
|
LiteralValue::Float(f) => Box::new(FloatBox::new(*f)),
|
|
|
|
|
|
LiteralValue::Bool(b) => Box::new(BoolBox::new(*b)),
|
|
|
|
|
|
LiteralValue::Void => Box::new(VoidBox::new()),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// NyashBoxからLiteralValueに変換
|
|
|
|
|
|
pub fn from_nyash_box(box_val: &dyn NyashBox) -> Option<LiteralValue> {
|
|
|
|
|
|
#[allow(unused_imports)]
|
|
|
|
|
|
use std::any::Any;
|
|
|
|
|
|
use crate::box_trait::{StringBox, IntegerBox, BoolBox, VoidBox};
|
|
|
|
|
|
use crate::boxes::math_box::FloatBox;
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(string_box) = box_val.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
Some(LiteralValue::String(string_box.value.clone()))
|
|
|
|
|
|
} else if let Some(int_box) = box_val.as_any().downcast_ref::<IntegerBox>() {
|
|
|
|
|
|
Some(LiteralValue::Integer(int_box.value))
|
|
|
|
|
|
} else if let Some(float_box) = box_val.as_any().downcast_ref::<FloatBox>() {
|
|
|
|
|
|
Some(LiteralValue::Float(float_box.value))
|
|
|
|
|
|
} else if let Some(bool_box) = box_val.as_any().downcast_ref::<BoolBox>() {
|
|
|
|
|
|
Some(LiteralValue::Bool(bool_box.value))
|
|
|
|
|
|
} else if box_val.as_any().downcast_ref::<VoidBox>().is_some() {
|
|
|
|
|
|
Some(LiteralValue::Void)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
None
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for LiteralValue {
|
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
|
match self {
|
|
|
|
|
|
LiteralValue::String(s) => write!(f, "\"{}\"", s),
|
|
|
|
|
|
LiteralValue::Integer(i) => write!(f, "{}", i),
|
|
|
|
|
|
LiteralValue::Float(fl) => write!(f, "{}", fl),
|
|
|
|
|
|
LiteralValue::Bool(b) => write!(f, "{}", b),
|
|
|
|
|
|
LiteralValue::Void => write!(f, "void"),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 単項演算子の種類
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
|
pub enum UnaryOperator {
|
|
|
|
|
|
Minus, // -x
|
|
|
|
|
|
Not, // not x
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 二項演算子の種類
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
|
pub enum BinaryOperator {
|
|
|
|
|
|
Add,
|
|
|
|
|
|
Subtract,
|
|
|
|
|
|
Multiply,
|
|
|
|
|
|
Divide,
|
|
|
|
|
|
Equal,
|
|
|
|
|
|
NotEqual,
|
|
|
|
|
|
Less,
|
|
|
|
|
|
Greater,
|
|
|
|
|
|
LessEqual,
|
|
|
|
|
|
GreaterEqual,
|
|
|
|
|
|
And,
|
|
|
|
|
|
Or,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for UnaryOperator {
|
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
|
let symbol = match self {
|
|
|
|
|
|
UnaryOperator::Minus => "-",
|
|
|
|
|
|
UnaryOperator::Not => "not",
|
|
|
|
|
|
};
|
|
|
|
|
|
write!(f, "{}", symbol)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for BinaryOperator {
|
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
|
let symbol = match self {
|
|
|
|
|
|
BinaryOperator::Add => "+",
|
|
|
|
|
|
BinaryOperator::Subtract => "-",
|
|
|
|
|
|
BinaryOperator::Multiply => "*",
|
|
|
|
|
|
BinaryOperator::Divide => "/",
|
|
|
|
|
|
BinaryOperator::Equal => "==",
|
|
|
|
|
|
BinaryOperator::NotEqual => "!=",
|
|
|
|
|
|
BinaryOperator::Less => "<",
|
|
|
|
|
|
BinaryOperator::Greater => ">",
|
|
|
|
|
|
BinaryOperator::LessEqual => "<=",
|
|
|
|
|
|
BinaryOperator::GreaterEqual => ">=",
|
|
|
|
|
|
BinaryOperator::And => "&&",
|
|
|
|
|
|
BinaryOperator::Or => "||",
|
|
|
|
|
|
};
|
|
|
|
|
|
write!(f, "{}", symbol)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// AST Node - Everything is Box哲学に基づく統一構造
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum ASTNode {
|
|
|
|
|
|
/// プログラム全体 - 文のリスト
|
|
|
|
|
|
Program {
|
|
|
|
|
|
statements: Vec<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 文 (Statements) =====
|
|
|
|
|
|
|
|
|
|
|
|
/// 代入文: target = value
|
|
|
|
|
|
Assignment {
|
|
|
|
|
|
target: Box<ASTNode>,
|
|
|
|
|
|
value: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// print文: print(expression)
|
|
|
|
|
|
Print {
|
|
|
|
|
|
expression: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// if文: if condition { then_body } else { else_body }
|
|
|
|
|
|
If {
|
|
|
|
|
|
condition: Box<ASTNode>,
|
|
|
|
|
|
then_body: Vec<ASTNode>,
|
|
|
|
|
|
else_body: Option<Vec<ASTNode>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// loop文: loop(condition) { body } のみ
|
|
|
|
|
|
Loop {
|
|
|
|
|
|
condition: Box<ASTNode>,
|
|
|
|
|
|
body: Vec<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// return文: return value
|
|
|
|
|
|
Return {
|
|
|
|
|
|
value: Option<Box<ASTNode>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// break文
|
|
|
|
|
|
Break {
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// nowait文: nowait variable = expression
|
|
|
|
|
|
Nowait {
|
|
|
|
|
|
variable: String,
|
|
|
|
|
|
expression: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// await式: await expression
|
|
|
|
|
|
AwaitExpression {
|
|
|
|
|
|
expression: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// arrow文: (sender >> receiver).method(args)
|
|
|
|
|
|
Arrow {
|
|
|
|
|
|
sender: Box<ASTNode>,
|
|
|
|
|
|
receiver: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// try/catch/finally文: try { ... } catch (Type e) { ... } finally { ... }
|
|
|
|
|
|
TryCatch {
|
|
|
|
|
|
try_body: Vec<ASTNode>,
|
|
|
|
|
|
catch_clauses: Vec<CatchClause>,
|
|
|
|
|
|
finally_body: Option<Vec<ASTNode>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// throw文: throw expression
|
|
|
|
|
|
Throw {
|
|
|
|
|
|
expression: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 宣言 (Declarations) =====
|
|
|
|
|
|
|
|
|
|
|
|
/// box宣言: box Name { fields... methods... }
|
|
|
|
|
|
BoxDeclaration {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
fields: Vec<String>,
|
|
|
|
|
|
methods: HashMap<String, ASTNode>, // method_name -> FunctionDeclaration
|
|
|
|
|
|
constructors: HashMap<String, ASTNode>, // constructor_key -> FunctionDeclaration
|
|
|
|
|
|
init_fields: Vec<String>, // initブロック内のフィールド定義
|
|
|
|
|
|
is_interface: bool, // interface box かどうか
|
|
|
|
|
|
extends: Option<String>, // 継承元のBox名
|
|
|
|
|
|
implements: Vec<String>, // 実装するinterface名のリスト
|
|
|
|
|
|
type_parameters: Vec<String>, // 🔥 ジェネリクス型パラメータ (例: ["T", "U"])
|
|
|
|
|
|
/// 🔥 Static boxかどうかのフラグ
|
|
|
|
|
|
is_static: bool,
|
|
|
|
|
|
/// 🔥 Static初期化ブロック (static { ... })
|
|
|
|
|
|
static_init: Option<Vec<ASTNode>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// 関数宣言: functionName(params) { body }
|
|
|
|
|
|
FunctionDeclaration {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
params: Vec<String>,
|
|
|
|
|
|
body: Vec<ASTNode>,
|
|
|
|
|
|
is_static: bool, // 🔥 静的メソッドフラグ
|
2025-08-11 07:55:41 +09:00
|
|
|
|
is_override: bool, // 🔥 オーバーライドフラグ
|
2025-08-09 15:14:44 +09:00
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// グローバル変数: global name = value
|
|
|
|
|
|
GlobalVar {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
value: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 式 (Expressions) =====
|
|
|
|
|
|
|
|
|
|
|
|
/// リテラル値: "string", 42, true, etc
|
|
|
|
|
|
Literal {
|
|
|
|
|
|
value: LiteralValue,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// 変数参照: variableName
|
|
|
|
|
|
Variable {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// 単項演算: operator operand
|
|
|
|
|
|
UnaryOp {
|
|
|
|
|
|
operator: UnaryOperator,
|
|
|
|
|
|
operand: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// 二項演算: left operator right
|
|
|
|
|
|
BinaryOp {
|
|
|
|
|
|
operator: BinaryOperator,
|
|
|
|
|
|
left: Box<ASTNode>,
|
|
|
|
|
|
right: Box<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// メソッド呼び出し: object.method(arguments)
|
|
|
|
|
|
MethodCall {
|
|
|
|
|
|
object: Box<ASTNode>,
|
|
|
|
|
|
method: String,
|
|
|
|
|
|
arguments: Vec<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// フィールドアクセス: object.field
|
|
|
|
|
|
FieldAccess {
|
|
|
|
|
|
object: Box<ASTNode>,
|
|
|
|
|
|
field: String,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// コンストラクタ呼び出し: new ClassName(arguments)
|
|
|
|
|
|
New {
|
|
|
|
|
|
class: String,
|
|
|
|
|
|
arguments: Vec<ASTNode>,
|
|
|
|
|
|
type_arguments: Vec<String>, // 🔥 ジェネリクス型引数 (例: ["IntegerBox", "StringBox"])
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// this参照
|
|
|
|
|
|
This {
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// me参照
|
|
|
|
|
|
Me {
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-08-11 07:55:41 +09:00
|
|
|
|
/// 🔥 from呼び出し: from Parent.method(arguments) or from Parent.constructor(arguments)
|
|
|
|
|
|
FromCall {
|
|
|
|
|
|
parent: String, // Parent名
|
|
|
|
|
|
method: String, // method名またはconstructor
|
|
|
|
|
|
arguments: Vec<ASTNode>, // 引数
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
/// thisフィールドアクセス: this.field
|
|
|
|
|
|
ThisField {
|
|
|
|
|
|
field: String,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// meフィールドアクセス: me.field
|
|
|
|
|
|
MeField {
|
|
|
|
|
|
field: String,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// ファイル読み込み: include "filename.nyash"
|
|
|
|
|
|
Include {
|
|
|
|
|
|
filename: String,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// ローカル変数宣言: local x, y, z
|
|
|
|
|
|
Local {
|
|
|
|
|
|
variables: Vec<String>,
|
|
|
|
|
|
/// 初期化値(変数と同じ順序、Noneは初期化なし)
|
|
|
|
|
|
initial_values: Vec<Option<Box<ASTNode>>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// Outbox変数宣言: outbox x, y, z (static関数内専用)
|
|
|
|
|
|
Outbox {
|
|
|
|
|
|
variables: Vec<String>,
|
|
|
|
|
|
/// 初期化値(変数と同じ順序、Noneは初期化なし)
|
|
|
|
|
|
initial_values: Vec<Option<Box<ASTNode>>>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// 関数呼び出し: functionName(arguments)
|
|
|
|
|
|
FunctionCall {
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
arguments: Vec<ASTNode>,
|
|
|
|
|
|
span: Span,
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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::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",
|
2025-08-11 07:55:41 +09:00
|
|
|
|
ASTNode::FromCall { .. } => "FromCall",
|
2025-08-09 15:14:44 +09:00
|
|
|
|
ASTNode::ThisField { .. } => "ThisField",
|
|
|
|
|
|
ASTNode::MeField { .. } => "MeField",
|
|
|
|
|
|
ASTNode::Include { .. } => "Include",
|
|
|
|
|
|
ASTNode::Local { .. } => "Local",
|
|
|
|
|
|
ASTNode::Outbox { .. } => "Outbox",
|
|
|
|
|
|
ASTNode::FunctionCall { .. } => "FunctionCall",
|
|
|
|
|
|
ASTNode::Nowait { .. } => "Nowait",
|
|
|
|
|
|
ASTNode::Arrow { .. } => "Arrow",
|
|
|
|
|
|
ASTNode::TryCatch { .. } => "TryCatch",
|
|
|
|
|
|
ASTNode::Throw { .. } => "Throw",
|
|
|
|
|
|
ASTNode::AwaitExpression { .. } => "AwaitExpression",
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 🌟 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::MethodCall { .. } => ASTNodeType::Expression,
|
|
|
|
|
|
ASTNode::FieldAccess { .. } => ASTNodeType::Expression,
|
|
|
|
|
|
ASTNode::New { .. } => ASTNodeType::Expression,
|
|
|
|
|
|
ASTNode::This { .. } => ASTNodeType::Expression,
|
|
|
|
|
|
ASTNode::Me { .. } => ASTNodeType::Expression,
|
2025-08-11 07:55:41 +09:00
|
|
|
|
ASTNode::FromCall { .. } => ASTNodeType::Expression,
|
2025-08-09 15:14:44 +09:00
|
|
|
|
ASTNode::ThisField { .. } => ASTNodeType::Expression,
|
|
|
|
|
|
ASTNode::MeField { .. } => 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::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::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 let Some(parent) = extends {
|
|
|
|
|
|
desc.push_str(&format!(", extends {}", parent));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !implements.is_empty() {
|
|
|
|
|
|
desc.push_str(&format!(", implements [{}]", implements.join(", ")));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
desc.push(')');
|
|
|
|
|
|
desc
|
|
|
|
|
|
}
|
2025-08-11 07:55:41 +09:00
|
|
|
|
ASTNode::FunctionDeclaration { name, params, body, is_static, is_override, .. } => {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
let static_str = if *is_static { "static " } else { "" };
|
2025-08-11 07:55:41 +09:00
|
|
|
|
let override_str = if *is_override { "override " } else { "" };
|
|
|
|
|
|
format!("FunctionDeclaration({}{}{}({}), {} statements)",
|
|
|
|
|
|
override_str, static_str, name, params.join(", "), body.len())
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
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(),
|
2025-08-11 07:55:41 +09:00
|
|
|
|
ASTNode::FromCall { parent, method, arguments, .. } => {
|
|
|
|
|
|
format!("FromCall({}.{}, {} args)", parent, method, arguments.len())
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
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::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)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 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::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,
|
2025-08-11 07:55:41 +09:00
|
|
|
|
ASTNode::FromCall { span, .. } => *span,
|
2025-08-09 15:14:44 +09:00
|
|
|
|
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::AwaitExpression { 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 =====
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
|
mod tests {
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
use crate::box_trait::{StringBox, IntegerBox, BoolBox};
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_ast_node_creation() {
|
|
|
|
|
|
// Program node
|
|
|
|
|
|
let program = ASTNode::Program {
|
|
|
|
|
|
statements: vec![],
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
assert_eq!(program.node_type(), "Program");
|
|
|
|
|
|
assert!(program.info().contains("Program(0 statements)"));
|
|
|
|
|
|
|
|
|
|
|
|
// Variable node
|
|
|
|
|
|
let variable = ASTNode::Variable {
|
|
|
|
|
|
name: "test_var".to_string(),
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
assert_eq!(variable.node_type(), "Variable");
|
|
|
|
|
|
assert!(variable.is_expression());
|
|
|
|
|
|
assert!(!variable.is_statement());
|
|
|
|
|
|
|
|
|
|
|
|
// Assignment node
|
|
|
|
|
|
let assignment = ASTNode::Assignment {
|
|
|
|
|
|
target: Box::new(ASTNode::Variable { name: "x".to_string(), span: Span::unknown() }),
|
|
|
|
|
|
value: Box::new(ASTNode::Literal {
|
|
|
|
|
|
value: LiteralValue::Integer(42),
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
}),
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
assert_eq!(assignment.node_type(), "Assignment");
|
|
|
|
|
|
assert!(!assignment.is_expression());
|
|
|
|
|
|
assert!(assignment.is_statement());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_binary_operator() {
|
|
|
|
|
|
let add_op = BinaryOperator::Add;
|
|
|
|
|
|
assert_eq!(format!("{}", add_op), "+");
|
|
|
|
|
|
|
|
|
|
|
|
let equals_op = BinaryOperator::Equal;
|
|
|
|
|
|
assert_eq!(format!("{}", equals_op), "==");
|
|
|
|
|
|
|
|
|
|
|
|
let less_equals_op = BinaryOperator::LessEqual;
|
|
|
|
|
|
assert_eq!(format!("{}", less_equals_op), "<=");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_complex_ast() {
|
|
|
|
|
|
// box TestBox { value }のAST
|
|
|
|
|
|
let mut methods = HashMap::new();
|
|
|
|
|
|
methods.insert("getValue".to_string(), ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name: "getValue".to_string(),
|
|
|
|
|
|
params: vec![],
|
|
|
|
|
|
body: vec![
|
|
|
|
|
|
ASTNode::Return {
|
|
|
|
|
|
value: Some(Box::new(ASTNode::FieldAccess {
|
|
|
|
|
|
object: Box::new(ASTNode::This { span: Span::unknown() }),
|
|
|
|
|
|
field: "value".to_string(),
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
})),
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
is_static: false, // 通常のメソッド
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
let box_decl = ASTNode::BoxDeclaration {
|
|
|
|
|
|
name: "TestBox".to_string(),
|
|
|
|
|
|
fields: vec!["value".to_string()],
|
|
|
|
|
|
methods,
|
|
|
|
|
|
constructors: HashMap::new(),
|
|
|
|
|
|
init_fields: vec![],
|
|
|
|
|
|
is_interface: false,
|
|
|
|
|
|
extends: None,
|
|
|
|
|
|
implements: vec![],
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(box_decl.node_type(), "BoxDeclaration");
|
|
|
|
|
|
assert!(box_decl.info().contains("TestBox"));
|
|
|
|
|
|
assert!(box_decl.info().contains("1 fields"));
|
|
|
|
|
|
assert!(box_decl.info().contains("1 methods"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_method_call() {
|
|
|
|
|
|
// obj.getValue()のAST
|
|
|
|
|
|
let method_call = ASTNode::MethodCall {
|
|
|
|
|
|
object: Box::new(ASTNode::Variable { name: "obj".to_string(), span: Span::unknown() }),
|
|
|
|
|
|
method: "getValue".to_string(),
|
|
|
|
|
|
arguments: vec![],
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(method_call.node_type(), "MethodCall");
|
|
|
|
|
|
assert!(method_call.is_expression());
|
|
|
|
|
|
assert!(method_call.info().contains("getValue"));
|
|
|
|
|
|
assert!(method_call.info().contains("0 args"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_binary_operation() {
|
|
|
|
|
|
// x + y のAST
|
|
|
|
|
|
let binary_op = ASTNode::BinaryOp {
|
|
|
|
|
|
operator: BinaryOperator::Add,
|
|
|
|
|
|
left: Box::new(ASTNode::Variable { name: "x".to_string(), span: Span::unknown() }),
|
|
|
|
|
|
right: Box::new(ASTNode::Variable { name: "y".to_string(), span: Span::unknown() }),
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(binary_op.node_type(), "BinaryOp");
|
|
|
|
|
|
assert!(binary_op.is_expression());
|
|
|
|
|
|
assert!(binary_op.info().contains("+"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|