feat(tazjin/rlox): Support trivial literals in bytecode compiler
Adds support for true, false & nil. These each come with a new separate opcode and are pushed directly on the stack. Change-Id: I405b5b09496dcf99d514d3411c083e0834377167 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2571 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
This commit is contained in:
parent
127ef98486
commit
47ffa80711
5 changed files with 52 additions and 6 deletions
|
@ -1,9 +1,12 @@
|
|||
use super::chunk::{self, Chunk};
|
||||
use super::chunk::Chunk;
|
||||
use super::errors::{Error, ErrorKind, LoxResult};
|
||||
use super::opcode::OpCode;
|
||||
use super::value::Value;
|
||||
use crate::scanner::{self, Token, TokenKind};
|
||||
|
||||
#[cfg(feature = "disassemble")]
|
||||
use super::chunk;
|
||||
|
||||
struct Compiler<T: Iterator<Item = Token>> {
|
||||
tokens: T,
|
||||
chunk: Chunk,
|
||||
|
@ -101,6 +104,18 @@ fn rule_for<T: Iterator<Item = Token>>(token: &TokenKind) -> ParseRule<T> {
|
|||
ParseRule::new(Some(Compiler::number), None, Precedence::None)
|
||||
}
|
||||
|
||||
TokenKind::True => {
|
||||
ParseRule::new(Some(Compiler::literal), None, Precedence::None)
|
||||
}
|
||||
|
||||
TokenKind::False => {
|
||||
ParseRule::new(Some(Compiler::literal), None, Precedence::None)
|
||||
}
|
||||
|
||||
TokenKind::Nil => {
|
||||
ParseRule::new(Some(Compiler::literal), None, Precedence::None)
|
||||
}
|
||||
|
||||
_ => ParseRule::new(None, None, Precedence::None),
|
||||
}
|
||||
}
|
||||
|
@ -180,6 +195,17 @@ impl<T: Iterator<Item = Token>> Compiler<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn literal(&mut self) -> LoxResult<()> {
|
||||
match self.previous().kind {
|
||||
TokenKind::Nil => self.emit_op(OpCode::OpNil),
|
||||
TokenKind::True => self.emit_op(OpCode::OpTrue),
|
||||
TokenKind::False => self.emit_op(OpCode::OpFalse),
|
||||
_ => unreachable!("only called for literal value tokens"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_precedence(&mut self, precedence: Precedence) -> LoxResult<()> {
|
||||
self.advance();
|
||||
let rule: ParseRule<T> = rule_for(&self.previous().kind);
|
||||
|
@ -206,7 +232,7 @@ impl<T: Iterator<Item = Token>> Compiler<T> {
|
|||
}
|
||||
|
||||
fn consume(&mut self, expected: &TokenKind, err: ErrorKind) {
|
||||
if (self.current().kind == *expected) {
|
||||
if self.current().kind == *expected {
|
||||
self.advance();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ mod vm;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use chunk::Chunk;
|
||||
pub struct Interpreter {}
|
||||
|
||||
impl crate::Lox for Interpreter {
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
#[derive(Debug)]
|
||||
pub enum OpCode {
|
||||
/// Access a constant for use.
|
||||
/// Push a constant onto the stack.
|
||||
OpConstant(usize),
|
||||
|
||||
// Literal pushes
|
||||
OpNil,
|
||||
OpTrue,
|
||||
OpFalse,
|
||||
|
||||
/// Return from the current function.
|
||||
OpReturn,
|
||||
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
use super::value::Value;
|
||||
use super::*;
|
||||
|
||||
use crate::Lox;
|
||||
|
||||
fn expect_num(code: &str, value: f64) {
|
||||
fn expect(code: &str, value: Value) {
|
||||
let result = Interpreter::create()
|
||||
.interpret(code.into())
|
||||
.expect("evaluation failed");
|
||||
assert_eq!(result, value::Value::Number(value));
|
||||
assert_eq!(result, value);
|
||||
}
|
||||
|
||||
fn expect_num(code: &str, value: f64) {
|
||||
expect(code, Value::Number(value))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -46,3 +51,10 @@ fn arithmetic() {
|
|||
expect_num("-4 * -4 + (14 - 5)", 25.0);
|
||||
expect_num("(702 + 408) - ((239 - 734) / -5) + -4", 1007.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivial_literals() {
|
||||
expect("true", Value::Bool(true));
|
||||
expect("false", Value::Bool(false));
|
||||
expect("nil", Value::Nil);
|
||||
}
|
||||
|
|
|
@ -72,6 +72,10 @@ impl VM {
|
|||
self.push(c);
|
||||
}
|
||||
|
||||
OpCode::OpNil => self.push(Value::Nil),
|
||||
OpCode::OpTrue => self.push(Value::Bool(true)),
|
||||
OpCode::OpFalse => self.push(Value::Bool(false)),
|
||||
|
||||
OpCode::OpNegate => {
|
||||
let v = self.pop();
|
||||
with_type!(
|
||||
|
|
Loading…
Reference in a new issue