Files
hakorune/src/parser/common.rs
Selfhosting Dev 2f306dd6a5 feat: 大規模リファクタリング - SRP原則に基づくモジュール分割
## MIR builder_calls.rs リファクタリング
- 879行 → 629行 (28%削減) + 7専門モジュール
- calls/ ディレクトリに機能別分割:
  - call_target.rs: CallTarget型定義
  - method_resolution.rs: メソッド解決ロジック
  - extern_calls.rs: 外部呼び出し処理
  - special_handlers.rs: 特殊ハンドラー
  - function_lowering.rs: 関数変換ユーティリティ
  - call_unified.rs: 統一Call実装
  - mod.rs: モジュール統合

## Parser statements.rs リファクタリング
- 723行 → 8専門モジュール
- statements/ ディレクトリに機能別分割:
  - control_flow.rs: if/loop/break/continue/return
  - declarations.rs: 宣言系ディスパッチャー
  - exceptions.rs: try/throw/catch/cleanup
  - helpers.rs: ヘルパー関数
  - io_async.rs: print/nowait
  - modules.rs: import/using/from
  - variables.rs: local/outbox/assignments
  - mod.rs: 統合モジュール

## 効果
 単一責任原則(SRP)の達成
 保守性・再利用性の向上
 ChatGPT5 Pro設計の型安全Call解決システム実装
 スモークテスト通過確認済み

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-25 09:01:55 +09:00

163 lines
5.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Parser Common Utilities
*
* パーサーモジュール間で共有されるヘルパー関数や型定義
* Extracted from parser/mod.rs as part of modularization
*/
use super::ParseError;
use crate::ast::Span;
use crate::tokenizer::{Token, TokenType};
/// Parser utility methods
pub trait ParserUtils {
fn tokens(&self) -> &Vec<Token>;
fn current(&self) -> usize;
fn current_mut(&mut self) -> &mut usize;
/// 現在のトークンを取得
fn current_token(&self) -> &Token {
self.tokens().get(self.current()).unwrap_or(&Token {
token_type: TokenType::EOF,
line: 0,
column: 0,
})
}
/// 次のトークンを先読み(位置を進めない)
fn peek_token(&self) -> &TokenType {
if self.current() + 1 < self.tokens().len() {
&self.tokens()[self.current() + 1].token_type
} else {
&TokenType::EOF
}
}
/// N個先のトークンを先読み
#[allow(dead_code)]
fn peek_nth_token(&self, n: usize) -> &TokenType {
if self.current() + n < self.tokens().len() {
&self.tokens()[self.current() + n].token_type
} else {
&TokenType::EOF
}
}
/// 位置を1つ進める改行スキップCursor無効時のみ最小限
fn advance(&mut self) {
if !self.is_at_end() {
// 現在のトークンで深度を更新(進める前)
self.update_depth_before_advance();
*self.current_mut() += 1;
// 新しいトークンで深度を更新(進めた後)
self.update_depth_after_advance();
// 改行スキップは Cursor 無効時のみ最小限で行う(互換用)。
// 環境変数 NYASH_PARSER_TOKEN_CURSOR=1 の場合は Cursor 側で一元管理する。
let cursor_on = std::env::var("NYASH_PARSER_TOKEN_CURSOR").ok().as_deref() == Some("1");
if !cursor_on {
let allow_sc = std::env::var("NYASH_PARSER_ALLOW_SEMICOLON").ok().map(|v| {
let lv = v.to_ascii_lowercase();
lv == "1" || lv == "true" || lv == "on"
}).unwrap_or(false);
loop {
let is_nl = matches!(self.current_token().token_type, TokenType::NEWLINE);
let is_sc = allow_sc && matches!(self.current_token().token_type, TokenType::SEMICOLON);
if (is_nl || is_sc) && !self.is_at_end() {
*self.current_mut() += 1; // 非再帰的に前進
continue;
}
break;
}
}
}
}
/// advance前の深度更新閉じ括弧の処理
fn update_depth_before_advance(&mut self) {
// デフォルト実装は何もしないNyashParserでオーバーライド
}
/// advance後の深度更新開き括弧の処理
fn update_depth_after_advance(&mut self) {
// デフォルト実装は何もしないNyashParserでオーバーライド
}
// 旧来の should_auto_skip_newlines / skip_newlines 系は撤去Cursor に集約)
/// 指定されたトークンタイプを消費 (期待通りでなければエラー)
fn consume(&mut self, expected: TokenType) -> Result<Token, ParseError> {
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)
}
/// 複数のトークンタイプのいずれかにマッチするかチェック
#[allow(dead_code)]
fn match_any_token(&self, token_types: &[TokenType]) -> bool {
let current_discriminant = std::mem::discriminant(&self.current_token().token_type);
token_types
.iter()
.any(|tt| std::mem::discriminant(tt) == current_discriminant)
}
/// 終端に達したかチェック
fn is_at_end(&self) -> bool {
self.current() >= self.tokens().len()
|| matches!(self.current_token().token_type, TokenType::EOF)
}
/// 現在のトークンが行の終わりNEWLINE or EOFかチェック
#[allow(dead_code)]
fn is_line_end(&self) -> bool {
matches!(
self.current_token().token_type,
TokenType::NEWLINE | TokenType::EOF
)
}
/// エラー報告用の現在位置情報を取得
#[allow(dead_code)]
fn current_position(&self) -> (usize, usize) {
let token = self.current_token();
(token.line, token.column)
}
/// 現在のトークンからSpanを作成
#[allow(dead_code)]
fn current_span(&self) -> Span {
let token = self.current_token();
Span {
start: 0, // Token doesn't have byte offset, so using 0
end: 0,
line: token.line,
column: token.column,
}
}
}
/// Helper function to create unknown span
#[allow(dead_code)]
pub fn unknown_span() -> Span {
Span::unknown()
}