Files
hakorune/src/parser/expressions.rs
Moe Charm fa1a3ad644 feat(Phase 9.75j): Complete warning elimination - 106→0 warnings (100% improvement)
 Major code quality improvements:
• Fixed all unused variable and parameter warnings
• Added appropriate #[allow(dead_code)] annotations
• Renamed constants to follow Rust naming conventions
• Achieved completely warning-free codebase

🔧 Key changes:
• Parser expressions: Fixed arg_count and statement_count usage
• MIR modules: Added dead_code allows for future-use code
• Backend modules: Prefixed unused parameters with underscore
• Effect constants: Renamed 'read' to 'READ_ALIAS' for conventions

📊 Results:
• Before: 106 warnings (noisy build output)
• After: 0 warnings (clean build)
• Improvement: 100% warning reduction

🎯 This continues the bug fixing initiative "つづきのしゅうせいおねがいにゃ!"
from Phase 9.75i (birth() fixes, static methods, Copilot apps).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-16 17:39:04 +09:00

558 lines
21 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.

/*!
* Nyash Parser - Expression Parsing Module
*
*Expressionの解析を担当するモジュール
* 演算子の優先順位に従った再帰下降パーサー実装
*/
use crate::tokenizer::TokenType;
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, UnaryOperator, Span};
use super::{NyashParser, ParseError};
use super::common::ParserUtils;
// Debug macros are now imported from the parent module via #[macro_export]
use crate::must_advance;
impl NyashParser {
/// 式をパース (演算子優先順位あり)
pub(super) fn parse_expression(&mut self) -> Result<ASTNode, ParseError> {
self.parse_or()
}
/// OR演算子をパース: ||
fn parse_or(&mut self) -> Result<ASTNode, ParseError> {
let mut expr = self.parse_and()?;
while self.match_token(&TokenType::OR) {
let operator = BinaryOperator::Or;
self.advance();
let right = self.parse_and()?;
expr = ASTNode::BinaryOp {
operator,
left: Box::new(expr),
right: Box::new(right),
span: Span::unknown(),
};
}
Ok(expr)
}
/// AND演算子をパース: &&
fn parse_and(&mut self) -> Result<ASTNode, ParseError> {
let mut expr = self.parse_equality()?;
while self.match_token(&TokenType::AND) {
let operator = BinaryOperator::And;
self.advance();
let right = self.parse_equality()?;
expr = ASTNode::BinaryOp {
operator,
left: Box::new(expr),
right: Box::new(right),
span: Span::unknown(),
};
}
Ok(expr)
}
/// 等値演算子をパース: == !=
fn parse_equality(&mut self) -> Result<ASTNode, ParseError> {
let mut expr = self.parse_comparison()?;
while self.match_token(&TokenType::EQUALS) || self.match_token(&TokenType::NotEquals) {
let operator = match &self.current_token().token_type {
TokenType::EQUALS => BinaryOperator::Equal,
TokenType::NotEquals => BinaryOperator::NotEqual,
_ => unreachable!(),
};
self.advance();
let right = self.parse_comparison()?;
expr = ASTNode::BinaryOp {
operator,
left: Box::new(expr),
right: Box::new(right),
span: Span::unknown(),
};
}
Ok(expr)
}
/// 比較演算子をパース: < <= > >=
fn parse_comparison(&mut self) -> Result<ASTNode, ParseError> {
let mut expr = self.parse_term()?;
while self.match_token(&TokenType::LESS) ||
self.match_token(&TokenType::LessEquals) ||
self.match_token(&TokenType::GREATER) ||
self.match_token(&TokenType::GreaterEquals) {
let operator = match &self.current_token().token_type {
TokenType::LESS => BinaryOperator::Less,
TokenType::LessEquals => BinaryOperator::LessEqual,
TokenType::GREATER => BinaryOperator::Greater,
TokenType::GreaterEquals => BinaryOperator::GreaterEqual,
_ => unreachable!(),
};
self.advance();
let right = self.parse_term()?;
expr = ASTNode::BinaryOp {
operator,
left: Box::new(expr),
right: Box::new(right),
span: Span::unknown(),
};
}
Ok(expr)
}
/// 項をパース: + - >>
fn parse_term(&mut self) -> Result<ASTNode, ParseError> {
let mut expr = self.parse_factor()?;
while self.match_token(&TokenType::PLUS) || self.match_token(&TokenType::MINUS) || self.match_token(&TokenType::ARROW) {
if self.match_token(&TokenType::ARROW) {
// >> Arrow演算子
self.advance();
let right = self.parse_factor()?;
expr = ASTNode::Arrow {
sender: Box::new(expr),
receiver: Box::new(right),
span: Span::unknown(),
};
} else {
let operator = match &self.current_token().token_type {
TokenType::PLUS => BinaryOperator::Add,
TokenType::MINUS => BinaryOperator::Subtract,
_ => unreachable!(),
};
self.advance();
let right = self.parse_factor()?;
expr = ASTNode::BinaryOp {
operator,
left: Box::new(expr),
right: Box::new(right),
span: Span::unknown(),
};
}
}
Ok(expr)
}
/// 因子をパース: * /
fn parse_factor(&mut self) -> Result<ASTNode, ParseError> {
let mut expr = self.parse_unary()?;
while self.match_token(&TokenType::MULTIPLY) || self.match_token(&TokenType::DIVIDE) || self.match_token(&TokenType::MODULO) {
let operator = match &self.current_token().token_type {
TokenType::MULTIPLY => BinaryOperator::Multiply,
TokenType::DIVIDE => BinaryOperator::Divide,
TokenType::MODULO => BinaryOperator::Modulo,
_ => unreachable!(),
};
self.advance();
let right = self.parse_unary()?;
expr = ASTNode::BinaryOp {
operator,
left: Box::new(expr),
right: Box::new(right),
span: Span::unknown(),
};
}
Ok(expr)
}
/// 単項演算子をパース
fn parse_unary(&mut self) -> Result<ASTNode, ParseError> {
if self.match_token(&TokenType::MINUS) {
self.advance(); // consume '-'
let operand = self.parse_unary()?; // 再帰的に単項演算をパース
return Ok(ASTNode::UnaryOp {
operator: UnaryOperator::Minus,
operand: Box::new(operand),
span: Span::unknown(),
});
}
if self.match_token(&TokenType::NOT) {
self.advance(); // consume 'not'
let operand = self.parse_unary()?; // 再帰的に単項演算をパース
return Ok(ASTNode::UnaryOp {
operator: UnaryOperator::Not,
operand: Box::new(operand),
span: Span::unknown(),
});
}
if self.match_token(&TokenType::AWAIT) {
self.advance(); // consume 'await'
let expression = self.parse_unary()?; // 再帰的にパース
return Ok(ASTNode::AwaitExpression {
expression: Box::new(expression),
span: Span::unknown(),
});
}
self.parse_call()
}
/// 関数・メソッド呼び出しをパース
fn parse_call(&mut self) -> Result<ASTNode, ParseError> {
let mut expr = self.parse_primary()?;
loop {
if self.match_token(&TokenType::DOT) {
self.advance(); // consume '.'
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) {
// メソッド呼び出し: obj.method(args)
self.advance(); // consume '('
let mut arguments = Vec::new();
let mut _arg_count = 0;
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
must_advance!(self, _unused, "method call argument parsing");
arguments.push(self.parse_expression()?);
_arg_count += 1;
if self.match_token(&TokenType::COMMA) {
self.advance();
// カンマの後の trailing comma をチェック
}
}
self.consume(TokenType::RPAREN)?;
expr = ASTNode::MethodCall {
object: Box::new(expr),
method: method_name,
arguments,
span: Span::unknown(),
};
} else {
// フィールドアクセス: obj.field
expr = ASTNode::FieldAccess {
object: Box::new(expr),
field: method_name,
span: Span::unknown(),
};
}
} else {
let line = self.current_token().line;
return Err(ParseError::UnexpectedToken {
found: self.current_token().token_type.clone(),
expected: "identifier".to_string(),
line,
});
}
} else if self.match_token(&TokenType::LPAREN) {
// 関数呼び出し: function(args)
if let ASTNode::Variable { name, .. } = expr {
self.advance(); // consume '('
let mut arguments = Vec::new();
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
must_advance!(self, _unused, "function call argument parsing");
arguments.push(self.parse_expression()?);
if self.match_token(&TokenType::COMMA) {
self.advance();
}
}
self.consume(TokenType::RPAREN)?;
expr = ASTNode::FunctionCall { name, arguments, span: Span::unknown() };
} else {
break;
}
} else {
break;
}
}
Ok(expr)
}
/// 基本式をパース: リテラル、変数、括弧、this、new
fn parse_primary(&mut self) -> Result<ASTNode, ParseError> {
match &self.current_token().token_type {
TokenType::STRING(s) => {
let value = s.clone();
self.advance();
// 🌟 文字列リテラル自動変換: "text" → new StringBox("text")
Ok(ASTNode::New {
class: "StringBox".to_string(),
arguments: vec![ASTNode::Literal {
value: LiteralValue::String(value),
span: Span::unknown(),
}],
type_arguments: vec![],
span: Span::unknown(),
})
}
TokenType::NUMBER(n) => {
let value = *n;
self.advance();
// 🌟 整数リテラル自動変換: 42 → new IntegerBox(42)
Ok(ASTNode::New {
class: "IntegerBox".to_string(),
arguments: vec![ASTNode::Literal {
value: LiteralValue::Integer(value),
span: Span::unknown(),
}],
type_arguments: vec![],
span: Span::unknown(),
})
}
TokenType::FLOAT(f) => {
let value = *f;
self.advance();
// 🌟 浮動小数点リテラル自動変換: 3.14 → new FloatBox(3.14)
Ok(ASTNode::New {
class: "FloatBox".to_string(),
arguments: vec![ASTNode::Literal {
value: LiteralValue::Float(value),
span: Span::unknown(),
}],
type_arguments: vec![],
span: Span::unknown(),
})
}
TokenType::TRUE => {
self.advance();
// 🌟 真偽値リテラル自動変換: true → new BoolBox(true)
Ok(ASTNode::New {
class: "BoolBox".to_string(),
arguments: vec![ASTNode::Literal {
value: LiteralValue::Bool(true),
span: Span::unknown(),
}],
type_arguments: vec![],
span: Span::unknown(),
})
}
TokenType::FALSE => {
self.advance();
// 🌟 真偽値リテラル自動変換: false → new BoolBox(false)
Ok(ASTNode::New {
class: "BoolBox".to_string(),
arguments: vec![ASTNode::Literal {
value: LiteralValue::Bool(false),
span: Span::unknown(),
}],
type_arguments: vec![],
span: Span::unknown(),
})
}
TokenType::NULL => {
self.advance();
Ok(ASTNode::Literal {
value: LiteralValue::Null,
span: Span::unknown(),
})
}
TokenType::THIS => {
self.advance();
Ok(ASTNode::This { span: Span::unknown() })
}
TokenType::ME => {
self.advance();
Ok(ASTNode::Me { span: Span::unknown() })
}
TokenType::NEW => {
self.advance();
if let TokenType::IDENTIFIER(class_name) = &self.current_token().token_type {
let class_name = class_name.clone();
self.advance();
// 🔥 ジェネリクス型引数のパース (<IntegerBox, StringBox>)
let type_arguments = if self.match_token(&TokenType::LESS) {
self.advance(); // consume '<'
let mut args = Vec::new();
loop {
if let TokenType::IDENTIFIER(type_name) = &self.current_token().token_type {
args.push(type_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 argument".to_string(),
line,
});
}
}
self.consume(TokenType::GREATER)?; // consume '>'
args
} else {
Vec::new()
};
self.consume(TokenType::LPAREN)?;
let mut arguments = Vec::new();
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
must_advance!(self, _unused, "new expression argument parsing");
arguments.push(self.parse_expression()?);
if self.match_token(&TokenType::COMMA) {
self.advance();
}
}
self.consume(TokenType::RPAREN)?;
Ok(ASTNode::New {
class: class_name,
arguments,
type_arguments,
span: Span::unknown(),
})
} else {
let line = self.current_token().line;
Err(ParseError::UnexpectedToken {
found: self.current_token().token_type.clone(),
expected: "class name".to_string(),
line,
})
}
}
TokenType::FROM => {
// from構文をパース: from Parent.method(arguments)
self.parse_from_call()
}
TokenType::IDENTIFIER(name) => {
let name = name.clone();
self.advance();
Ok(ASTNode::Variable { name, span: Span::unknown() })
}
TokenType::LPAREN => {
self.advance(); // consume '('
let expr = self.parse_expression()?;
self.consume(TokenType::RPAREN)?;
Ok(expr)
}
_ => {
let line = self.current_token().line;
Err(ParseError::InvalidExpression { line })
}
}
}
/// from構文をパース: from Parent.method(arguments)
pub(super) fn parse_from_call(&mut self) -> Result<ASTNode, ParseError> {
self.advance(); // consume 'from'
// Parent名を取得
let parent = 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: "parent class name".to_string(),
line,
});
};
// DOT とmethod名は任意pack透明化対応
let method = if self.match_token(&TokenType::DOT) {
// DOTがある場合: from Parent.method() 形式
self.advance(); // consume DOT
// method名を取得 (IDENTIFIERまたはINITを受け入れ)
match &self.current_token().token_type {
TokenType::IDENTIFIER(name) => {
let name = name.clone();
self.advance();
name
}
TokenType::INIT => {
self.advance();
"init".to_string()
}
TokenType::PACK => {
self.advance();
"pack".to_string()
}
TokenType::BIRTH => {
self.advance();
"birth".to_string()
}
_ => {
let line = self.current_token().line;
return Err(ParseError::UnexpectedToken {
found: self.current_token().token_type.clone(),
expected: "method name".to_string(),
line,
});
}
}
} else {
// DOTがない場合: from Parent() 形式 - 透明化システム廃止
// Phase 8.9: 明示的birth()構文を強制
let line = self.current_token().line;
return Err(ParseError::TransparencySystemRemoved {
suggestion: format!("Use 'from {}.birth()' instead of 'from {}()'", parent, parent),
line,
});
};
// 引数リストをパース
self.consume(TokenType::LPAREN)?;
let mut arguments = Vec::new();
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
must_advance!(self, _unused, "from call argument parsing");
arguments.push(self.parse_expression()?);
if self.match_token(&TokenType::COMMA) {
self.advance();
// カンマの後の trailing comma をチェック
}
}
self.consume(TokenType::RPAREN)?;
Ok(ASTNode::FromCall {
parent,
method,
arguments,
span: Span::unknown(),
})
}
}