[rlox] Add Not op

This commit is contained in:
ctsk
2023-10-08 21:31:07 +02:00
parent 8ace98a215
commit f617738674
3 changed files with 69 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
use crate::bc::Value::Number; use crate::bc::Value::{Bool, Number};
use std::convert::From; use std::convert::From;
use std::fmt; use std::fmt;
@@ -9,6 +9,7 @@ pub enum Op {
Nil, Nil,
True, True,
False, False,
Not,
Negate, Negate,
Add, Add,
Subtract, Subtract,
@@ -30,6 +31,13 @@ impl Value {
_ => None, _ => None,
} }
} }
pub fn as_bool(self) -> Option<bool> {
match self {
Bool(val) => Some(val),
_ => None,
}
}
} }
impl From<f64> for Value { impl From<f64> for Value {
@@ -38,6 +46,12 @@ impl From<f64> for Value {
} }
} }
impl From<bool> for Value {
fn from(value: bool) -> Self {
Bool(value)
}
}
pub struct Chunk { pub struct Chunk {
pub code: Vec<Op>, pub code: Vec<Op>,
pub debug_info: Vec<usize>, pub debug_info: Vec<usize>,
@@ -139,7 +153,8 @@ impl fmt::Debug for TraceInfo<'_> {
match op { match op {
Op::Return | Op::Nil | Op::True Op::Return | Op::Nil | Op::True
| Op::False | Op::Negate | Op::Add | Op::False | Op::Negate | Op::Add
| Op::Subtract | Op::Multiply | Op::Divide => { | Op::Subtract | Op::Multiply | Op::Divide
| Op::Not => {
write!(f, "{:?}", op) write!(f, "{:?}", op)
} }
Op::Constant { offset } => { Op::Constant { offset } => {

View File

@@ -333,11 +333,16 @@ impl<'src> Parser<'src> {
None => panic!("Expected further tokens"), None => panic!("Expected further tokens"),
Some(token) => match token { Some(token) => match token {
Token { Token {
ttype: TokenType::Minus, ttype: ttype@(TokenType::Minus | TokenType::Bang),
span: _, span: _,
} => { } => {
self._expression(chunk, Precedence::Unary); self._expression(chunk, Precedence::Unary);
chunk.add_op(Op::Negate, 0); let op = match ttype {
TokenType::Minus => Op::Negate,
TokenType::Bang => Op::Not,
_ => unreachable!(),
};
chunk.add_op(op, 0);
} }
Token { Token {
ttype: TokenType::Number, ttype: TokenType::Number,
@@ -467,14 +472,17 @@ mod tests {
); );
} }
#[test] fn test_parse_expression(source: &str, expected: &Chunk) {
fn test_parser() {
let source = "1 + 1 * (2 + 1)";
let scanner = Scanner::new(source); let scanner = Scanner::new(source);
let mut parser = Parser::new(scanner); let mut parser = Parser::new(scanner);
let mut chunk = Chunk::new(); let mut chunk = Chunk::new();
parser.expression(&mut chunk); parser.expression(&mut chunk);
assert!(chunk.instr_eq(expected));
}
#[test]
fn test_parser() {
let source = "1 + 1 * (2 + 1)";
use crate::bc::Op::*; use crate::bc::Op::*;
let expected = Chunk::new_with( let expected = Chunk::new_with(
vec![ vec![
@@ -490,17 +498,12 @@ mod tests {
vec![1., 1., 2., 1.].into_iter().map(Value::from).collect(), vec![1., 1., 2., 1.].into_iter().map(Value::from).collect(),
); );
assert!(chunk.instr_eq(&expected)); test_parse_expression(source, &expected);
} }
#[test] #[test]
fn parse_nil() { fn parse_nil() {
let source = "nil + nil"; let source = "nil + nil";
let scanner = Scanner::new(source);
let mut parser = Parser::new(scanner);
let mut chunk = Chunk::new();
parser.expression(&mut chunk);
use crate::bc::Op::*; use crate::bc::Op::*;
let expected = Chunk::new_with( let expected = Chunk::new_with(
vec![Nil, Nil, Add], vec![Nil, Nil, Add],
@@ -508,17 +511,12 @@ mod tests {
vec![], vec![],
); );
assert!(chunk.instr_eq(&expected)); test_parse_expression(source, &expected);
} }
#[test] #[test]
fn parse_bool_literals() { fn parse_bool_literals() {
let source = "true * false"; let source = "true * false";
let scanner = Scanner::new(source);
let mut parser = Parser::new(scanner);
let mut chunk = Chunk::new();
parser.expression(&mut chunk);
use crate::bc::Op::*; use crate::bc::Op::*;
let expected = Chunk::new_with( let expected = Chunk::new_with(
vec![True, False, Multiply], vec![True, False, Multiply],
@@ -526,7 +524,19 @@ mod tests {
vec![], vec![],
); );
assert!(chunk.instr_eq(&expected)); test_parse_expression(source, &expected);
}
#[test]
fn parse_bool_expression() {
let source = "!false";
use crate::bc::Op::*;
let expected = Chunk::new_with(
vec![False, Not],
vec![],
vec![],
);
test_parse_expression(source, &expected);
} }
} }

View File

@@ -51,6 +51,13 @@ impl VM {
.ok_or(self.type_err("Number", top_of_stack)) .ok_or(self.type_err("Number", top_of_stack))
} }
fn pop_bool(&mut self) -> Result<bool, VMError> {
let top_of_stack = self.pop()?;
top_of_stack
.as_bool()
.ok_or(self.type_err("Boolean", top_of_stack))
}
pub fn run(&mut self, chunk: &Chunk) -> Result<Option<Value>, VMError> { pub fn run(&mut self, chunk: &Chunk) -> Result<Option<Value>, VMError> {
while self.pc < chunk.code.len() { while self.pc < chunk.code.len() {
let instr = chunk.code[self.pc]; let instr = chunk.code[self.pc];
@@ -83,6 +90,10 @@ impl VM {
let new_val = -self.pop_num()?; let new_val = -self.pop_num()?;
self.push(new_val.into()); self.push(new_val.into());
} }
Op::Not => {
let new_val = !self.pop_bool()?;
self.push(new_val.into());
}
Op::Add | Op::Subtract | Op::Multiply | Op::Divide => { Op::Add | Op::Subtract | Op::Multiply | Op::Divide => {
let b = self.pop_num()?; let b = self.pop_num()?;
let a = self.pop_num()?; let a = self.pop_num()?;
@@ -158,4 +169,17 @@ mod tests {
vm.type_err("Number", Value::Nil) vm.type_err("Number", Value::Nil)
); );
} }
#[test]
fn simple_booleans() {
let chunk = Chunk::new_with(
vec![Op::False, Op::Not],
vec![],
vec![],
);
let mut vm = VM::new();
vm.run(&chunk).unwrap();
assert_eq!(vm.stack[0], true.into());
}
} }