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)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
@ -24,6 +24,7 @@ impl Interpreter {
|
|||||||
match expr {
|
match expr {
|
||||||
Ast::I64(val) => Value::I64(val),
|
Ast::I64(val) => Value::I64(val),
|
||||||
Ast::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, *lhs, *rhs),
|
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"),
|
// _ => 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)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -36,18 +36,27 @@ pub enum BinOpType {
|
|||||||
Shr,
|
Shr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Types for unary operators
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum UnOpType {
|
||||||
|
/// Negation
|
||||||
|
Neg,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Ast {
|
pub enum Ast {
|
||||||
/// Integer literal (64-bit)
|
/// Integer literal (64-bit)
|
||||||
I64(i64),
|
I64(i64),
|
||||||
/// Binary operation. Consists of type, left hand side and right hand side
|
/// Binary operation. Consists of type, left hand side and right hand side
|
||||||
BinOp(BinOpType, Box<Ast>, Box<Ast>),
|
BinOp(BinOpType, Box<Ast>, Box<Ast>),
|
||||||
|
/// Unary operation. Consists of type and the value that is operated on
|
||||||
|
UnOp(UnOpType, Box<Ast>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
## Grammar
|
## Grammar
|
||||||
### Expressions
|
### Expressions
|
||||||
expr_primary = LITERAL | "(" expr ")"
|
expr_primary = LITERAL | "(" expr ")" | "-" expr_primary
|
||||||
expr_mul = expr_primary (("*" | "/" | "%") expr_primary)*
|
expr_mul = expr_primary (("*" | "/" | "%") expr_primary)*
|
||||||
expr_add = expr_mul (("+" | "-") expr_mul)*
|
expr_add = expr_mul (("+" | "-") expr_mul)*
|
||||||
expr_shift = expr_add ((">>" | "<<") expr_add)*
|
expr_shift = expr_add ((">>" | "<<") expr_add)*
|
||||||
@ -111,7 +120,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
Token::I64(val) => Ast::I64(val),
|
Token::I64(val) => Ast::I64(val),
|
||||||
|
|
||||||
Token::LParen => {
|
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 ")"`
|
// expression inside the parentheses `"(" expr ")"`
|
||||||
let inner = self.parse_expr();
|
let inner = self.parse_expr();
|
||||||
|
|
||||||
@ -123,6 +132,8 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
inner
|
inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token::Sub => Ast::UnOp(UnOpType::Neg, self.parse_primary().into()),
|
||||||
|
|
||||||
tok => panic!("Error parsing primary expr: Unexpected Token '{:?}'", tok),
|
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 {
|
impl BinOpType {
|
||||||
/// Get the precedence for a binary operator. Higher value means the OP is stronger binding.
|
/// 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.
|
/// 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
|
/// 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
|
/// See: https://en.cppreference.com/w/c/language/operator_precedence
|
||||||
fn precedence(&self) -> u8 {
|
fn precedence(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user