Implement unary negation
This commit is contained in:
parent
74dbf724a5
commit
3c6fb5466e
@ -1,4 +1,4 @@
|
||||
use crate::parser::{Ast, BinOpType};
|
||||
use crate::parser::{Ast, BinOpType, UnOpType};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Value {
|
||||
@ -24,6 +24,7 @@ impl Interpreter {
|
||||
match expr {
|
||||
Ast::I64(val) => Value::I64(val),
|
||||
Ast::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, *lhs, *rhs),
|
||||
Ast::UnOp(uo, val) => self.resolve_unop(uo, *val),
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,6 +48,16 @@ impl Interpreter {
|
||||
// _ => panic!("Value types are not compatible"),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_unop(&mut self, uo: UnOpType, val: Ast) -> Value {
|
||||
let val = self.resolve_expr(val);
|
||||
match val {
|
||||
Value::I64(val) => match uo {
|
||||
UnOpType::Neg => Value::I64(-val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -36,18 +36,27 @@ pub enum BinOpType {
|
||||
Shr,
|
||||
}
|
||||
|
||||
/// Types for unary operators
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum UnOpType {
|
||||
/// Negation
|
||||
Neg,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Ast {
|
||||
/// Integer literal (64-bit)
|
||||
I64(i64),
|
||||
/// Binary operation. Consists of type, left hand side and right hand side
|
||||
BinOp(BinOpType, Box<Ast>, Box<Ast>),
|
||||
/// Unary operation. Consists of type and the value that is operated on
|
||||
UnOp(UnOpType, Box<Ast>),
|
||||
}
|
||||
|
||||
/*
|
||||
## Grammar
|
||||
### Expressions
|
||||
expr_primary = LITERAL | "(" expr ")"
|
||||
expr_primary = LITERAL | "(" expr ")" | "-" expr_primary
|
||||
expr_mul = expr_primary (("*" | "/" | "%") expr_primary)*
|
||||
expr_add = expr_mul (("+" | "-") expr_mul)*
|
||||
expr_shift = expr_add ((">>" | "<<") expr_add)*
|
||||
@ -111,7 +120,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
Token::I64(val) => Ast::I64(val),
|
||||
|
||||
Token::LParen => {
|
||||
// The tokens was an opening parenthesis, so parse a full expression again as the
|
||||
// The tokens was an opening parenthesis, so parse a full expression again as the
|
||||
// expression inside the parentheses `"(" expr ")"`
|
||||
let inner = self.parse_expr();
|
||||
|
||||
@ -123,6 +132,8 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
inner
|
||||
}
|
||||
|
||||
Token::Sub => Ast::UnOp(UnOpType::Neg, self.parse_primary().into()),
|
||||
|
||||
tok => panic!("Error parsing primary expr: Unexpected Token '{:?}'", tok),
|
||||
}
|
||||
}
|
||||
@ -146,9 +157,9 @@ pub fn parse<T: Iterator<Item = Token>, A: IntoIterator<IntoIter = T>>(tokens: A
|
||||
impl BinOpType {
|
||||
/// Get the precedence for a binary operator. Higher value means the OP is stronger binding.
|
||||
/// For example Multiplication is stronger than addition, so Mul has higher precedence than Add.
|
||||
///
|
||||
///
|
||||
/// The operator precedences are derived from the C language operator precedences. While not all
|
||||
/// C operators are included or the exact same, the precedence oder is the same.
|
||||
/// C operators are included or the exact same, the precedence oder is the same.
|
||||
/// See: https://en.cppreference.com/w/c/language/operator_precedence
|
||||
fn precedence(&self) -> u8 {
|
||||
match self {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user