grammar: add '<<' shift-left safely (Phase 1); map to AST/MIR/VM; keep '>>' as legacy ARROW
- Tokenizer: add SHIFT_LEFT for '<<' (before <= detection) - Parser: introduce parse_shift() layer; left-associative; only '<<' handled in Phase 1 - AST: add BinaryOperator::Shl and display - MIR builder: map Shl -> BinaryOp::Shl - Interpreter: implement Shl in both execution paths (integer-only, type error otherwise) No change to '>>' (legacy ARROW remains). No runtime gate yet for SHL as it does not collide with existing syntax.
This commit is contained in:
BIN
app_llvm_test
Normal file
BIN
app_llvm_test
Normal file
Binary file not shown.
@ -333,6 +333,7 @@ pub enum BinaryOperator {
|
||||
Multiply,
|
||||
Divide,
|
||||
Modulo,
|
||||
Shl, // << shift-left (Phase 1)
|
||||
Equal,
|
||||
NotEqual,
|
||||
Less,
|
||||
@ -361,6 +362,7 @@ impl fmt::Display for BinaryOperator {
|
||||
BinaryOperator::Multiply => "*",
|
||||
BinaryOperator::Divide => "/",
|
||||
BinaryOperator::Modulo => "%",
|
||||
BinaryOperator::Shl => "<<",
|
||||
BinaryOperator::Equal => "==",
|
||||
BinaryOperator::NotEqual => "!=",
|
||||
BinaryOperator::Less => "<",
|
||||
|
||||
@ -323,6 +323,19 @@ impl NyashInterpreter {
|
||||
}
|
||||
}
|
||||
|
||||
BinaryOperator::Shl => {
|
||||
// Integer-only left shift
|
||||
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.wrapping_shl(ri as u32))));
|
||||
}
|
||||
Err(RuntimeError::TypeError {
|
||||
message: format!("Shift-left '<<' 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());
|
||||
Ok(Box::new(result))
|
||||
|
||||
@ -256,6 +256,17 @@ 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))))
|
||||
} else {
|
||||
Err(RuntimeError::InvalidOperation { message: format!("Shift-left '<<' requires integers (got {} and {})", left_val.type_name(), right_val.type_name()) })
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -114,6 +114,7 @@ impl super::MirBuilder {
|
||||
BinaryOperator::Multiply => Ok(BinaryOpType::Arithmetic(BinaryOp::Mul)),
|
||||
BinaryOperator::Divide => Ok(BinaryOpType::Arithmetic(BinaryOp::Div)),
|
||||
BinaryOperator::Modulo => Ok(BinaryOpType::Arithmetic(BinaryOp::Mod)),
|
||||
BinaryOperator::Shl => Ok(BinaryOpType::Arithmetic(BinaryOp::Shl)),
|
||||
BinaryOperator::Equal => Ok(BinaryOpType::Comparison(CompareOp::Eq)),
|
||||
BinaryOperator::NotEqual => Ok(BinaryOpType::Comparison(CompareOp::Ne)),
|
||||
BinaryOperator::Less => Ok(BinaryOpType::Comparison(CompareOp::Lt)),
|
||||
|
||||
@ -231,13 +231,13 @@ impl NyashParser {
|
||||
|
||||
/// 項をパース: + - >>
|
||||
fn parse_term(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let mut expr = self.parse_factor()?;
|
||||
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_factor()?;
|
||||
let right = self.parse_shift()?;
|
||||
expr = ASTNode::Arrow {
|
||||
sender: Box::new(expr),
|
||||
receiver: Box::new(right),
|
||||
@ -250,7 +250,7 @@ impl NyashParser {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.advance();
|
||||
let right = self.parse_factor()?;
|
||||
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);
|
||||
@ -268,6 +268,22 @@ impl NyashParser {
|
||||
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 '<<'
|
||||
let rhs = self.parse_factor()?;
|
||||
expr = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Shl,
|
||||
left: Box::new(expr),
|
||||
right: Box::new(rhs),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
/// 因子をパース: * /
|
||||
fn parse_factor(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let mut expr = self.parse_unary()?;
|
||||
|
||||
@ -59,6 +59,7 @@ pub enum TokenType {
|
||||
|
||||
// 演算子 (長いものから先に定義)
|
||||
ARROW, // >> (legacy arrow)
|
||||
SHIFT_LEFT, // << (bitwise shift-left)
|
||||
FAT_ARROW, // => (peek arms)
|
||||
EQUALS, // ==
|
||||
NotEquals, // !=
|
||||
@ -269,6 +270,12 @@ impl NyashTokenizer {
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::NotEquals, start_line, start_column))
|
||||
}
|
||||
// Shift-left must be detected before <= and <
|
||||
Some('<') if self.peek_char() == Some('<') => {
|
||||
self.advance();
|
||||
self.advance();
|
||||
Ok(Token::new(TokenType::SHIFT_LEFT, start_line, start_column))
|
||||
}
|
||||
Some('<') if self.peek_char() == Some('=') => {
|
||||
self.advance();
|
||||
self.advance();
|
||||
|
||||
Reference in New Issue
Block a user