about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-01-18T17·27+0300
committertazjin <mail@tazj.in>2021-01-19T09·57+0000
commit5868d4bd49a7b80a395f1ecabedeb0b8f4ddffce (patch)
tree7f9b786e665f7ea103b256d9cab92bbb982d4770
parent2d136e03279e481021a23948fdf5556f25394cd3 (diff)
refactor(tazjin/rlox): Prepare scanner for shared use r/2132
In the book, the clox interpreter has its own scanner which uses a
pull-based model for a single pass compiler.

I can't be bothered to write another scanner, or amend this one into
pull-mode to work with the treewalk interpreter, so instead I will
just reuse it and pull from a vector of tokens.

The tokens are shared between both interpreters and the scanner is not
what I'm interested in here.

Change-Id: Ib07e89127fce2b047f9b3e1ff7e9908d798b3b2b
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2420
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
-rw-r--r--users/tazjin/rlox/src/main.rs1
-rw-r--r--users/tazjin/rlox/src/scanner.rs (renamed from users/tazjin/rlox/src/treewalk/scanner.rs)21
-rw-r--r--users/tazjin/rlox/src/treewalk/errors.rs18
-rw-r--r--users/tazjin/rlox/src/treewalk/interpreter.rs4
-rw-r--r--users/tazjin/rlox/src/treewalk/mod.rs3
5 files changed, 35 insertions, 12 deletions
diff --git a/users/tazjin/rlox/src/main.rs b/users/tazjin/rlox/src/main.rs
index c9cc96d2e6..3a956833c1 100644
--- a/users/tazjin/rlox/src/main.rs
+++ b/users/tazjin/rlox/src/main.rs
@@ -5,6 +5,7 @@ use std::io::Write;
 use std::process;
 
 mod bytecode;
+mod scanner;
 mod treewalk;
 
 /// Trait for making the different interpreters callable in the same
diff --git a/users/tazjin/rlox/src/treewalk/scanner.rs b/users/tazjin/rlox/src/scanner.rs
index af90754841..314b56d6d3 100644
--- a/users/tazjin/rlox/src/treewalk/scanner.rs
+++ b/users/tazjin/rlox/src/scanner.rs
@@ -1,5 +1,3 @@
-use crate::treewalk::errors::{Error, ErrorKind};
-
 #[derive(Clone, Debug, PartialEq)]
 pub enum TokenKind {
     // Single-character tokens.
@@ -59,10 +57,15 @@ pub struct Token {
     pub line: usize,
 }
 
+pub enum ScannerError {
+    UnexpectedChar { line: usize, unexpected: char },
+    UnterminatedString { line: usize },
+}
+
 struct Scanner<'a> {
     source: &'a [char],
     tokens: Vec<Token>,
-    errors: Vec<Error>,
+    errors: Vec<ScannerError>,
     start: usize,   // offset of first character in current lexeme
     current: usize, // current offset into source
     line: usize,    // current line in source
@@ -131,9 +134,9 @@ impl<'a> Scanner<'a> {
 
             chr if chr.is_alphabetic() || chr == '_' => self.scan_identifier(),
 
-            unexpected => self.errors.push(Error {
+            unexpected => self.errors.push(ScannerError::UnexpectedChar {
                 line: self.line,
-                kind: ErrorKind::UnexpectedChar(unexpected),
+                unexpected,
             }),
         };
     }
@@ -181,10 +184,8 @@ impl<'a> Scanner<'a> {
         }
 
         if self.is_at_end() {
-            self.errors.push(Error {
-                line: self.line,
-                kind: ErrorKind::UnterminatedString,
-            });
+            self.errors
+                .push(ScannerError::UnterminatedString { line: self.line });
             return;
         }
 
@@ -263,7 +264,7 @@ impl<'a> Scanner<'a> {
     }
 }
 
-pub fn scan<'a>(input: &'a [char]) -> Result<Vec<Token>, Vec<Error>> {
+pub fn scan<'a>(input: &'a [char]) -> Result<Vec<Token>, Vec<ScannerError>> {
     let mut scanner = Scanner {
         source: &input,
         tokens: vec![],
diff --git a/users/tazjin/rlox/src/treewalk/errors.rs b/users/tazjin/rlox/src/treewalk/errors.rs
index 54d2718eed..391663d51b 100644
--- a/users/tazjin/rlox/src/treewalk/errors.rs
+++ b/users/tazjin/rlox/src/treewalk/errors.rs
@@ -1,4 +1,6 @@
+use crate::scanner::ScannerError;
 use crate::treewalk::interpreter::Value;
+
 use std::fmt;
 
 #[derive(Debug)]
@@ -39,3 +41,19 @@ impl fmt::Display for Error {
         write!(f, "[line {}] Error: {:?}", self.line, self.kind)
     }
 }
+
+impl From<ScannerError> for Error {
+    fn from(err: ScannerError) -> Self {
+        match err {
+            ScannerError::UnexpectedChar { line, unexpected } => Error {
+                line,
+                kind: ErrorKind::UnexpectedChar(unexpected),
+            },
+
+            ScannerError::UnterminatedString { line } => Error {
+                line,
+                kind: ErrorKind::UnterminatedString,
+            },
+        }
+    }
+}
diff --git a/users/tazjin/rlox/src/treewalk/interpreter.rs b/users/tazjin/rlox/src/treewalk/interpreter.rs
index 1263e6cb81..3285775bbe 100644
--- a/users/tazjin/rlox/src/treewalk/interpreter.rs
+++ b/users/tazjin/rlox/src/treewalk/interpreter.rs
@@ -200,7 +200,9 @@ impl Lox for Interpreter {
     fn interpret(&mut self, code: String) -> Result<Value, Vec<Error>> {
         let chars: Vec<char> = code.chars().collect();
 
-        let mut program = scanner::scan(&chars).and_then(|tokens| parser::parse(tokens))?;
+        let mut program = scanner::scan(&chars)
+            .map_err(|errors| errors.into_iter().map(Into::into).collect())
+            .and_then(|tokens| parser::parse(tokens))?;
 
         let globals = self
             .env
diff --git a/users/tazjin/rlox/src/treewalk/mod.rs b/users/tazjin/rlox/src/treewalk/mod.rs
index d53bd13f8e..2d82b3320a 100644
--- a/users/tazjin/rlox/src/treewalk/mod.rs
+++ b/users/tazjin/rlox/src/treewalk/mod.rs
@@ -1,5 +1,6 @@
+use crate::scanner;
+
 mod errors;
 pub mod interpreter;
 mod parser;
 mod resolver;
-mod scanner;