diff options
Diffstat (limited to 'users/tazjin/rlox/src/bytecode/compiler.rs')
-rw-r--r-- | users/tazjin/rlox/src/bytecode/compiler.rs | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs index f2fdeb0e9feb..f993e35557ad 100644 --- a/users/tazjin/rlox/src/bytecode/compiler.rs +++ b/users/tazjin/rlox/src/bytecode/compiler.rs @@ -1,6 +1,6 @@ use super::chunk::Chunk; use super::errors::{Error, ErrorKind, LoxResult}; -use super::interner::Interner; +use super::interner::{InternedStr, Interner}; use super::opcode::OpCode; use super::value::Value; use crate::scanner::{self, Token, TokenKind}; @@ -182,8 +182,30 @@ impl<T: Iterator<Item = Token>> Compiler<T> { self.parse_precedence(Precedence::Assignment) } + fn var_declaration(&mut self) -> LoxResult<()> { + let global = self.parse_variable()?; + + if self.match_token(&TokenKind::Equal) { + self.expression()?; + } else { + self.emit_op(OpCode::OpNil); + } + + self.expect_semicolon("expect ';' after variable declaration")?; + self.define_variable(global) + } + + fn define_variable(&mut self, var: usize) -> LoxResult<()> { + self.emit_op(OpCode::OpDefineGlobal(var)); + Ok(()) + } + fn declaration(&mut self) -> LoxResult<()> { - self.statement()?; + if self.match_token(&TokenKind::Var) { + self.var_declaration()?; + } else { + self.statement()?; + } if self.panic { self.synchronise(); @@ -202,22 +224,14 @@ impl<T: Iterator<Item = Token>> Compiler<T> { fn print_statement(&mut self) -> LoxResult<()> { self.expression()?; - consume!( - self, - TokenKind::Semicolon, - ErrorKind::ExpectedToken("Expected ';' after value") - ); + self.expect_semicolon("expect ';' after print statement")?; self.emit_op(OpCode::OpPrint); Ok(()) } fn expression_statement(&mut self) -> LoxResult<()> { self.expression()?; - consume!( - self, - TokenKind::Semicolon, - ErrorKind::ExpectedToken("Expected ';' after expression") - ); + self.expect_semicolon("expect ';' after expression")?; self.emit_op(OpCode::OpPop); Ok(()) } @@ -346,6 +360,34 @@ impl<T: Iterator<Item = Token>> Compiler<T> { Ok(()) } + fn identifier_str( + &mut self, + token_fn: fn(&Self) -> &Token, + ) -> LoxResult<InternedStr> { + let ident = match &token_fn(self).kind { + TokenKind::Identifier(ident) => ident.to_string(), + _ => { + return Err(Error { + line: self.current().line, + kind: ErrorKind::ExpectedToken("Expected identifier"), + }) + } + }; + + Ok(self.strings.intern(ident)) + } + + fn parse_variable(&mut self) -> LoxResult<usize> { + consume!( + self, + TokenKind::Identifier(_), + ErrorKind::ExpectedToken("expected identifier") + ); + + let id = self.identifier_str(Self::previous)?; + Ok(self.emit_constant(Value::String(id.into()))) + } + fn current_chunk(&mut self) -> &mut Chunk { &mut self.chunk } @@ -367,9 +409,10 @@ impl<T: Iterator<Item = Token>> Compiler<T> { self.current_chunk().add_op(op, line); } - fn emit_constant(&mut self, val: Value) { + fn emit_constant(&mut self, val: Value) -> usize { let idx = self.chunk.add_constant(val); self.emit_op(OpCode::OpConstant(idx)); + idx } fn previous(&self) -> &Token { @@ -430,6 +473,11 @@ impl<T: Iterator<Item = Token>> Compiler<T> { } } } + + fn expect_semicolon(&mut self, msg: &'static str) -> LoxResult<()> { + consume!(self, TokenKind::Semicolon, ErrorKind::ExpectedToken(msg)); + Ok(()) + } } pub fn compile(code: &str) -> Result<(Interner, Chunk), Vec<Error>> { |