Implement more operators

- Mod
- Bitwise Or
- Bitwise And
- Bitwise Xor
- Shift Left
- Shift Right
This commit is contained in:
Kai-Philipp Nosper 2022-01-27 23:10:38 +01:00
parent 0b75c30784
commit a569781691
3 changed files with 82 additions and 9 deletions

View File

@ -37,6 +37,12 @@ impl Interpreter {
BinOpType::Mul => Value::I64(lhs * rhs),
BinOpType::Sub => Value::I64(lhs - rhs),
BinOpType::Div => Value::I64(lhs / rhs),
BinOpType::Mod => Value::I64(lhs % rhs),
BinOpType::BOr => Value::I64(lhs | rhs),
BinOpType::BAnd => Value::I64(lhs & rhs),
BinOpType::BXor => Value::I64(lhs ^ rhs),
BinOpType::Shr => Value::I64(lhs >> rhs),
BinOpType::Shl => Value::I64(lhs << rhs),
},
// _ => panic!("Value types are not compatible"),
}
@ -45,8 +51,8 @@ impl Interpreter {
#[cfg(test)]
mod test {
use crate::parser::{Ast, BinOpType};
use super::{Interpreter, Value};
use crate::parser::{Ast, BinOpType};
#[test]
fn test_interpreter_expr() {

View File

@ -19,6 +19,24 @@ pub enum Token {
/// Slash (/)
Div,
/// Percent (%)
Mod,
/// Pipe (|)
BOr,
/// Ampersand (&)
BAnd,
/// Circumflex (^)
BXor,
/// Shift Left (<<)
Shl,
/// Shift Right (>>)
Shr,
/// End of file
EoF,
}
@ -57,7 +75,7 @@ impl<'a> Lexer<'a> {
sval.push(self.next().unwrap());
}
// Next char is not a number, so stop and finish the number token
_ => break
_ => break,
}
}
@ -65,10 +83,22 @@ impl<'a> Lexer<'a> {
tokens.push(Token::I64(sval.parse().unwrap()));
}
'>' if matches!(self.peek(), Some('>')) => {
self.next();
tokens.push(Token::Shr);
}
'<' if matches!(self.peek(), Some('<')) => {
self.next();
tokens.push(Token::Shl);
}
'+' => tokens.push(Token::Add),
'-' => tokens.push(Token::Sub),
'*' => tokens.push(Token::Mul),
'/' => tokens.push(Token::Div),
'%' => tokens.push(Token::Mod),
'|' => tokens.push(Token::BOr),
'&' => tokens.push(Token::BAnd),
'^' => tokens.push(Token::BXor),
//TODO: Don't panic, keep calm
_ => panic!("Lexer encountered unexpected char: '{}'", ch),
@ -102,8 +132,17 @@ impl Token {
Some(match self {
Token::Add => BinOpType::Add,
Token::Sub => BinOpType::Sub,
Token::Mul => BinOpType::Mul,
Token::Div => BinOpType::Div,
Token::Mod => BinOpType::Mod,
Token::BAnd => BinOpType::BAnd,
Token::BOr => BinOpType::BOr,
Token::BXor => BinOpType::BXor,
Token::Shl => BinOpType::Shl,
Token::Shr => BinOpType::Shr,
_ => return None,
})
}
@ -115,7 +154,7 @@ mod tests {
#[test]
fn test_lexer() {
let code = "33 +5*2 + 4456467*2334+3";
let code = "33 +5*2 + 4456467*2334+3 % - / << ^ | & >>";
let expected = vec![
Token::I64(33),
Token::Add,
@ -128,6 +167,14 @@ mod tests {
Token::I64(2334),
Token::Add,
Token::I64(3),
Token::Mod,
Token::Sub,
Token::Div,
Token::Shl,
Token::BXor,
Token::BOr,
Token::BAnd,
Token::Shr,
];
let actual = lex(code);

View File

@ -16,6 +16,24 @@ pub enum BinOpType {
/// Divide
Div,
/// Modulo
Mod,
/// Bitwise OR (inclusive or)
BOr,
/// Bitwise And
BAnd,
/// Bitwise Xor (exclusive or)
BXor,
/// Shift Left
Shl,
/// Shift Right
Shr,
}
#[derive(Debug, PartialEq, Eq, Clone)]
@ -55,8 +73,6 @@ impl<T: Iterator<Item = Token>> Parser<T> {
self.parse_expr_precedence(lhs, 0)
}
/// Parse binary expressions with a precedence equal to or higher than min_prec
fn parse_expr_precedence(&mut self, mut lhs: Ast, min_prec: u8) -> Ast {
while let Some(binop) = &self.peek().try_to_binop() {
@ -115,8 +131,12 @@ impl BinOpType {
/// For example Multiplication is stronger than addition, so Mul has higher precedence than Add.
fn precedence(&self) -> u8 {
match self {
BinOpType::Add | BinOpType::Sub => 0,
BinOpType::Mul | BinOpType::Div => 1,
BinOpType::BOr => 0,
BinOpType::BXor => 1,
BinOpType::BAnd => 2,
BinOpType::Shl | BinOpType::Shr => 3,
BinOpType::Add | BinOpType::Sub => 4,
BinOpType::Mul | BinOpType::Div | BinOpType::Mod => 5,
}
}
}
@ -136,12 +156,12 @@ mod tests {
Token::I64(2),
Token::Mul,
Token::I64(3),
Token::Add,
Token::Sub,
Token::I64(4),
];
let expected = Ast::BinOp(
BinOpType::Add,
BinOpType::Sub,
Ast::BinOp(
BinOpType::Add,
Ast::I64(1).into(),