🎉 initial commit: Nyash Programming Language完成版
🚀 主要機能: • Everything is Box哲学による革新的アーキテクチャ • WebAssemblyブラウザー対応プレイグラウンド • アーティスト協同制作デモ - 複数Boxインスタンス実証 • 視覚的デバッグシステム - DebugBox完全統合 • static box Mainパターン - メモリ安全設計 ⚡ 言語機能: • NOT/AND/OR/除算演算子完全実装 • ジェネリクス/テンプレートシステム • 非同期処理(nowait/await) • try/catchエラーハンドリング • Canvas統合グラフィックス 🎨 ブラウザー体験: • 9種類のインタラクティブデモ • リアルタイムコード実行 • WebCanvas/WebConsole/WebDisplay • モバイル対応完了 🤖 Built with Claude Code collaboration Ready for public release!
This commit is contained in:
414
src/parser/expressions.rs
Normal file
414
src/parser/expressions.rs
Normal file
@ -0,0 +1,414 @@
|
||||
/*!
|
||||
* Nyash Parser - Expression Parsing Module
|
||||
*
|
||||
* 式(Expression)の解析を担当するモジュール
|
||||
* 演算子の優先順位に従った再帰下降パーサー実装
|
||||
*/
|
||||
|
||||
use crate::tokenizer::TokenType;
|
||||
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, UnaryOperator, Span};
|
||||
use super::{NyashParser, ParseError};
|
||||
|
||||
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) {
|
||||
let operator = match &self.current_token().token_type {
|
||||
TokenType::MULTIPLY => BinaryOperator::Multiply,
|
||||
TokenType::DIVIDE => BinaryOperator::Divide,
|
||||
_ => 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();
|
||||
|
||||
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
||||
arguments.push(self.parse_expression()?);
|
||||
if self.match_token(&TokenType::COMMA) {
|
||||
self.advance();
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
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();
|
||||
Ok(ASTNode::Literal {
|
||||
value: LiteralValue::String(value),
|
||||
span: Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
TokenType::NUMBER(n) => {
|
||||
let value = *n;
|
||||
self.advance();
|
||||
Ok(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(value),
|
||||
span: Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
TokenType::FLOAT(f) => {
|
||||
let value = *f;
|
||||
self.advance();
|
||||
Ok(ASTNode::Literal {
|
||||
value: LiteralValue::Float(value),
|
||||
span: Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
TokenType::TRUE => {
|
||||
self.advance();
|
||||
Ok(ASTNode::Literal {
|
||||
value: LiteralValue::Bool(true),
|
||||
span: Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
TokenType::FALSE => {
|
||||
self.advance();
|
||||
Ok(ASTNode::Literal {
|
||||
value: LiteralValue::Bool(false),
|
||||
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() {
|
||||
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::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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user