refactor(tazjin/rlox): Prepare scanner for shared use
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
This commit is contained in:
		
							parent
							
								
									2d136e0327
								
							
						
					
					
						commit
						5868d4bd49
					
				
					 5 changed files with 35 additions and 12 deletions
				
			
		| 
						 | 
					@ -5,6 +5,7 @@ use std::io::Write;
 | 
				
			||||||
use std::process;
 | 
					use std::process;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod bytecode;
 | 
					mod bytecode;
 | 
				
			||||||
 | 
					mod scanner;
 | 
				
			||||||
mod treewalk;
 | 
					mod treewalk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Trait for making the different interpreters callable in the same
 | 
					/// Trait for making the different interpreters callable in the same
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,3 @@
 | 
				
			||||||
use crate::treewalk::errors::{Error, ErrorKind};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Debug, PartialEq)]
 | 
					#[derive(Clone, Debug, PartialEq)]
 | 
				
			||||||
pub enum TokenKind {
 | 
					pub enum TokenKind {
 | 
				
			||||||
    // Single-character tokens.
 | 
					    // Single-character tokens.
 | 
				
			||||||
| 
						 | 
					@ -59,10 +57,15 @@ pub struct Token {
 | 
				
			||||||
    pub line: usize,
 | 
					    pub line: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum ScannerError {
 | 
				
			||||||
 | 
					    UnexpectedChar { line: usize, unexpected: char },
 | 
				
			||||||
 | 
					    UnterminatedString { line: usize },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Scanner<'a> {
 | 
					struct Scanner<'a> {
 | 
				
			||||||
    source: &'a [char],
 | 
					    source: &'a [char],
 | 
				
			||||||
    tokens: Vec<Token>,
 | 
					    tokens: Vec<Token>,
 | 
				
			||||||
    errors: Vec<Error>,
 | 
					    errors: Vec<ScannerError>,
 | 
				
			||||||
    start: usize,   // offset of first character in current lexeme
 | 
					    start: usize,   // offset of first character in current lexeme
 | 
				
			||||||
    current: usize, // current offset into source
 | 
					    current: usize, // current offset into source
 | 
				
			||||||
    line: usize,    // current line in source
 | 
					    line: usize,    // current line in source
 | 
				
			||||||
| 
						 | 
					@ -131,9 +134,9 @@ impl<'a> Scanner<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            chr if chr.is_alphabetic() || chr == '_' => self.scan_identifier(),
 | 
					            chr if chr.is_alphabetic() || chr == '_' => self.scan_identifier(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            unexpected => self.errors.push(Error {
 | 
					            unexpected => self.errors.push(ScannerError::UnexpectedChar {
 | 
				
			||||||
                line: self.line,
 | 
					                line: self.line,
 | 
				
			||||||
                kind: ErrorKind::UnexpectedChar(unexpected),
 | 
					                unexpected,
 | 
				
			||||||
            }),
 | 
					            }),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -181,10 +184,8 @@ impl<'a> Scanner<'a> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.is_at_end() {
 | 
					        if self.is_at_end() {
 | 
				
			||||||
            self.errors.push(Error {
 | 
					            self.errors
 | 
				
			||||||
                line: self.line,
 | 
					                .push(ScannerError::UnterminatedString { line: self.line });
 | 
				
			||||||
                kind: ErrorKind::UnterminatedString,
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
            return;
 | 
					            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 {
 | 
					    let mut scanner = Scanner {
 | 
				
			||||||
        source: &input,
 | 
					        source: &input,
 | 
				
			||||||
        tokens: vec![],
 | 
					        tokens: vec![],
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,6 @@
 | 
				
			||||||
 | 
					use crate::scanner::ScannerError;
 | 
				
			||||||
use crate::treewalk::interpreter::Value;
 | 
					use crate::treewalk::interpreter::Value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::fmt;
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
| 
						 | 
					@ -39,3 +41,19 @@ impl fmt::Display for Error {
 | 
				
			||||||
        write!(f, "[line {}] Error: {:?}", self.line, self.kind)
 | 
					        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,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,7 +200,9 @@ impl Lox for Interpreter {
 | 
				
			||||||
    fn interpret(&mut self, code: String) -> Result<Value, Vec<Error>> {
 | 
					    fn interpret(&mut self, code: String) -> Result<Value, Vec<Error>> {
 | 
				
			||||||
        let chars: Vec<char> = code.chars().collect();
 | 
					        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
 | 
					        let globals = self
 | 
				
			||||||
            .env
 | 
					            .env
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
 | 
					use crate::scanner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod errors;
 | 
					mod errors;
 | 
				
			||||||
pub mod interpreter;
 | 
					pub mod interpreter;
 | 
				
			||||||
mod parser;
 | 
					mod parser;
 | 
				
			||||||
mod resolver;
 | 
					mod resolver;
 | 
				
			||||||
mod scanner;
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue