grammar: introduce bitwise ops & shifts; retire legacy >> ARROW
- Tokenizer: add tokens for << >> & | ^ (SHIFT_LEFT/RIGHT, BIT_AND/OR/XOR); keep ||, &&, |> - Parser: precedence layers for bit ops (| ^ &) and shift (<< >>); remove >> Arrow production - AST: add BitAnd/BitOr/BitXor/Shr with Display - MIR builder: map bit ops and Shr to MIR BinaryOp - Interpreter: implement integer-only bit ops and shifts, mask shift count to 0..63 Compatibility: legacy >> Arrow removed from parser; use |> for pipeline.
This commit is contained in:
@ -333,7 +333,11 @@ pub enum BinaryOperator {
|
||||
Multiply,
|
||||
Divide,
|
||||
Modulo,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor,
|
||||
Shl, // << shift-left (Phase 1)
|
||||
Shr,
|
||||
Equal,
|
||||
NotEqual,
|
||||
Less,
|
||||
@ -362,7 +366,11 @@ impl fmt::Display for BinaryOperator {
|
||||
BinaryOperator::Multiply => "*",
|
||||
BinaryOperator::Divide => "/",
|
||||
BinaryOperator::Modulo => "%",
|
||||
BinaryOperator::BitAnd => "&",
|
||||
BinaryOperator::BitOr => "|",
|
||||
BinaryOperator::BitXor => "^",
|
||||
BinaryOperator::Shl => "<<",
|
||||
BinaryOperator::Shr => ">>",
|
||||
BinaryOperator::Equal => "==",
|
||||
BinaryOperator::NotEqual => "!=",
|
||||
BinaryOperator::Less => "<",
|
||||
|
||||
@ -329,12 +329,46 @@ impl NyashInterpreter {
|
||||
crate::runtime::semantics::coerce_to_i64(left_val.as_ref()),
|
||||
crate::runtime::semantics::coerce_to_i64(right_val.as_ref()),
|
||||
) {
|
||||
return Ok(Box::new(IntegerBox::new(li.wrapping_shl(ri as u32))));
|
||||
let sh = (ri as u32) & 63;
|
||||
return Ok(Box::new(IntegerBox::new(li.wrapping_shl(sh))));
|
||||
}
|
||||
Err(RuntimeError::TypeError {
|
||||
message: format!("Shift-left '<<' requires integers (got {} and {})", left_val.type_name(), right_val.type_name())
|
||||
})
|
||||
}
|
||||
BinaryOperator::Shr => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
crate::runtime::semantics::coerce_to_i64(left_val.as_ref()),
|
||||
crate::runtime::semantics::coerce_to_i64(right_val.as_ref()),
|
||||
) {
|
||||
let sh = (ri as u32) & 63;
|
||||
return Ok(Box::new(IntegerBox::new(((li as u64) >> sh) as i64)));
|
||||
}
|
||||
Err(RuntimeError::TypeError {
|
||||
message: format!("Shift-right '>>' requires integers (got {} and {})", left_val.type_name(), right_val.type_name())
|
||||
})
|
||||
}
|
||||
BinaryOperator::BitAnd => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
crate::runtime::semantics::coerce_to_i64(left_val.as_ref()),
|
||||
crate::runtime::semantics::coerce_to_i64(right_val.as_ref()),
|
||||
) { return Ok(Box::new(IntegerBox::new(li & ri))); }
|
||||
Err(RuntimeError::TypeError { message: format!("Bitwise '&' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) })
|
||||
}
|
||||
BinaryOperator::BitOr => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
crate::runtime::semantics::coerce_to_i64(left_val.as_ref()),
|
||||
crate::runtime::semantics::coerce_to_i64(right_val.as_ref()),
|
||||
) { return Ok(Box::new(IntegerBox::new(li | ri))); }
|
||||
Err(RuntimeError::TypeError { message: format!("Bitwise '|' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) })
|
||||
}
|
||||
BinaryOperator::BitXor => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
crate::runtime::semantics::coerce_to_i64(left_val.as_ref()),
|
||||
crate::runtime::semantics::coerce_to_i64(right_val.as_ref()),
|
||||
) { return Ok(Box::new(IntegerBox::new(li ^ ri))); }
|
||||
Err(RuntimeError::TypeError { message: format!("Bitwise '^' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) })
|
||||
}
|
||||
|
||||
BinaryOperator::Less => {
|
||||
let result = CompareBox::less(left_val.as_ref(), right_val.as_ref());
|
||||
|
||||
@ -256,17 +256,44 @@ impl NyashInterpreter {
|
||||
Ok(Box::new(BoolBox::new(self.is_truthy(right_val))))
|
||||
}
|
||||
},
|
||||
|
||||
BinaryOperator::Shl => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
left_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
right_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
) {
|
||||
Ok(Box::new(IntegerBox::new(li.value.wrapping_shl(ri.value as u32))))
|
||||
Ok(Box::new(IntegerBox::new(li.value.wrapping_shl((ri.value as u32) & 63))))
|
||||
} else {
|
||||
Err(RuntimeError::InvalidOperation { message: format!("Shift-left '<<' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) })
|
||||
}
|
||||
},
|
||||
BinaryOperator::Shr => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
left_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
right_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
) {
|
||||
Ok(Box::new(IntegerBox::new(((li.value as u64) >> ((ri.value as u32) & 63)) as i64)))
|
||||
} else {
|
||||
Err(RuntimeError::InvalidOperation { message: format!("Shift-right '>>' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) })
|
||||
}
|
||||
},
|
||||
BinaryOperator::BitAnd => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
left_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
right_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
) { Ok(Box::new(IntegerBox::new(li.value & ri.value))) } else { Err(RuntimeError::InvalidOperation { message: format!("Bitwise '&' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) }) }
|
||||
},
|
||||
BinaryOperator::BitOr => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
left_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
right_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
) { Ok(Box::new(IntegerBox::new(li.value | ri.value))) } else { Err(RuntimeError::InvalidOperation { message: format!("Bitwise '|' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) }) }
|
||||
},
|
||||
BinaryOperator::BitXor => {
|
||||
if let (Some(li), Some(ri)) = (
|
||||
left_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
right_val.as_any().downcast_ref::<IntegerBox>(),
|
||||
) { Ok(Box::new(IntegerBox::new(li.value ^ ri.value))) } else { Err(RuntimeError::InvalidOperation { message: format!("Bitwise '^' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) }) }
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -115,6 +115,10 @@ impl super::MirBuilder {
|
||||
BinaryOperator::Divide => Ok(BinaryOpType::Arithmetic(BinaryOp::Div)),
|
||||
BinaryOperator::Modulo => Ok(BinaryOpType::Arithmetic(BinaryOp::Mod)),
|
||||
BinaryOperator::Shl => Ok(BinaryOpType::Arithmetic(BinaryOp::Shl)),
|
||||
BinaryOperator::Shr => Ok(BinaryOpType::Arithmetic(BinaryOp::Shr)),
|
||||
BinaryOperator::BitAnd => Ok(BinaryOpType::Arithmetic(BinaryOp::BitAnd)),
|
||||
BinaryOperator::BitOr => Ok(BinaryOpType::Arithmetic(BinaryOp::BitOr)),
|
||||
BinaryOperator::BitXor => Ok(BinaryOpType::Arithmetic(BinaryOp::BitXor)),
|
||||
BinaryOperator::Equal => Ok(BinaryOpType::Comparison(CompareOp::Eq)),
|
||||
BinaryOperator::NotEqual => Ok(BinaryOpType::Comparison(CompareOp::Ne)),
|
||||
BinaryOperator::Less => Ok(BinaryOpType::Comparison(CompareOp::Lt)),
|
||||
|
||||
@ -133,7 +133,7 @@ impl NyashParser {
|
||||
|
||||
/// AND演算子をパース: &&
|
||||
fn parse_and(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let mut expr = self.parse_equality()?;
|
||||
let mut expr = self.parse_bit_or()?;
|
||||
|
||||
while self.match_token(&TokenType::AND) {
|
||||
let operator = BinaryOperator::And;
|
||||
@ -154,6 +154,42 @@ impl NyashParser {
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
/// ビットOR: |
|
||||
fn parse_bit_or(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let mut expr = self.parse_bit_xor()?;
|
||||
while self.match_token(&TokenType::BIT_OR) {
|
||||
let operator = BinaryOperator::BitOr;
|
||||
self.advance();
|
||||
let right = self.parse_bit_xor()?;
|
||||
expr = ASTNode::BinaryOp { operator, left: Box::new(expr), right: Box::new(right), span: Span::unknown() };
|
||||
}
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
/// ビットXOR: ^
|
||||
fn parse_bit_xor(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let mut expr = self.parse_bit_and()?;
|
||||
while self.match_token(&TokenType::BIT_XOR) {
|
||||
let operator = BinaryOperator::BitXor;
|
||||
self.advance();
|
||||
let right = self.parse_bit_and()?;
|
||||
expr = ASTNode::BinaryOp { operator, left: Box::new(expr), right: Box::new(right), span: Span::unknown() };
|
||||
}
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
/// ビットAND: &
|
||||
fn parse_bit_and(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let mut expr = self.parse_equality()?;
|
||||
while self.match_token(&TokenType::BIT_AND) {
|
||||
let operator = BinaryOperator::BitAnd;
|
||||
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()?;
|
||||
@ -229,21 +265,11 @@ impl NyashParser {
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
/// 項をパース: + - >>
|
||||
/// 項をパース: + -
|
||||
fn parse_term(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let mut expr = self.parse_shift()?;
|
||||
|
||||
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_shift()?;
|
||||
expr = ASTNode::Arrow {
|
||||
sender: Box::new(expr),
|
||||
receiver: Box::new(right),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
} else {
|
||||
while self.match_token(&TokenType::PLUS) || self.match_token(&TokenType::MINUS) {
|
||||
let operator = match &self.current_token().token_type {
|
||||
TokenType::PLUS => BinaryOperator::Add,
|
||||
TokenType::MINUS => BinaryOperator::Subtract,
|
||||
@ -263,23 +289,27 @@ impl NyashParser {
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
/// シフトをパース: << のみ(Phase 1)
|
||||
/// シフトをパース: << >>
|
||||
fn parse_shift(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let mut expr = self.parse_factor()?;
|
||||
while self.match_token(&TokenType::SHIFT_LEFT) {
|
||||
self.advance(); // consume '<<'
|
||||
loop {
|
||||
if self.match_token(&TokenType::SHIFT_LEFT) {
|
||||
self.advance();
|
||||
let rhs = self.parse_factor()?;
|
||||
expr = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Shl,
|
||||
left: Box::new(expr),
|
||||
right: Box::new(rhs),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
expr = ASTNode::BinaryOp { operator: BinaryOperator::Shl, left: Box::new(expr), right: Box::new(rhs), span: Span::unknown() };
|
||||
continue;
|
||||
}
|
||||
if self.match_token(&TokenType::SHIFT_RIGHT) {
|
||||
self.advance();
|
||||
let rhs = self.parse_factor()?;
|
||||
expr = ASTNode::BinaryOp { operator: BinaryOperator::Shr, left: Box::new(expr), right: Box::new(rhs), span: Span::unknown() };
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
@ -58,8 +58,11 @@ pub enum TokenType {
|
||||
USING, // using (名前空間インポート)
|
||||
|
||||
// 演算子 (長いものから先に定義)
|
||||
ARROW, // >> (legacy arrow)
|
||||
SHIFT_LEFT, // << (bitwise shift-left)
|
||||
SHIFT_RIGHT, // >> (bitwise shift-right)
|
||||
BIT_AND, // & (bitwise and)
|
||||
BIT_OR, // | (bitwise or)
|
||||
BIT_XOR, // ^ (bitwise xor)
|
||||
FAT_ARROW, // => (peek arms)
|
||||
EQUALS, // ==
|
||||
NotEquals, // !=
|
||||
@ -248,7 +251,7 @@ impl NyashTokenizer {
|
||||
Some('>') if self.peek_char() == Some('>') => {
|
||||
self.advance();
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::ARROW, start_line, start_column))
|
||||
Ok(Token::new(TokenType::SHIFT_RIGHT, start_line, start_column))
|
||||
}
|
||||
Some(':') if self.peek_char() == Some(':') => {
|
||||
self.advance();
|
||||
@ -296,6 +299,11 @@ impl NyashTokenizer {
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::OR, start_line, start_column))
|
||||
}
|
||||
Some('|') if self.peek_char() == Some('>') => {
|
||||
self.advance();
|
||||
self.advance();
|
||||
return Ok(Token::new(TokenType::PIPE_FORWARD, start_line, start_column));
|
||||
}
|
||||
Some('<') => {
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::LESS, start_line, start_column))
|
||||
@ -304,6 +312,18 @@ impl NyashTokenizer {
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::GREATER, start_line, start_column))
|
||||
}
|
||||
Some('&') => {
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::BIT_AND, start_line, start_column))
|
||||
}
|
||||
Some('|') => {
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::BIT_OR, start_line, start_column))
|
||||
}
|
||||
Some('^') => {
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::BIT_XOR, start_line, start_column))
|
||||
}
|
||||
Some('=') => {
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::ASSIGN, start_line, start_column))
|
||||
|
||||
Reference in New Issue
Block a user