2025-08-16 11:35:57 +09:00
|
|
|
|
/*!
|
|
|
|
|
|
* Parser Common Utilities
|
2025-09-17 07:43:07 +09:00
|
|
|
|
*
|
2025-08-16 11:35:57 +09:00
|
|
|
|
* パーサーモジュール間で共有されるヘルパー関数や型定義
|
|
|
|
|
|
* Extracted from parser/mod.rs as part of modularization
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
use super::ParseError;
|
2025-09-17 07:43:07 +09:00
|
|
|
|
use crate::ast::Span;
|
|
|
|
|
|
use crate::tokenizer::{Token, TokenType};
|
2025-08-16 11:35:57 +09:00
|
|
|
|
|
|
|
|
|
|
/// Parser utility methods
|
|
|
|
|
|
pub trait ParserUtils {
|
|
|
|
|
|
fn tokens(&self) -> &Vec<Token>;
|
|
|
|
|
|
fn current(&self) -> usize;
|
|
|
|
|
|
fn current_mut(&mut self) -> &mut usize;
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// 現在のトークンを取得
|
|
|
|
|
|
fn current_token(&self) -> &Token {
|
|
|
|
|
|
self.tokens().get(self.current()).unwrap_or(&Token {
|
|
|
|
|
|
token_type: TokenType::EOF,
|
|
|
|
|
|
line: 0,
|
|
|
|
|
|
column: 0,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +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-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// N個先のトークンを先読み
|
2025-08-16 17:39:04 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-08-16 11:35:57 +09:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// 位置を1つ進める
|
|
|
|
|
|
fn advance(&mut self) {
|
|
|
|
|
|
if !self.is_at_end() {
|
|
|
|
|
|
*self.current_mut() += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// NEWLINEトークンをスキップ
|
|
|
|
|
|
fn skip_newlines(&mut self) {
|
2025-09-21 08:53:00 +09:00
|
|
|
|
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.advance();
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2025-08-16 11:35:57 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// 指定されたトークンタイプを消費 (期待通りでなければエラー)
|
|
|
|
|
|
fn consume(&mut self, expected: TokenType) -> Result<Token, ParseError> {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
if std::mem::discriminant(&self.current_token().token_type)
|
|
|
|
|
|
== std::mem::discriminant(&expected)
|
|
|
|
|
|
{
|
2025-08-16 11:35:57 +09:00
|
|
|
|
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,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// 現在のトークンが指定されたタイプかチェック
|
|
|
|
|
|
fn match_token(&self, token_type: &TokenType) -> bool {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
std::mem::discriminant(&self.current_token().token_type)
|
|
|
|
|
|
== std::mem::discriminant(token_type)
|
2025-08-16 11:35:57 +09:00
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// 複数のトークンタイプのいずれかにマッチするかチェック
|
2025-08-16 17:39:04 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-08-16 11:35:57 +09:00
|
|
|
|
fn match_any_token(&self, token_types: &[TokenType]) -> bool {
|
|
|
|
|
|
let current_discriminant = std::mem::discriminant(&self.current_token().token_type);
|
2025-09-17 07:43:07 +09:00
|
|
|
|
token_types
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.any(|tt| std::mem::discriminant(tt) == current_discriminant)
|
2025-08-16 11:35:57 +09:00
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// 終端に達したかチェック
|
|
|
|
|
|
fn is_at_end(&self) -> bool {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.current() >= self.tokens().len()
|
|
|
|
|
|
|| matches!(self.current_token().token_type, TokenType::EOF)
|
2025-08-16 11:35:57 +09:00
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// 現在のトークンが行の終わり(NEWLINE or EOF)かチェック
|
2025-08-16 17:39:04 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-08-16 11:35:57 +09:00
|
|
|
|
fn is_line_end(&self) -> bool {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
matches!(
|
|
|
|
|
|
self.current_token().token_type,
|
|
|
|
|
|
TokenType::NEWLINE | TokenType::EOF
|
|
|
|
|
|
)
|
2025-08-16 11:35:57 +09:00
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// エラー報告用の現在位置情報を取得
|
2025-08-16 17:39:04 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-08-16 11:35:57 +09:00
|
|
|
|
fn current_position(&self) -> (usize, usize) {
|
|
|
|
|
|
let token = self.current_token();
|
|
|
|
|
|
(token.line, token.column)
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-16 11:35:57 +09:00
|
|
|
|
/// 現在のトークンからSpanを作成
|
2025-08-16 17:39:04 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-08-16 11:35:57 +09:00
|
|
|
|
fn current_span(&self) -> Span {
|
|
|
|
|
|
let token = self.current_token();
|
|
|
|
|
|
Span {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
start: 0, // Token doesn't have byte offset, so using 0
|
2025-08-16 11:35:57 +09:00
|
|
|
|
end: 0,
|
|
|
|
|
|
line: token.line,
|
|
|
|
|
|
column: token.column,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Helper function to create unknown span
|
2025-08-16 17:39:04 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-08-16 11:35:57 +09:00
|
|
|
|
pub fn unknown_span() -> Span {
|
|
|
|
|
|
Span::unknown()
|
2025-09-17 07:43:07 +09:00
|
|
|
|
}
|