diff --git a/src/ast.rs b/src/ast.rs index 220652e1..42753ad3 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -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 => "<", diff --git a/src/interpreter/expressions/operators.rs b/src/interpreter/expressions/operators.rs index d49c250a..1d2547ab 100644 --- a/src/interpreter/expressions/operators.rs +++ b/src/interpreter/expressions/operators.rs @@ -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()); diff --git a/src/interpreter/operators.rs b/src/interpreter/operators.rs index fbb78b77..43994f35 100644 --- a/src/interpreter/operators.rs +++ b/src/interpreter/operators.rs @@ -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::(), right_val.as_any().downcast_ref::(), ) { - 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::(), + right_val.as_any().downcast_ref::(), + ) { + 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::(), + right_val.as_any().downcast_ref::(), + ) { 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::(), + right_val.as_any().downcast_ref::(), + ) { 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::(), + right_val.as_any().downcast_ref::(), + ) { 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()) }) } + }, } } diff --git a/src/mir/builder/ops.rs b/src/mir/builder/ops.rs index 1235df25..59186d2b 100644 --- a/src/mir/builder/ops.rs +++ b/src/mir/builder/ops.rs @@ -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)), diff --git a/src/parser/expressions.rs b/src/parser/expressions.rs index 5c6bf4a8..94d1fa0f 100644 --- a/src/parser/expressions.rs +++ b/src/parser/expressions.rs @@ -133,7 +133,7 @@ impl NyashParser { /// AND演算子をパース: && fn parse_and(&mut self) -> Result { - let mut expr = self.parse_equality()?; + let mut expr = self.parse_bit_or()?; while self.match_token(&TokenType::AND) { let operator = BinaryOperator::And; @@ -153,6 +153,42 @@ impl NyashParser { Ok(expr) } + + /// ビットOR: | + fn parse_bit_or(&mut self) -> Result { + 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 { + 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 { + 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 { @@ -229,57 +265,51 @@ impl NyashParser { Ok(expr) } - /// 項をパース: + - >> + /// 項をパース: + - fn parse_term(&mut self) -> Result { 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 { - let operator = match &self.current_token().token_type { - TokenType::PLUS => BinaryOperator::Add, - TokenType::MINUS => BinaryOperator::Subtract, - _ => unreachable!(), - }; - self.advance(); - let right = self.parse_shift()?; - if std::env::var("NYASH_GRAMMAR_DIFF").ok().as_deref() == Some("1") { - let name = match operator { BinaryOperator::Add=>"add", BinaryOperator::Subtract=>"sub", _=>"term" }; - let ok = crate::grammar::engine::get().syntax_is_allowed_binop(name); - if !ok { eprintln!("[GRAMMAR-DIFF][Parser] binop '{}' not allowed by syntax rules", name); } - } - expr = ASTNode::BinaryOp { - operator, - left: Box::new(expr), - right: Box::new(right), - span: Span::unknown(), - }; + 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, + _ => unreachable!(), + }; + self.advance(); + let right = self.parse_shift()?; + if std::env::var("NYASH_GRAMMAR_DIFF").ok().as_deref() == Some("1") { + let name = match operator { BinaryOperator::Add=>"add", BinaryOperator::Subtract=>"sub", _=>"term" }; + let ok = crate::grammar::engine::get().syntax_is_allowed_binop(name); + if !ok { eprintln!("[GRAMMAR-DIFF][Parser] binop '{}' not allowed by syntax rules", name); } } + expr = ASTNode::BinaryOp { + operator, + left: Box::new(expr), + right: Box::new(right), + span: Span::unknown(), + }; } Ok(expr) } - /// シフトをパース: << のみ(Phase 1) + /// シフトをパース: << >> fn parse_shift(&mut self) -> Result { let mut expr = self.parse_factor()?; - while self.match_token(&TokenType::SHIFT_LEFT) { - self.advance(); // consume '<<' - let rhs = self.parse_factor()?; - expr = ASTNode::BinaryOp { - operator: BinaryOperator::Shl, - left: Box::new(expr), - right: Box::new(rhs), - span: Span::unknown(), - }; + 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() }; + 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) } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 21f78584..5012e2e6 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -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))