2025-08-09 15:14:44 +09:00
|
|
|
|
/*!
|
|
|
|
|
|
* Nyash Parser - Rust Implementation
|
|
|
|
|
|
*
|
|
|
|
|
|
* Python版nyashc_v4.pyのNyashParserをRustで完全再実装
|
|
|
|
|
|
* Token列をAST (Abstract Syntax Tree) に変換
|
|
|
|
|
|
*
|
|
|
|
|
|
* TODO: リファクタリング計画
|
|
|
|
|
|
* - expressions.rs: 式パーサー (parse_expression, parse_or, parse_and等)
|
|
|
|
|
|
* - statements.rs: 文パーサー (parse_statement, parse_if, parse_loop等)
|
|
|
|
|
|
* - declarations.rs: 宣言パーサー (parse_box_declaration, parse_function_declaration等)
|
|
|
|
|
|
* - errors.rs: エラー型定義とハンドリング
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// サブモジュール宣言
|
|
|
|
|
|
mod expressions;
|
|
|
|
|
|
mod statements;
|
|
|
|
|
|
// mod declarations;
|
|
|
|
|
|
// mod errors;
|
|
|
|
|
|
|
|
|
|
|
|
use crate::tokenizer::{Token, TokenType, TokenizeError};
|
|
|
|
|
|
use crate::ast::{ASTNode, Span};
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
2025-08-10 11:32:32 +09:00
|
|
|
|
// ===== 🔥 Debug Macros =====
|
|
|
|
|
|
|
|
|
|
|
|
/// Infinite loop detection macro - must be called in every loop that advances tokens
|
|
|
|
|
|
/// Prevents parser from hanging due to token consumption bugs
|
|
|
|
|
|
/// Uses parser's debug_fuel field for centralized fuel management
|
|
|
|
|
|
macro_rules! must_advance {
|
|
|
|
|
|
($parser:expr, $fuel:expr, $location:literal) => {
|
|
|
|
|
|
// デバッグ燃料がSomeの場合のみ制限チェック
|
|
|
|
|
|
if let Some(ref mut limit) = $parser.debug_fuel {
|
|
|
|
|
|
if *limit == 0 {
|
|
|
|
|
|
eprintln!("🚨 PARSER INFINITE LOOP DETECTED at {}", $location);
|
|
|
|
|
|
eprintln!("🔍 Current token: {:?} at line {}", $parser.current_token().token_type, $parser.current_token().line);
|
|
|
|
|
|
eprintln!("🔍 Parser position: {}/{}", $parser.current, $parser.tokens.len());
|
|
|
|
|
|
return Err(ParseError::InfiniteLoop {
|
|
|
|
|
|
location: $location.to_string(),
|
|
|
|
|
|
token: $parser.current_token().token_type.clone(),
|
|
|
|
|
|
line: $parser.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
*limit -= 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
// None の場合は無制限なのでチェックしない
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Initialize debug fuel for loop monitoring
|
|
|
|
|
|
macro_rules! debug_fuel {
|
|
|
|
|
|
() => {
|
|
|
|
|
|
100_000 // Default: 100k iterations should be enough for any reasonable program
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
// Two-phase parser structures are no longer needed - simplified to direct parsing
|
|
|
|
|
|
|
|
|
|
|
|
/// パースエラー
|
|
|
|
|
|
#[derive(Error, Debug)]
|
|
|
|
|
|
pub enum ParseError {
|
|
|
|
|
|
#[error("Unexpected token {found:?}, expected {expected} at line {line}")]
|
|
|
|
|
|
UnexpectedToken { found: TokenType, expected: String, line: usize },
|
|
|
|
|
|
|
|
|
|
|
|
#[error("Unexpected end of file")]
|
|
|
|
|
|
UnexpectedEOF,
|
|
|
|
|
|
|
|
|
|
|
|
#[error("Invalid expression at line {line}")]
|
|
|
|
|
|
InvalidExpression { line: usize },
|
|
|
|
|
|
|
|
|
|
|
|
#[error("Invalid statement at line {line}")]
|
|
|
|
|
|
InvalidStatement { line: usize },
|
|
|
|
|
|
|
|
|
|
|
|
#[error("Circular dependency detected between static boxes: {cycle}")]
|
|
|
|
|
|
CircularDependency { cycle: String },
|
|
|
|
|
|
|
2025-08-10 11:32:32 +09:00
|
|
|
|
#[error("🚨 Infinite loop detected in parser at {location} - token: {token:?} at line {line}")]
|
|
|
|
|
|
InfiniteLoop { location: String, token: TokenType, line: usize },
|
|
|
|
|
|
|
2025-08-15 11:47:46 +00:00
|
|
|
|
#[error("🔥 Transparency system removed: {suggestion} at line {line}")]
|
|
|
|
|
|
TransparencySystemRemoved { suggestion: String, line: usize },
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
#[error("Tokenize error: {0}")]
|
|
|
|
|
|
TokenizeError(#[from] TokenizeError),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Nyashパーサー - トークン列をASTに変換
|
|
|
|
|
|
pub struct NyashParser {
|
|
|
|
|
|
tokens: Vec<Token>,
|
|
|
|
|
|
current: usize,
|
|
|
|
|
|
/// 🔥 Static box依存関係追跡(循環依存検出用)
|
|
|
|
|
|
static_box_dependencies: std::collections::HashMap<String, std::collections::HashSet<String>>,
|
2025-08-10 11:32:32 +09:00
|
|
|
|
/// 🔥 デバッグ燃料:無限ループ検出用制限値 (None = 無制限)
|
|
|
|
|
|
debug_fuel: Option<usize>,
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl NyashParser {
|
|
|
|
|
|
/// 新しいパーサーを作成
|
|
|
|
|
|
pub fn new(tokens: Vec<Token>) -> Self {
|
|
|
|
|
|
Self {
|
|
|
|
|
|
tokens,
|
|
|
|
|
|
current: 0,
|
|
|
|
|
|
static_box_dependencies: std::collections::HashMap::new(),
|
2025-08-10 11:32:32 +09:00
|
|
|
|
debug_fuel: Some(100_000), // デフォルト値
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 文字列からパース (トークナイズ + パース)
|
|
|
|
|
|
pub fn parse_from_string(input: impl Into<String>) -> Result<ASTNode, ParseError> {
|
2025-08-10 11:32:32 +09:00
|
|
|
|
Self::parse_from_string_with_fuel(input, Some(100_000))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 文字列からパース (デバッグ燃料指定版)
|
|
|
|
|
|
/// fuel: Some(n) = n回まで、None = 無制限
|
|
|
|
|
|
pub fn parse_from_string_with_fuel(input: impl Into<String>, fuel: Option<usize>) -> Result<ASTNode, ParseError> {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
let mut tokenizer = crate::tokenizer::NyashTokenizer::new(input);
|
|
|
|
|
|
let tokens = tokenizer.tokenize()?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut parser = Self::new(tokens);
|
2025-08-10 11:32:32 +09:00
|
|
|
|
parser.debug_fuel = fuel;
|
2025-08-10 07:54:03 +09:00
|
|
|
|
let result = parser.parse();
|
|
|
|
|
|
result
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// パース実行 - Program ASTを返す
|
|
|
|
|
|
pub fn parse(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
self.parse_program()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== パース関数群 =====
|
|
|
|
|
|
|
|
|
|
|
|
/// プログラム全体をパース
|
|
|
|
|
|
fn parse_program(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
let mut statements = Vec::new();
|
2025-08-10 07:54:03 +09:00
|
|
|
|
let mut statement_count = 0;
|
2025-08-09 15:14:44 +09:00
|
|
|
|
|
|
|
|
|
|
while !self.is_at_end() {
|
2025-08-10 07:54:03 +09:00
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
// EOF tokenはスキップ
|
|
|
|
|
|
if matches!(self.current_token().token_type, TokenType::EOF) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NEWLINE tokenはスキップ(文の区切りとして使用)
|
|
|
|
|
|
if matches!(self.current_token().token_type, TokenType::NEWLINE) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let statement = self.parse_statement()?;
|
|
|
|
|
|
statements.push(statement);
|
2025-08-10 07:54:03 +09:00
|
|
|
|
statement_count += 1;
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
// 🔥 すべてのstatic box解析後に循環依存検出
|
|
|
|
|
|
self.check_circular_dependencies()?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(ASTNode::Program { statements, span: Span::unknown() })
|
|
|
|
|
|
}
|
|
|
|
|
|
// Statement parsing methods are now in statements.rs module
|
|
|
|
|
|
|
|
|
|
|
|
/// box宣言をパース: box Name { fields... methods... }
|
|
|
|
|
|
fn parse_box_declaration(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
self.consume(TokenType::BOX)?;
|
|
|
|
|
|
|
|
|
|
|
|
let name = if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
|
|
|
|
|
let name = name.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
name
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "identifier".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 🔥 ジェネリクス型パラメータのパース (<T, U>)
|
|
|
|
|
|
let type_parameters = if self.match_token(&TokenType::LESS) {
|
|
|
|
|
|
self.advance(); // consume '<'
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if let TokenType::IDENTIFIER(param_name) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param_name.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance(); // consume ','
|
|
|
|
|
|
} else {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "type parameter name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::GREATER)?; // consume '>'
|
|
|
|
|
|
params
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Vec::new()
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-12 08:29:25 +00:00
|
|
|
|
// from句のパース(Multi-delegation)🚀
|
2025-08-11 09:40:24 +09:00
|
|
|
|
let extends = if self.match_token(&TokenType::FROM) {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
self.advance(); // consume 'from'
|
|
|
|
|
|
|
2025-08-12 08:29:25 +00:00
|
|
|
|
let mut parent_list = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type {
|
|
|
|
|
|
parent_list.push(parent_name.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance(); // consume ','
|
|
|
|
|
|
} else {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "parent class name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
2025-08-12 08:29:25 +00:00
|
|
|
|
|
|
|
|
|
|
parent_list
|
2025-08-09 15:14:44 +09:00
|
|
|
|
} else {
|
2025-08-12 08:29:25 +00:00
|
|
|
|
Vec::new()
|
2025-08-09 15:14:44 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// interface句のパース(インターフェース実装)
|
|
|
|
|
|
let implements = if self.match_token(&TokenType::INTERFACE) {
|
|
|
|
|
|
self.advance(); // consume 'interface'
|
|
|
|
|
|
|
|
|
|
|
|
let mut interface_list = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if let TokenType::IDENTIFIER(interface_name) = &self.current_token().token_type {
|
|
|
|
|
|
interface_list.push(interface_name.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance(); // consume ','
|
|
|
|
|
|
} else {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "interface name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface_list
|
|
|
|
|
|
} else {
|
|
|
|
|
|
vec![]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
self.skip_newlines(); // ブレース後の改行をスキップ
|
|
|
|
|
|
|
|
|
|
|
|
let mut fields = Vec::new();
|
|
|
|
|
|
let mut methods = HashMap::new();
|
|
|
|
|
|
let mut constructors = HashMap::new();
|
|
|
|
|
|
let mut init_fields = Vec::new();
|
2025-08-12 20:27:20 +00:00
|
|
|
|
let mut weak_fields = Vec::new(); // 🔗 Track weak fields
|
2025-08-09 15:14:44 +09:00
|
|
|
|
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines(); // ループ開始時に改行をスキップ
|
|
|
|
|
|
|
|
|
|
|
|
// RBRACEに到達していればループを抜ける
|
|
|
|
|
|
if self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-11 09:40:24 +09:00
|
|
|
|
// initブロックの処理(initメソッドではない場合のみ)
|
|
|
|
|
|
if self.match_token(&TokenType::INIT) && self.peek_token() != &TokenType::LPAREN {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
self.advance(); // consume 'init'
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
// initブロック内のフィールド定義を読み込み
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-12 20:27:20 +00:00
|
|
|
|
// Check for weak modifier
|
|
|
|
|
|
let is_weak = if self.match_token(&TokenType::WEAK) {
|
|
|
|
|
|
self.advance(); // consume 'weak'
|
|
|
|
|
|
true
|
|
|
|
|
|
} else {
|
|
|
|
|
|
false
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
if let TokenType::IDENTIFIER(field_name) = &self.current_token().token_type {
|
|
|
|
|
|
init_fields.push(field_name.clone());
|
2025-08-12 20:27:20 +00:00
|
|
|
|
if is_weak {
|
|
|
|
|
|
weak_fields.push(field_name.clone()); // 🔗 Add to weak fields list
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
// カンマがあればスキップ
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 不正なトークンがある場合はエラー
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
2025-08-12 20:27:20 +00:00
|
|
|
|
expected: if is_weak { "field name after 'weak'" } else { "field name" }.to_string(),
|
2025-08-09 15:14:44 +09:00
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
line: self.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-11 09:40:24 +09:00
|
|
|
|
// overrideキーワードをチェック
|
|
|
|
|
|
let mut is_override = false;
|
|
|
|
|
|
if self.match_token(&TokenType::OVERRIDE) {
|
|
|
|
|
|
is_override = true;
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initトークンをメソッド名として特別処理
|
|
|
|
|
|
if self.match_token(&TokenType::INIT) && self.peek_token() == &TokenType::LPAREN {
|
|
|
|
|
|
let field_or_method = "init".to_string();
|
|
|
|
|
|
self.advance(); // consume 'init'
|
|
|
|
|
|
|
|
|
|
|
|
// コンストラクタとして処理
|
|
|
|
|
|
if self.match_token(&TokenType::LPAREN) {
|
|
|
|
|
|
// initは常にコンストラクタ
|
|
|
|
|
|
if is_override {
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
expected: "method definition, not constructor after override keyword".to_string(),
|
|
|
|
|
|
found: TokenType::INIT,
|
|
|
|
|
|
line: self.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
// コンストラクタの処理
|
|
|
|
|
|
self.advance(); // consume '('
|
|
|
|
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
|
|
|
|
|
must_advance!(self, _unused, "constructor parameter parsing");
|
|
|
|
|
|
|
|
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let constructor = ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name: field_or_method.clone(),
|
|
|
|
|
|
params: params.clone(),
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static: false,
|
|
|
|
|
|
is_override: false,
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// パラメータの数でコンストラクタを区別
|
|
|
|
|
|
let constructor_key = format!("{}/{}", field_or_method, params.len());
|
|
|
|
|
|
constructors.insert(constructor_key, constructor);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// packトークンをメソッド名として特別処理
|
|
|
|
|
|
else if self.match_token(&TokenType::PACK) && self.peek_token() == &TokenType::LPAREN {
|
|
|
|
|
|
let field_or_method = "pack".to_string();
|
|
|
|
|
|
self.advance(); // consume 'pack'
|
|
|
|
|
|
|
|
|
|
|
|
// コンストラクタとして処理
|
|
|
|
|
|
if self.match_token(&TokenType::LPAREN) {
|
|
|
|
|
|
// packは常にコンストラクタ
|
|
|
|
|
|
if is_override {
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
expected: "method definition, not constructor after override keyword".to_string(),
|
|
|
|
|
|
found: TokenType::PACK,
|
|
|
|
|
|
line: self.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
// コンストラクタの処理
|
|
|
|
|
|
self.advance(); // consume '('
|
|
|
|
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
|
|
|
|
|
must_advance!(self, _unused, "constructor parameter parsing");
|
|
|
|
|
|
|
|
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let constructor = ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name: field_or_method.clone(),
|
|
|
|
|
|
params: params.clone(),
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static: false,
|
|
|
|
|
|
is_override: false,
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-15 19:34:26 +09:00
|
|
|
|
// パラメータの数でコンストラクタを区別
|
|
|
|
|
|
let constructor_key = format!("{}/{}", field_or_method, params.len());
|
|
|
|
|
|
constructors.insert(constructor_key, constructor);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// birthトークンをメソッド名として特別処理
|
|
|
|
|
|
else if self.match_token(&TokenType::BIRTH) && self.peek_token() == &TokenType::LPAREN {
|
|
|
|
|
|
let field_or_method = "birth".to_string();
|
|
|
|
|
|
self.advance(); // consume 'birth'
|
|
|
|
|
|
|
|
|
|
|
|
// コンストラクタとして処理
|
|
|
|
|
|
if self.match_token(&TokenType::LPAREN) {
|
|
|
|
|
|
// birthは常にコンストラクタ
|
|
|
|
|
|
if is_override {
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
expected: "method definition, not constructor after override keyword".to_string(),
|
|
|
|
|
|
found: TokenType::BIRTH,
|
|
|
|
|
|
line: self.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
// コンストラクタの処理
|
|
|
|
|
|
self.advance(); // consume '('
|
|
|
|
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
|
|
|
|
|
must_advance!(self, _unused, "constructor parameter parsing");
|
|
|
|
|
|
|
|
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let constructor = ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name: field_or_method.clone(),
|
|
|
|
|
|
params: params.clone(),
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static: false,
|
|
|
|
|
|
is_override: false,
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-11 09:40:24 +09:00
|
|
|
|
// パラメータの数でコンストラクタを区別
|
|
|
|
|
|
let constructor_key = format!("{}/{}", field_or_method, params.len());
|
|
|
|
|
|
constructors.insert(constructor_key, constructor);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if let TokenType::IDENTIFIER(field_or_method) = &self.current_token().token_type {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
let field_or_method = field_or_method.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
// メソッド定義またはコンストラクタか?
|
|
|
|
|
|
if self.match_token(&TokenType::LPAREN) {
|
2025-08-15 19:34:26 +09:00
|
|
|
|
// Box名と同じまたは"init"または"pack"または"birth"の場合はコンストラクタ
|
|
|
|
|
|
if field_or_method == name || field_or_method == "init" || field_or_method == "pack" || field_or_method == "birth" {
|
2025-08-11 09:40:24 +09:00
|
|
|
|
// コンストラクタはoverrideできない
|
|
|
|
|
|
if is_override {
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
expected: "method definition, not constructor after override keyword".to_string(),
|
|
|
|
|
|
found: TokenType::IDENTIFIER(field_or_method.clone()),
|
|
|
|
|
|
line: self.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
// コンストラクタの処理
|
|
|
|
|
|
self.advance(); // consume '('
|
|
|
|
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
2025-08-10 11:32:32 +09:00
|
|
|
|
must_advance!(self, _unused, "constructor parameter parsing");
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let constructor = ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name: field_or_method.clone(),
|
|
|
|
|
|
params: params.clone(),
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static: false, // コンストラクタは静的でない
|
2025-08-11 07:55:41 +09:00
|
|
|
|
is_override: false, // デフォルトは非オーバーライド
|
2025-08-09 15:14:44 +09:00
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// パラメータの数でコンストラクタを区別
|
|
|
|
|
|
let constructor_key = format!("{}/{}", field_or_method, params.len());
|
|
|
|
|
|
constructors.insert(constructor_key, constructor);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 通常のメソッド定義
|
|
|
|
|
|
self.advance(); // consume '('
|
|
|
|
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
2025-08-10 11:32:32 +09:00
|
|
|
|
must_advance!(self, _unused, "box method parameter parsing");
|
2025-08-10 07:54:03 +09:00
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
2025-08-10 07:54:03 +09:00
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
// カンマの後に閉じ括弧があるかチェック(trailing comma)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if !self.match_token(&TokenType::RPAREN) {
|
|
|
|
|
|
// IDENTIFIERでもRPARENでもない場合はエラー
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "parameter name or ')'".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines(); // メソッド本体内の改行をスキップ
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let method = ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name: field_or_method.clone(),
|
|
|
|
|
|
params,
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static: false, // メソッドは通常静的でない
|
2025-08-11 09:40:24 +09:00
|
|
|
|
is_override, // overrideキーワードの有無を反映
|
2025-08-09 15:14:44 +09:00
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
methods.insert(field_or_method, method);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// フィールド定義
|
2025-08-11 09:40:24 +09:00
|
|
|
|
if is_override {
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
expected: "method definition after override keyword".to_string(),
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
line: self.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
fields.push(field_or_method);
|
|
|
|
|
|
}
|
|
|
|
|
|
self.skip_newlines(); // フィールド/メソッド定義後の改行をスキップ
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 予期しないトークンの場合、詳細なエラー情報を出力してスキップ
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
eprintln!("Debug: Unexpected token {:?} at line {}", self.current_token().token_type, line);
|
|
|
|
|
|
self.advance(); // トークンをスキップして続行
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
2025-08-11 10:14:47 +09:00
|
|
|
|
// 🔍 デリゲーションメソッドチェック:親Boxに存在しないメソッドのoverride検出
|
2025-08-12 08:29:25 +00:00
|
|
|
|
if !extends.is_empty() {
|
|
|
|
|
|
// For multi-delegation, validate against all parents
|
|
|
|
|
|
for parent_name in &extends {
|
|
|
|
|
|
self.validate_override_methods(&name, parent_name, &methods)?;
|
|
|
|
|
|
}
|
2025-08-11 10:14:47 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
Ok(ASTNode::BoxDeclaration {
|
|
|
|
|
|
name,
|
|
|
|
|
|
fields,
|
|
|
|
|
|
methods,
|
|
|
|
|
|
constructors,
|
|
|
|
|
|
init_fields,
|
2025-08-12 20:27:20 +00:00
|
|
|
|
weak_fields, // 🔗 Add weak fields to the construction
|
2025-08-09 15:14:44 +09:00
|
|
|
|
is_interface: false,
|
|
|
|
|
|
extends,
|
|
|
|
|
|
implements,
|
|
|
|
|
|
type_parameters,
|
|
|
|
|
|
is_static: false,
|
|
|
|
|
|
static_init: None,
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// インターフェースBox宣言をパース: interface box Name { method1() method2() }
|
|
|
|
|
|
fn parse_interface_box_declaration(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
self.consume(TokenType::INTERFACE)?;
|
|
|
|
|
|
self.consume(TokenType::BOX)?;
|
|
|
|
|
|
|
|
|
|
|
|
let name = if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
|
|
|
|
|
let name = name.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
name
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "identifier".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
self.skip_newlines(); // ブレース後の改行をスキップ
|
|
|
|
|
|
|
|
|
|
|
|
let mut methods = HashMap::new();
|
|
|
|
|
|
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines(); // ループ開始時に改行をスキップ
|
|
|
|
|
|
if let TokenType::IDENTIFIER(method_name) = &self.current_token().token_type {
|
|
|
|
|
|
let method_name = method_name.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
// インターフェースメソッドはシグネチャのみ
|
|
|
|
|
|
if self.match_token(&TokenType::LPAREN) {
|
|
|
|
|
|
self.advance(); // consume '('
|
|
|
|
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
|
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
|
|
|
|
|
|
// インターフェースメソッドは実装なし(空のbody)
|
|
|
|
|
|
let method_decl = ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name: method_name.clone(),
|
|
|
|
|
|
params,
|
|
|
|
|
|
body: vec![], // 空の実装
|
|
|
|
|
|
is_static: false, // インターフェースメソッドは通常静的でない
|
2025-08-11 07:55:41 +09:00
|
|
|
|
is_override: false, // デフォルトは非オーバーライド
|
2025-08-09 15:14:44 +09:00
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
methods.insert(method_name, method_decl);
|
|
|
|
|
|
|
|
|
|
|
|
// メソッド宣言後の改行をスキップ
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "(".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "method name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(ASTNode::BoxDeclaration {
|
|
|
|
|
|
name,
|
|
|
|
|
|
fields: vec![], // インターフェースはフィールドなし
|
|
|
|
|
|
methods,
|
|
|
|
|
|
constructors: HashMap::new(), // インターフェースにコンストラクタなし
|
|
|
|
|
|
init_fields: vec![], // インターフェースにinitブロックなし
|
2025-08-12 20:27:20 +00:00
|
|
|
|
weak_fields: vec![], // 🔗 インターフェースにweak fieldsなし
|
2025-08-09 15:14:44 +09:00
|
|
|
|
is_interface: true, // インターフェースフラグ
|
2025-08-12 08:29:25 +00:00
|
|
|
|
extends: vec![], // 🚀 Multi-delegation: Changed from None to vec![]
|
2025-08-09 15:14:44 +09:00
|
|
|
|
implements: vec![],
|
|
|
|
|
|
type_parameters: Vec::new(), // 🔥 インターフェースではジェネリクス未対応
|
|
|
|
|
|
is_static: false, // インターフェースは非static
|
|
|
|
|
|
static_init: None, // インターフェースにstatic initなし
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// グローバル変数をパース: global name = value
|
|
|
|
|
|
fn parse_global_var(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
self.consume(TokenType::GLOBAL)?;
|
|
|
|
|
|
|
|
|
|
|
|
let name = if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
|
|
|
|
|
let name = name.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
name
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "identifier".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::ASSIGN)?;
|
|
|
|
|
|
let value = Box::new(self.parse_expression()?);
|
|
|
|
|
|
|
|
|
|
|
|
Ok(ASTNode::GlobalVar { name, value, span: Span::unknown() })
|
|
|
|
|
|
}
|
|
|
|
|
|
// Statement parsing methods are now in statements.rs module
|
|
|
|
|
|
|
|
|
|
|
|
/// function宣言をパース: function name(params) { body }
|
|
|
|
|
|
fn parse_function_declaration(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
self.consume(TokenType::FUNCTION)?;
|
|
|
|
|
|
|
|
|
|
|
|
// 関数名を取得
|
|
|
|
|
|
let name = if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
|
|
|
|
|
let name = name.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
name
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "function name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// パラメータリストをパース
|
|
|
|
|
|
self.consume(TokenType::LPAREN)?;
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
2025-08-10 11:32:32 +09:00
|
|
|
|
must_advance!(self, _unused, "function declaration parameter parsing");
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if !self.match_token(&TokenType::RPAREN) {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "parameter name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
|
|
|
|
|
|
// 関数本体をパース
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
|
|
|
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name,
|
|
|
|
|
|
params,
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static: false, // 通常の関数は静的でない
|
2025-08-11 07:55:41 +09:00
|
|
|
|
is_override: false, // デフォルトは非オーバーライド
|
2025-08-09 15:14:44 +09:00
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 静的宣言をパース - 🔥 static function / static box 記法
|
|
|
|
|
|
fn parse_static_declaration(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
self.consume(TokenType::STATIC)?;
|
|
|
|
|
|
|
|
|
|
|
|
// 次のトークンで分岐: function か box か
|
|
|
|
|
|
match &self.current_token().token_type {
|
|
|
|
|
|
TokenType::FUNCTION => self.parse_static_function(),
|
|
|
|
|
|
TokenType::BOX => self.parse_static_box(),
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "function or box after static".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 静的関数宣言をパース - static function Name() { ... }
|
|
|
|
|
|
fn parse_static_function(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
self.consume(TokenType::FUNCTION)?;
|
|
|
|
|
|
|
|
|
|
|
|
// 関数名を取得(Box名.関数名の形式をサポート)
|
|
|
|
|
|
let name = if let TokenType::IDENTIFIER(first_part) = &self.current_token().token_type {
|
|
|
|
|
|
let mut full_name = first_part.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
// ドット記法をチェック(例:Math.min)
|
|
|
|
|
|
if self.match_token(&TokenType::DOT) {
|
|
|
|
|
|
self.advance(); // DOTを消費
|
|
|
|
|
|
|
|
|
|
|
|
if let TokenType::IDENTIFIER(method_name) = &self.current_token().token_type {
|
|
|
|
|
|
full_name = format!("{}.{}", full_name, method_name);
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "method name after dot".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
full_name
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "static function name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// パラメータリストをパース
|
|
|
|
|
|
self.consume(TokenType::LPAREN)?;
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
2025-08-10 11:32:32 +09:00
|
|
|
|
must_advance!(self, _unused, "static function parameter parsing");
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if !self.match_token(&TokenType::RPAREN) {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "parameter name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
|
|
|
|
|
|
// 関数本体をパース
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
self.skip_newlines(); // ブレースの後の改行をスキップ
|
|
|
|
|
|
|
|
|
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines(); // ループ開始時の改行をスキップ
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name,
|
|
|
|
|
|
params,
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static: true, // 🔥 静的関数フラグを設定
|
2025-08-11 07:55:41 +09:00
|
|
|
|
is_override: false, // デフォルトは非オーバーライド
|
2025-08-09 15:14:44 +09:00
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 静的Box宣言をパース - static box Name { ... }
|
|
|
|
|
|
fn parse_static_box(&mut self) -> Result<ASTNode, ParseError> {
|
|
|
|
|
|
self.consume(TokenType::BOX)?;
|
|
|
|
|
|
|
|
|
|
|
|
let name = if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
|
|
|
|
|
let name = name.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
name
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "identifier".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 🔥 ジェネリクス型パラメータのパース (<T, U>)
|
|
|
|
|
|
let type_parameters = if self.match_token(&TokenType::LESS) {
|
|
|
|
|
|
self.advance(); // consume '<'
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if let TokenType::IDENTIFIER(param_name) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param_name.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance(); // consume ','
|
|
|
|
|
|
} else {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "type parameter name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::GREATER)?; // consume '>'
|
|
|
|
|
|
params
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Vec::new()
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-12 08:29:25 +00:00
|
|
|
|
// from句のパース(Multi-delegation)- static boxでもデリゲーション可能 🚀
|
2025-08-11 09:40:24 +09:00
|
|
|
|
let extends = if self.match_token(&TokenType::FROM) {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
self.advance(); // consume 'from'
|
|
|
|
|
|
|
2025-08-12 08:29:25 +00:00
|
|
|
|
let mut parent_list = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type {
|
|
|
|
|
|
parent_list.push(parent_name.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance(); // consume ','
|
|
|
|
|
|
} else {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "parent class name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
2025-08-12 08:29:25 +00:00
|
|
|
|
|
|
|
|
|
|
parent_list
|
2025-08-09 15:14:44 +09:00
|
|
|
|
} else {
|
2025-08-12 08:29:25 +00:00
|
|
|
|
Vec::new()
|
2025-08-09 15:14:44 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-12 08:29:25 +00:00
|
|
|
|
// interface句のパース(インターフェース実装)- static boxでもinterface実装可能
|
2025-08-09 15:14:44 +09:00
|
|
|
|
let implements = if self.match_token(&TokenType::INTERFACE) {
|
|
|
|
|
|
self.advance(); // consume 'interface'
|
|
|
|
|
|
|
|
|
|
|
|
let mut interface_list = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if let TokenType::IDENTIFIER(interface_name) = &self.current_token().token_type {
|
|
|
|
|
|
interface_list.push(interface_name.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance(); // consume ','
|
|
|
|
|
|
} else {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: "interface name".to_string(),
|
|
|
|
|
|
line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface_list
|
|
|
|
|
|
} else {
|
|
|
|
|
|
vec![]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
self.skip_newlines(); // ブレース後の改行をスキップ
|
|
|
|
|
|
|
|
|
|
|
|
let mut fields = Vec::new();
|
|
|
|
|
|
let mut methods = HashMap::new();
|
|
|
|
|
|
let constructors = HashMap::new();
|
|
|
|
|
|
let mut init_fields = Vec::new();
|
2025-08-12 20:27:20 +00:00
|
|
|
|
let mut weak_fields = Vec::new(); // 🔗 Track weak fields for static box
|
2025-08-09 15:14:44 +09:00
|
|
|
|
let mut static_init = None;
|
|
|
|
|
|
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines(); // ループ開始時に改行をスキップ
|
|
|
|
|
|
|
|
|
|
|
|
// RBRACEに到達していればループを抜ける
|
|
|
|
|
|
if self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 🔥 static { } ブロックの処理
|
|
|
|
|
|
if self.match_token(&TokenType::STATIC) {
|
|
|
|
|
|
self.advance(); // consume 'static'
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut static_body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
static_body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
static_init = Some(static_body);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initブロックの処理
|
|
|
|
|
|
if self.match_token(&TokenType::INIT) {
|
|
|
|
|
|
self.advance(); // consume 'init'
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
// initブロック内のフィールド定義を読み込み
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-12 20:27:20 +00:00
|
|
|
|
// Check for weak modifier
|
|
|
|
|
|
let is_weak = if self.match_token(&TokenType::WEAK) {
|
|
|
|
|
|
self.advance(); // consume 'weak'
|
|
|
|
|
|
true
|
|
|
|
|
|
} else {
|
|
|
|
|
|
false
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
if let TokenType::IDENTIFIER(field_name) = &self.current_token().token_type {
|
|
|
|
|
|
init_fields.push(field_name.clone());
|
2025-08-12 20:27:20 +00:00
|
|
|
|
if is_weak {
|
|
|
|
|
|
weak_fields.push(field_name.clone()); // 🔗 Add to weak fields list
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
// カンマがあればスキップ
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 不正なトークンがある場合はエラー
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
2025-08-12 20:27:20 +00:00
|
|
|
|
expected: if is_weak { "field name after 'weak'" } else { "field name" }.to_string(),
|
2025-08-09 15:14:44 +09:00
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
line: self.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if let TokenType::IDENTIFIER(field_or_method) = &self.current_token().token_type {
|
|
|
|
|
|
let field_or_method = field_or_method.clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
|
|
|
|
|
|
// メソッド定義か?
|
|
|
|
|
|
if self.match_token(&TokenType::LPAREN) {
|
|
|
|
|
|
// メソッド定義
|
|
|
|
|
|
self.advance(); // consume '('
|
|
|
|
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
|
|
|
|
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
|
|
|
|
|
params.push(param.clone());
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if self.match_token(&TokenType::COMMA) {
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RPAREN)?;
|
|
|
|
|
|
self.consume(TokenType::LBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
|
|
|
|
|
self.skip_newlines();
|
|
|
|
|
|
if !self.match_token(&TokenType::RBRACE) {
|
|
|
|
|
|
body.push(self.parse_statement()?);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
let method = ASTNode::FunctionDeclaration {
|
|
|
|
|
|
name: field_or_method.clone(),
|
|
|
|
|
|
params,
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static: false, // static box内のメソッドは通常メソッド
|
2025-08-11 07:55:41 +09:00
|
|
|
|
is_override: false, // デフォルトは非オーバーライド
|
2025-08-09 15:14:44 +09:00
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
methods.insert(field_or_method, method);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// フィールド定義
|
|
|
|
|
|
fields.push(field_or_method);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
expected: "method or field name".to_string(),
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
line: self.current_token().line,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.consume(TokenType::RBRACE)?;
|
|
|
|
|
|
|
|
|
|
|
|
// 🔥 Static初期化ブロックから依存関係を抽出
|
|
|
|
|
|
if let Some(ref init_stmts) = static_init {
|
|
|
|
|
|
let dependencies = self.extract_dependencies_from_statements(init_stmts);
|
|
|
|
|
|
self.static_box_dependencies.insert(name.clone(), dependencies);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.static_box_dependencies.insert(name.clone(), std::collections::HashSet::new());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(ASTNode::BoxDeclaration {
|
|
|
|
|
|
name,
|
|
|
|
|
|
fields,
|
|
|
|
|
|
methods,
|
|
|
|
|
|
constructors,
|
|
|
|
|
|
init_fields,
|
2025-08-12 20:27:20 +00:00
|
|
|
|
weak_fields, // 🔗 Add weak fields to static box construction
|
2025-08-09 15:14:44 +09:00
|
|
|
|
is_interface: false,
|
|
|
|
|
|
extends,
|
|
|
|
|
|
implements,
|
|
|
|
|
|
type_parameters,
|
|
|
|
|
|
is_static: true, // 🔥 static boxフラグを設定
|
|
|
|
|
|
static_init, // 🔥 static初期化ブロック
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 代入文または関数呼び出しをパース
|
|
|
|
|
|
fn parse_assignment_or_function_call(&mut self) -> Result<ASTNode, ParseError> {
|
2025-08-10 07:54:03 +09:00
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
// まず左辺を式としてパース
|
|
|
|
|
|
let expr = self.parse_expression()?;
|
|
|
|
|
|
|
|
|
|
|
|
// 次のトークンが = なら代入文
|
|
|
|
|
|
if self.match_token(&TokenType::ASSIGN) {
|
|
|
|
|
|
self.advance(); // consume '='
|
|
|
|
|
|
let value = Box::new(self.parse_expression()?);
|
|
|
|
|
|
|
|
|
|
|
|
// 左辺が代入可能な形式かチェック
|
|
|
|
|
|
match &expr {
|
|
|
|
|
|
ASTNode::Variable { .. } |
|
|
|
|
|
|
ASTNode::FieldAccess { .. } => {
|
|
|
|
|
|
Ok(ASTNode::Assignment {
|
|
|
|
|
|
target: Box::new(expr),
|
|
|
|
|
|
value,
|
|
|
|
|
|
span: Span::unknown(),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
Err(ParseError::InvalidStatement { line })
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 代入文でなければ式文として返す
|
|
|
|
|
|
Ok(expr)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Expression parsing methods are now in expressions.rs module
|
|
|
|
|
|
|
|
|
|
|
|
// ===== ユーティリティメソッド =====
|
|
|
|
|
|
|
|
|
|
|
|
/// 現在のトークンを取得
|
|
|
|
|
|
fn current_token(&self) -> &Token {
|
|
|
|
|
|
self.tokens.get(self.current).unwrap_or(&Token {
|
|
|
|
|
|
token_type: TokenType::EOF,
|
|
|
|
|
|
line: 0,
|
|
|
|
|
|
column: 0,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-11 09:40:24 +09:00
|
|
|
|
/// 次のトークンを先読み(位置を進めない)
|
|
|
|
|
|
fn peek_token(&self) -> &TokenType {
|
|
|
|
|
|
if self.current + 1 < self.tokens.len() {
|
|
|
|
|
|
&self.tokens[self.current + 1].token_type
|
|
|
|
|
|
} else {
|
|
|
|
|
|
&TokenType::EOF
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
/// 位置を1つ進める
|
|
|
|
|
|
fn advance(&mut self) {
|
|
|
|
|
|
if !self.is_at_end() {
|
|
|
|
|
|
self.current += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// NEWLINEトークンをスキップ
|
|
|
|
|
|
fn skip_newlines(&mut self) {
|
2025-08-10 07:54:03 +09:00
|
|
|
|
let mut skip_count = 0;
|
2025-08-09 15:14:44 +09:00
|
|
|
|
while matches!(self.current_token().token_type, TokenType::NEWLINE) && !self.is_at_end() {
|
|
|
|
|
|
self.advance();
|
2025-08-10 07:54:03 +09:00
|
|
|
|
skip_count += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
if skip_count > 0 {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 指定されたトークンタイプを消費 (期待通りでなければエラー)
|
|
|
|
|
|
fn consume(&mut self, expected: TokenType) -> Result<Token, ParseError> {
|
2025-08-10 07:54:03 +09:00
|
|
|
|
|
2025-08-09 15:14:44 +09:00
|
|
|
|
if std::mem::discriminant(&self.current_token().token_type) ==
|
|
|
|
|
|
std::mem::discriminant(&expected) {
|
|
|
|
|
|
let token = self.current_token().clone();
|
|
|
|
|
|
self.advance();
|
|
|
|
|
|
Ok(token)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let line = self.current_token().line;
|
|
|
|
|
|
Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: self.current_token().token_type.clone(),
|
|
|
|
|
|
expected: format!("{:?}", expected),
|
|
|
|
|
|
line,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 現在のトークンが指定されたタイプかチェック
|
|
|
|
|
|
fn match_token(&self, token_type: &TokenType) -> bool {
|
|
|
|
|
|
std::mem::discriminant(&self.current_token().token_type) ==
|
|
|
|
|
|
std::mem::discriminant(token_type)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 終端に達したかチェック
|
|
|
|
|
|
fn is_at_end(&self) -> bool {
|
|
|
|
|
|
self.current >= self.tokens.len() ||
|
|
|
|
|
|
matches!(self.current_token().token_type, TokenType::EOF)
|
|
|
|
|
|
}
|
|
|
|
|
|
// Include, local, outbox, try/catch/throw parsing methods are now in statements.rs module
|
|
|
|
|
|
// Two-phase parser helper methods are no longer needed - simplified to direct parsing
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 🔥 Static Box循環依存検出 =====
|
|
|
|
|
|
|
|
|
|
|
|
/// Static初期化ブロック内の文から依存関係を抽出
|
|
|
|
|
|
fn extract_dependencies_from_statements(&self, statements: &[ASTNode]) -> std::collections::HashSet<String> {
|
|
|
|
|
|
let mut dependencies = std::collections::HashSet::new();
|
|
|
|
|
|
|
|
|
|
|
|
for stmt in statements {
|
|
|
|
|
|
self.extract_dependencies_from_ast(stmt, &mut dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dependencies
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// AST内から静的Box参照を再帰的に検出
|
|
|
|
|
|
fn extract_dependencies_from_ast(&self, node: &ASTNode, dependencies: &mut std::collections::HashSet<String>) {
|
|
|
|
|
|
match node {
|
|
|
|
|
|
ASTNode::FieldAccess { object, .. } => {
|
|
|
|
|
|
// Math.PI のような参照を検出
|
|
|
|
|
|
if let ASTNode::Variable { name, .. } = object.as_ref() {
|
|
|
|
|
|
dependencies.insert(name.clone());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ASTNode::MethodCall { object, .. } => {
|
|
|
|
|
|
// Config.getDebug() のような呼び出しを検出
|
|
|
|
|
|
if let ASTNode::Variable { name, .. } = object.as_ref() {
|
|
|
|
|
|
dependencies.insert(name.clone());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ASTNode::Assignment { target, value, .. } => {
|
|
|
|
|
|
self.extract_dependencies_from_ast(target, dependencies);
|
|
|
|
|
|
self.extract_dependencies_from_ast(value, dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
ASTNode::BinaryOp { left, right, .. } => {
|
|
|
|
|
|
self.extract_dependencies_from_ast(left, dependencies);
|
|
|
|
|
|
self.extract_dependencies_from_ast(right, dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
ASTNode::UnaryOp { operand, .. } => {
|
|
|
|
|
|
self.extract_dependencies_from_ast(operand, dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
ASTNode::If { condition, then_body, else_body, .. } => {
|
|
|
|
|
|
self.extract_dependencies_from_ast(condition, dependencies);
|
|
|
|
|
|
for stmt in then_body {
|
|
|
|
|
|
self.extract_dependencies_from_ast(stmt, dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(else_stmts) = else_body {
|
|
|
|
|
|
for stmt in else_stmts {
|
|
|
|
|
|
self.extract_dependencies_from_ast(stmt, dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ASTNode::Loop { condition, body, .. } => {
|
|
|
|
|
|
self.extract_dependencies_from_ast(condition, dependencies);
|
|
|
|
|
|
for stmt in body {
|
|
|
|
|
|
self.extract_dependencies_from_ast(stmt, dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ASTNode::Return { value, .. } => {
|
|
|
|
|
|
if let Some(val) = value {
|
|
|
|
|
|
self.extract_dependencies_from_ast(val, dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ASTNode::Print { expression, .. } => {
|
|
|
|
|
|
self.extract_dependencies_from_ast(expression, dependencies);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 他のAST nodeタイプも必要に応じて追加
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 循環依存検出(深さ優先探索)
|
|
|
|
|
|
fn check_circular_dependencies(&self) -> Result<(), ParseError> {
|
|
|
|
|
|
let mut visited = std::collections::HashSet::new();
|
|
|
|
|
|
let mut rec_stack = std::collections::HashSet::new();
|
|
|
|
|
|
let mut path = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
for box_name in self.static_box_dependencies.keys() {
|
|
|
|
|
|
if !visited.contains(box_name) {
|
|
|
|
|
|
if self.has_cycle_dfs(box_name, &mut visited, &mut rec_stack, &mut path)? {
|
|
|
|
|
|
return Ok(()); // エラーは既にhas_cycle_dfs内で返される
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// DFS による循環依存検出
|
|
|
|
|
|
fn has_cycle_dfs(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
current: &str,
|
|
|
|
|
|
visited: &mut std::collections::HashSet<String>,
|
|
|
|
|
|
rec_stack: &mut std::collections::HashSet<String>,
|
|
|
|
|
|
path: &mut Vec<String>,
|
|
|
|
|
|
) -> Result<bool, ParseError> {
|
|
|
|
|
|
visited.insert(current.to_string());
|
|
|
|
|
|
rec_stack.insert(current.to_string());
|
|
|
|
|
|
path.push(current.to_string());
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(dependencies) = self.static_box_dependencies.get(current) {
|
|
|
|
|
|
for dependency in dependencies {
|
|
|
|
|
|
if !visited.contains(dependency) {
|
|
|
|
|
|
if self.has_cycle_dfs(dependency, visited, rec_stack, path)? {
|
|
|
|
|
|
return Ok(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if rec_stack.contains(dependency) {
|
|
|
|
|
|
// 循環依存を発見!
|
|
|
|
|
|
let cycle_start_pos = path.iter().position(|x| x == dependency).unwrap_or(0);
|
|
|
|
|
|
let cycle_path: Vec<String> = path[cycle_start_pos..].iter().cloned().collect();
|
|
|
|
|
|
let cycle_display = format!("{} -> {}", cycle_path.join(" -> "), dependency);
|
|
|
|
|
|
|
|
|
|
|
|
return Err(ParseError::CircularDependency {
|
|
|
|
|
|
cycle: cycle_display
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rec_stack.remove(current);
|
|
|
|
|
|
path.pop();
|
|
|
|
|
|
Ok(false)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-11 10:14:47 +09:00
|
|
|
|
/// 🔍 デリゲーションメソッドチェック:親Boxに存在しないメソッドのoverride検出
|
|
|
|
|
|
/// Phase 1: 基本的なoverride構文チェック
|
|
|
|
|
|
/// Phase 2 (将来実装): 完全な親Box参照によるメソッド存在チェック
|
|
|
|
|
|
fn validate_override_methods(&self, child_name: &str, parent_name: &str, methods: &HashMap<String, ASTNode>) -> Result<(), ParseError> {
|
|
|
|
|
|
let mut override_count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 🚨 override付きメソッドのチェック
|
|
|
|
|
|
for (method_name, method_node) in methods {
|
|
|
|
|
|
if let ASTNode::FunctionDeclaration { is_override, .. } = method_node {
|
|
|
|
|
|
if *is_override {
|
|
|
|
|
|
override_count += 1;
|
|
|
|
|
|
eprintln!("🔍 DEBUG: Found override method '{}' in '{}' extending '{}'",
|
|
|
|
|
|
method_name, child_name, parent_name);
|
|
|
|
|
|
|
|
|
|
|
|
// Phase 1: 基本的な危険パターンチェック
|
|
|
|
|
|
// 明らかに存在しないであろうメソッド名をチェック
|
|
|
|
|
|
let suspicious_methods = [
|
|
|
|
|
|
"nonExistentMethod", "invalidMethod", "fakeMethod",
|
|
|
|
|
|
"notRealMethod", "testFailureMethod"
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
if suspicious_methods.contains(&method_name.as_str()) {
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: TokenType::OVERRIDE,
|
|
|
|
|
|
expected: format!("🚨 OVERRIDE ERROR: Method '{}' appears to be invalid. Check if this method exists in parent '{}'.", method_name, parent_name),
|
|
|
|
|
|
line: 0,
|
|
|
|
|
|
});
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
2025-08-11 10:14:47 +09:00
|
|
|
|
|
|
|
|
|
|
// 🎯 基本的なメソッド名バリデーション
|
|
|
|
|
|
if method_name.is_empty() {
|
|
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
|
|
found: TokenType::OVERRIDE,
|
|
|
|
|
|
expected: "🚨 OVERRIDE ERROR: Method name cannot be empty.".to_string(),
|
|
|
|
|
|
line: 0,
|
|
|
|
|
|
});
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-11 07:55:41 +09:00
|
|
|
|
|
2025-08-11 10:14:47 +09:00
|
|
|
|
// ✅ チェック完了レポート
|
|
|
|
|
|
if override_count > 0 {
|
|
|
|
|
|
eprintln!("✅ DEBUG: Override validation completed for '{}' extending '{}' - {} override method(s) found",
|
|
|
|
|
|
child_name, parent_name, override_count);
|
2025-08-11 07:55:41 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-11 10:14:47 +09:00
|
|
|
|
Ok(())
|
2025-08-11 07:55:41 +09:00
|
|
|
|
}
|
2025-08-11 10:14:47 +09:00
|
|
|
|
}
|
|
|
|
|
|
|