about summary refs log tree commit diff
path: root/users/tazjin/rlox/src/bytecode
diff options
context:
space:
mode:
Diffstat (limited to 'users/tazjin/rlox/src/bytecode')
-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])
     }
 }