about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-02-27T12·18+0200
committertazjin <mail@tazj.in>2021-02-27T13·05+0000
commitee974b3eddffa47d0d16beeada6658f37a21a8d4 (patch)
treef15fbf315a39c7dcfa84097778cb3f3bbdf78c42
parentda2dfb42c6c1cb3a63686be06e9ff04f445506b2 (diff)
feat(tazjin/rlox): Bootstrap rough shape of bytecode compiler r/2237
This one necessarily has to diverge more from the book than the
treewalk interpreter did, so some of this is expected to change, but
I'm happy with the rough shape.

Since we're reusing the old scanner, the compiler/parser struct owns
an iterator over all tokens with which the pull-scanner from the
bytecode chapters is simulated.

Change-Id: Icfa0bd4729d9df786e08f7e49a25cba1b9989a91
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2556
Tested-by: BuildkiteCI
Reviewed-by: tazjin <mail@tazj.in>
-rw-r--r--users/tazjin/rlox/src/bytecode/compiler.rs84
-rw-r--r--users/tazjin/rlox/src/bytecode/errors.rs1
-rw-r--r--users/tazjin/rlox/src/bytecode/mod.rs3
3 files changed, 87 insertions, 1 deletions
diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs
new file mode 100644
index 000000000000..0197885a52d2
--- /dev/null
+++ b/users/tazjin/rlox/src/bytecode/compiler.rs
@@ -0,0 +1,84 @@
+use super::chunk::Chunk;
+use super::errors::{Error, ErrorKind, LoxResult};
+use super::opcode::OpCode;
+use crate::scanner;
+
+struct Compiler<T: Iterator<Item = scanner::Token>> {
+    // panic: bool,
+    errors: Vec<Error>,
+    tokens: T,
+    chunk: Chunk,
+
+    // TODO(tazjin): Restructure so that these don't need to be Option?
+    current: Option<scanner::Token>,
+    previous: Option<scanner::Token>,
+}
+
+impl<T: Iterator<Item = scanner::Token>> Compiler<T> {
+    fn compile(&mut self) -> LoxResult<()> {
+        self.advance();
+        self.expression();
+        self.consume(
+            &scanner::TokenKind::Eof,
+            ErrorKind::ExpectedToken("Expected end of expression"),
+        )?;
+
+        self.end_compiler()
+    }
+
+    fn advance(&mut self) {
+        self.previous = self.current.take();
+        self.current = self.tokens.next();
+    }
+
+    fn expression(&mut self) {
+        unimplemented!()
+    }
+
+    fn consume(
+        &mut self,
+        expected: &scanner::TokenKind,
+        err: ErrorKind,
+    ) -> LoxResult<()> {
+        unimplemented!()
+    }
+
+    fn current_chunk(&mut self) -> &mut Chunk {
+        &mut self.chunk
+    }
+
+    fn end_compiler(&mut self) -> LoxResult<()> {
+        let line = self.previous().line;
+        self.current_chunk().add_op(OpCode::OpReturn, line);
+        Ok(())
+    }
+
+    fn previous(&self) -> &scanner::Token {
+        self.previous
+            .as_ref()
+            .expect("invalid internal compiler state: missing previous token")
+    }
+}
+
+pub fn compile(code: &str) -> Result<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>>()
+    })?;
+
+    let mut compiler = Compiler {
+        tokens: tokens.into_iter().peekable(),
+        errors: vec![],
+        current: None,
+        previous: None,
+        chunk: Default::default(),
+    };
+
+    compiler.compile()?;
+
+    if compiler.errors.is_empty() {
+        Ok(unimplemented!())
+    } else {
+        Err(compiler.errors)
+    }
+}
diff --git a/users/tazjin/rlox/src/bytecode/errors.rs b/users/tazjin/rlox/src/bytecode/errors.rs
index 99b2aa406c99..4d6daff0f3f0 100644
--- a/users/tazjin/rlox/src/bytecode/errors.rs
+++ b/users/tazjin/rlox/src/bytecode/errors.rs
@@ -6,6 +6,7 @@ use std::fmt;
 pub enum ErrorKind {
     UnexpectedChar(char),
     UnterminatedString,
+    ExpectedToken(&'static str),
     InternalError(&'static str),
 }
 
diff --git a/users/tazjin/rlox/src/bytecode/mod.rs b/users/tazjin/rlox/src/bytecode/mod.rs
index 34ceaf28bfa4..362d8bb1252f 100644
--- a/users/tazjin/rlox/src/bytecode/mod.rs
+++ b/users/tazjin/rlox/src/bytecode/mod.rs
@@ -3,6 +3,7 @@
 //! https://craftinginterpreters.com/chunks-of-bytecode.html
 
 mod chunk;
+mod compiler;
 mod errors;
 mod opcode;
 mod value;
@@ -20,7 +21,7 @@ impl crate::Lox for Interpreter {
     }
 
     fn interpret(&mut self, code: String) -> Result<Self::Value, Vec<Self::Error>> {
-        let chunk: Chunk = Default::default();
+        let chunk = compiler::compile(&code)?;
         vm::interpret(chunk).map_err(|e| vec![e])
     }
 }