diff options
author | Vincent Ambo <mail@tazj.in> | 2021-10-21T09·00+0200 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2021-10-22T09·42+0000 |
commit | 670662a360447509940dac417195cf419d7f42c5 (patch) | |
tree | d602009e12bac63309f60e2a4e271317bb6b17b4 /users/tazjin/rlox/src/bytecode/compiler.rs | |
parent | d57e43e1615ae28cfdc74c1c65cbe7863d782018 (diff) |
feat(tazjin/rlox): Implement simple conditionals r/2986
... basically just optional blocks (no else). Change-Id: If091c6b8fdeb6c13a5f3dd284d0a9a87f9f4228d Reviewed-on: https://cl.tvl.fyi/c/depot/+/3739 Tested-by: BuildkiteCI Reviewed-by: tazjin <mail@tazj.in>
Diffstat (limited to 'users/tazjin/rlox/src/bytecode/compiler.rs')
-rw-r--r-- | users/tazjin/rlox/src/bytecode/compiler.rs | 65 |
1 files changed, 51 insertions, 14 deletions
diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs index 392fc9b72d6e..1b87e94a5512 100644 --- a/users/tazjin/rlox/src/bytecode/compiler.rs +++ b/users/tazjin/rlox/src/bytecode/compiler.rs @@ -1,7 +1,7 @@ use super::chunk::Chunk; use super::errors::{Error, ErrorKind, LoxResult}; use super::interner::{InternedStr, Interner}; -use super::opcode::{CodeIdx, ConstantIdx, OpCode, StackIdx}; +use super::opcode::{CodeIdx, CodeOffset, ConstantIdx, OpCode, StackIdx}; use super::value::Value; use crate::scanner::{self, Token, TokenKind}; @@ -236,9 +236,13 @@ impl<T: Iterator<Item = Token>> Compiler<T> { fn define_variable(&mut self, var: Option<ConstantIdx>) -> LoxResult<()> { if self.locals.scope_depth == 0 { - self.emit_op(OpCode::OpDefineGlobal(var.expect("should be global"))); + self.emit_op(OpCode::OpDefineGlobal( + var.expect("should be global"), + )); } else { - self.locals.locals.last_mut() + self.locals + .locals + .last_mut() .expect("fatal: variable not yet added at definition") .depth = Depth::At(self.locals.scope_depth); } @@ -263,6 +267,8 @@ impl<T: Iterator<Item = Token>> Compiler<T> { fn statement(&mut self) -> LoxResult<()> { if self.match_token(&TokenKind::Print) { self.print_statement() + } else if self.match_token(&TokenKind::If) { + self.if_statement() } else if self.match_token(&TokenKind::LeftBrace) { self.begin_scope(); self.block()?; @@ -289,7 +295,9 @@ impl<T: Iterator<Item = Token>> Compiler<T> { self.locals.scope_depth -= 1; while self.locals.locals.len() > 0 - && self.locals.locals[self.locals.locals.len() - 1].depth.above(self.locals.scope_depth) + && self.locals.locals[self.locals.locals.len() - 1] + .depth + .above(self.locals.scope_depth) { self.emit_op(OpCode::OpPop); self.locals.locals.remove(self.locals.locals.len() - 1); @@ -319,6 +327,28 @@ impl<T: Iterator<Item = Token>> Compiler<T> { Ok(()) } + fn if_statement(&mut self) -> LoxResult<()> { + consume!( + self, + TokenKind::LeftParen, + ErrorKind::ExpectedToken("Expected '(' after 'if'") + ); + + self.expression()?; + + consume!( + self, + TokenKind::RightParen, + ErrorKind::ExpectedToken("Expected ')' after condition") + ); + + let then_jump = self.emit_op(OpCode::OpJumpPlaceholder(false)); + self.statement()?; + self.patch_jump(then_jump); + + Ok(()) + } + fn number(&mut self) -> LoxResult<()> { if let TokenKind::Number(num) = self.previous().kind { self.emit_constant(Value::Number(num), true); @@ -431,16 +461,12 @@ impl<T: Iterator<Item = Token>> Compiler<T> { self.expression()?; match local_idx { Some(idx) => self.emit_op(OpCode::OpSetLocal(idx)), - None => { - self.emit_op(OpCode::OpSetGlobal(ident.unwrap())) - } + None => self.emit_op(OpCode::OpSetGlobal(ident.unwrap())), }; } else { match local_idx { Some(idx) => self.emit_op(OpCode::OpGetLocal(idx)), - None => { - self.emit_op(OpCode::OpGetGlobal(ident.unwrap())) - } + None => self.emit_op(OpCode::OpGetGlobal(ident.unwrap())), }; } @@ -477,10 +503,7 @@ impl<T: Iterator<Item = Token>> Compiler<T> { Ok(()) } - fn identifier_str( - &mut self, - token: &Token, - ) -> LoxResult<InternedStr> { + fn identifier_str(&mut self, token: &Token) -> LoxResult<InternedStr> { let ident = match &token.kind { TokenKind::Identifier(ident) => ident.to_string(), _ => { @@ -594,6 +617,20 @@ impl<T: Iterator<Item = Token>> Compiler<T> { idx } + fn patch_jump(&mut self, idx: CodeIdx) { + let offset = CodeOffset(self.chunk.code.len() - idx.0 - 1); + + if let OpCode::OpJumpPlaceholder(false) = self.chunk.code[idx.0] { + self.chunk.code[idx.0] = OpCode::OpJumpIfFalse(offset); + return; + } + + panic!( + "attempted to patch unsupported op: {:?}", + self.chunk.code[idx.0] + ); + } + fn previous(&self) -> &Token { self.previous .as_ref() |