feat(tazjin/rlox): Implement global variable definition
identifier_str might look a bit overengineered, but we want to reuse this bit of code and it needs a reference to the token from which to pick the identifier. The problem with this is that the token would be owned by self, but the function needs to mutate (the interner), so this implementation is the most straightforward way of acquiring and working with an immutable reference to the token before interning the identifier. Change-Id: I618ce8f789cb59b3a9c5b79a13111ea6d00b2424 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2592 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
This commit is contained in:
parent
b7b94335cc
commit
29b2a54705
5 changed files with 80 additions and 15 deletions
|
|
@ -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>> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue