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…
	
	Add table
		Add a link
		
	
		Reference in a new issue