## 主な成果 - Nyashスクリプトでプラグイン作成可能という革命的発見 - C ABI制約の分析と埋め込みVMによる解決策 - MIR/VM/JIT層での箱引数サポートの詳細分析 ## ドキュメント作成 - Phase 12基本構想(README.md) - Gemini/Codex先生の技術分析 - C ABIとの整合性問題と解決策 - 埋め込みVM実装ロードマップ - 箱引数サポートの技術詳細 ## 重要な洞察 - 制約は「リンク時にC ABI必要」のみ - 埋め込みVMでMIRバイトコード実行により解決可能 - Nyashスクリプト→C ABIプラグイン変換が実現可能 Everything is Box → Everything is Plugin → Everything is Possible!
563 lines
21 KiB
Rust
563 lines
21 KiB
Rust
/*!
|
||
* 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::INCLUDE => {
|
||
// Allow include as an expression: include "path"
|
||
self.parse_include()
|
||
}
|
||
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(),
|
||
})
|
||
}
|
||
}
|