diff options
author | Vincent Ambo <mail@tazj.in> | 2021-03-02T11·11+0200 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2021-03-02T19·48+0000 |
commit | 432e7a7dddf56224297285c9f47f0aa3963eb5b5 (patch) | |
tree | de3ee9a64b116e43f4ea4911e27d9a58603de9b7 /users/tazjin/rlox/src/bytecode/compiler.rs | |
parent | bcea8e0d169974ba57a54ca098f480d6294a7fb1 (diff) |
feat(tazjin/rlox): Intern all string constants r/2263
This is again a step closer to the book, but there are some notable differences: * Only constants encountered by the compiler are interned, all other string operations (well, concatenation) happen with heap objects. * OpReturn will always ensure that a returned string value is newly heap allocated and does not reference the interner. Change-Id: If4f04309446e01b8ff2db51094e9710d465dbc50 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2582 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin/rlox/src/bytecode/compiler.rs')
-rw-r--r-- | users/tazjin/rlox/src/bytecode/compiler.rs | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs index 39bb2f4907a7..ae38654c5d38 100644 --- a/users/tazjin/rlox/src/bytecode/compiler.rs +++ b/users/tazjin/rlox/src/bytecode/compiler.rs @@ -1,5 +1,6 @@ use super::chunk::Chunk; use super::errors::{Error, ErrorKind, LoxResult}; +use super::interner::Interner; use super::opcode::OpCode; use super::value::Value; use crate::scanner::{self, Token, TokenKind}; @@ -12,8 +13,8 @@ struct Compiler<T: Iterator<Item = Token>> { chunk: Chunk, panic: bool, errors: Vec<Error>, + strings: Interner, - // TODO(tazjin): Restructure so that these don't need to be Option? current: Option<Token>, previous: Option<Token>, } @@ -146,7 +147,7 @@ fn rule_for<T: Iterator<Item = Token>>(token: &TokenKind) -> ParseRule<T> { TokenKind::String(_) => { ParseRule::new(Some(Compiler::string), None, Precedence::None) - }, + } _ => ParseRule::new(None, None, Precedence::None), } @@ -260,13 +261,13 @@ impl<T: Iterator<Item = Token>> Compiler<T> { } fn string(&mut self) -> LoxResult<()> { - match &self.previous().kind { - TokenKind::String(s) => { - let s = s.clone(); - self.emit_constant(Value::String(s)); - } + let val = match &self.previous().kind { + TokenKind::String(s) => s.clone(), _ => unreachable!("only called for strings"), - } + }; + + let id = self.strings.intern(val); + self.emit_constant(Value::String(id.into())); Ok(()) } @@ -353,7 +354,7 @@ impl<T: Iterator<Item = Token>> Compiler<T> { } } -pub fn compile(code: &str) -> Result<Chunk, Vec<Error>> { +pub fn compile(code: &str) -> Result<(Interner, Chunk), Vec<Error>> { let chars = code.chars().collect::<Vec<char>>(); let tokens = scanner::scan(&chars).map_err(|errors| { errors.into_iter().map(Into::into).collect::<Vec<Error>>() @@ -364,6 +365,7 @@ pub fn compile(code: &str) -> Result<Chunk, Vec<Error>> { chunk: Default::default(), panic: false, errors: vec![], + strings: Interner::with_capacity(1024), current: None, previous: None, }; @@ -371,7 +373,7 @@ pub fn compile(code: &str) -> Result<Chunk, Vec<Error>> { compiler.compile()?; if compiler.errors.is_empty() { - Ok(compiler.chunk) + Ok((compiler.strings, compiler.chunk)) } else { Err(compiler.errors) } |