refactor(parser): Step 3 - Extract declarations module
- Create declarations module with box_definition, static_box, dependency_helpers - Move parse_box_declaration, parse_interface_box_declaration from mod.rs - Move parse_static_box and dependency checking logic - Temporarily restore parse_global_var, parse_function_declaration, parse_static_declaration to mod.rs - Fix visibility issues (pub vs pub(super)) - Fix TokenType::IMPLEMENTS not defined issue - Fix Loop AST node condition type mismatch - Build passes successfully Next: Step 4 - Extract items module for global_vars, functions, static_items
This commit is contained in:
628
src/parser/declarations/box_definition.rs
Normal file
628
src/parser/declarations/box_definition.rs
Normal file
@ -0,0 +1,628 @@
|
||||
/*!
|
||||
* Box Definition Parser Module
|
||||
*
|
||||
* Box宣言(box, interface box, static box)の解析を担当
|
||||
* Nyashの中核概念「Everything is Box」を実現する重要モジュール
|
||||
*/
|
||||
|
||||
use crate::tokenizer::TokenType;
|
||||
use crate::ast::{ASTNode, Span};
|
||||
use crate::parser::{NyashParser, ParseError};
|
||||
use crate::parser::common::ParserUtils;
|
||||
use crate::{must_advance, debug_fuel};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
impl NyashParser {
|
||||
/// box宣言をパース: box Name { fields... methods... }
|
||||
pub 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();
|
||||
|
||||
while !self.match_token(&TokenType::GREATER) && !self.is_at_end() {
|
||||
must_advance!(self, _unused, "generic type 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.skip_newlines();
|
||||
}
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
found: self.current_token().token_type.clone(),
|
||||
expected: "type parameter name".to_string(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.consume(TokenType::GREATER)?; // consume '>'
|
||||
params
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
// 🚀 Multi-delegation support: "from Parent1, Parent2, ..."
|
||||
let extends = if self.match_token(&TokenType::FROM) {
|
||||
self.advance(); // consume 'from'
|
||||
let mut parents = Vec::new();
|
||||
|
||||
// Parse first parent (required)
|
||||
if let TokenType::IDENTIFIER(parent) = &self.current_token().token_type {
|
||||
parents.push(parent.clone());
|
||||
self.advance();
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
found: self.current_token().token_type.clone(),
|
||||
expected: "parent box name after 'from'".to_string(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
|
||||
// Parse additional parents (optional)
|
||||
while self.match_token(&TokenType::COMMA) {
|
||||
self.advance(); // consume ','
|
||||
self.skip_newlines();
|
||||
|
||||
if let TokenType::IDENTIFIER(parent) = &self.current_token().token_type {
|
||||
parents.push(parent.clone());
|
||||
self.advance();
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
found: self.current_token().token_type.clone(),
|
||||
expected: "parent box name after comma".to_string(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
parents
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
// implementsキーワードのチェック
|
||||
// TODO: TokenType::IMPLEMENTS is not defined in current version
|
||||
let implements = if false { // self.match_token(&TokenType::IMPLEMENTS) {
|
||||
self.advance(); // consume 'implements'
|
||||
let mut interfaces = Vec::new();
|
||||
|
||||
loop {
|
||||
must_advance!(self, _unused, "interface implementation parsing");
|
||||
|
||||
if let TokenType::IDENTIFIER(interface) = &self.current_token().token_type {
|
||||
interfaces.push(interface.clone());
|
||||
self.advance();
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
found: self.current_token().token_type.clone(),
|
||||
expected: "interface name".to_string(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
|
||||
if self.match_token(&TokenType::COMMA) {
|
||||
self.advance();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
interfaces
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
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();
|
||||
let mut weak_fields = Vec::new(); // 🔗 Track weak fields
|
||||
|
||||
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
||||
self.skip_newlines(); // ループ開始時に改行をスキップ
|
||||
|
||||
// RBRACEに到達していればループを抜ける
|
||||
if self.match_token(&TokenType::RBRACE) {
|
||||
break;
|
||||
}
|
||||
|
||||
// initブロックの処理(initメソッドではない場合のみ)
|
||||
if self.match_token(&TokenType::INIT) && self.peek_token() != &TokenType::LPAREN {
|
||||
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;
|
||||
}
|
||||
|
||||
// Check for weak modifier
|
||||
let is_weak = if self.match_token(&TokenType::WEAK) {
|
||||
self.advance(); // consume 'weak'
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if let TokenType::IDENTIFIER(field_name) = &self.current_token().token_type {
|
||||
init_fields.push(field_name.clone());
|
||||
if is_weak {
|
||||
weak_fields.push(field_name.clone()); // 🔗 Add to weak fields list
|
||||
}
|
||||
self.advance();
|
||||
|
||||
// カンマがあればスキップ
|
||||
if self.match_token(&TokenType::COMMA) {
|
||||
self.advance();
|
||||
}
|
||||
} else {
|
||||
// 不正なトークンがある場合はエラー
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: if is_weak { "field name after 'weak'" } else { "field name" }.to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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() {
|
||||
must_advance!(self, _unused, "constructor body parsing");
|
||||
|
||||
self.skip_newlines();
|
||||
if self.match_token(&TokenType::RBRACE) {
|
||||
break;
|
||||
}
|
||||
body.push(self.parse_statement()?);
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
|
||||
let constructor = ASTNode::FunctionDeclaration {
|
||||
name: field_or_method.clone(),
|
||||
params,
|
||||
body,
|
||||
is_static: false,
|
||||
is_override: false, // コンストラクタは常に非オーバーライド
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
constructors.insert(field_or_method, constructor);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// packキーワードの処理(ビルトインBox継承用)
|
||||
if self.match_token(&TokenType::PACK) && self.peek_token() == &TokenType::LPAREN {
|
||||
let field_or_method = "pack".to_string();
|
||||
self.advance(); // consume 'pack'
|
||||
|
||||
// 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,
|
||||
});
|
||||
}
|
||||
// packコンストラクタの処理
|
||||
self.advance(); // consume '('
|
||||
|
||||
let mut params = Vec::new();
|
||||
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
||||
must_advance!(self, _unused, "pack 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() {
|
||||
must_advance!(self, _unused, "pack body parsing");
|
||||
|
||||
self.skip_newlines();
|
||||
if self.match_token(&TokenType::RBRACE) {
|
||||
break;
|
||||
}
|
||||
body.push(self.parse_statement()?);
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
|
||||
let constructor = ASTNode::FunctionDeclaration {
|
||||
name: field_or_method.clone(),
|
||||
params,
|
||||
body,
|
||||
is_static: false,
|
||||
is_override: false, // packは常に非オーバーライド
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
constructors.insert(field_or_method, constructor);
|
||||
continue;
|
||||
}
|
||||
|
||||
// birthキーワードの処理(生命を与えるコンストラクタ)
|
||||
if self.match_token(&TokenType::BIRTH) && self.peek_token() == &TokenType::LPAREN {
|
||||
let field_or_method = "birth".to_string();
|
||||
self.advance(); // consume 'birth'
|
||||
|
||||
// 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,
|
||||
});
|
||||
}
|
||||
// birthコンストラクタの処理
|
||||
self.advance(); // consume '('
|
||||
|
||||
let mut params = Vec::new();
|
||||
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
||||
must_advance!(self, _unused, "birth 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() {
|
||||
must_advance!(self, _unused, "birth body parsing");
|
||||
|
||||
self.skip_newlines();
|
||||
if self.match_token(&TokenType::RBRACE) {
|
||||
break;
|
||||
}
|
||||
body.push(self.parse_statement()?);
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
|
||||
let constructor = ASTNode::FunctionDeclaration {
|
||||
name: field_or_method.clone(),
|
||||
params,
|
||||
body,
|
||||
is_static: false,
|
||||
is_override: false, // birthは常に非オーバーライド
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
constructors.insert(field_or_method, constructor);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Box名と同じ名前のコンストラクタをチェック
|
||||
if self.match_token(&TokenType::IDENTIFIER(name.clone())) && self.peek_token() == &TokenType::LPAREN {
|
||||
let constructor_name = name.clone();
|
||||
self.advance(); // consume identifier
|
||||
|
||||
// コンストラクタは常にオーバーライド不可
|
||||
if is_override {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "method definition, not constructor after override keyword".to_string(),
|
||||
found: TokenType::IDENTIFIER(constructor_name.clone()),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
// Box名コンストラクタの処理
|
||||
self.advance(); // consume '('
|
||||
|
||||
let mut params = Vec::new();
|
||||
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
||||
must_advance!(self, _unused, "Box 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() {
|
||||
must_advance!(self, _unused, "Box constructor body parsing");
|
||||
|
||||
self.skip_newlines();
|
||||
if self.match_token(&TokenType::RBRACE) {
|
||||
break;
|
||||
}
|
||||
body.push(self.parse_statement()?);
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
|
||||
let constructor = ASTNode::FunctionDeclaration {
|
||||
name: constructor_name.clone(),
|
||||
params,
|
||||
body,
|
||||
is_static: false,
|
||||
is_override: false,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
constructors.insert(constructor_name, constructor);
|
||||
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() {
|
||||
must_advance!(self, _unused, "method 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() {
|
||||
must_advance!(self, _unused, "method body parsing");
|
||||
|
||||
self.skip_newlines();
|
||||
if self.match_token(&TokenType::RBRACE) {
|
||||
break;
|
||||
}
|
||||
body.push(self.parse_statement()?);
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
|
||||
let method = ASTNode::FunctionDeclaration {
|
||||
name: field_or_method.clone(),
|
||||
params,
|
||||
body,
|
||||
is_static: false,
|
||||
is_override,
|
||||
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)?;
|
||||
|
||||
// 🔥 Override validation
|
||||
for parent in &extends {
|
||||
self.validate_override_methods(&name, parent, &methods)?;
|
||||
}
|
||||
|
||||
Ok(ASTNode::BoxDeclaration {
|
||||
name,
|
||||
fields,
|
||||
methods,
|
||||
constructors,
|
||||
init_fields,
|
||||
weak_fields, // 🔗 Add weak fields to AST
|
||||
is_interface: false,
|
||||
extends,
|
||||
implements,
|
||||
type_parameters,
|
||||
is_static: false, // 通常のboxはnon-static
|
||||
static_init: None, // 通常のboxはstatic初期化ブロックなし
|
||||
span: Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
/// interface box宣言をパース: interface box Name { methods... }
|
||||
pub 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, // インターフェースメソッドは通常静的でない
|
||||
is_override: false, // デフォルトは非オーバーライド
|
||||
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ブロックなし
|
||||
weak_fields: vec![], // 🔗 インターフェースにweak fieldsなし
|
||||
is_interface: true, // インターフェースフラグ
|
||||
extends: vec![], // 🚀 Multi-delegation: Changed from None to vec![]
|
||||
implements: vec![],
|
||||
type_parameters: Vec::new(), // 🔥 インターフェースではジェネリクス未対応
|
||||
is_static: false, // インターフェースは非static
|
||||
static_init: None, // インターフェースにstatic initなし
|
||||
span: Span::unknown(),
|
||||
})
|
||||
}
|
||||
}
|
||||
144
src/parser/declarations/dependency_helpers.rs
Normal file
144
src/parser/declarations/dependency_helpers.rs
Normal file
@ -0,0 +1,144 @@
|
||||
/*!
|
||||
* Dependency Analysis Helpers
|
||||
*
|
||||
* Static box依存関係の解析と循環依存検出
|
||||
*/
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::parser::{NyashParser, ParseError};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
impl NyashParser {
|
||||
/// Static初期化ブロック内の文から依存関係を抽出
|
||||
pub(super) fn extract_dependencies_from_statements(&self, statements: &[ASTNode]) -> HashSet<String> {
|
||||
let mut dependencies = HashSet::new();
|
||||
|
||||
for stmt in statements {
|
||||
self.extract_dependencies_from_ast(stmt, &mut dependencies);
|
||||
}
|
||||
|
||||
dependencies
|
||||
}
|
||||
|
||||
/// AST内から静的Box参照を再帰的に検出
|
||||
pub(super) fn extract_dependencies_from_ast(&self, node: &ASTNode, dependencies: &mut 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);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// その他のASTノードは無視
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 循環依存検出
|
||||
pub fn check_circular_dependencies(&self) -> Result<(), ParseError> {
|
||||
// すべてのstatic boxに対して循環検出を実行
|
||||
let all_boxes: Vec<_> = self.static_box_dependencies.keys().cloned().collect();
|
||||
|
||||
for box_name in &all_boxes {
|
||||
let mut visited = HashSet::new();
|
||||
let mut stack = Vec::new();
|
||||
|
||||
if self.has_cycle_dfs(box_name, &mut visited, &mut stack)? {
|
||||
// 循環を文字列化
|
||||
let cycle_str = stack.join(" -> ");
|
||||
return Err(ParseError::CircularDependency { cycle: cycle_str });
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// DFSで循環依存を検出
|
||||
fn has_cycle_dfs(
|
||||
&self,
|
||||
current: &str,
|
||||
visited: &mut HashSet<String>,
|
||||
stack: &mut Vec<String>,
|
||||
) -> Result<bool, ParseError> {
|
||||
// 既にスタックにあれば循環
|
||||
if stack.contains(¤t.to_string()) {
|
||||
stack.push(current.to_string()); // 循環を完成させる
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// 既に訪問済みで循環がなければスキップ
|
||||
if visited.contains(current) {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
visited.insert(current.to_string());
|
||||
stack.push(current.to_string());
|
||||
|
||||
// 依存先をチェック
|
||||
if let Some(dependencies) = self.static_box_dependencies.get(current) {
|
||||
for dep in dependencies {
|
||||
if self.has_cycle_dfs(dep, visited, stack)? {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack.pop();
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Override メソッドの検証
|
||||
pub(super) fn validate_override_methods(&self, child_name: &str, parent_name: &str, methods: &HashMap<String, ASTNode>) -> Result<(), ParseError> {
|
||||
// 現時点では簡単な検証のみ
|
||||
// TODO: 親クラスのメソッドシグネチャとの比較
|
||||
for (method_name, method_ast) in methods {
|
||||
if let ASTNode::FunctionDeclaration { is_override, .. } = method_ast {
|
||||
if *is_override {
|
||||
// 将来的にここで親クラスのメソッドが存在するかチェック
|
||||
eprintln!("🔍 Validating override method '{}' in '{}' from '{}'", method_name, child_name, parent_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
15
src/parser/declarations/mod.rs
Normal file
15
src/parser/declarations/mod.rs
Normal file
@ -0,0 +1,15 @@
|
||||
/*!
|
||||
* Parser Declarations Module
|
||||
*
|
||||
* 宣言(Declaration)の解析を担当するモジュール群
|
||||
* Box定義、関数定義、use文などの宣言を処理
|
||||
*/
|
||||
|
||||
pub mod box_definition;
|
||||
pub mod static_box;
|
||||
pub mod dependency_helpers;
|
||||
|
||||
// Re-export commonly used items
|
||||
pub use box_definition::*;
|
||||
pub use static_box::*;
|
||||
pub use dependency_helpers::*;
|
||||
290
src/parser/declarations/static_box.rs
Normal file
290
src/parser/declarations/static_box.rs
Normal file
@ -0,0 +1,290 @@
|
||||
/*!
|
||||
* Static Box Definition Parser
|
||||
*
|
||||
* static box宣言と関連ヘルパー関数
|
||||
*/
|
||||
|
||||
use crate::tokenizer::TokenType;
|
||||
use crate::ast::{ASTNode, Span};
|
||||
use crate::parser::{NyashParser, ParseError};
|
||||
use crate::parser::common::ParserUtils;
|
||||
use crate::{must_advance, debug_fuel};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
impl NyashParser {
|
||||
/// static box宣言をパース: static box Name { ... }
|
||||
pub 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()
|
||||
};
|
||||
|
||||
// from句のパース(Multi-delegation)- static boxでもデリゲーション可能 🚀
|
||||
let extends = if self.match_token(&TokenType::FROM) {
|
||||
self.advance(); // consume 'from'
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
parent_list
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
// interface句のパース(インターフェース実装)- static boxでも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 constructors = HashMap::new();
|
||||
let mut init_fields = Vec::new();
|
||||
let mut weak_fields = Vec::new(); // 🔗 Track weak fields for static box
|
||||
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;
|
||||
}
|
||||
|
||||
// Check for weak modifier
|
||||
let is_weak = if self.match_token(&TokenType::WEAK) {
|
||||
self.advance(); // consume 'weak'
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if let TokenType::IDENTIFIER(field_name) = &self.current_token().token_type {
|
||||
init_fields.push(field_name.clone());
|
||||
if is_weak {
|
||||
weak_fields.push(field_name.clone()); // 🔗 Add to weak fields list
|
||||
}
|
||||
self.advance();
|
||||
|
||||
// カンマがあればスキップ
|
||||
if self.match_token(&TokenType::COMMA) {
|
||||
self.advance();
|
||||
}
|
||||
} else {
|
||||
// 不正なトークンがある場合はエラー
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: if is_weak { "field name after 'weak'" } else { "field name" }.to_string(),
|
||||
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内のメソッドは通常メソッド
|
||||
is_override: false, // デフォルトは非オーバーライド
|
||||
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,
|
||||
weak_fields, // 🔗 Add weak fields to static box construction
|
||||
is_interface: false,
|
||||
extends,
|
||||
implements,
|
||||
type_parameters,
|
||||
is_static: true, // 🔥 static boxフラグを設定
|
||||
static_init, // 🔥 static初期化ブロック
|
||||
span: Span::unknown(),
|
||||
})
|
||||
}
|
||||
}
|
||||
1121
src/parser/mod.rs
1121
src/parser/mod.rs
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user