├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── builtins.rs ├── bytecode.rs ├── bytecode_interpreter.rs ├── compiler.rs ├── debugger.rs ├── error_formatting.rs ├── expr.rs ├── extensions.rs ├── gc.rs ├── input.rs ├── line_reader.rs ├── main.rs ├── parser.rs ├── repl.rs ├── scanner.rs ├── treewalk_interpreter.rs └── value.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ trunk ] 6 | pull_request: 7 | branches: [ trunk ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | *~ 3 | Cargo.lock 4 | .repl-history.txt 5 | .debugger-history.txt -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crafting-interpreters-rs" 3 | version = "0.1.0" 4 | authors = ["Thomas Peters "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | clap = "2.33" 11 | serde = { version = "1.0", features = ["derive"] } 12 | ctrlc = "3.1.7" 13 | rustyline = "8.0.0" 14 | colored = "2" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Thomas D. Peters. All rights reserved. 2 | 3 | Boost Software License - Version 1.0 - August 17th, 2003 4 | 5 | Permission is hereby granted, free of charge, to any person or organization 6 | obtaining a copy of the software and accompanying documentation covered by 7 | this license (the "Software") to use, reproduce, display, distribute, 8 | execute, and transmit the Software, and to prepare derivative works of the 9 | Software, and to permit third-parties to whom the Software is furnished to 10 | do so, all subject to the following: 11 | 12 | The copyright notices in the Software and this entire statement, including 13 | the above license grant, this restriction and the following disclaimer, 14 | must be included in all copies of the Software, in whole or in part, and 15 | all derivative works of the Software, unless such copies or derivative 16 | works are solely in the form of machine-executable object code generated by 17 | a source language processor. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crafting Interpreters in Rust 2 | 3 | Giving https://craftinginterpreters.com/ a try, while learning Rust at the same time. 4 | 5 | ~~Just getting started with both :)~~ 6 | 7 | :crab: :crab: :crab: This now includes two fairly complete implementations of Bob Nystrom's Lox language: one as a tree-walk interpreter, and the other as a bytecode interpreter. The treewalk interpreter does not include a garbage collector (the bytecode interpreter does). The bytecode interpreter is written completely in safe Rust (though an unsafe version would likely be much faster). :crab: :crab: :crab: 8 | 9 | ## Examples 10 | 11 | Consider fib.lox 12 | 13 | ``` 14 | fun fib(n) { 15 | if (n < 2) return n; 16 | return fib(n - 1) + fib(n - 2); 17 | } 18 | 19 | var before = clock(); 20 | print fib(25); 21 | var after = clock(); 22 | print after - before; 23 | ``` 24 | 25 | We can run this in the treewalk interpreter using 26 | 27 | ``` 28 | cargo run --release --quiet -- fib.lox --treewalk 29 | ``` 30 | 31 | On my laptop, this prints a timing of 1755 milliseconds. We can run the same thing in the bytecode interpreter using 32 | 33 | ``` 34 | cargo run --release --quiet -- fib.lox 35 | ``` 36 | 37 | On the same laptop, this shows a timing of 401 milliseconds. 38 | For comparison, on the same laptop, [the tiger compiler](https://github.com/tdp2110/HaskellTiger) 39 | computes the same answer in `0.00s user 0.00s system 4% cpu 0.077 total` (not counting compilation :)). A C compiler, 40 | or tigerc using the llvm backend :), computes this in `0.00s user 0.00s system 65% cpu 0.004 total`. 41 | 42 | Now consider hello_world.lox 43 | 44 | ``` 45 | print "hello world!"; 46 | ``` 47 | 48 | We can tokenize this with 49 | 50 | ``` 51 | cargo run --release --quiet -- hello_world.lox --show-tokens 52 | ``` 53 | 54 | Which gives output 55 | 56 | ``` 57 | [ 58 | Token { ty: Print, lexeme: "print", literal: None, line: 1, col: 4}, 59 | Token { ty: String, lexeme: ""hello world!"", literal: Some(Str("hello world!")), line: 1, col: 19}, 60 | Token { ty: Semicolon, lexeme: ";", literal: None, line: 1, col: 20}, 61 | Token { ty: Eof, lexeme: "", literal: None, line: 1, col: 20}, 62 | ] 63 | ``` 64 | 65 | We can show the AST with 66 | 67 | ``` 68 | cargo run --release --quiet -- hello_world.lox --show-ast 69 | ``` 70 | 71 | Which gives 72 | 73 | ``` 74 | [ 75 | Print( 76 | Literal( 77 | String( 78 | "hello world!", 79 | ), 80 | ), 81 | ), 82 | ] 83 | ``` 84 | 85 | Finally, we can show compiled bytecode with 86 | 87 | ``` 88 | cargo run --release --quiet -- hello_world.lox --disassemble 89 | ``` 90 | 91 | Giving 92 | 93 | ``` 94 | ============ hello_world.lox ============ 95 | ------------ constants ----------- 96 | 0 "hello world!" 97 | 98 | ------------ code ----------------- 99 | 0000 OP_CONSTANT "hello world!" (idx=0) line 1 100 | 0001 OP_PRINT line 1 101 | 0002 OP_NIL line 1 102 | 0003 OP_RETURN line 1 103 | ``` 104 | 105 | ## Debugger 106 | 107 | This project includes a basic (in-progress, possibly never to progress further) debugger. 108 | 109 | For example, consider f.lox 110 | 111 | ``` 112 | fun a() { b(); } 113 | fun b() { c(); } 114 | fun c() { 115 | c("too", "many"); 116 | } 117 | 118 | a(); 119 | ``` 120 | 121 | We can explore this in the debugger with 122 | 123 | ``` 124 | $ cargo run --release --quiet -- f.lox --debug 125 | (loxdb) b 4 126 | inserted breakpoint at line 4 127 | (loxdb) g 128 | reached breakpoint at line 4 129 | (loxdb) list 130 | 2 fun b() { c(); } 131 | 3 fun c() { 132 | ==> 4 c("too", "many"); 133 | 5 } 134 | 6 135 | 7 a(); 136 | 137 | ==> 0000 OP_GET_GLOBAL String("c") (idx=0) line 4 138 | 0001 OP_CONSTANT "too" (idx=1) line 4 139 | 0002 OP_CONSTANT "many" (idx=2) line 4 140 | 0003 OP_CALL 2 line 4 141 | (loxdb) bt 142 | [line 7] in script 143 | [line 1] in a() 144 | [line 2] in b() 145 | [line 4] in c() 146 | (loxdb) g 147 | Lox runtime error: Expected 0 arguments but found 2.. 148 | 149 | Traceback: 150 | 151 | [line 7] in script 152 | [line 1] in a() 153 | [line 2] in b() 154 | [line 4] in c() 155 | ``` 156 | 157 | ## REPL 158 | 159 | A REPL for interactive development is also available, which uses the slower treewalk interpreter. Launch with 160 | 161 | ``` 162 | cargo run --release --quiet 163 | ``` 164 | 165 | Here's an example session: 166 | 167 | ``` 168 | $ cargo run --release --quiet 169 | ============================================ 170 | Welcome to lox! using tree-walk interpreter. 171 | ============================================ 172 | 173 | >>> var x = 42; 174 | >>> fun f(n) { return n + 1; } 175 | >>> f(x); 176 | 43 177 | ``` 178 | 179 | ## Extensions 180 | 181 | Using the `--Xlists` command line switch (eg `cargo run --release --quiet -- --Xlists`), we can enable lists 182 | 183 | ``` 184 | =================================================== 185 | Welcome to lox 0.1.0! Using tree-walk interpreter. 186 | 187 | Authors: Thomas Peters 188 | =================================================== 189 | 190 | >>> var xs = [1,2,3] 191 | >>> xs 192 | [1, 2, 3] 193 | ``` 194 | 195 | Lists don't have much functionality yet, but they have lengths 196 | 197 | ``` 198 | >>> len(xs) 199 | 3 200 | ``` 201 | 202 | can be concatenated 203 | 204 | ``` 205 | >>> var ys = xs + xs 206 | >>> ys 207 | [1, 2, 3, 1, 2, 3] 208 | ``` 209 | 210 | can be mapped over 211 | 212 | ``` 213 | >>> fun square(x) { return x * x; } 214 | >>> map(square, xs) 215 | [1, 4, 9] 216 | >>> 217 | ``` 218 | 219 | can be iterated 220 | 221 | ``` 222 | >>> fun printFun(elt) { print elt; } 223 | >>> forEach(xs, printFun) 224 | 1 225 | 2 226 | 3 227 | ``` 228 | 229 | and also have expected indexing operators 230 | 231 | ``` 232 | >>> xs[0] = -xs[0] 233 | -1 234 | >>> xs 235 | [-1, 2, 3] 236 | ``` 237 | -------------------------------------------------------------------------------- /src/builtins.rs: -------------------------------------------------------------------------------- 1 | use std::time::{SystemTime, UNIX_EPOCH}; 2 | 3 | use crate::bytecode_interpreter; 4 | use crate::value; 5 | 6 | /* 7 | Arity checking is done in the interpreter prior to calling a builtin function. 8 | */ 9 | 10 | pub fn exp( 11 | _interp: &mut bytecode_interpreter::Interpreter, 12 | args: &[value::Value], 13 | ) -> Result { 14 | match args[0] { 15 | value::Value::Number(num) => Ok(value::Value::Number(num.exp())), 16 | _ => Err(format!( 17 | "Invalid call: expected number, got {:?}.", 18 | value::type_of(&args[0]) 19 | )), 20 | } 21 | } 22 | 23 | pub fn sqrt( 24 | _interp: &mut bytecode_interpreter::Interpreter, 25 | args: &[value::Value], 26 | ) -> Result { 27 | match args[0] { 28 | value::Value::Number(num) => Ok(value::Value::Number(num.sqrt())), 29 | _ => Err(format!( 30 | "Invalid call: expected number, got {:?}.", 31 | value::type_of(&args[0]) 32 | )), 33 | } 34 | } 35 | 36 | pub fn clock( 37 | _interp: &mut bytecode_interpreter::Interpreter, 38 | _args: &[value::Value], 39 | ) -> Result { 40 | let start = SystemTime::now(); 41 | let since_the_epoch = start.duration_since(UNIX_EPOCH).unwrap(); 42 | 43 | Ok(value::Value::Number(since_the_epoch.as_millis() as f64)) 44 | } 45 | 46 | pub fn len( 47 | interp: &mut bytecode_interpreter::Interpreter, 48 | args: &[value::Value], 49 | ) -> Result { 50 | match &args[0] { 51 | value::Value::String(id) => Ok(value::Value::Number(interp.heap.get_str(*id).len() as f64)), 52 | value::Value::List(id) => Ok(value::Value::Number( 53 | interp.heap.get_list_elements(*id).len() as f64, 54 | )), 55 | val => Err(format!( 56 | "Ojbect of type {:?} has no len.", 57 | value::type_of(val) 58 | )), 59 | } 60 | } 61 | 62 | pub fn for_each( 63 | interp: &mut bytecode_interpreter::Interpreter, 64 | args: &[value::Value], 65 | ) -> Result { 66 | match &args[0] { 67 | value::Value::List(id) => { 68 | let list_elements = interp.heap.get_list_elements(*id).clone(); 69 | let callable = args[1].clone(); 70 | for element in list_elements.iter() { 71 | interp.stack.push(callable.clone()); 72 | interp.stack.push(element.clone()); 73 | 74 | // stash the current frame number if we're going to call a pure lox function ... 75 | let frame_idx = interp.frames.len(); 76 | 77 | if let Err(bytecode_interpreter::InterpreterError::Runtime(err)) = 78 | interp.call_value(callable.clone(), 1) 79 | { 80 | return Err(err); 81 | } 82 | 83 | // If we're calling a pure lox function, `interp.call_value` doesn't actually 84 | // call the value, it just sets up a call frame. We loop the interpreter 85 | // until it his an error or returns to the call frame with `frame_idx`. 86 | // Unfortunately, this doesn't play well with our current debugger 87 | // implementation, which manually calls `interpreter.step()` 88 | loop { 89 | if interp.frames.len() == frame_idx { 90 | break; 91 | } 92 | 93 | if let Err(bytecode_interpreter::InterpreterError::Runtime(err)) = interp.step() 94 | { 95 | return Err(err); 96 | } 97 | } 98 | } 99 | Ok(value::Value::Nil) 100 | } 101 | val => Err(format!( 102 | "Can't call forEach on value of type {:?}.", 103 | value::type_of(val) 104 | )), 105 | } 106 | } 107 | 108 | pub fn map( 109 | interp: &mut bytecode_interpreter::Interpreter, 110 | args: &[value::Value], 111 | ) -> Result { 112 | match &args[1] { 113 | value::Value::List(id) => { 114 | let list_elements = interp.heap.get_list_elements(*id).clone(); 115 | let callable = args[0].clone(); 116 | let mut res_elements = Vec::new(); 117 | for element in list_elements.iter() { 118 | interp.stack.push(callable.clone()); 119 | interp.stack.push(element.clone()); 120 | 121 | //stash the current frame number if we're going to call a pure lox function ... 122 | let frame_idx = interp.frames.len(); 123 | 124 | if let Err(bytecode_interpreter::InterpreterError::Runtime(err)) = 125 | interp.call_value(callable.clone(), 1) 126 | { 127 | return Err(err); 128 | } 129 | 130 | // If we're calling a pure lox function, `interp.call_value` doesn't actually 131 | // call the value, it just sets up a call frame. We loop the interpreter 132 | // until it his an error or returns to the call frame with `frame_idx`. 133 | // Unfortunately, this doesn't play well with our current debugger 134 | // implementation, which manually calls `interpreter.step()` 135 | loop { 136 | if interp.frames.len() == frame_idx { 137 | break; 138 | } 139 | 140 | if let Err(bytecode_interpreter::InterpreterError::Runtime(err)) = interp.step() 141 | { 142 | return Err(err); 143 | } 144 | } 145 | 146 | res_elements.push(interp.pop_stack()); 147 | } 148 | Ok(value::Value::List(interp.heap.manage_list(res_elements))) 149 | } 150 | val => Err(format!( 151 | "Can't call forEach on value of type {:?}.", 152 | value::type_of(val) 153 | )), 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/bytecode.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use std::f64; 4 | use std::fmt; 5 | 6 | #[derive(Default, Copy, Clone, Debug)] 7 | pub struct Lineno { 8 | pub value: usize, 9 | } 10 | 11 | #[allow(non_snake_case)] 12 | pub fn Lineno(value: usize) -> Lineno { 13 | Lineno { value } 14 | } 15 | 16 | #[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Copy, Clone)] 17 | pub enum UpvalueLoc { 18 | Upvalue(/*upvalue idx*/ usize), 19 | Local(/*stack idx*/ usize), 20 | } 21 | 22 | #[derive(Serialize, Deserialize, Debug, Clone)] 23 | #[serde(untagged)] 24 | pub enum Op { 25 | Return, 26 | Constant(usize), 27 | Closure(usize, Vec), 28 | Nil, 29 | True, 30 | False, 31 | Negate, 32 | Add, 33 | Subtract, 34 | Multiply, 35 | Divide, 36 | Not, 37 | Equal, 38 | Greater, 39 | Less, 40 | Print, 41 | Pop, 42 | DefineGlobal(usize), 43 | GetGlobal(usize), 44 | SetGlobal(usize), 45 | GetLocal(usize), 46 | SetLocal(usize), 47 | GetUpval(usize), 48 | SetUpval(usize), 49 | JumpIfFalse(usize), 50 | Jump(usize), 51 | Loop(usize), 52 | Call(u8), 53 | CloseUpvalue, 54 | Class(usize), 55 | SetProperty(usize), 56 | GetProperty(usize), 57 | Method(usize), 58 | Invoke(/*method_name*/ String, /*arg count*/ u8), 59 | Inherit, 60 | GetSuper(usize), 61 | SuperInvoke(/*method_name*/ String, /*arg count*/ u8), 62 | BuildList(usize), 63 | Subscr, 64 | SetItem, 65 | } 66 | 67 | #[derive(Default, Clone, Debug)] 68 | pub struct Function { 69 | pub arity: u8, 70 | pub chunk: Chunk, 71 | pub name: String, 72 | } 73 | 74 | #[derive(Debug, Clone, Default)] 75 | pub struct Closure { 76 | pub function: Function, 77 | pub upvalues: Vec, 78 | } 79 | 80 | #[derive(Debug, Clone)] 81 | pub enum Constant { 82 | Number(f64), 83 | String(String), 84 | Function(Closure), 85 | } 86 | 87 | impl fmt::Display for Constant { 88 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 89 | match self { 90 | Constant::Number(n) => write!(f, "{}", n), 91 | Constant::String(s) => write!(f, "\"{}\"", s), 92 | Constant::Function(Closure { 93 | function: 94 | Function { 95 | arity: _, 96 | chunk: _, 97 | name, 98 | }, 99 | upvalues: _, 100 | }) => write!(f, "", name), 101 | } 102 | } 103 | } 104 | 105 | #[derive(Debug, Default, Clone)] 106 | pub struct Chunk { 107 | pub code: Vec<(Op, Lineno)>, 108 | pub constants: Vec, 109 | } 110 | 111 | impl Chunk { 112 | pub fn add_constant_number(&mut self, c: f64) -> usize { 113 | if let Some(id) = self.find_number(c) { 114 | id 115 | } else { 116 | self.add_constant(Constant::Number(c)) 117 | } 118 | } 119 | 120 | pub fn add_constant_string(&mut self, s: String) -> usize { 121 | if let Some(id) = self.find_string(&s) { 122 | id 123 | } else { 124 | self.add_constant(Constant::String(s)) 125 | } 126 | } 127 | 128 | pub fn add_constant(&mut self, val: Constant) -> usize { 129 | let const_idx = self.constants.len(); 130 | self.constants.push(val); 131 | const_idx 132 | } 133 | 134 | fn find_string(&self, s: &str) -> Option { 135 | self.constants.iter().position(|c| { 136 | if let Constant::String(s2) = c { 137 | s == s2 138 | } else { 139 | false 140 | } 141 | }) 142 | } 143 | 144 | fn find_number(&self, num: f64) -> Option { 145 | self.constants.iter().position(|c| { 146 | if let Constant::Number(num2) = c { 147 | (num - num2).abs() < f64::EPSILON 148 | } else { 149 | false 150 | } 151 | }) 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/compiler.rs: -------------------------------------------------------------------------------- 1 | use crate::bytecode; 2 | use crate::extensions; 3 | use crate::scanner; 4 | 5 | #[derive(Debug)] 6 | struct Local { 7 | name: scanner::Token, 8 | depth: i64, 9 | is_captured: bool, 10 | } 11 | 12 | struct ClassCompiler { 13 | has_superclass: bool, 14 | } 15 | 16 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] 17 | enum FunctionType { 18 | Function, 19 | Script, 20 | Method, 21 | Initializer, 22 | } 23 | 24 | pub struct Compiler { 25 | tokens: Vec, 26 | token_idx: usize, 27 | levels: Vec, 28 | level_idx: usize, 29 | current_class: Option, 30 | extensions: extensions::Extensions, 31 | } 32 | 33 | impl Default for Compiler { 34 | fn default() -> Compiler { 35 | Compiler { 36 | tokens: Default::default(), 37 | token_idx: 0, 38 | levels: vec![Default::default()], 39 | level_idx: 0, 40 | current_class: None, 41 | extensions: Default::default(), 42 | } 43 | } 44 | } 45 | 46 | pub struct Level { 47 | function: bytecode::Function, 48 | function_type: FunctionType, 49 | locals: Vec, 50 | scope_depth: i64, 51 | upvals: Vec, 52 | } 53 | 54 | impl Default for Level { 55 | fn default() -> Level { 56 | Level { 57 | function: Default::default(), 58 | function_type: FunctionType::Script, 59 | locals: vec![Local { 60 | name: scanner::Token { 61 | ty: scanner::TokenType::Identifier, 62 | lexeme: Default::default(), 63 | literal: Some(scanner::Literal::Identifier("".to_string())), 64 | line: 0, 65 | col: -1, 66 | }, 67 | depth: 0, 68 | is_captured: false, 69 | }], 70 | scope_depth: 0, 71 | upvals: Default::default(), 72 | } 73 | } 74 | } 75 | 76 | #[derive(Eq, PartialEq, PartialOrd, Copy, Clone, Debug)] 77 | enum Precedence { 78 | None, 79 | Assignment, 80 | Or, 81 | And, 82 | Equality, 83 | Comparison, 84 | Term, 85 | Factor, 86 | Unary, 87 | Call, 88 | Primary, 89 | } 90 | 91 | #[derive(Debug, Copy, Clone)] 92 | enum ParseFn { 93 | Grouping, 94 | Unary, 95 | Binary, 96 | Number, 97 | Literal, 98 | String, 99 | Variable, 100 | And, 101 | Or, 102 | Call, 103 | Dot, 104 | This, 105 | Super, 106 | List, 107 | Subscript, 108 | } 109 | 110 | struct ParseRule { 111 | prefix: Option, 112 | infix: Option, 113 | precedence: Precedence, 114 | } 115 | 116 | enum Resolution { 117 | Local(usize), 118 | Global, 119 | Upvalue(usize), 120 | } 121 | 122 | #[derive(Debug)] 123 | pub struct ErrorInfo { 124 | pub what: String, 125 | pub line: usize, 126 | pub col: i64, 127 | } 128 | 129 | #[derive(Debug)] 130 | pub enum Error { 131 | Lexical(scanner::Error), 132 | Parse(ErrorInfo), 133 | Semantic(ErrorInfo), 134 | Internal(String), 135 | } 136 | 137 | impl Compiler { 138 | pub fn compile( 139 | input: String, 140 | extensions: extensions::Extensions, 141 | ) -> Result { 142 | let mut compiler = Compiler { 143 | extensions, 144 | ..Default::default() 145 | }; 146 | 147 | if extensions.lambdas { 148 | return Err(Error::Internal( 149 | "lambdas extension not implemented for bytecode interpreter".to_string(), 150 | )); 151 | } 152 | 153 | match scanner::scan_tokens(input) { 154 | Ok(tokens) => { 155 | compiler.tokens = tokens; 156 | 157 | while !compiler.is_at_end() { 158 | compiler.declaration()?; 159 | } 160 | 161 | compiler.emit_return(); 162 | 163 | Ok(std::mem::take(&mut compiler.current_level_mut().function)) 164 | } 165 | Err(err) => Err(Error::Lexical(err)), 166 | } 167 | } 168 | 169 | fn declaration(&mut self) -> Result<(), Error> { 170 | if self.matches(scanner::TokenType::Class) { 171 | self.class_decl() 172 | } else if self.matches(scanner::TokenType::Fun) { 173 | self.fun_decl() 174 | } else if self.matches(scanner::TokenType::Var) { 175 | self.var_decl() 176 | } else { 177 | self.statement() 178 | } 179 | } 180 | 181 | fn class_decl(&mut self) -> Result<(), Error> { 182 | self.consume(scanner::TokenType::Identifier, "Expected class name.")?; 183 | let class_name_tok = self.previous().clone(); 184 | let class_name = String::from_utf8(class_name_tok.clone().lexeme).unwrap(); 185 | let name_constant = self.identifier_constant(class_name.clone()); 186 | let line = self.previous().line; 187 | self.emit_op(bytecode::Op::Class(name_constant), line); 188 | self.define_variable(name_constant); 189 | 190 | let mut saved_class_compiler = None; 191 | 192 | std::mem::swap(&mut saved_class_compiler, &mut self.current_class); 193 | self.current_class = Some(ClassCompiler { 194 | has_superclass: false, 195 | }); 196 | 197 | if self.matches(scanner::TokenType::Less) { 198 | self.consume(scanner::TokenType::Identifier, "Expected superclass name.")?; 199 | self.variable(false)?; 200 | 201 | if Compiler::identifiers_equal(&class_name_tok.literal, &self.previous().literal) { 202 | return Err(Error::Semantic(ErrorInfo { 203 | what: format!( 204 | "A class cannot inherit from itself. Class name = {}", 205 | class_name 206 | ), 207 | line: self.previous().line, 208 | col: self.previous().col, 209 | })); 210 | } 211 | 212 | self.begin_scope(); 213 | self.add_local(Compiler::synthetic_token("super")); 214 | self.define_variable(0); 215 | 216 | self.named_variable(class_name_tok.clone(), false)?; 217 | self.emit_op(bytecode::Op::Inherit, self.previous().line); 218 | 219 | if let Some(current_class) = &mut self.current_class { 220 | current_class.has_superclass = true; 221 | } else { 222 | panic!() 223 | } 224 | } 225 | 226 | self.named_variable(class_name_tok, false)?; 227 | 228 | self.consume( 229 | scanner::TokenType::LeftBrace, 230 | "Expected '{' before class body.", 231 | )?; 232 | loop { 233 | if self.check(scanner::TokenType::RightBrace) || self.check(scanner::TokenType::Eof) { 234 | break; 235 | } 236 | 237 | self.method()?; 238 | } 239 | self.consume( 240 | scanner::TokenType::RightBrace, 241 | "Expected '}' after class body.", 242 | )?; 243 | self.emit_op(bytecode::Op::Pop, self.previous().line); 244 | 245 | if let Some(current_class) = &self.current_class { 246 | if current_class.has_superclass { 247 | self.end_scope(); 248 | } 249 | } 250 | 251 | std::mem::swap(&mut self.current_class, &mut saved_class_compiler); 252 | 253 | Ok(()) 254 | } 255 | 256 | fn method(&mut self) -> Result<(), Error> { 257 | self.consume(scanner::TokenType::Identifier, "Expected method name.")?; 258 | let method_name = if let Some(scanner::Literal::Identifier(method_name)) = 259 | &self.previous().literal.clone() 260 | { 261 | method_name.clone() 262 | } else { 263 | panic!( 264 | "expected identifier when parsing method, found {:?}", 265 | self.previous() 266 | ); 267 | }; 268 | 269 | let constant = self.identifier_constant(method_name.clone()); 270 | 271 | let function_type = if method_name == "init" { 272 | FunctionType::Initializer 273 | } else { 274 | FunctionType::Method 275 | }; 276 | 277 | self.function(function_type)?; 278 | 279 | self.emit_op(bytecode::Op::Method(constant), self.previous().line); 280 | 281 | Ok(()) 282 | } 283 | 284 | fn fun_decl(&mut self) -> Result<(), Error> { 285 | let global_idx = self.parse_variable("Expected function name.")?; 286 | self.mark_initialized(); 287 | self.function(FunctionType::Function)?; 288 | self.define_variable(global_idx); 289 | Ok(()) 290 | } 291 | 292 | fn function(&mut self, function_type: FunctionType) -> Result<(), Error> { 293 | let level = Level { 294 | function_type, 295 | function: bytecode::Function { 296 | name: if let Some(scanner::Literal::Identifier(funname)) = &self.previous().literal 297 | { 298 | funname.clone() 299 | } else { 300 | panic!("expected identifier"); 301 | }, 302 | ..Default::default() 303 | }, 304 | ..Default::default() 305 | }; 306 | self.push_level(level); 307 | 308 | if function_type != FunctionType::Function { 309 | let local = self.current_level_mut().locals.first_mut().unwrap(); 310 | local.name.literal = Some(scanner::Literal::Identifier("this".to_string())); 311 | } 312 | 313 | self.begin_scope(); 314 | self.consume( 315 | scanner::TokenType::LeftParen, 316 | "Expected '(' after function name.", 317 | )?; 318 | 319 | if !self.check(scanner::TokenType::RightParen) { 320 | loop { 321 | self.current_function_mut().arity += 1; 322 | let param_const_idx = self.parse_variable("Expected parameter name")?; 323 | self.define_variable(param_const_idx); 324 | 325 | if !self.matches(scanner::TokenType::Comma) { 326 | break; 327 | } 328 | } 329 | } 330 | 331 | self.consume( 332 | scanner::TokenType::RightParen, 333 | "Expected ')' after parameter list.", 334 | )?; 335 | 336 | self.consume( 337 | scanner::TokenType::LeftBrace, 338 | "Expected '{' before function body.", 339 | )?; 340 | self.block()?; 341 | self.emit_return(); 342 | 343 | let function = std::mem::take(&mut self.current_level_mut().function); 344 | let upvals = std::mem::take(&mut self.current_level_mut().upvals); 345 | self.pop_level(); 346 | let const_idx = self 347 | .current_chunk() 348 | .add_constant(bytecode::Constant::Function(bytecode::Closure { 349 | function, 350 | upvalues: Vec::new(), 351 | })); 352 | self.emit_op( 353 | bytecode::Op::Closure(const_idx, upvals), 354 | self.previous().line, 355 | ); 356 | 357 | Ok(()) 358 | } 359 | 360 | fn var_decl(&mut self) -> Result<(), Error> { 361 | let global_idx = self.parse_variable("Expected variable name.")?; 362 | 363 | if self.matches(scanner::TokenType::Equal) { 364 | self.expression()?; 365 | } else { 366 | let line = self.previous().line; 367 | self.emit_op(bytecode::Op::Nil, line) 368 | } 369 | 370 | self.consume( 371 | scanner::TokenType::Semicolon, 372 | "Expected ';' after variable declaration", 373 | )?; 374 | 375 | self.define_variable(global_idx); 376 | Ok(()) 377 | } 378 | 379 | fn mark_initialized(&mut self) -> bool { 380 | let scope_depth = self.scope_depth(); 381 | if scope_depth > 0 { 382 | if let Some(last) = self.locals_mut().last_mut() { 383 | last.depth = scope_depth; 384 | } else { 385 | panic!("expected nonempty locals!"); 386 | } 387 | true 388 | } else { 389 | false 390 | } 391 | } 392 | 393 | fn define_variable(&mut self, global_idx: usize) { 394 | if self.mark_initialized() { 395 | return; 396 | } 397 | let line = self.previous().line; 398 | self.emit_op(bytecode::Op::DefineGlobal(global_idx), line); 399 | } 400 | 401 | fn declare_variable(&mut self) -> Result<(), Error> { 402 | //global variables are implicitly declared 403 | if self.scope_depth() == 0 { 404 | return Ok(()); 405 | } 406 | 407 | let name = self.previous().clone(); 408 | 409 | let has_redeclaration = self.locals().iter().rev().any(|local| { 410 | local.depth != -1 411 | && local.depth == self.scope_depth() 412 | && Compiler::identifiers_equal(&local.name.literal, &name.literal) 413 | }); 414 | if has_redeclaration { 415 | return Err(Error::Semantic(ErrorInfo { 416 | what: format!( 417 | "Redeclaration of variable {} in the same scope.", 418 | String::from_utf8(name.lexeme).unwrap() 419 | ), 420 | line: self.previous().line, 421 | col: self.previous().col, 422 | })); 423 | } 424 | 425 | self.add_local(name); 426 | Ok(()) 427 | } 428 | 429 | fn identifiers_equal(id1: &Option, id2: &Option) -> bool { 430 | match (id1, id2) { 431 | ( 432 | Some(scanner::Literal::Identifier(name1)), 433 | Some(scanner::Literal::Identifier(name2)), 434 | ) => name1 == name2, 435 | _ => { 436 | panic!( 437 | "expected identifier in `identifiers_equal` but found {:?} and {:?}.", 438 | id1, id2 439 | ); 440 | } 441 | } 442 | } 443 | 444 | fn identifier_equal(id1: &Option, name2: &str) -> bool { 445 | match id1 { 446 | Some(scanner::Literal::Identifier(name1)) => name1 == name2, 447 | _ => { 448 | panic!( 449 | "expected identifier in `identifier_equal` but found {:?}.", 450 | id1 451 | ); 452 | } 453 | } 454 | } 455 | 456 | fn synthetic_token(text: &str) -> scanner::Token { 457 | scanner::Token { 458 | ty: scanner::TokenType::Identifier, 459 | lexeme: text.as_bytes().to_vec(), 460 | literal: Some(scanner::Literal::Identifier(String::from(text))), 461 | line: 0, 462 | col: -1, 463 | } 464 | } 465 | 466 | fn add_local(&mut self, name: scanner::Token) { 467 | self.locals_mut().push(Local { 468 | name, 469 | depth: -1, // declare undefined 470 | is_captured: false, 471 | }); 472 | } 473 | 474 | fn parse_variable(&mut self, error_msg: &str) -> Result { 475 | self.consume(scanner::TokenType::Identifier, error_msg)?; 476 | self.declare_variable()?; 477 | 478 | if self.scope_depth() > 0 { 479 | return Ok(0); 480 | } 481 | 482 | if let Some(scanner::Literal::Identifier(name)) = &self.previous().literal.clone() { 483 | Ok(self.identifier_constant(name.clone())) 484 | } else { 485 | panic!( 486 | "expected identifier when parsing variable, found {:?}", 487 | self.previous() 488 | ); 489 | } 490 | } 491 | 492 | fn identifier_constant(&mut self, name: String) -> usize { 493 | self.current_chunk().add_constant_string(name) 494 | } 495 | 496 | fn statement(&mut self) -> Result<(), Error> { 497 | if self.matches(scanner::TokenType::Print) { 498 | self.print_statement()?; 499 | } else if self.matches(scanner::TokenType::For) { 500 | self.for_statement()?; 501 | } else if self.matches(scanner::TokenType::If) { 502 | self.if_statement()?; 503 | } else if self.matches(scanner::TokenType::Return) { 504 | self.return_statement()?; 505 | } else if self.matches(scanner::TokenType::While) { 506 | self.while_statement()?; 507 | } else if self.matches(scanner::TokenType::LeftBrace) { 508 | self.begin_scope(); 509 | self.block()?; 510 | self.end_scope(); 511 | } else { 512 | self.expression_statement()?; 513 | } 514 | Ok(()) 515 | } 516 | 517 | fn return_statement(&mut self) -> Result<(), Error> { 518 | if self.function_type() == FunctionType::Script { 519 | return Err(Error::Semantic(ErrorInfo { 520 | what: "Cannot return from top-level code.".to_string(), 521 | line: self.previous().line, 522 | col: self.previous().col, 523 | })); 524 | } 525 | 526 | if self.matches(scanner::TokenType::Semicolon) { 527 | self.emit_return(); 528 | } else { 529 | self.expression()?; 530 | self.consume( 531 | scanner::TokenType::Semicolon, 532 | "Expected ';' after return value.", 533 | )?; 534 | self.emit_op(bytecode::Op::Return, self.previous().line); 535 | } 536 | Ok(()) 537 | } 538 | 539 | fn for_statement(&mut self) -> Result<(), Error> { 540 | self.begin_scope(); 541 | self.consume(scanner::TokenType::LeftParen, "Expected '(' after 'for'.")?; 542 | if self.matches(scanner::TokenType::Semicolon) { 543 | } else if self.matches(scanner::TokenType::Var) { 544 | self.var_decl()?; 545 | } else { 546 | self.expression_statement()?; 547 | } 548 | 549 | let mut loop_start = self.current_chunk().code.len(); 550 | 551 | // condition 552 | let mut maybe_exit_jump = None; 553 | if !self.matches(scanner::TokenType::Semicolon) { 554 | self.expression()?; 555 | self.consume( 556 | scanner::TokenType::Semicolon, 557 | "Expected ';' after loop condition", 558 | )?; 559 | maybe_exit_jump = Some(self.emit_jump(bytecode::Op::JumpIfFalse(/*placeholder*/ 0))); 560 | self.emit_op(bytecode::Op::Pop, self.previous().line); 561 | } 562 | let maybe_exit_jump = maybe_exit_jump; 563 | 564 | // increment 565 | if !self.matches(scanner::TokenType::RightParen) { 566 | let body_jump = self.emit_jump(bytecode::Op::Jump(/*placeholder*/ 0)); 567 | 568 | let increment_start = self.current_chunk().code.len() + 1; 569 | self.expression()?; 570 | self.emit_op(bytecode::Op::Pop, self.previous().line); 571 | self.consume( 572 | scanner::TokenType::RightParen, 573 | "Expected ')' after for clauses.", 574 | )?; 575 | 576 | self.emit_loop(loop_start); 577 | loop_start = increment_start; 578 | self.patch_jump(body_jump); 579 | } 580 | 581 | self.statement()?; 582 | 583 | self.emit_loop(loop_start); 584 | 585 | if let Some(exit_jump) = maybe_exit_jump { 586 | self.patch_jump(exit_jump); 587 | self.emit_op(bytecode::Op::Pop, self.previous().line); 588 | } 589 | 590 | self.end_scope(); 591 | 592 | Ok(()) 593 | } 594 | 595 | fn while_statement(&mut self) -> Result<(), Error> { 596 | let loop_start = self.current_chunk().code.len(); 597 | self.consume(scanner::TokenType::LeftParen, "Expected '(' after 'while'.")?; 598 | self.expression()?; 599 | self.consume( 600 | scanner::TokenType::RightParen, 601 | "Expected ')' after condition.", 602 | )?; 603 | 604 | let exit_jump = self.emit_jump(bytecode::Op::JumpIfFalse(/*placeholder*/ 0)); 605 | 606 | self.emit_op(bytecode::Op::Pop, self.previous().line); 607 | self.statement()?; 608 | 609 | self.emit_loop(loop_start); 610 | 611 | self.patch_jump(exit_jump); 612 | self.emit_op(bytecode::Op::Pop, self.previous().line); 613 | Ok(()) 614 | } 615 | 616 | fn emit_loop(&mut self, loop_start: usize) { 617 | let offset = self.current_chunk().code.len() - loop_start + 2; 618 | self.emit_op(bytecode::Op::Loop(offset), self.previous().line); 619 | } 620 | 621 | fn if_statement(&mut self) -> Result<(), Error> { 622 | self.consume(scanner::TokenType::LeftParen, "Expected '(' after 'if'.")?; 623 | self.expression()?; 624 | self.consume( 625 | scanner::TokenType::RightParen, 626 | "Expected ')' after condition.", 627 | )?; 628 | 629 | let then_jump = self.emit_jump(bytecode::Op::JumpIfFalse(/*placeholder value*/ 0)); 630 | self.emit_op(bytecode::Op::Pop, self.previous().line); 631 | self.statement()?; 632 | let else_jump = self.emit_jump(bytecode::Op::Jump(/*placeholder value*/ 0)); 633 | 634 | self.patch_jump(then_jump); 635 | self.emit_op(bytecode::Op::Pop, self.previous().line); 636 | 637 | if self.matches(scanner::TokenType::Else) { 638 | self.statement()?; 639 | } 640 | self.patch_jump(else_jump); 641 | 642 | Ok(()) 643 | } 644 | 645 | fn patch_jump(&mut self, jump_location: usize) { 646 | let true_jump = self.current_chunk().code.len() - jump_location - 1; 647 | let (maybe_jump, lineno) = &self.current_chunk().code[jump_location]; 648 | if let bytecode::Op::JumpIfFalse(_) = maybe_jump { 649 | self.current_chunk().code[jump_location] = 650 | (bytecode::Op::JumpIfFalse(true_jump), *lineno); 651 | } else if let bytecode::Op::Jump(_) = maybe_jump { 652 | self.current_chunk().code[jump_location] = (bytecode::Op::Jump(true_jump), *lineno); 653 | } else { 654 | panic!( 655 | "attempted to patch a jump but didn't find a jump! Found {:?}.", 656 | maybe_jump 657 | ); 658 | } 659 | } 660 | 661 | fn emit_jump(&mut self, op: bytecode::Op) -> usize { 662 | self.emit_op(op, self.previous().line); 663 | self.current_chunk().code.len() - 1 664 | } 665 | 666 | fn block(&mut self) -> Result<(), Error> { 667 | while !self.check(scanner::TokenType::RightBrace) && !self.check(scanner::TokenType::Eof) { 668 | self.declaration()?; 669 | } 670 | 671 | self.consume(scanner::TokenType::RightBrace, "Expected '}' after block")?; 672 | 673 | Ok(()) 674 | } 675 | 676 | fn begin_scope(&mut self) { 677 | self.current_level_mut().scope_depth += 1 678 | } 679 | 680 | fn end_scope(&mut self) { 681 | self.current_level_mut().scope_depth -= 1; 682 | 683 | let mut pop_count = 0; 684 | for local in self.locals().iter().rev() { 685 | if local.depth > self.scope_depth() { 686 | pop_count += 1; 687 | } else { 688 | break; 689 | } 690 | } 691 | let pop_count = pop_count; 692 | 693 | let line = self.previous().line; 694 | 695 | for _ in 0..pop_count { 696 | let local = self.locals_mut().pop().unwrap(); 697 | 698 | if local.is_captured { 699 | self.emit_op(bytecode::Op::CloseUpvalue, line); 700 | } else { 701 | self.emit_op(bytecode::Op::Pop, line); 702 | } 703 | } 704 | } 705 | 706 | fn expression_statement(&mut self) -> Result<(), Error> { 707 | self.expression()?; 708 | self.consume( 709 | scanner::TokenType::Semicolon, 710 | "Expected ';' after expression.", 711 | )?; 712 | let line = self.previous().line; 713 | self.emit_op(bytecode::Op::Pop, line); 714 | Ok(()) 715 | } 716 | 717 | fn print_statement(&mut self) -> Result<(), Error> { 718 | self.expression()?; 719 | self.consume(scanner::TokenType::Semicolon, "Expected ';' after value.")?; 720 | self.emit_op(bytecode::Op::Print, self.previous().clone().line); 721 | Ok(()) 722 | } 723 | 724 | fn matches(&mut self, ty: scanner::TokenType) -> bool { 725 | if self.check(ty) { 726 | self.advance(); 727 | return true; 728 | } 729 | false 730 | } 731 | 732 | fn check(&self, ty: scanner::TokenType) -> bool { 733 | if self.is_at_end() { 734 | return false; 735 | } 736 | 737 | self.peek().ty == ty 738 | } 739 | 740 | fn expression(&mut self) -> Result<(), Error> { 741 | self.parse_precedence(Precedence::Assignment) 742 | } 743 | 744 | fn grouping(&mut self, _can_assign: bool) -> Result<(), Error> { 745 | self.expression()?; 746 | 747 | self.consume( 748 | scanner::TokenType::RightParen, 749 | "Expected ')' after expression.", 750 | )?; 751 | Ok(()) 752 | } 753 | 754 | fn number(&mut self, _can_assign: bool) -> Result<(), Error> { 755 | let tok = self.previous().clone(); 756 | 757 | match tok.literal { 758 | Some(scanner::Literal::Number(n)) => { 759 | self.emit_number(n, tok.line); 760 | Ok(()) 761 | } 762 | _ => panic!( 763 | "Expected number at line={},col={}. current token {:?}", 764 | tok.line, tok.col, tok 765 | ), 766 | } 767 | } 768 | 769 | fn literal(&mut self, _can_assign: bool) -> Result<(), Error> { 770 | let tok = self.previous().clone(); 771 | 772 | match tok.ty { 773 | scanner::TokenType::Nil => { 774 | self.emit_op(bytecode::Op::Nil, tok.line); 775 | Ok(()) 776 | } 777 | scanner::TokenType::True => { 778 | self.emit_op(bytecode::Op::True, tok.line); 779 | Ok(()) 780 | } 781 | scanner::TokenType::False => { 782 | self.emit_op(bytecode::Op::False, tok.line); 783 | Ok(()) 784 | } 785 | _ => { 786 | panic!("shouldn't get in literal with tok = {:?}.", tok); 787 | } 788 | } 789 | } 790 | 791 | fn variable(&mut self, can_assign: bool) -> Result<(), Error> { 792 | let tok = self.previous().clone(); 793 | self.named_variable(tok, can_assign) 794 | } 795 | 796 | fn named_variable(&mut self, tok: scanner::Token, can_assign: bool) -> Result<(), Error> { 797 | let name = match tok.ty { 798 | scanner::TokenType::Identifier => { 799 | if let Some(scanner::Literal::Identifier(n)) = tok.literal.clone() { 800 | Some(n) 801 | } else { 802 | None 803 | } 804 | } 805 | scanner::TokenType::This => Some("this".to_string()), 806 | _ => None, 807 | } 808 | .unwrap(); 809 | 810 | let get_op: bytecode::Op; 811 | let set_op: bytecode::Op; 812 | 813 | match self.resolve_variable(&name) { 814 | Ok(Resolution::Local(idx)) => { 815 | get_op = bytecode::Op::GetLocal(idx); 816 | set_op = bytecode::Op::SetLocal(idx); 817 | } 818 | Ok(Resolution::Global) => { 819 | let idx = self.identifier_constant(name); 820 | get_op = bytecode::Op::GetGlobal(idx); 821 | set_op = bytecode::Op::SetGlobal(idx); 822 | } 823 | Ok(Resolution::Upvalue(idx)) => { 824 | get_op = bytecode::Op::GetUpval(idx); 825 | set_op = bytecode::Op::SetUpval(idx); 826 | } 827 | Err(err) => { 828 | return Err(err); 829 | } 830 | } 831 | 832 | if can_assign && self.matches(scanner::TokenType::Equal) { 833 | self.expression()?; 834 | self.emit_op(set_op, tok.line); 835 | } else { 836 | self.emit_op(get_op, tok.line); 837 | } 838 | Ok(()) 839 | } 840 | 841 | fn resolve_variable(&mut self, name: &str) -> Result { 842 | if let Some(idx) = self.resolve_local(name)? { 843 | return Ok(Resolution::Local(idx)); 844 | } 845 | if let Some(idx) = self.resolve_upval(name)? { 846 | return Ok(Resolution::Upvalue(idx)); 847 | } 848 | 849 | Ok(Resolution::Global) 850 | } 851 | 852 | fn resolve_upval(&mut self, name: &str) -> Result, Error> { 853 | if self.level_idx < 1 { 854 | return Ok(None); 855 | } 856 | 857 | let prev_level_idx = self.level_idx - 1; 858 | 859 | if let Some(local_idx) = 860 | Compiler::resolve_local_static(&self.levels[prev_level_idx], name, self.previous())? 861 | { 862 | self.levels[prev_level_idx].locals[local_idx].is_captured = true; 863 | 864 | return Ok(Some(self.add_upval(bytecode::UpvalueLoc::Local(local_idx)))); 865 | } 866 | 867 | self.level_idx -= 1; 868 | 869 | if let Some(upval_idx) = self.resolve_upval(name)? { 870 | self.level_idx += 1; // couldn't figure out how to satisfy borrow checker with scopeguard! 871 | return Ok(Some( 872 | self.add_upval(bytecode::UpvalueLoc::Upvalue(upval_idx)), 873 | )); 874 | } 875 | self.level_idx += 1; 876 | 877 | Ok(None) 878 | } 879 | 880 | fn add_upval(&mut self, upvalue: bytecode::UpvalueLoc) -> usize { 881 | if let Some(res) = self 882 | .current_level() 883 | .upvals 884 | .iter() 885 | .position(|query_upval| *query_upval == upvalue) 886 | { 887 | return res; 888 | } 889 | 890 | self.current_level_mut().upvals.push(upvalue); 891 | self.current_level().upvals.len() - 1 892 | } 893 | 894 | fn resolve_local(&self, name: &str) -> Result, Error> { 895 | Compiler::resolve_local_static(self.current_level(), name, self.previous()) 896 | } 897 | 898 | fn resolve_local_static( 899 | level: &Level, 900 | name: &str, 901 | prev_tok: &scanner::Token, 902 | ) -> Result, Error> { 903 | for (idx, local) in level.locals.iter().rev().enumerate() { 904 | if Compiler::identifier_equal(&local.name.literal, name) { 905 | if local.depth == -1 { 906 | return Err(Compiler::error_at_tok( 907 | "Cannot read local variable in its own initializer.", 908 | prev_tok, 909 | )); 910 | } 911 | return Ok(Some(level.locals.len() - 1 - idx)); 912 | } 913 | } 914 | Ok(None) 915 | } 916 | 917 | fn string(&mut self, _can_assign: bool) -> Result<(), Error> { 918 | let tok = self.previous().clone(); 919 | 920 | match tok.literal { 921 | Some(scanner::Literal::Str(s)) => { 922 | let const_idx = self.current_chunk().add_constant_string(s); 923 | self.emit_op(bytecode::Op::Constant(const_idx), tok.line); 924 | Ok(()) 925 | } 926 | _ => panic!("expected literal when parsing string"), 927 | } 928 | } 929 | 930 | fn binary(&mut self, _can_assign: bool) -> Result<(), Error> { 931 | let operator = self.previous().clone(); 932 | 933 | let rule = Compiler::get_rule(operator.ty); 934 | 935 | self.parse_precedence(Compiler::next_precedence(rule.precedence))?; 936 | 937 | match operator.ty { 938 | scanner::TokenType::Plus => { 939 | self.emit_op(bytecode::Op::Add, operator.line); 940 | Ok(()) 941 | } 942 | scanner::TokenType::Minus => { 943 | self.emit_op(bytecode::Op::Subtract, operator.line); 944 | Ok(()) 945 | } 946 | scanner::TokenType::Star => { 947 | self.emit_op(bytecode::Op::Multiply, operator.line); 948 | Ok(()) 949 | } 950 | scanner::TokenType::Slash => { 951 | self.emit_op(bytecode::Op::Divide, operator.line); 952 | Ok(()) 953 | } 954 | scanner::TokenType::BangEqual => { 955 | self.emit_op(bytecode::Op::Equal, operator.line); 956 | self.emit_op(bytecode::Op::Not, operator.line); 957 | Ok(()) 958 | } 959 | scanner::TokenType::EqualEqual => { 960 | self.emit_op(bytecode::Op::Equal, operator.line); 961 | Ok(()) 962 | } 963 | scanner::TokenType::Greater => { 964 | self.emit_op(bytecode::Op::Greater, operator.line); 965 | Ok(()) 966 | } 967 | scanner::TokenType::GreaterEqual => { 968 | self.emit_op(bytecode::Op::Less, operator.line); 969 | self.emit_op(bytecode::Op::Not, operator.line); 970 | Ok(()) 971 | } 972 | scanner::TokenType::Less => { 973 | self.emit_op(bytecode::Op::Less, operator.line); 974 | Ok(()) 975 | } 976 | scanner::TokenType::LessEqual => { 977 | self.emit_op(bytecode::Op::Greater, operator.line); 978 | self.emit_op(bytecode::Op::Not, operator.line); 979 | Ok(()) 980 | } 981 | _ => Err(Error::Parse(ErrorInfo { 982 | what: format!("Invalid token {:?} in binary expression", operator.ty), 983 | line: operator.line, 984 | col: operator.col, 985 | })), 986 | } 987 | } 988 | 989 | fn and(&mut self, _can_assign: bool) -> Result<(), Error> { 990 | let end_jump = self.emit_jump(bytecode::Op::JumpIfFalse(/*placeholder*/ 0)); 991 | self.emit_op(bytecode::Op::Pop, self.previous().line); 992 | self.parse_precedence(Precedence::And)?; 993 | self.patch_jump(end_jump); 994 | Ok(()) 995 | } 996 | 997 | fn or(&mut self, _can_assign: bool) -> Result<(), Error> { 998 | let else_jump = self.emit_jump(bytecode::Op::JumpIfFalse(/*placeholder*/ 0)); 999 | let end_jump = self.emit_jump(bytecode::Op::Jump(/*placeholder*/ 0)); 1000 | 1001 | self.patch_jump(else_jump); 1002 | self.emit_op(bytecode::Op::Pop, self.previous().line); 1003 | 1004 | self.parse_precedence(Precedence::Or)?; 1005 | self.patch_jump(end_jump); 1006 | Ok(()) 1007 | } 1008 | 1009 | fn call(&mut self, _can_assign: bool) -> Result<(), Error> { 1010 | let arg_count = self.argument_list()?; 1011 | self.emit_op(bytecode::Op::Call(arg_count), self.previous().line); 1012 | Ok(()) 1013 | } 1014 | 1015 | fn super_(&mut self, _can_assign: bool) -> Result<(), Error> { 1016 | let tok = self.previous().clone(); 1017 | match &self.current_class { 1018 | None => { 1019 | return Err(Error::Semantic(ErrorInfo { 1020 | what: "Can't use 'super' outside of a class".to_string(), 1021 | line: tok.line, 1022 | col: tok.col, 1023 | })) 1024 | } 1025 | Some(class) => { 1026 | if !class.has_superclass { 1027 | return Err(Error::Semantic(ErrorInfo { 1028 | what: "Can't use 'super' in a class with no superclass".to_string(), 1029 | line: tok.line, 1030 | col: tok.col, 1031 | })); 1032 | } 1033 | } 1034 | } 1035 | self.consume( 1036 | scanner::TokenType::Dot, 1037 | "Expected '.' after 'super' keyword.", 1038 | )?; 1039 | self.consume( 1040 | scanner::TokenType::Identifier, 1041 | "Expected superclass method name.", 1042 | )?; 1043 | 1044 | let method_name = if let Some(scanner::Literal::Identifier(method_name)) = 1045 | &self.previous().literal.clone() 1046 | { 1047 | method_name.clone() 1048 | } else { 1049 | panic!() 1050 | }; 1051 | 1052 | self.named_variable(Compiler::synthetic_token("this"), false)?; 1053 | 1054 | let op = if self.matches(scanner::TokenType::LeftParen) { 1055 | let arg_count = self.argument_list()?; 1056 | self.named_variable(Compiler::synthetic_token("super"), false)?; 1057 | bytecode::Op::SuperInvoke(method_name, arg_count) 1058 | } else { 1059 | self.named_variable(Compiler::synthetic_token("super"), false)?; 1060 | bytecode::Op::GetSuper(self.identifier_constant(method_name)) 1061 | }; 1062 | self.emit_op(op, self.previous().line); 1063 | Ok(()) 1064 | } 1065 | 1066 | fn this(&mut self, _can_assign: bool) -> Result<(), Error> { 1067 | let tok = self.previous().clone(); 1068 | if self.current_class.is_none() { 1069 | return Err(Error::Semantic(ErrorInfo { 1070 | what: "Cannot use 'this' outside of class.".to_string(), 1071 | line: tok.line, 1072 | col: tok.col, 1073 | })); 1074 | } 1075 | 1076 | self.variable(false) 1077 | } 1078 | 1079 | fn dot(&mut self, can_assign: bool) -> Result<(), Error> { 1080 | self.consume( 1081 | scanner::TokenType::Identifier, 1082 | "Expected property name after '.'.", 1083 | )?; 1084 | let property_name = String::from_utf8(self.previous().clone().lexeme).unwrap(); 1085 | let property_constant = self.identifier_constant(property_name.clone()); 1086 | let op = if can_assign && self.matches(scanner::TokenType::Equal) { 1087 | self.expression()?; 1088 | bytecode::Op::SetProperty(property_constant) 1089 | } else if self.matches(scanner::TokenType::LeftParen) { 1090 | let arg_count = self.argument_list()?; 1091 | bytecode::Op::Invoke(property_name, arg_count) 1092 | } else { 1093 | bytecode::Op::GetProperty(property_constant) 1094 | }; 1095 | self.emit_op(op, self.previous().line); 1096 | Ok(()) 1097 | } 1098 | 1099 | fn subscr(&mut self, _can_assign: bool) -> Result<(), Error> { 1100 | if !self.extensions.lists { 1101 | return Err(Error::Parse(ErrorInfo { 1102 | what: "Unexpected '['".to_string(), 1103 | line: self.previous().line, 1104 | col: self.previous().col, 1105 | })); 1106 | } 1107 | 1108 | self.expression()?; 1109 | self.consume( 1110 | scanner::TokenType::RightBracket, 1111 | "Expected ] after subscript", 1112 | )?; 1113 | self.emit_op(bytecode::Op::Subscr, self.previous().line); 1114 | Ok(()) 1115 | } 1116 | 1117 | fn list(&mut self, _can_assign: bool) -> Result<(), Error> { 1118 | if !self.extensions.lists { 1119 | return Err(Error::Parse(ErrorInfo { 1120 | what: "Unexpected '['".to_string(), 1121 | line: self.previous().line, 1122 | col: self.previous().col, 1123 | })); 1124 | } 1125 | 1126 | let arg_count = self.list_elements()?; 1127 | self.emit_op(bytecode::Op::BuildList(arg_count), self.previous().line); 1128 | Ok(()) 1129 | } 1130 | 1131 | fn list_elements(&mut self) -> Result { 1132 | let mut num_elements: usize = 0; 1133 | if !self.check(scanner::TokenType::RightBracket) { 1134 | loop { 1135 | self.expression()?; 1136 | num_elements += 1; 1137 | if !self.matches(scanner::TokenType::Comma) { 1138 | break; 1139 | } 1140 | } 1141 | } 1142 | self.consume(scanner::TokenType::RightBracket, "Expected ']'.")?; 1143 | Ok(num_elements) 1144 | } 1145 | 1146 | fn argument_list(&mut self) -> Result { 1147 | let mut arg_count: u8 = 0; 1148 | if !self.check(scanner::TokenType::RightParen) { 1149 | loop { 1150 | self.expression()?; 1151 | arg_count += 1; 1152 | if !self.matches(scanner::TokenType::Comma) { 1153 | break; 1154 | } 1155 | } 1156 | } 1157 | self.consume( 1158 | scanner::TokenType::RightParen, 1159 | "Expected ')' after argument list.", 1160 | )?; 1161 | Ok(arg_count) 1162 | } 1163 | 1164 | fn unary(&mut self, _can_assign: bool) -> Result<(), Error> { 1165 | let operator = self.previous().clone(); 1166 | 1167 | self.parse_precedence(Precedence::Unary)?; 1168 | 1169 | match operator.ty { 1170 | scanner::TokenType::Minus => { 1171 | self.emit_op(bytecode::Op::Negate, operator.line); 1172 | Ok(()) 1173 | } 1174 | scanner::TokenType::Bang => { 1175 | self.emit_op(bytecode::Op::Not, operator.line); 1176 | Ok(()) 1177 | } 1178 | _ => Err(Error::Parse(ErrorInfo { 1179 | what: format!("Invalid token in unary op {:?}", operator.ty), 1180 | line: operator.line, 1181 | col: operator.col, 1182 | })), 1183 | } 1184 | } 1185 | 1186 | fn emit_number(&mut self, n: f64, lineno: usize) { 1187 | let const_idx = self.current_chunk().add_constant_number(n); 1188 | self.emit_op(bytecode::Op::Constant(const_idx), lineno); 1189 | } 1190 | 1191 | fn emit_op(&mut self, op: bytecode::Op, lineno: usize) { 1192 | self.current_chunk() 1193 | .code 1194 | .push((op, bytecode::Lineno(lineno))) 1195 | } 1196 | 1197 | fn emit_return(&mut self) { 1198 | let op = match self.current_level().function_type { 1199 | FunctionType::Initializer => bytecode::Op::GetLocal(0), 1200 | _ => bytecode::Op::Nil, 1201 | }; 1202 | 1203 | self.emit_op(op, self.previous().line); 1204 | self.emit_op(bytecode::Op::Return, self.previous().line); 1205 | } 1206 | 1207 | fn parse_precedence(&mut self, precedence: Precedence) -> Result<(), Error> { 1208 | self.advance(); 1209 | 1210 | let can_assign = precedence <= Precedence::Assignment; 1211 | 1212 | match Compiler::get_rule(self.previous().ty).prefix { 1213 | Some(parse_fn) => self.apply_parse_fn(parse_fn, can_assign)?, 1214 | None => { 1215 | return Err(self.error("Expected expression.")); 1216 | } 1217 | } 1218 | 1219 | while precedence <= Compiler::get_rule(self.peek().ty).precedence { 1220 | self.advance(); 1221 | match Compiler::get_rule(self.previous().ty).infix { 1222 | Some(parse_fn) => self.apply_parse_fn(parse_fn, can_assign)?, 1223 | None => panic!("could not find infix rule to apply tok = {:?}", self.peek()), 1224 | } 1225 | } 1226 | 1227 | if can_assign && self.matches(scanner::TokenType::Equal) { 1228 | if let Some((bytecode::Op::Subscr, _)) = self.current_chunk().code.last() { 1229 | self.fixup_subscript_to_setitem()?; 1230 | } else { 1231 | return Err(self.error("Invalid assignment target")); 1232 | } 1233 | } 1234 | 1235 | Ok(()) 1236 | } 1237 | 1238 | fn fixup_subscript_to_setitem(&mut self) -> Result<(), Error> { 1239 | self.current_chunk().code.pop(); // pop the subscript op 1240 | self.expression()?; // consume right hand side 1241 | self.emit_op(bytecode::Op::SetItem, self.previous().line); 1242 | Ok(()) 1243 | } 1244 | 1245 | fn error(&self, what: &str) -> Error { 1246 | Compiler::error_at_tok(what, self.previous()) 1247 | } 1248 | 1249 | fn error_at_tok(what: &str, prev_tok: &scanner::Token) -> Error { 1250 | Error::Semantic(ErrorInfo { 1251 | what: what.to_string(), 1252 | line: prev_tok.line, 1253 | col: prev_tok.col, 1254 | }) 1255 | } 1256 | 1257 | fn apply_parse_fn(&mut self, parse_fn: ParseFn, can_assign: bool) -> Result<(), Error> { 1258 | match parse_fn { 1259 | ParseFn::Grouping => self.grouping(can_assign), 1260 | ParseFn::Unary => self.unary(can_assign), 1261 | ParseFn::Binary => self.binary(can_assign), 1262 | ParseFn::Number => self.number(can_assign), 1263 | ParseFn::Literal => self.literal(can_assign), 1264 | ParseFn::String => self.string(can_assign), 1265 | ParseFn::Variable => self.variable(can_assign), 1266 | ParseFn::And => self.and(can_assign), 1267 | ParseFn::Or => self.or(can_assign), 1268 | ParseFn::Call => self.call(can_assign), 1269 | ParseFn::Dot => self.dot(can_assign), 1270 | ParseFn::This => self.this(can_assign), 1271 | ParseFn::Super => self.super_(can_assign), 1272 | ParseFn::List => self.list(can_assign), 1273 | ParseFn::Subscript => self.subscr(can_assign), 1274 | } 1275 | } 1276 | 1277 | fn consume( 1278 | &mut self, 1279 | tok: scanner::TokenType, 1280 | on_err_str: &str, 1281 | ) -> Result<&scanner::Token, Error> { 1282 | if self.check(tok) { 1283 | return Ok(self.advance()); 1284 | } 1285 | Err(Error::Parse(ErrorInfo { 1286 | what: format!( 1287 | "Expected token {:?}, but found token {:?}: {}", 1288 | tok, 1289 | self.peek().ty, 1290 | on_err_str 1291 | ), 1292 | line: self.peek().line, 1293 | col: self.peek().col, 1294 | })) 1295 | } 1296 | 1297 | fn advance(&mut self) -> &scanner::Token { 1298 | if !self.is_at_end() { 1299 | self.token_idx += 1 1300 | } 1301 | 1302 | self.previous() 1303 | } 1304 | 1305 | fn previous(&self) -> &scanner::Token { 1306 | &self.tokens[self.token_idx - 1] 1307 | } 1308 | 1309 | fn is_at_end(&self) -> bool { 1310 | self.peek().ty == scanner::TokenType::Eof 1311 | } 1312 | 1313 | fn peek(&self) -> &scanner::Token { 1314 | &self.tokens[self.token_idx] 1315 | } 1316 | 1317 | fn next_precedence(precedence: Precedence) -> Precedence { 1318 | match precedence { 1319 | Precedence::None => Precedence::Assignment, 1320 | Precedence::Assignment => Precedence::Or, 1321 | Precedence::Or => Precedence::And, 1322 | Precedence::And => Precedence::Equality, 1323 | Precedence::Equality => Precedence::Comparison, 1324 | Precedence::Comparison => Precedence::Term, 1325 | Precedence::Term => Precedence::Factor, 1326 | Precedence::Factor => Precedence::Unary, 1327 | Precedence::Unary => Precedence::Call, 1328 | Precedence::Call => Precedence::Primary, 1329 | Precedence::Primary => panic!("primary has no next precedence!"), 1330 | } 1331 | } 1332 | 1333 | fn get_rule(operator: scanner::TokenType) -> ParseRule { 1334 | match operator { 1335 | scanner::TokenType::LeftParen => ParseRule { 1336 | prefix: Some(ParseFn::Grouping), 1337 | infix: Some(ParseFn::Call), 1338 | precedence: Precedence::Call, 1339 | }, 1340 | scanner::TokenType::RightParen => ParseRule { 1341 | prefix: None, 1342 | infix: None, 1343 | precedence: Precedence::None, 1344 | }, 1345 | scanner::TokenType::LeftBrace => ParseRule { 1346 | prefix: None, 1347 | infix: None, 1348 | precedence: Precedence::None, 1349 | }, 1350 | scanner::TokenType::RightBrace => ParseRule { 1351 | prefix: None, 1352 | infix: None, 1353 | precedence: Precedence::None, 1354 | }, 1355 | scanner::TokenType::LeftBracket => ParseRule { 1356 | prefix: Some(ParseFn::List), 1357 | infix: Some(ParseFn::Subscript), 1358 | precedence: Precedence::Call, 1359 | }, 1360 | scanner::TokenType::RightBracket => ParseRule { 1361 | prefix: None, 1362 | infix: None, 1363 | precedence: Precedence::None, 1364 | }, 1365 | scanner::TokenType::Comma => ParseRule { 1366 | prefix: None, 1367 | infix: None, 1368 | precedence: Precedence::None, 1369 | }, 1370 | scanner::TokenType::Dot => ParseRule { 1371 | prefix: None, 1372 | infix: Some(ParseFn::Dot), 1373 | precedence: Precedence::Call, 1374 | }, 1375 | scanner::TokenType::Minus => ParseRule { 1376 | prefix: Some(ParseFn::Unary), 1377 | infix: Some(ParseFn::Binary), 1378 | precedence: Precedence::Term, 1379 | }, 1380 | scanner::TokenType::Plus => ParseRule { 1381 | prefix: None, 1382 | infix: Some(ParseFn::Binary), 1383 | precedence: Precedence::Term, 1384 | }, 1385 | scanner::TokenType::Semicolon => ParseRule { 1386 | prefix: None, 1387 | infix: None, 1388 | precedence: Precedence::None, 1389 | }, 1390 | scanner::TokenType::Slash => ParseRule { 1391 | prefix: None, 1392 | infix: Some(ParseFn::Binary), 1393 | precedence: Precedence::Factor, 1394 | }, 1395 | scanner::TokenType::Star => ParseRule { 1396 | prefix: None, 1397 | infix: Some(ParseFn::Binary), 1398 | precedence: Precedence::Factor, 1399 | }, 1400 | scanner::TokenType::Bang => ParseRule { 1401 | prefix: Some(ParseFn::Unary), 1402 | infix: None, 1403 | precedence: Precedence::None, 1404 | }, 1405 | scanner::TokenType::BangEqual => ParseRule { 1406 | prefix: None, 1407 | infix: Some(ParseFn::Binary), 1408 | precedence: Precedence::Equality, 1409 | }, 1410 | scanner::TokenType::Equal => ParseRule { 1411 | prefix: None, 1412 | infix: None, 1413 | precedence: Precedence::None, 1414 | }, 1415 | scanner::TokenType::EqualEqual => ParseRule { 1416 | prefix: None, 1417 | infix: Some(ParseFn::Binary), 1418 | precedence: Precedence::Equality, 1419 | }, 1420 | scanner::TokenType::Greater => ParseRule { 1421 | prefix: None, 1422 | infix: Some(ParseFn::Binary), 1423 | precedence: Precedence::Comparison, 1424 | }, 1425 | scanner::TokenType::GreaterEqual => ParseRule { 1426 | prefix: None, 1427 | infix: Some(ParseFn::Binary), 1428 | precedence: Precedence::Comparison, 1429 | }, 1430 | scanner::TokenType::Less => ParseRule { 1431 | prefix: None, 1432 | infix: Some(ParseFn::Binary), 1433 | precedence: Precedence::Comparison, 1434 | }, 1435 | scanner::TokenType::LessEqual => ParseRule { 1436 | prefix: None, 1437 | infix: Some(ParseFn::Binary), 1438 | precedence: Precedence::Comparison, 1439 | }, 1440 | scanner::TokenType::Identifier => ParseRule { 1441 | prefix: Some(ParseFn::Variable), 1442 | infix: None, 1443 | precedence: Precedence::None, 1444 | }, 1445 | scanner::TokenType::String => ParseRule { 1446 | prefix: Some(ParseFn::String), 1447 | infix: None, 1448 | precedence: Precedence::None, 1449 | }, 1450 | scanner::TokenType::Number => ParseRule { 1451 | prefix: Some(ParseFn::Number), 1452 | infix: None, 1453 | precedence: Precedence::None, 1454 | }, 1455 | scanner::TokenType::And => ParseRule { 1456 | prefix: None, 1457 | infix: Some(ParseFn::And), 1458 | precedence: Precedence::And, 1459 | }, 1460 | scanner::TokenType::Class => ParseRule { 1461 | prefix: None, 1462 | infix: None, 1463 | precedence: Precedence::None, 1464 | }, 1465 | scanner::TokenType::Else => ParseRule { 1466 | prefix: None, 1467 | infix: None, 1468 | precedence: Precedence::None, 1469 | }, 1470 | scanner::TokenType::False => ParseRule { 1471 | prefix: Some(ParseFn::Literal), 1472 | infix: None, 1473 | precedence: Precedence::None, 1474 | }, 1475 | scanner::TokenType::For => ParseRule { 1476 | prefix: None, 1477 | infix: None, 1478 | precedence: Precedence::None, 1479 | }, 1480 | scanner::TokenType::Fun => ParseRule { 1481 | prefix: None, 1482 | infix: None, 1483 | precedence: Precedence::None, 1484 | }, 1485 | scanner::TokenType::If => ParseRule { 1486 | prefix: None, 1487 | infix: None, 1488 | precedence: Precedence::None, 1489 | }, 1490 | scanner::TokenType::Nil => ParseRule { 1491 | prefix: Some(ParseFn::Literal), 1492 | infix: None, 1493 | precedence: Precedence::None, 1494 | }, 1495 | scanner::TokenType::Or => ParseRule { 1496 | prefix: None, 1497 | infix: Some(ParseFn::Or), 1498 | precedence: Precedence::Or, 1499 | }, 1500 | scanner::TokenType::Print => ParseRule { 1501 | prefix: None, 1502 | infix: None, 1503 | precedence: Precedence::None, 1504 | }, 1505 | scanner::TokenType::Return => ParseRule { 1506 | prefix: None, 1507 | infix: None, 1508 | precedence: Precedence::None, 1509 | }, 1510 | scanner::TokenType::Super => ParseRule { 1511 | prefix: Some(ParseFn::Super), 1512 | infix: None, 1513 | precedence: Precedence::None, 1514 | }, 1515 | scanner::TokenType::This => ParseRule { 1516 | prefix: Some(ParseFn::This), 1517 | infix: None, 1518 | precedence: Precedence::None, 1519 | }, 1520 | scanner::TokenType::True => ParseRule { 1521 | prefix: Some(ParseFn::Literal), 1522 | infix: None, 1523 | precedence: Precedence::None, 1524 | }, 1525 | scanner::TokenType::Var => ParseRule { 1526 | prefix: None, 1527 | infix: None, 1528 | precedence: Precedence::None, 1529 | }, 1530 | scanner::TokenType::While => ParseRule { 1531 | prefix: None, 1532 | infix: None, 1533 | precedence: Precedence::None, 1534 | }, 1535 | scanner::TokenType::Lambda => unimplemented!(), 1536 | scanner::TokenType::Eof => ParseRule { 1537 | prefix: None, 1538 | infix: None, 1539 | precedence: Precedence::None, 1540 | }, 1541 | } 1542 | } 1543 | 1544 | fn current_chunk(&mut self) -> &mut bytecode::Chunk { 1545 | &mut self.current_level_mut().function.chunk 1546 | } 1547 | 1548 | fn current_level(&self) -> &Level { 1549 | &self.levels[self.level_idx] 1550 | } 1551 | 1552 | fn current_level_mut(&mut self) -> &mut Level { 1553 | &mut self.levels[self.level_idx] 1554 | } 1555 | 1556 | fn push_level(&mut self, level: Level) { 1557 | self.levels.push(level); 1558 | self.level_idx += 1; 1559 | } 1560 | 1561 | fn pop_level(&mut self) { 1562 | self.levels.pop(); 1563 | self.level_idx -= 1; 1564 | } 1565 | 1566 | fn current_function_mut(&mut self) -> &mut bytecode::Function { 1567 | &mut self.current_level_mut().function 1568 | } 1569 | 1570 | fn function_type(&self) -> FunctionType { 1571 | self.current_level().function_type 1572 | } 1573 | 1574 | fn scope_depth(&self) -> i64 { 1575 | self.current_level().scope_depth 1576 | } 1577 | 1578 | fn locals(&self) -> &Vec { 1579 | &self.current_level().locals 1580 | } 1581 | 1582 | fn locals_mut(&mut self) -> &mut Vec { 1583 | &mut self.current_level_mut().locals 1584 | } 1585 | } 1586 | 1587 | #[cfg(test)] 1588 | mod tests { 1589 | use crate::compiler::*; 1590 | 1591 | fn check_semantic_error(code: &str, f: &dyn Fn(&str) -> ()) { 1592 | let func_or_err = Compiler::compile(String::from(code), extensions::Extensions::default()); 1593 | 1594 | match func_or_err { 1595 | Err(Error::Semantic(err)) => f(&err.what), 1596 | _ => panic!("expected semantic error"), 1597 | } 1598 | } 1599 | 1600 | #[test] 1601 | fn test_compiles_1() { 1602 | Compiler::compile( 1603 | String::from("print 42 * 12;"), 1604 | extensions::Extensions::default(), 1605 | ) 1606 | .unwrap(); 1607 | } 1608 | 1609 | #[test] 1610 | fn test_compiles_2() { 1611 | Compiler::compile( 1612 | String::from("print -2 * 3 + (-4 / 2);"), 1613 | extensions::Extensions::default(), 1614 | ) 1615 | .unwrap(); 1616 | } 1617 | 1618 | #[test] 1619 | fn test_var_decl_compiles_1() { 1620 | Compiler::compile( 1621 | String::from("var x = 2;"), 1622 | extensions::Extensions::default(), 1623 | ) 1624 | .unwrap(); 1625 | } 1626 | 1627 | #[test] 1628 | fn test_var_decl_implicit_nil() { 1629 | Compiler::compile(String::from("var x;"), extensions::Extensions::default()).unwrap(); 1630 | } 1631 | 1632 | #[test] 1633 | fn test_var_reading_2() { 1634 | Compiler::compile( 1635 | String::from("var x; print x;"), 1636 | extensions::Extensions::default(), 1637 | ) 1638 | .unwrap(); 1639 | } 1640 | 1641 | #[test] 1642 | fn test_var_reading_3() { 1643 | Compiler::compile( 1644 | String::from("var x; print x * 2 + x;"), 1645 | extensions::Extensions::default(), 1646 | ) 1647 | .unwrap(); 1648 | } 1649 | 1650 | #[test] 1651 | fn test_this_outside_method_1() { 1652 | check_semantic_error("print this;", &|err: &str| { 1653 | assert!(err.starts_with("Cannot use 'this' outside of class")) 1654 | }) 1655 | } 1656 | 1657 | #[test] 1658 | fn test_this_outside_method_2() { 1659 | check_semantic_error("fun foo() {print this;}", &|err: &str| { 1660 | assert!(err.starts_with("Cannot use 'this' outside of class")) 1661 | }) 1662 | } 1663 | 1664 | #[test] 1665 | fn test_self_ineritance_is_error() { 1666 | check_semantic_error("class A < A {}", &|err: &str| { 1667 | assert!(err.starts_with("A class cannot inherit from itself.")) 1668 | }) 1669 | } 1670 | 1671 | #[test] 1672 | fn test_cant_use_super_outside_class() { 1673 | check_semantic_error("fun f() { super.bar(); }", &|err: &str| { 1674 | assert!(err.starts_with("Can't use 'super' outside of a class")) 1675 | }) 1676 | } 1677 | 1678 | #[test] 1679 | fn test_cant_use_super_in_class_with_no_superclass() { 1680 | check_semantic_error("class Foo { bar() { super.bar(); } }", &|err: &str| { 1681 | assert!(err.starts_with("Can't use 'super' in a class with no superclass")) 1682 | }) 1683 | } 1684 | 1685 | #[test] 1686 | fn test_setitem_illegal_target_globals() { 1687 | let func_or_err = Compiler::compile( 1688 | String::from( 1689 | "var x = 2;\n\ 1690 | var y = 3;\n\ 1691 | x * y = 5;", 1692 | ), 1693 | extensions::Extensions::default(), 1694 | ); 1695 | 1696 | match func_or_err { 1697 | Err(Error::Semantic(err)) => assert!(err.what.starts_with("Invalid assignment target")), 1698 | _ => panic!("expected semantic error"), 1699 | } 1700 | } 1701 | 1702 | #[test] 1703 | fn test_setitem_illegal_target_locals() { 1704 | let func_or_err = Compiler::compile( 1705 | String::from( 1706 | "{\n\ 1707 | var x = 2;\n\ 1708 | var y = 3;\n\ 1709 | x * y = 5;\n\ 1710 | }\n", 1711 | ), 1712 | extensions::Extensions::default(), 1713 | ); 1714 | 1715 | match func_or_err { 1716 | Err(Error::Semantic(err)) => assert!(err.what.starts_with("Invalid assignment target")), 1717 | _ => panic!("expected semantic error"), 1718 | } 1719 | } 1720 | 1721 | #[test] 1722 | fn test_redeclaration_of_locals_is_error() { 1723 | let func_or_err = Compiler::compile( 1724 | String::from( 1725 | "{\n\ 1726 | var x = 2;\n\ 1727 | var x = 3;\n\ 1728 | }", 1729 | ), 1730 | extensions::Extensions::default(), 1731 | ); 1732 | 1733 | match func_or_err { 1734 | Err(Error::Semantic(err)) => assert!(err.what.starts_with("Redeclaration of variable")), 1735 | _ => panic!("expected semantic error"), 1736 | } 1737 | } 1738 | } 1739 | -------------------------------------------------------------------------------- /src/debugger.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::collections::HashSet; 3 | use std::sync::atomic::{AtomicBool, Ordering}; 4 | use std::sync::Arc; 5 | 6 | use crate::bytecode; 7 | use crate::bytecode_interpreter; 8 | use crate::line_reader; 9 | 10 | const VERSION: &str = env!("CARGO_PKG_VERSION"); 11 | const AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); 12 | 13 | macro_rules! vec_of_strings { 14 | ($($x:expr),*) => (vec![$($x.to_string()),*]); 15 | } 16 | 17 | pub struct Debugger { 18 | interpreter: bytecode_interpreter::Interpreter, 19 | lines: Vec, 20 | last_command: Option, 21 | interrupted: Arc, 22 | breakpoints: HashSet, 23 | command_map: HashMap, 24 | command_list: Vec<(Vec, DebugCommand)>, 25 | } 26 | 27 | #[derive(Copy, Clone, Eq, PartialEq)] 28 | enum DebugCommand { 29 | Dis, 30 | Op, 31 | Step, 32 | Quit, 33 | Stack, 34 | Globals, 35 | Upvals, 36 | List, 37 | RepeatOrNil, 38 | Go, 39 | Break(usize), 40 | Backtrace, 41 | Heap, 42 | Help, 43 | Unknown, 44 | } 45 | 46 | enum ShouldBreak { 47 | True, 48 | False, 49 | } 50 | 51 | enum Verbosity { 52 | Verbose, 53 | None, 54 | } 55 | 56 | impl Debugger { 57 | pub fn new(func: bytecode::Function, input: String) -> Debugger { 58 | let lines: Vec = input.lines().map(|s| s.to_string()).collect(); 59 | let mut interpreter = bytecode_interpreter::Interpreter::default(); 60 | interpreter.prepare_interpret(func); 61 | 62 | let interrupted = Arc::new(AtomicBool::new(true)); 63 | 64 | { 65 | let interrupted_clone = interrupted.clone(); 66 | 67 | ctrlc::set_handler(move || { 68 | interrupted_clone.store(true, Ordering::Release); 69 | }) 70 | .expect("Error setting Ctrl-C handler"); 71 | } 72 | 73 | let command_list = vec![ 74 | (vec_of_strings!["dis"], DebugCommand::Dis), 75 | (vec_of_strings!["op"], DebugCommand::Op), 76 | (vec_of_strings!["step", "s"], DebugCommand::Step), 77 | (vec_of_strings!["quit", "q"], DebugCommand::Quit), 78 | (vec_of_strings!["stack"], DebugCommand::Stack), 79 | (vec_of_strings!["globals"], DebugCommand::Globals), 80 | (vec_of_strings!["upvals"], DebugCommand::Upvals), 81 | (vec_of_strings!["list"], DebugCommand::List), 82 | (vec_of_strings![""], DebugCommand::RepeatOrNil), 83 | (vec_of_strings!["go", "g"], DebugCommand::Go), 84 | (vec_of_strings!["backtrace", "bt"], DebugCommand::Backtrace), 85 | (vec_of_strings!["heap"], DebugCommand::Heap), 86 | (vec_of_strings!["help", "h"], DebugCommand::Help), 87 | ]; 88 | 89 | let command_map = command_list.iter().fold(HashMap::new(), |mut acc, elt| { 90 | let (command_strings, command) = elt; 91 | for command_string in command_strings { 92 | acc.insert(command_string.clone(), *command); 93 | } 94 | acc 95 | }); 96 | 97 | Debugger { 98 | interpreter, 99 | lines, 100 | last_command: None, 101 | interrupted, 102 | breakpoints: Default::default(), 103 | command_map, 104 | command_list, 105 | } 106 | } 107 | 108 | pub fn debug(&mut self) { 109 | println!( 110 | "===================================================\n\ 111 | Welcome to loxdb {}, the lox debugger! \n\ 112 | Authors: {}\n\ 113 | \n\ 114 | Enter \"help\" (or \"h\") for list of commands.\n\ 115 | ===================================================\n", 116 | VERSION, AUTHORS 117 | ); 118 | let mut line_reader = line_reader::LineReader::new(".debugger-history.txt", "(loxdb) "); 119 | 120 | loop { 121 | if !self.interpreter.is_done() && !self.interrupted.load(Ordering::Acquire) { 122 | if self.breakpoints.contains(&self.interpreter.next_line()) { 123 | self.interrupted.store(true, Ordering::Release); 124 | self.breakpoints.remove(&self.interpreter.next_line()); 125 | println!( 126 | "reached breakpoint at line {}", 127 | self.interpreter.next_line() 128 | ); 129 | } else { 130 | self.execute_command(DebugCommand::Step, Verbosity::None); 131 | continue; 132 | } 133 | } 134 | 135 | let readline = line_reader.readline(); 136 | 137 | match readline { 138 | line_reader::LineReadStatus::Line(line) => { 139 | let line = line.trim(); 140 | 141 | let command = self.read_command(line); 142 | if let ShouldBreak::True = self.execute_command(command, Verbosity::Verbose) { 143 | break; 144 | } 145 | if command != DebugCommand::RepeatOrNil { 146 | self.last_command = Some(command); 147 | } 148 | } 149 | line_reader::LineReadStatus::Done => break, 150 | } 151 | } 152 | } 153 | 154 | fn execute_command(&mut self, command: DebugCommand, verbosity: Verbosity) -> ShouldBreak { 155 | match command { 156 | DebugCommand::Dis => { 157 | let func = &self.interpreter.frame().closure.function; 158 | let dis_output = bytecode_interpreter::disassemble_chunk(&func.chunk, &func.name); 159 | println!("{}", dis_output); 160 | } 161 | DebugCommand::Op => { 162 | let frame = self.interpreter.frame(); 163 | println!("{:?}", frame.closure.function.chunk.code[frame.ip].0); 164 | } 165 | DebugCommand::Step => { 166 | if self.interpreter.is_done() { 167 | println!("cannot step a completed program"); 168 | return ShouldBreak::True; 169 | } 170 | match self.interpreter.step() { 171 | Ok(()) => { 172 | if let Verbosity::Verbose = verbosity { 173 | self.list() 174 | } 175 | } 176 | Err(err) => println!( 177 | "{}.\n\nTraceback:\n\n{}", 178 | err, 179 | self.interpreter.format_backtrace() 180 | ), 181 | } 182 | } 183 | DebugCommand::Quit => { 184 | return ShouldBreak::True; 185 | } 186 | DebugCommand::Stack => { 187 | for val in self.interpreter.stack.iter().rev() { 188 | println!("{}", self.interpreter.format_val(val)); 189 | } 190 | } 191 | DebugCommand::Globals => { 192 | if self.interpreter.globals.is_empty() { 193 | println!(""); 194 | } 195 | for (name, val) in &self.interpreter.globals { 196 | println!("{}: {}", name, self.interpreter.format_val(val)); 197 | } 198 | } 199 | DebugCommand::Upvals => { 200 | if self.interpreter.upvalues.is_empty() { 201 | println!("") 202 | } 203 | for val in &self.interpreter.upvalues { 204 | println!("{}", self.interpreter.format_upval(&val.borrow())); 205 | } 206 | } 207 | DebugCommand::List => self.list(), 208 | DebugCommand::Go => { 209 | self.interrupted.store(false, Ordering::Release); 210 | let line = self.interpreter.next_line(); 211 | self.run_until_off_line(line); 212 | } 213 | DebugCommand::Break(lineno) => { 214 | println!("inserted breakpoint at line {}", lineno); 215 | self.breakpoints.insert(lineno); 216 | } 217 | DebugCommand::RepeatOrNil => { 218 | if let Some(last_command) = self.last_command { 219 | self.execute_command(last_command, verbosity); 220 | } 221 | } 222 | DebugCommand::Backtrace => { 223 | println!("{}", self.interpreter.format_backtrace()); 224 | } 225 | DebugCommand::Heap => println!("{}", self.interpreter.heap.summarize_stats()), 226 | DebugCommand::Help => self.print_help(), 227 | DebugCommand::Unknown => {} 228 | } 229 | ShouldBreak::False 230 | } 231 | 232 | fn run_until_off_line(&mut self, line: usize) { 233 | loop { 234 | if self.interpreter.is_done() || self.interpreter.next_line() != line { 235 | break; 236 | } 237 | self.execute_command(DebugCommand::Step, Verbosity::None); 238 | } 239 | } 240 | 241 | fn print_help(&self) { 242 | println!("Debugger commands:"); 243 | for (command_strings, command) in &self.command_list { 244 | if *command != DebugCommand::RepeatOrNil { 245 | println!( 246 | " {:<15} -- {}", 247 | command_strings.join(", "), 248 | Debugger::describe_command(*command) 249 | ); 250 | } 251 | } 252 | } 253 | 254 | fn describe_command(cmd: DebugCommand) -> String { 255 | match cmd { 256 | DebugCommand::Dis => "Disassemble for current frame.".to_string(), 257 | DebugCommand::Op => "Show the current opcode.".to_string(), 258 | DebugCommand::Step => "Step to next opcode.".to_string(), 259 | DebugCommand::Quit => "Quit the debugger.".to_string(), 260 | DebugCommand::Stack => "Show the stack.".to_string(), 261 | DebugCommand::Globals => "Show the globals.".to_string(), 262 | DebugCommand::Upvals => "Show the upvalues.".to_string(), 263 | DebugCommand::List => { 264 | "List the source and disassembly around current line/op.".to_string() 265 | } 266 | DebugCommand::RepeatOrNil => panic!(), 267 | DebugCommand::Go => { 268 | "Execute until program termination, a breakpoint is hit, or program is interrupted." 269 | .to_string() 270 | } 271 | DebugCommand::Break(lineno) => format!("Set a breakpoint at line {}.", lineno), 272 | DebugCommand::Backtrace => "Show backtrace.".to_string(), 273 | DebugCommand::Heap => "Show heap statistics.".to_string(), 274 | DebugCommand::Help => "Show debugger commands.".to_string(), 275 | DebugCommand::Unknown => panic!(), 276 | } 277 | } 278 | 279 | fn list(&self) { 280 | if let Some(frame) = self.interpreter.maybe_frame() { 281 | let ip = frame.ip; 282 | 283 | if self.interpreter.is_done() { 284 | println!("program completed"); 285 | return; 286 | } 287 | 288 | let maxdist = 4; 289 | 290 | self.lines 291 | .iter() 292 | .enumerate() 293 | .filter(|(idx, _)| { 294 | let next_line = self.interpreter.next_line(); 295 | if next_line < *idx { 296 | *idx - next_line < maxdist 297 | } else { 298 | next_line - *idx < maxdist 299 | } 300 | }) 301 | .for_each(|(idx, line)| { 302 | let prefix = if idx + 1 == self.interpreter.next_line() { 303 | "==>" 304 | } else { 305 | " " 306 | }; 307 | println!("{} {:<4} {}", prefix, idx + 1, line) 308 | }); 309 | 310 | println!(); 311 | 312 | let chunk = &self.interpreter.frame().closure.function.chunk; 313 | let dissed_code = bytecode_interpreter::disassemble_code(chunk); 314 | dissed_code 315 | .iter() 316 | .enumerate() 317 | .filter(|(idx, _)| { 318 | if ip < *idx { 319 | *idx - ip < maxdist 320 | } else { 321 | ip - *idx < maxdist 322 | } 323 | }) 324 | .for_each(|(idx, line)| { 325 | let prefix = if idx == ip { "==>" } else { " " }; 326 | println!("{} {}", prefix, line); 327 | }); 328 | } 329 | } 330 | 331 | fn read_command(&self, input: &str) -> DebugCommand { 332 | match self.command_map.get(input) { 333 | Some(cmd) => *cmd, 334 | None => { 335 | let words: Vec<_> = input.split_whitespace().collect(); 336 | if words.len() == 2 && words[0] == "b" { 337 | if let Ok(lineno) = words[1].parse::() { 338 | return DebugCommand::Break(lineno); 339 | } 340 | } 341 | println!("unknown command: {}", input); 342 | DebugCommand::Unknown 343 | } 344 | } 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /src/error_formatting.rs: -------------------------------------------------------------------------------- 1 | use crate::compiler; 2 | use crate::input; 3 | use crate::parser; 4 | use crate::scanner; 5 | 6 | use colored::*; 7 | 8 | fn format_input(input: &input::Input, line: usize, col: i64) { 9 | eprintln!( 10 | "in {}, at line {}, column {}:", 11 | match &input.source { 12 | input::Source::Literal => "", 13 | input::Source::File(filename) => filename, 14 | }, 15 | line, 16 | col 17 | ); 18 | eprintln!("{}", input.content.lines().nth(line - 1).unwrap()); 19 | eprint!("{:~<1$}", "".blue().bold(), col as usize); 20 | eprintln!("{}", "^".blue().bold()); 21 | } 22 | 23 | enum CompilerErrorKind { 24 | Parse, 25 | Semantic, 26 | } 27 | 28 | fn format_compiler_error_info( 29 | err: &compiler::ErrorInfo, 30 | input: &input::Input, 31 | kind: CompilerErrorKind, 32 | ) { 33 | eprintln!( 34 | "loxi: {}: {}", 35 | match kind { 36 | CompilerErrorKind::Parse => "parse error", 37 | CompilerErrorKind::Semantic => "semantic error", 38 | } 39 | .to_string() 40 | .red() 41 | .bold(), 42 | err.what.white().bold(), 43 | ); 44 | 45 | format_input(input, err.line, err.col); 46 | } 47 | 48 | pub fn format_compiler_error(err: &compiler::Error, input: &input::Input) { 49 | match err { 50 | compiler::Error::Lexical(err) => format_lexical_error(err, input), 51 | compiler::Error::Parse(err) => { 52 | format_compiler_error_info(err, input, CompilerErrorKind::Parse) 53 | } 54 | compiler::Error::Semantic(err) => { 55 | format_compiler_error_info(err, input, CompilerErrorKind::Semantic) 56 | } 57 | compiler::Error::Internal(err) => { 58 | eprintln!( 59 | "loxi: {}: {}", 60 | "internal error".red().bold(), 61 | err.white().bold() 62 | ); 63 | } 64 | } 65 | } 66 | 67 | pub fn format_parse_error(err: &parser::Error, input: &input::Input) { 68 | let err_str = format!("{:?}", err); 69 | eprintln!( 70 | "loxi: {}: {}", 71 | "parse error".red().bold(), 72 | err_str.white().bold() 73 | ); 74 | 75 | let (line, col) = match err { 76 | parser::Error::UnexpectedToken(tok) => (&tok.line, &tok.col), 77 | parser::Error::TokenMismatch { found, .. } => (&found.line, &found.col), 78 | parser::Error::MaxParamsExceeded { line, col, .. } => (line, col), 79 | parser::Error::ReturnNotInFun { line, col, .. } => (line, col), 80 | parser::Error::InvalidAssignment { line, col, .. } => (line, col), 81 | parser::Error::TooManyArguments { line, col, .. } => (line, col), 82 | parser::Error::ExpectedExpression { line, col, .. } => (line, col), 83 | parser::Error::InvalidTokenInUnaryOp { line, col, .. } => (line, col), 84 | parser::Error::InvalidTokenInBinaryOp { line, col, .. } => (line, col), 85 | }; 86 | 87 | format_input(input, *line, *col); 88 | } 89 | 90 | pub fn format_lexical_error(err: &scanner::Error, input: &input::Input) { 91 | eprintln!( 92 | "loxi: {}: {}", 93 | "lexical error".red().bold(), 94 | err.what.white().bold(), 95 | ); 96 | 97 | format_input(input, err.line, err.col); 98 | } 99 | -------------------------------------------------------------------------------- /src/expr.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub enum Expr { 3 | Literal(Literal), 4 | This(SourceLocation), 5 | Unary(UnaryOp, Box), 6 | Binary(Box, BinaryOp, Box), 7 | Call(Box, SourceLocation, Vec), 8 | Get(Box, Symbol), 9 | Grouping(Box), 10 | Variable(Symbol), 11 | Assign(Symbol, Box), 12 | Logical(Box, LogicalOp, Box), 13 | Set(Box, Symbol, Box), 14 | Super(SourceLocation, Symbol), 15 | List(Vec), 16 | Subscript { 17 | value: Box, 18 | slice: Box, 19 | source_location: SourceLocation, 20 | }, 21 | SetItem { 22 | lhs: Box, 23 | slice: Box, 24 | rhs: Box, 25 | source_location: SourceLocation, 26 | }, 27 | Lambda(LambdaDecl), 28 | } 29 | 30 | #[derive(Debug, Clone, Copy)] 31 | pub struct SourceLocation { 32 | pub line: usize, 33 | pub col: i64, 34 | } 35 | 36 | #[derive(Debug, Clone)] 37 | pub enum LogicalOp { 38 | Or, 39 | And, 40 | } 41 | 42 | #[derive(Debug, Eq, PartialEq, Hash, Clone)] 43 | pub struct Symbol { 44 | pub name: String, 45 | pub line: usize, 46 | pub col: i64, 47 | } 48 | 49 | #[derive(Debug, Clone)] 50 | pub struct FunDecl { 51 | pub name: Symbol, 52 | pub params: Vec, 53 | pub body: Vec, 54 | } 55 | 56 | #[derive(Debug, Clone)] 57 | pub struct LambdaDecl { 58 | pub params: Vec, 59 | pub body: Vec, 60 | } 61 | 62 | #[derive(Debug, Clone)] 63 | pub struct ClassDecl { 64 | pub name: Symbol, 65 | pub superclass: Option, 66 | pub methods: Vec, 67 | } 68 | 69 | #[derive(Debug, Clone)] 70 | pub enum Stmt { 71 | Expr(Expr), 72 | FunDecl(FunDecl), 73 | ClassDecl(ClassDecl), 74 | If(Expr, Box, Option>), 75 | Print(Expr), 76 | VarDecl(Symbol, Option), 77 | Block(Vec), 78 | Return(SourceLocation, Option), 79 | While(Expr, Box), 80 | } 81 | 82 | #[derive(Debug, Copy, Clone)] 83 | pub enum UnaryOpTy { 84 | Minus, 85 | Bang, 86 | } 87 | 88 | #[derive(Debug, Copy, Clone)] 89 | pub struct UnaryOp { 90 | pub ty: UnaryOpTy, 91 | pub line: usize, 92 | pub col: i64, 93 | } 94 | 95 | #[derive(Debug, Copy, Clone)] 96 | pub enum BinaryOpTy { 97 | EqualEqual, 98 | NotEqual, 99 | Less, 100 | LessEqual, 101 | Greater, 102 | GreaterEqual, 103 | Plus, 104 | Minus, 105 | Star, 106 | Slash, 107 | } 108 | 109 | #[derive(Debug, Copy, Clone)] 110 | pub struct BinaryOp { 111 | pub ty: BinaryOpTy, 112 | pub line: usize, 113 | pub col: i64, 114 | } 115 | 116 | #[derive(Debug, Clone)] 117 | pub enum Literal { 118 | Number(f64), 119 | String(String), 120 | True, 121 | False, 122 | Nil, 123 | } 124 | -------------------------------------------------------------------------------- /src/extensions.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Default)] 2 | pub struct Extensions { 3 | pub lists: bool, 4 | pub lambdas: bool, 5 | } 6 | -------------------------------------------------------------------------------- /src/gc.rs: -------------------------------------------------------------------------------- 1 | use crate::value; 2 | 3 | use std::collections::HashMap; 4 | 5 | enum GCData { 6 | String(String), 7 | Closure(value::Closure), 8 | Class(value::Class), 9 | Instance(value::Instance), 10 | BoundMethod(value::BoundMethod), 11 | List(Vec), 12 | } 13 | 14 | impl GCData { 15 | fn as_str(&self) -> Option<&String> { 16 | match self { 17 | GCData::String(s) => Some(s), 18 | _ => None, 19 | } 20 | } 21 | fn as_list(&self) -> Option<&Vec> { 22 | match self { 23 | GCData::List(elements) => Some(elements), 24 | _ => None, 25 | } 26 | } 27 | fn as_list_mut(&mut self) -> Option<&mut Vec> { 28 | match self { 29 | GCData::List(elements) => Some(elements), 30 | _ => None, 31 | } 32 | } 33 | fn as_closure(&self) -> Option<&value::Closure> { 34 | match self { 35 | GCData::Closure(c) => Some(c), 36 | _ => None, 37 | } 38 | } 39 | fn as_bound_method(&self) -> Option<&value::BoundMethod> { 40 | match self { 41 | GCData::BoundMethod(m) => Some(m), 42 | _ => None, 43 | } 44 | } 45 | fn as_class(&self) -> Option<&value::Class> { 46 | match self { 47 | GCData::Class(c) => Some(c), 48 | _ => None, 49 | } 50 | } 51 | fn as_class_mut(&mut self) -> Option<&mut value::Class> { 52 | match self { 53 | GCData::Class(c) => Some(c), 54 | _ => None, 55 | } 56 | } 57 | fn as_instance(&self) -> Option<&value::Instance> { 58 | match self { 59 | GCData::Instance(inst) => Some(inst), 60 | _ => None, 61 | } 62 | } 63 | fn as_instance_mut(&mut self) -> Option<&mut value::Instance> { 64 | match self { 65 | GCData::Instance(inst) => Some(inst), 66 | _ => None, 67 | } 68 | } 69 | } 70 | 71 | struct GCVal { 72 | is_marked: bool, 73 | data: GCData, 74 | } 75 | 76 | impl GCVal { 77 | fn from(data: GCData) -> GCVal { 78 | GCVal { 79 | is_marked: false, 80 | data, 81 | } 82 | } 83 | } 84 | 85 | pub type HeapId = usize; 86 | 87 | pub struct Heap { 88 | bytes_allocated: usize, 89 | next_gc: usize, 90 | id_counter: usize, 91 | values: HashMap, 92 | } 93 | 94 | impl Default for Heap { 95 | fn default() -> Heap { 96 | let next_gc = std::env::var("LOX_GC_TRIGGER_SIZE") 97 | .ok() 98 | .and_then(|env_str| env_str.parse::().ok()) 99 | .unwrap_or(1024 * 1024); 100 | Heap { 101 | bytes_allocated: 0, 102 | next_gc, 103 | id_counter: 0, 104 | values: Default::default(), 105 | } 106 | } 107 | } 108 | 109 | impl Heap { 110 | pub fn summarize_stats(&self) -> String { 111 | format!( 112 | "Heap stats: bytes_allocated {}\n\ 113 | next_gc {}\n\ 114 | num_values: {}", 115 | self.bytes_allocated, 116 | self.next_gc, 117 | self.values.len() 118 | ) 119 | } 120 | 121 | pub fn manage_str(&mut self, s: String) -> HeapId { 122 | self.bytes_allocated += s.len(); 123 | let id = self.generate_id(); 124 | self.values.insert(id, GCVal::from(GCData::String(s))); 125 | id 126 | } 127 | 128 | pub fn manage_list(&mut self, elements: Vec) -> HeapId { 129 | self.bytes_allocated += elements.len(); 130 | let id = self.generate_id(); 131 | self.values.insert(id, GCVal::from(GCData::List(elements))); 132 | id 133 | } 134 | 135 | pub fn manage_closure(&mut self, c: value::Closure) -> HeapId { 136 | self.bytes_allocated += c.function.chunk.code.len(); 137 | self.bytes_allocated += c.function.chunk.constants.len(); 138 | let id = self.generate_id(); 139 | self.values.insert(id, GCVal::from(GCData::Closure(c))); 140 | id 141 | } 142 | 143 | pub fn manage_class(&mut self, c: value::Class) -> HeapId { 144 | let id = self.generate_id(); 145 | self.bytes_allocated += c.name.len(); 146 | self.bytes_allocated += c.methods.keys().map(|method_name| method_name.len()).len(); 147 | self.values.insert(id, GCVal::from(GCData::Class(c))); 148 | id 149 | } 150 | 151 | pub fn manage_instance(&mut self, inst: value::Instance) -> HeapId { 152 | let id = self.generate_id(); 153 | self.bytes_allocated += inst.fields.keys().map(|attr| attr.len()).sum::(); 154 | self.values.insert(id, GCVal::from(GCData::Instance(inst))); 155 | id 156 | } 157 | 158 | pub fn manage_bound_method(&mut self, method: value::BoundMethod) -> HeapId { 159 | let id = self.generate_id(); 160 | self.values 161 | .insert(id, GCVal::from(GCData::BoundMethod(method))); 162 | id 163 | } 164 | 165 | fn generate_id(&mut self) -> HeapId { 166 | self.id_counter += 1; 167 | loop { 168 | if !self.values.contains_key(&self.id_counter) { 169 | return self.id_counter; 170 | } 171 | self.id_counter += 1; 172 | } 173 | } 174 | 175 | pub fn get_str(&self, id: HeapId) -> &String { 176 | self.values.get(&id).unwrap().data.as_str().unwrap() 177 | } 178 | 179 | pub fn get_closure(&self, id: HeapId) -> &value::Closure { 180 | self.values.get(&id).unwrap().data.as_closure().unwrap() 181 | } 182 | 183 | pub fn get_bound_method(&self, id: HeapId) -> &value::BoundMethod { 184 | self.values 185 | .get(&id) 186 | .unwrap() 187 | .data 188 | .as_bound_method() 189 | .unwrap() 190 | } 191 | 192 | pub fn get_list_elements(&self, id: HeapId) -> &Vec { 193 | self.values.get(&id).unwrap().data.as_list().unwrap() 194 | } 195 | 196 | pub fn get_list_elements_mut(&mut self, id: HeapId) -> &mut Vec { 197 | self.values 198 | .get_mut(&id) 199 | .unwrap() 200 | .data 201 | .as_list_mut() 202 | .unwrap() 203 | } 204 | 205 | pub fn get_class(&self, id: HeapId) -> &value::Class { 206 | self.values.get(&id).unwrap().data.as_class().unwrap() 207 | } 208 | 209 | pub fn get_class_mut(&mut self, id: HeapId) -> &mut value::Class { 210 | self.values 211 | .get_mut(&id) 212 | .unwrap() 213 | .data 214 | .as_class_mut() 215 | .unwrap() 216 | } 217 | 218 | pub fn get_instance(&self, id: HeapId) -> &value::Instance { 219 | self.values.get(&id).unwrap().data.as_instance().unwrap() 220 | } 221 | 222 | pub fn get_instance_mut(&mut self, id: HeapId) -> &mut value::Instance { 223 | self.values 224 | .get_mut(&id) 225 | .unwrap() 226 | .data 227 | .as_instance_mut() 228 | .unwrap() 229 | } 230 | 231 | pub fn unmark(&mut self) { 232 | for val in self.values.values_mut() { 233 | val.is_marked = false; 234 | } 235 | } 236 | 237 | pub fn mark(&mut self, id: HeapId) { 238 | self.values.get_mut(&id).unwrap().is_marked = true; 239 | } 240 | 241 | pub fn is_marked(&self, id: HeapId) -> bool { 242 | self.values.get(&id).unwrap().is_marked 243 | } 244 | 245 | pub fn children(&self, id: HeapId) -> Vec { 246 | match &self.values.get(&id).unwrap().data { 247 | GCData::String(_) => Vec::new(), 248 | GCData::Closure(closure) => self.closure_children(closure), 249 | GCData::Class(class) => self.class_children(class), 250 | GCData::Instance(instance) => self.instance_children(instance), 251 | GCData::BoundMethod(method) => self.bound_method_children(method), 252 | GCData::List(elements) => self.list_children(elements), 253 | } 254 | } 255 | 256 | pub fn bound_method_children(&self, method: &value::BoundMethod) -> Vec { 257 | vec![method.instance_id, method.closure_id] 258 | } 259 | 260 | pub fn class_children(&self, class: &value::Class) -> Vec { 261 | class.methods.values().copied().collect() 262 | } 263 | 264 | pub fn instance_children(&self, instance: &value::Instance) -> Vec { 265 | let mut res = vec![instance.class_id]; 266 | 267 | for field in instance.fields.values() { 268 | if let Some(id) = Heap::extract_id(field) { 269 | res.push(id) 270 | } 271 | } 272 | 273 | res 274 | } 275 | 276 | pub fn list_children(&self, elements: &[value::Value]) -> Vec { 277 | let mut res = Vec::new(); 278 | 279 | for element in elements { 280 | if let Some(id) = Heap::extract_id(element) { 281 | res.push(id) 282 | } 283 | } 284 | 285 | res 286 | } 287 | 288 | pub fn closure_children(&self, closure: &value::Closure) -> Vec { 289 | let res: Vec = closure 290 | .upvalues 291 | .iter() 292 | .filter_map(|upval| match &*upval.borrow() { 293 | value::Upvalue::Open(_) => None, 294 | value::Upvalue::Closed(value) => Heap::extract_id(value), 295 | }) 296 | .collect(); 297 | res 298 | } 299 | 300 | pub fn extract_id(val: &value::Value) -> Option { 301 | match val { 302 | value::Value::Number(_) => None, 303 | value::Value::Bool(_) => None, 304 | value::Value::String(id) => Some(*id), 305 | value::Value::Function(id) => Some(*id), 306 | value::Value::Instance(id) => Some(*id), 307 | value::Value::BoundMethod(id) => Some(*id), 308 | value::Value::Class(id) => Some(*id), 309 | value::Value::NativeFunction(_) => None, 310 | value::Value::Nil => None, 311 | value::Value::List(id) => Some(*id), 312 | } 313 | } 314 | 315 | pub fn sweep(&mut self) { 316 | self.values.retain(|_, val| val.is_marked) 317 | } 318 | 319 | pub fn should_collect(&self) -> bool { 320 | self.bytes_allocated >= self.next_gc 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/input.rs: -------------------------------------------------------------------------------- 1 | pub enum Source { 2 | Literal, 3 | File(String), 4 | } 5 | 6 | pub struct Input { 7 | pub source: Source, 8 | pub content: String, 9 | } 10 | -------------------------------------------------------------------------------- /src/line_reader.rs: -------------------------------------------------------------------------------- 1 | pub struct LineReader { 2 | rl: rustyline::Editor<()>, 3 | history_file: String, 4 | prompt: String, 5 | } 6 | 7 | impl Drop for LineReader { 8 | fn drop(&mut self) { 9 | self.rl.save_history(&self.history_file).ok(); 10 | } 11 | } 12 | 13 | pub enum LineReadStatus { 14 | Line(String), 15 | Done, 16 | } 17 | 18 | impl LineReader { 19 | pub fn new(history_file: &str, prompt: &str) -> LineReader { 20 | let mut rl = rustyline::Editor::<()>::new(); 21 | rl.load_history(history_file).ok(); 22 | LineReader { 23 | rl, 24 | history_file: history_file.into(), 25 | prompt: prompt.into(), 26 | } 27 | } 28 | 29 | pub fn readline(&mut self) -> LineReadStatus { 30 | let res = self.rl.readline(&self.prompt); 31 | 32 | match res { 33 | Ok(line) => { 34 | self.rl.add_history_entry(line.as_str()); 35 | LineReadStatus::Line(line) 36 | } 37 | Err(_) => LineReadStatus::Done, 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate clap; 2 | extern crate ctrlc; 3 | 4 | use clap::{App, Arg}; 5 | 6 | use std::fs; 7 | 8 | mod builtins; 9 | mod bytecode; 10 | mod bytecode_interpreter; 11 | mod compiler; 12 | mod debugger; 13 | mod error_formatting; 14 | mod expr; 15 | mod extensions; 16 | mod gc; 17 | mod input; 18 | mod line_reader; 19 | mod parser; 20 | mod repl; 21 | mod scanner; 22 | mod treewalk_interpreter; 23 | mod value; 24 | 25 | const INPUT_STR: &str = "INPUT"; 26 | const SHOW_TOKENS_STR: &str = "tokens"; 27 | const SHOW_AST_STR: &str = "ast"; 28 | const DISASSEMBLE_STR: &str = "disassemble"; 29 | const DEBUG_STR: &str = "debug"; 30 | const TREEWALK_STR: &str = "treewalk"; 31 | const LITERAL_INPUT: &str = "c"; 32 | const EXTENSION_LISTS: &str = "Xlists"; 33 | const EXTENSION_LAMBDAS: &str = "Xlambdas"; 34 | 35 | fn get_input(matches: &clap::ArgMatches<'_>) -> Option { 36 | if let Some(literal_input) = matches.value_of(LITERAL_INPUT) { 37 | return Some(input::Input { 38 | source: input::Source::Literal, 39 | content: literal_input.to_string(), 40 | }); 41 | } 42 | if let Some(input_file) = matches.value_of(INPUT_STR) { 43 | match fs::read_to_string(input_file) { 44 | Ok(input) => { 45 | return Some(input::Input { 46 | source: input::Source::File(input_file.to_string()), 47 | content: input, 48 | }); 49 | } 50 | Err(err) => { 51 | println!("Error reading {}: {}", input_file, err); 52 | std::process::exit(-1); 53 | } 54 | } 55 | } 56 | 57 | None 58 | } 59 | 60 | fn main() { 61 | let matches = App::new("loxi") 62 | .version("0.1.0") 63 | .about("lox language interpreter") 64 | .author("Thomas Peters") 65 | .arg( 66 | Arg::with_name(INPUT_STR) 67 | .help("sets input file to use") 68 | .required(false) 69 | .index(1), 70 | ) 71 | .arg( 72 | Arg::with_name(SHOW_TOKENS_STR) 73 | .long("--show-tokens") 74 | .takes_value(false) 75 | .help("show the token stream"), 76 | ) 77 | .arg( 78 | Arg::with_name(SHOW_AST_STR) 79 | .long("--show-ast") 80 | .takes_value(false) 81 | .help("show the AST"), 82 | ) 83 | .arg( 84 | Arg::with_name(DISASSEMBLE_STR) 85 | .long("--disassemble") 86 | .takes_value(false) 87 | .help("show the bytecode"), 88 | ) 89 | .arg( 90 | Arg::with_name(DEBUG_STR) 91 | .long("--debug") 92 | .takes_value(false) 93 | .help("run in the debugger"), 94 | ) 95 | .arg( 96 | Arg::with_name(TREEWALK_STR) 97 | .long("--treewalk") 98 | .takes_value(false) 99 | .help("run the tree-walk interpreter instead of the bytecode interpreter"), 100 | ) 101 | .arg( 102 | Arg::with_name(LITERAL_INPUT) 103 | .long("-c") 104 | .takes_value(true) 105 | .help("provide a literal string of Lox code"), 106 | ) 107 | .arg( 108 | Arg::with_name(EXTENSION_LISTS) 109 | .long(&format!["--{}", EXTENSION_LISTS]) 110 | .takes_value(false) 111 | .help("use the lists extension"), 112 | ) 113 | .arg( 114 | Arg::with_name(EXTENSION_LAMBDAS) 115 | .long(&format!["--{}", EXTENSION_LAMBDAS]) 116 | .takes_value(false) 117 | .help("use the lambdas extension"), 118 | ) 119 | .get_matches(); 120 | 121 | let extensions = extensions::Extensions { 122 | lists: matches.is_present(EXTENSION_LISTS), 123 | lambdas: matches.is_present(EXTENSION_LAMBDAS), 124 | }; 125 | 126 | if let Some(input) = get_input(&matches) { 127 | if matches.is_present(SHOW_TOKENS_STR) 128 | || matches.is_present(SHOW_AST_STR) 129 | || matches.is_present(TREEWALK_STR) 130 | { 131 | match scanner::scan_tokens(input.content.clone()) { 132 | Ok(tokens) => { 133 | if matches.is_present(SHOW_TOKENS_STR) { 134 | println!("{:#?}", tokens); 135 | std::process::exit(0); 136 | } 137 | 138 | let stmts_maybe = parser::parse(extensions, tokens); 139 | 140 | match stmts_maybe { 141 | Ok(stmts) => { 142 | if matches.is_present(SHOW_AST_STR) { 143 | println!("{:#?}", stmts); 144 | std::process::exit(0); 145 | } 146 | 147 | let mut interpreter: treewalk_interpreter::Interpreter = 148 | Default::default(); 149 | let interpret_result = interpreter.interpret(&stmts); 150 | 151 | match interpret_result { 152 | Ok(_) => { 153 | std::process::exit(0); 154 | } 155 | Err(err) => { 156 | println!( 157 | "Runtime Error: {}\n\n{}", 158 | err, 159 | interpreter.format_backtrace() 160 | ); 161 | std::process::exit(-1); 162 | } 163 | } 164 | } 165 | Err(err) => { 166 | error_formatting::format_parse_error(&err, &input); 167 | std::process::exit(-1) 168 | } 169 | } 170 | } 171 | Err(err) => { 172 | error_formatting::format_lexical_error(&err, &input); 173 | std::process::exit(-1); 174 | } 175 | } 176 | } 177 | 178 | let func_or_err = compiler::Compiler::compile(input.content.clone(), extensions); 179 | 180 | match func_or_err { 181 | Ok(func) => { 182 | if matches.is_present(DISASSEMBLE_STR) { 183 | println!( 184 | "{}", 185 | bytecode_interpreter::disassemble_chunk(&func.chunk, "") 186 | ); 187 | std::process::exit(0); 188 | } 189 | if matches.is_present(DEBUG_STR) { 190 | debugger::Debugger::new(func, input.content).debug(); 191 | std::process::exit(0); 192 | } 193 | let mut interpreter = bytecode_interpreter::Interpreter::default(); 194 | let res = interpreter.interpret(func); 195 | match res { 196 | Ok(()) => { 197 | std::process::exit(0); 198 | } 199 | Err(bytecode_interpreter::InterpreterError::Runtime(err)) => { 200 | println!( 201 | "Runtime error: {}\n\n{}", 202 | err, 203 | interpreter.format_backtrace() 204 | ); 205 | 206 | std::process::exit(1); 207 | } 208 | } 209 | } 210 | Err(err) => { 211 | error_formatting::format_compiler_error(&err, &input); 212 | std::process::exit(1); 213 | } 214 | } 215 | } else { 216 | repl::run(extensions); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | use crate::expr; 2 | use crate::extensions; 3 | use crate::scanner; 4 | 5 | use std::fmt; 6 | 7 | #[derive(Default)] 8 | struct Parser { 9 | tokens: Vec, 10 | current: usize, 11 | in_fundec: bool, // in rust, booleans default to false: https://doc.rust-lang.org/std/primitive.bool.html#impl-Default 12 | extensions: extensions::Extensions, 13 | } 14 | 15 | pub enum Error { 16 | UnexpectedToken(scanner::Token), 17 | TokenMismatch { 18 | expected: scanner::TokenType, 19 | found: scanner::Token, 20 | maybe_on_err_string: Option, 21 | }, 22 | MaxParamsExceeded { 23 | kind: FunctionKind, 24 | line: usize, 25 | col: i64, 26 | }, 27 | ReturnNotInFun { 28 | line: usize, 29 | col: i64, 30 | }, 31 | InvalidAssignment { 32 | line: usize, 33 | col: i64, 34 | }, 35 | TooManyArguments { 36 | line: usize, 37 | col: i64, 38 | }, 39 | ExpectedExpression { 40 | token_type: scanner::TokenType, 41 | line: usize, 42 | col: i64, 43 | }, 44 | InvalidTokenInUnaryOp { 45 | token_type: scanner::TokenType, 46 | line: usize, 47 | col: i64, 48 | }, 49 | InvalidTokenInBinaryOp { 50 | token_type: scanner::TokenType, 51 | line: usize, 52 | col: i64, 53 | }, 54 | } 55 | 56 | impl fmt::Debug for Error { 57 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 58 | match &self { 59 | Error::UnexpectedToken(tok) => write!( 60 | f, 61 | "Unexpected token {:?} at line={},col={}", 62 | tok.ty, tok.line, tok.col 63 | ), 64 | Error::TokenMismatch { 65 | maybe_on_err_string, 66 | expected, 67 | found, 68 | } => { 69 | write!( 70 | f, 71 | "Expected token {:?} but found {:?} at line={},col={}", 72 | expected, found.ty, found.line, found.col 73 | )?; 74 | if let Some(on_err_string) = maybe_on_err_string { 75 | write!(f, ": {}", on_err_string)?; 76 | } 77 | fmt::Result::Ok(()) 78 | } 79 | Error::MaxParamsExceeded { kind, line, col } => write!( 80 | f, 81 | "Cannot have more than 255 parameters in a {:?} declaration. Line={},col={}", 82 | kind, line, col 83 | ), 84 | Error::ReturnNotInFun { line, col } => write!( 85 | f, 86 | "return statement not enclosed in a FunDecl at line={},col={}", 87 | line, col 88 | ), 89 | Error::InvalidAssignment { line, col } => { 90 | write!(f, "invalid assignment target at line={},col={}", line, col) 91 | } 92 | Error::TooManyArguments { line, col } => write!( 93 | f, 94 | "Cannot have more than 255 arguments to a function call. Line={},col={}", 95 | line, col 96 | ), 97 | Error::ExpectedExpression { 98 | token_type, 99 | line, 100 | col, 101 | } => write!( 102 | f, 103 | "Expected expression, but found token {:?} at line={},col={}", 104 | token_type, line, col 105 | ), 106 | Error::InvalidTokenInUnaryOp { 107 | token_type, 108 | line, 109 | col, 110 | } => write!( 111 | f, 112 | "invalid token in unary op {:?} at line={},col={}", 113 | token_type, line, col 114 | ), 115 | Error::InvalidTokenInBinaryOp { 116 | token_type, 117 | line, 118 | col, 119 | } => write!( 120 | f, 121 | "invalid token in binary op {:?} at line={},col={}", 122 | token_type, line, col 123 | ), 124 | } 125 | } 126 | } 127 | 128 | #[derive(Debug)] 129 | pub enum FunctionKind { 130 | Function, 131 | Method, 132 | Lambda, 133 | } 134 | 135 | pub fn parse( 136 | extensions: extensions::Extensions, 137 | tokens: Vec, 138 | ) -> Result, Error> { 139 | let mut p = Parser { 140 | tokens, 141 | extensions, 142 | ..Default::default() 143 | }; 144 | let stmts_or_err = p.parse(); 145 | 146 | match stmts_or_err { 147 | Ok(stmts_or_err) => { 148 | if !p.is_at_end() { 149 | let tok = &p.tokens[p.current]; 150 | Err(Error::UnexpectedToken(tok.clone())) 151 | } else { 152 | Ok(stmts_or_err) 153 | } 154 | } 155 | Err(err) => Err(err), 156 | } 157 | } 158 | 159 | /* 160 | Recursive descent using the following grammar 161 | 162 | program → declaration* EOF ; 163 | 164 | declaration → classDecl 165 | | funDecl 166 | | varDecl 167 | | statement ; 168 | 169 | classDecl → "class" IDENTIFIER ( "<" IDENTIFIER )? 170 | "{" function* "}" ; 171 | 172 | funDecl → "fun" function ; 173 | function → IDENTIFIER "(" parameters? ")" block ; 174 | parameters → IDENTIFIER ( "," IDENTIFIER )* ; 175 | 176 | statement → exprStmt 177 | | forStmt 178 | | ifStmt 179 | | printStmt 180 | | returnStmt 181 | | whileStmt 182 | | block ; 183 | 184 | returnStmt → "return" expression? ";" ; 185 | 186 | forStmt → "for" "(" ( varDecl | exprStmt | ";" ) 187 | expression? ";" 188 | expression? ")" statement ; 189 | 190 | whileStmt → "while" "(" expression ")" statement ; 191 | 192 | ifStmt → "if" "(" expression ")" statement ( "else" statement )? ; 193 | 194 | block → "{" declaration* "}" ; 195 | 196 | varDecl → "var" IDENTIFIER ( "=" expression )? ";" ; 197 | 198 | exprStmt → expression ";" ; 199 | printStmt → "print" expression ";" ; 200 | 201 | expression → assignment ; 202 | assignment → ( call "." )? IDENTIFIER "=" assignment 203 | | logic_or; 204 | logic_or → logic_and ( "or" logic_and )* ; 205 | logic_and → equality ( "and" equality )* ; 206 | 207 | equality → comparison ( ( "!=" | "==" ) comparison )* ; 208 | comparison → addition ( ( ">" | ">=" | "<" | "<=" ) addition )* ; 209 | addition → multiplication ( ( "-" | "+" ) multiplication )* ; 210 | multiplication → unary ( ( "/" | "*" ) unary )* ; 211 | unary → ( "!" | "-" ) unary | call ; 212 | call → primary ( "(" arguments? ")" | "." IDENTIFIER | "[" expression "]" )* ; 213 | arguments → expression ( "," expression )* ; 214 | 215 | primary → "true" | "false" | "nil" | "this" 216 | | NUMBER | STRING | IDENTIFIER | "(" expression ")" 217 | | "super" "." IDENTIFIER 218 | | "[" arguments? "]" ; 219 | 220 | */ 221 | impl Parser { 222 | pub fn parse(&mut self) -> Result, Error> { 223 | let mut statements = Vec::new(); 224 | 225 | while !self.is_at_end() { 226 | let stmt = self.declaration()?; 227 | statements.push(stmt); 228 | } 229 | 230 | Ok(statements) 231 | } 232 | 233 | fn declaration(&mut self) -> Result { 234 | if self.matches(scanner::TokenType::Var) { 235 | return self.var_decl(); 236 | } 237 | 238 | if self.matches(scanner::TokenType::Fun) { 239 | return Ok(expr::Stmt::FunDecl(self.fun_decl(FunctionKind::Function)?)); 240 | } 241 | 242 | if self.matches(scanner::TokenType::Class) { 243 | return self.class_decl(); 244 | } 245 | 246 | self.statement() 247 | } 248 | 249 | fn class_decl(&mut self) -> Result { 250 | let name_tok = self 251 | .consume(scanner::TokenType::Identifier, "Expected class name")? 252 | .clone(); 253 | 254 | let class_symbol = expr::Symbol { 255 | name: String::from_utf8(name_tok.lexeme).unwrap(), 256 | line: name_tok.line, 257 | col: name_tok.col, 258 | }; 259 | 260 | let superclass_maybe = if self.matches(scanner::TokenType::Less) { 261 | let superclass_tok = 262 | self.consume(scanner::TokenType::Identifier, "Expected class name.")?; 263 | Some(expr::Symbol { 264 | name: String::from_utf8(superclass_tok.lexeme.clone()).unwrap(), 265 | line: superclass_tok.line, 266 | col: superclass_tok.col, 267 | }) 268 | } else { 269 | None 270 | }; 271 | 272 | self.consume(scanner::TokenType::LeftBrace, "Expected { after class name")?; 273 | 274 | let mut methods = Vec::new(); 275 | while !self.check(scanner::TokenType::RightBrace) && !self.is_at_end() { 276 | methods.push(self.fun_decl(FunctionKind::Method)?); 277 | } 278 | let methods = methods; 279 | 280 | self.consume( 281 | scanner::TokenType::RightBrace, 282 | "Expected } after class body", 283 | )?; 284 | 285 | Ok(expr::Stmt::ClassDecl(expr::ClassDecl { 286 | name: class_symbol, 287 | superclass: superclass_maybe, 288 | methods, 289 | })) 290 | } 291 | 292 | fn fun_decl(&mut self, kind: FunctionKind) -> Result { 293 | let name_tok = self 294 | .consume( 295 | scanner::TokenType::Identifier, 296 | format!("Expected {:?} name", kind).as_ref(), 297 | )? 298 | .clone(); 299 | 300 | let fun_symbol = expr::Symbol { 301 | name: String::from_utf8(name_tok.lexeme).unwrap(), 302 | line: name_tok.line, 303 | col: name_tok.col, 304 | }; 305 | 306 | let (parameters, body) = self.params_and_body(kind)?; 307 | 308 | Ok(expr::FunDecl { 309 | name: fun_symbol, 310 | params: parameters, 311 | body, 312 | }) 313 | } 314 | 315 | fn params_and_body( 316 | &mut self, 317 | kind: FunctionKind, 318 | ) -> Result<(Vec, Vec), Error> { 319 | self.consume( 320 | scanner::TokenType::LeftParen, 321 | format!("Expected ( after {:?} name", kind).as_ref(), 322 | )?; 323 | 324 | let mut parameters = Vec::new(); 325 | 326 | if !self.check(scanner::TokenType::RightParen) { 327 | loop { 328 | if parameters.len() >= 255 { 329 | let peek_tok = self.peek(); 330 | return Err(Error::MaxParamsExceeded { 331 | kind, 332 | line: peek_tok.line, 333 | col: peek_tok.col, 334 | }); 335 | } 336 | 337 | let tok = self 338 | .consume(scanner::TokenType::Identifier, "Expected parameter name")? 339 | .clone(); 340 | 341 | parameters.push(expr::Symbol { 342 | name: String::from_utf8(tok.lexeme).unwrap(), 343 | line: tok.line, 344 | col: tok.col, 345 | }); 346 | 347 | if !self.matches(scanner::TokenType::Comma) { 348 | break; 349 | } 350 | } 351 | } 352 | let parameters = parameters; 353 | 354 | self.consume( 355 | scanner::TokenType::RightParen, 356 | "Expected ) after parameter list", 357 | )?; 358 | self.consume( 359 | scanner::TokenType::LeftBrace, 360 | "Expected { before function body", 361 | )?; 362 | let saved_is_in_fundec = self.in_fundec; 363 | self.in_fundec = true; 364 | let body = self.block()?; 365 | self.in_fundec = saved_is_in_fundec; 366 | 367 | Ok((parameters, body)) 368 | } 369 | 370 | fn var_decl(&mut self) -> Result { 371 | let name_token = self 372 | .consume(scanner::TokenType::Identifier, "Expected variable name")? 373 | .clone(); 374 | 375 | let maybe_initializer = if self.matches(scanner::TokenType::Equal) { 376 | Some(self.expression()?) 377 | } else { 378 | None 379 | }; 380 | 381 | self.consume( 382 | scanner::TokenType::Semicolon, 383 | "Expected ; after variable declaration", 384 | )?; 385 | 386 | Ok(expr::Stmt::VarDecl( 387 | expr::Symbol { 388 | name: String::from_utf8(name_token.lexeme).unwrap(), 389 | line: name_token.line, 390 | col: name_token.col, 391 | }, 392 | maybe_initializer, 393 | )) 394 | } 395 | 396 | fn statement(&mut self) -> Result { 397 | if self.matches(scanner::TokenType::Print) { 398 | return self.print_statement(); 399 | } 400 | 401 | if self.matches(scanner::TokenType::While) { 402 | return self.while_statement(); 403 | } 404 | 405 | if self.matches(scanner::TokenType::LeftBrace) { 406 | return Ok(expr::Stmt::Block(self.block()?)); 407 | } 408 | 409 | if self.matches(scanner::TokenType::For) { 410 | return self.for_statement(); 411 | } 412 | 413 | if self.matches(scanner::TokenType::If) { 414 | return self.if_statement(); 415 | } 416 | 417 | if self.matches(scanner::TokenType::Return) { 418 | return self.return_statement(); 419 | } 420 | 421 | self.expression_statement() 422 | } 423 | 424 | fn return_statement(&mut self) -> Result { 425 | let prev_tok = self.previous().clone(); 426 | 427 | if !self.in_fundec { 428 | return Err(Error::ReturnNotInFun { 429 | line: prev_tok.line, 430 | col: prev_tok.col, 431 | }); 432 | } 433 | 434 | let maybe_retval = if !self.matches(scanner::TokenType::Semicolon) { 435 | Some(self.expression()?) 436 | } else { 437 | None 438 | }; 439 | 440 | if maybe_retval.is_some() { 441 | self.consume( 442 | scanner::TokenType::Semicolon, 443 | "Expected ; after return value", 444 | )?; 445 | } 446 | 447 | Ok(expr::Stmt::Return( 448 | expr::SourceLocation { 449 | line: prev_tok.line, 450 | col: prev_tok.col, 451 | }, 452 | maybe_retval, 453 | )) 454 | } 455 | 456 | fn for_statement(&mut self) -> Result { 457 | self.consume(scanner::TokenType::LeftParen, "Expected ( after for.")?; 458 | 459 | let mut maybe_initializer: Option = None; 460 | if self.matches(scanner::TokenType::Semicolon) { 461 | } else if self.matches(scanner::TokenType::Var) { 462 | maybe_initializer = Some(self.var_decl()?) 463 | } else { 464 | maybe_initializer = Some(self.expression_statement()?) 465 | } 466 | let maybe_initializer = maybe_initializer; 467 | 468 | let mut maybe_condition: Option = None; 469 | if !self.check(scanner::TokenType::Semicolon) { 470 | maybe_condition = Some(self.expression()?) 471 | } 472 | let maybe_condition = maybe_condition; 473 | 474 | self.consume( 475 | scanner::TokenType::Semicolon, 476 | "Expected ; after loop condition", 477 | )?; 478 | 479 | let maybe_increment = if !self.check(scanner::TokenType::RightParen) { 480 | Some(self.expression()?) 481 | } else { 482 | None 483 | }; 484 | 485 | self.consume( 486 | scanner::TokenType::RightParen, 487 | "Expected ) after for clauses", 488 | )?; 489 | 490 | let mut body = self.statement()?; 491 | 492 | if let Some(increment) = maybe_increment { 493 | body = expr::Stmt::Block(vec![body, expr::Stmt::Expr(increment)]) 494 | } 495 | 496 | let condition = match maybe_condition { 497 | Some(cond) => cond, 498 | None => expr::Expr::Literal(expr::Literal::True), 499 | }; 500 | body = expr::Stmt::While(condition, Box::new(body)); 501 | 502 | if let Some(initializer) = maybe_initializer { 503 | body = expr::Stmt::Block(vec![initializer, body]) 504 | } 505 | let body = body; 506 | 507 | Ok(body) 508 | } 509 | 510 | fn while_statement(&mut self) -> Result { 511 | self.consume(scanner::TokenType::LeftParen, "Expected ( after while")?; 512 | let cond = self.expression()?; 513 | self.consume( 514 | scanner::TokenType::RightParen, 515 | "Expected ) after while condition", 516 | )?; 517 | let body = Box::new(self.statement()?); 518 | Ok(expr::Stmt::While(cond, body)) 519 | } 520 | 521 | fn if_statement(&mut self) -> Result { 522 | self.consume(scanner::TokenType::LeftParen, "Expected ( after if.")?; 523 | let cond = self.expression()?; 524 | self.consume( 525 | scanner::TokenType::RightParen, 526 | "Expected ) after if condition.", 527 | )?; 528 | let then_branch = Box::new(self.statement()?); 529 | let maybe_else_branch = if self.matches(scanner::TokenType::Else) { 530 | Some(Box::new(self.statement()?)) 531 | } else { 532 | None 533 | }; 534 | 535 | Ok(expr::Stmt::If(cond, then_branch, maybe_else_branch)) 536 | } 537 | 538 | fn block(&mut self) -> Result, Error> { 539 | let mut stmts = Vec::new(); 540 | 541 | while !self.check(scanner::TokenType::RightBrace) && !self.is_at_end() { 542 | stmts.push(self.declaration()?) 543 | } 544 | 545 | self.consume(scanner::TokenType::RightBrace, "Expected } after block.")?; 546 | 547 | Ok(stmts) 548 | } 549 | 550 | fn print_statement(&mut self) -> Result { 551 | let expr = self.expression()?; 552 | self.consume(scanner::TokenType::Semicolon, "Expected ; after value")?; 553 | Ok(expr::Stmt::Print(expr)) 554 | } 555 | 556 | fn expression_statement(&mut self) -> Result { 557 | let expr = self.expression()?; 558 | self.consume(scanner::TokenType::Semicolon, "Expected ; after value")?; 559 | Ok(expr::Stmt::Expr(expr)) 560 | } 561 | 562 | fn expression(&mut self) -> Result { 563 | self.assignment() 564 | } 565 | 566 | fn assignment(&mut self) -> Result { 567 | let expr = self.or()?; 568 | 569 | if self.matches(scanner::TokenType::Equal) { 570 | let equals = self.previous().clone(); 571 | let new_value = self.assignment()?; 572 | 573 | if let expr::Expr::Variable(sym) = &expr { 574 | return Ok(expr::Expr::Assign(sym.clone(), Box::new(new_value))); 575 | } else if let expr::Expr::Get(e, attr) = expr { 576 | return Ok(expr::Expr::Set(e, attr, Box::new(new_value))); 577 | } 578 | if let expr::Expr::Subscript { 579 | value, 580 | slice, 581 | source_location, 582 | } = expr 583 | { 584 | return Ok(expr::Expr::SetItem { 585 | lhs: value, 586 | slice, 587 | rhs: Box::new(new_value), 588 | source_location, 589 | }); 590 | } else { 591 | return Err(Error::InvalidAssignment { 592 | line: equals.line, 593 | col: equals.col, 594 | }); 595 | } 596 | } 597 | 598 | Ok(expr) 599 | } 600 | 601 | fn or(&mut self) -> Result { 602 | let mut expr = self.and()?; 603 | 604 | while self.matches(scanner::TokenType::Or) { 605 | let right = self.and()?; 606 | expr = expr::Expr::Logical(Box::new(expr), expr::LogicalOp::Or, Box::new(right)); 607 | } 608 | 609 | Ok(expr) 610 | } 611 | 612 | fn and(&mut self) -> Result { 613 | let mut expr = self.equality()?; 614 | 615 | while self.matches(scanner::TokenType::And) { 616 | let right = self.equality()?; 617 | expr = expr::Expr::Logical(Box::new(expr), expr::LogicalOp::And, Box::new(right)); 618 | } 619 | 620 | Ok(expr) 621 | } 622 | 623 | fn comparison(&mut self) -> Result { 624 | let mut expr = self.addition()?; 625 | 626 | while self.match_one_of(vec![ 627 | scanner::TokenType::Greater, 628 | scanner::TokenType::GreaterEqual, 629 | scanner::TokenType::Less, 630 | scanner::TokenType::LessEqual, 631 | ]) { 632 | let operator_token = self.previous().clone(); 633 | let right = Box::new(self.addition()?); 634 | let binop_maybe = Parser::op_token_to_binop(&operator_token); 635 | 636 | match binop_maybe { 637 | Ok(binop) => { 638 | let left = Box::new(expr); 639 | expr = expr::Expr::Binary(left, binop, right); 640 | } 641 | Err(err) => return Err(err), 642 | } 643 | } 644 | Ok(expr) 645 | } 646 | 647 | fn addition(&mut self) -> Result { 648 | let mut expr = self.multiplication()?; 649 | 650 | while self.match_one_of(vec![scanner::TokenType::Minus, scanner::TokenType::Plus]) { 651 | let operator_token = self.previous().clone(); 652 | let right = Box::new(self.multiplication()?); 653 | let binop_maybe = Parser::op_token_to_binop(&operator_token); 654 | 655 | match binop_maybe { 656 | Ok(binop) => { 657 | let left = Box::new(expr); 658 | expr = expr::Expr::Binary(left, binop, right); 659 | } 660 | Err(err) => return Err(err), 661 | } 662 | } 663 | Ok(expr) 664 | } 665 | 666 | fn multiplication(&mut self) -> Result { 667 | let mut expr = self.unary()?; 668 | 669 | while self.match_one_of(vec![scanner::TokenType::Slash, scanner::TokenType::Star]) { 670 | let operator_token = self.previous().clone(); 671 | let right = Box::new(self.unary()?); 672 | let binop_maybe = Parser::op_token_to_binop(&operator_token); 673 | 674 | match binop_maybe { 675 | Ok(binop) => { 676 | let left = Box::new(expr); 677 | expr = expr::Expr::Binary(left, binop, right); 678 | } 679 | Err(err) => return Err(err), 680 | } 681 | } 682 | Ok(expr) 683 | } 684 | 685 | fn unary(&mut self) -> Result { 686 | if self.match_one_of(vec![scanner::TokenType::Bang, scanner::TokenType::Minus]) { 687 | let operator_token = self.previous().clone(); 688 | let right = Box::new(self.unary()?); 689 | let unary_op_maybe = Parser::op_token_to_unary_op(&operator_token); 690 | 691 | return match unary_op_maybe { 692 | Ok(unary_op) => Ok(expr::Expr::Unary(unary_op, right)), 693 | Err(err) => Err(err), 694 | }; 695 | } 696 | self.call() 697 | } 698 | 699 | fn call(&mut self) -> Result { 700 | let mut expr = self.primary()?; 701 | 702 | loop { 703 | if self.matches(scanner::TokenType::LeftParen) { 704 | expr = self.finish_call(expr)?; 705 | } else if self.matches(scanner::TokenType::Dot) { 706 | let name_tok = self 707 | .consume( 708 | scanner::TokenType::Identifier, 709 | "Expected property name after '.'.", 710 | )? 711 | .clone(); 712 | expr = expr::Expr::Get( 713 | Box::new(expr), 714 | expr::Symbol { 715 | name: String::from_utf8(name_tok.lexeme).unwrap(), 716 | line: name_tok.line, 717 | col: name_tok.col, 718 | }, 719 | ); 720 | } else if self.extensions.lists && self.matches(scanner::TokenType::LeftBracket) { 721 | let slice_expr = self.expression()?; 722 | let token = self.consume( 723 | scanner::TokenType::RightBracket, 724 | "Expected ] after subscript", 725 | )?; 726 | expr = expr::Expr::Subscript { 727 | value: Box::new(expr), 728 | slice: Box::new(slice_expr), 729 | source_location: expr::SourceLocation { 730 | line: token.line, 731 | col: token.col, 732 | }, 733 | }; 734 | } else { 735 | break; 736 | } 737 | } 738 | Ok(expr) 739 | } 740 | 741 | fn finish_call(&mut self, callee: expr::Expr) -> Result { 742 | let mut arguments = Vec::new(); 743 | 744 | if !self.check(scanner::TokenType::RightParen) { 745 | loop { 746 | if arguments.len() >= 255 { 747 | let peek_tok = self.peek(); 748 | return Err(Error::TooManyArguments { 749 | line: peek_tok.line, 750 | col: peek_tok.col, 751 | }); 752 | } 753 | arguments.push(self.expression()?); 754 | if !self.matches(scanner::TokenType::Comma) { 755 | break; 756 | } 757 | } 758 | } 759 | 760 | let token = self.consume( 761 | scanner::TokenType::RightParen, 762 | "Expected ) after arguments.", 763 | )?; 764 | 765 | Ok(expr::Expr::Call( 766 | Box::new(callee), 767 | expr::SourceLocation { 768 | line: token.line, 769 | col: token.col, 770 | }, 771 | arguments, 772 | )) 773 | } 774 | 775 | fn primary(&mut self) -> Result { 776 | if self.matches(scanner::TokenType::False) { 777 | return Ok(expr::Expr::Literal(expr::Literal::False)); 778 | } 779 | if self.matches(scanner::TokenType::True) { 780 | return Ok(expr::Expr::Literal(expr::Literal::True)); 781 | } 782 | if self.matches(scanner::TokenType::Nil) { 783 | return Ok(expr::Expr::Literal(expr::Literal::Nil)); 784 | } 785 | if self.matches(scanner::TokenType::Super) { 786 | let super_tok = self.previous().clone(); 787 | self.consume(scanner::TokenType::Dot, "Expected '.' after 'super'.")?; 788 | let method_tok = self.consume( 789 | scanner::TokenType::Identifier, 790 | "Expected superclass method name.", 791 | )?; 792 | return Ok(expr::Expr::Super( 793 | expr::SourceLocation { 794 | line: super_tok.line, 795 | col: super_tok.col, 796 | }, 797 | expr::Symbol { 798 | name: String::from_utf8(method_tok.lexeme.clone()).unwrap(), 799 | line: method_tok.line, 800 | col: method_tok.col, 801 | }, 802 | )); 803 | } 804 | if self.matches(scanner::TokenType::Number) { 805 | match &self.previous().literal { 806 | Some(scanner::Literal::Number(n)) => { 807 | return Ok(expr::Expr::Literal(expr::Literal::Number(*n))) 808 | } 809 | Some(l) => panic!( 810 | "internal error in parser: when parsing number, found literal {:?}", 811 | l 812 | ), 813 | None => panic!("internal error in parser: when parsing number, found no literal"), 814 | } 815 | } 816 | if self.matches(scanner::TokenType::String) { 817 | match &self.previous().literal { 818 | Some(scanner::Literal::Str(s)) => { 819 | return Ok(expr::Expr::Literal(expr::Literal::String(s.clone()))) 820 | } 821 | Some(l) => panic!( 822 | "internal error in parser: when parsing string, found literal {:?}", 823 | l 824 | ), 825 | None => panic!("internal error in parser: when parsing string, found no literal"), 826 | } 827 | } 828 | if self.matches(scanner::TokenType::This) { 829 | let prev = self.previous(); 830 | return Ok(expr::Expr::This(expr::SourceLocation { 831 | line: prev.line, 832 | col: prev.col, 833 | })); 834 | } 835 | if self.matches(scanner::TokenType::Identifier) { 836 | match &self.previous().literal { 837 | Some(scanner::Literal::Identifier(s)) => { 838 | return Ok(expr::Expr::Variable(expr::Symbol { 839 | name: s.clone(), 840 | line: self.previous().line, 841 | col: self.previous().col, 842 | })) 843 | } 844 | Some(l) => panic!( 845 | "internal error in parser: when parsing identifier, found literal {:?}", 846 | l 847 | ), 848 | None => { 849 | panic!("internal error in parser: when parsing identifier, found no literal") 850 | } 851 | } 852 | } 853 | if self.matches(scanner::TokenType::LeftParen) { 854 | let expr = Box::new(self.expression()?); 855 | self.consume( 856 | scanner::TokenType::RightParen, 857 | "Expected ')' after expression.", 858 | )?; 859 | return Ok(expr::Expr::Grouping(expr)); 860 | } 861 | if self.extensions.lists && self.matches(scanner::TokenType::LeftBracket) { 862 | let mut list_elements = Vec::new(); 863 | 864 | if !self.check(scanner::TokenType::RightBracket) { 865 | loop { 866 | list_elements.push(self.expression()?); 867 | if !self.matches(scanner::TokenType::Comma) { 868 | break; 869 | } 870 | } 871 | } 872 | 873 | self.consume(scanner::TokenType::RightBracket, "Expected ].")?; 874 | 875 | return Ok(expr::Expr::List(list_elements)); 876 | } 877 | if self.extensions.lambdas && self.matches(scanner::TokenType::Lambda) { 878 | let (params, body) = self.params_and_body(FunctionKind::Lambda)?; 879 | return Ok(expr::Expr::Lambda(expr::LambdaDecl { params, body })); 880 | } 881 | 882 | Err(Error::ExpectedExpression { 883 | token_type: self.peek().ty, 884 | line: self.peek().line, 885 | col: self.peek().col, 886 | }) 887 | } 888 | 889 | fn consume( 890 | &mut self, 891 | tok: scanner::TokenType, 892 | on_err_str: &str, 893 | ) -> Result<&scanner::Token, Error> { 894 | if self.check(tok) { 895 | return Ok(self.advance()); 896 | } 897 | Err(Error::TokenMismatch { 898 | expected: tok, 899 | found: self.peek().clone(), 900 | maybe_on_err_string: Some(on_err_str.into()), 901 | }) 902 | } 903 | 904 | fn op_token_to_unary_op(tok: &scanner::Token) -> Result { 905 | match tok.ty { 906 | scanner::TokenType::Minus => Ok(expr::UnaryOp { 907 | ty: expr::UnaryOpTy::Minus, 908 | line: tok.line, 909 | col: tok.col, 910 | }), 911 | scanner::TokenType::Bang => Ok(expr::UnaryOp { 912 | ty: expr::UnaryOpTy::Bang, 913 | line: tok.line, 914 | col: tok.col, 915 | }), 916 | _ => Err(Error::InvalidTokenInUnaryOp { 917 | token_type: tok.ty, 918 | line: tok.line, 919 | col: tok.col, 920 | }), 921 | } 922 | } 923 | 924 | fn equality(&mut self) -> Result { 925 | let mut expr = self.comparison()?; 926 | 927 | while self.match_one_of(vec![ 928 | scanner::TokenType::BangEqual, 929 | scanner::TokenType::EqualEqual, 930 | ]) { 931 | let operator_token = self.previous().clone(); 932 | let right = Box::new(self.comparison()?); 933 | 934 | let binop_maybe = Parser::op_token_to_binop(&operator_token); 935 | 936 | match binop_maybe { 937 | Ok(binop) => { 938 | let left = Box::new(expr); 939 | expr = expr::Expr::Binary(left, binop, right); 940 | } 941 | Err(err) => return Err(err), 942 | } 943 | } 944 | Ok(expr) 945 | } 946 | 947 | fn op_token_to_binop(tok: &scanner::Token) -> Result { 948 | match tok.ty { 949 | scanner::TokenType::EqualEqual => Ok(expr::BinaryOp { 950 | ty: expr::BinaryOpTy::EqualEqual, 951 | line: tok.line, 952 | col: tok.col, 953 | }), 954 | scanner::TokenType::BangEqual => Ok(expr::BinaryOp { 955 | ty: expr::BinaryOpTy::NotEqual, 956 | line: tok.line, 957 | col: tok.col, 958 | }), 959 | scanner::TokenType::Less => Ok(expr::BinaryOp { 960 | ty: expr::BinaryOpTy::Less, 961 | line: tok.line, 962 | col: tok.col, 963 | }), 964 | scanner::TokenType::LessEqual => Ok(expr::BinaryOp { 965 | ty: expr::BinaryOpTy::LessEqual, 966 | line: tok.line, 967 | col: tok.col, 968 | }), 969 | scanner::TokenType::Greater => Ok(expr::BinaryOp { 970 | ty: expr::BinaryOpTy::Greater, 971 | line: tok.line, 972 | col: tok.col, 973 | }), 974 | scanner::TokenType::GreaterEqual => Ok(expr::BinaryOp { 975 | ty: expr::BinaryOpTy::GreaterEqual, 976 | line: tok.line, 977 | col: tok.col, 978 | }), 979 | scanner::TokenType::Plus => Ok(expr::BinaryOp { 980 | ty: expr::BinaryOpTy::Plus, 981 | line: tok.line, 982 | col: tok.col, 983 | }), 984 | scanner::TokenType::Minus => Ok(expr::BinaryOp { 985 | ty: expr::BinaryOpTy::Minus, 986 | line: tok.line, 987 | col: tok.col, 988 | }), 989 | scanner::TokenType::Star => Ok(expr::BinaryOp { 990 | ty: expr::BinaryOpTy::Star, 991 | line: tok.line, 992 | col: tok.col, 993 | }), 994 | scanner::TokenType::Slash => Ok(expr::BinaryOp { 995 | ty: expr::BinaryOpTy::Slash, 996 | line: tok.line, 997 | col: tok.col, 998 | }), 999 | _ => Err(Error::InvalidTokenInBinaryOp { 1000 | token_type: tok.ty, 1001 | line: tok.line, 1002 | col: tok.col, 1003 | }), 1004 | } 1005 | } 1006 | 1007 | fn match_one_of(&mut self, types: Vec) -> bool { 1008 | for ty in types.iter() { 1009 | if self.matches(*ty) { 1010 | return true; 1011 | } 1012 | } 1013 | false 1014 | } 1015 | 1016 | fn matches(&mut self, ty: scanner::TokenType) -> bool { 1017 | if self.check(ty) { 1018 | self.advance(); 1019 | return true; 1020 | } 1021 | false 1022 | } 1023 | 1024 | fn check(&self, ty: scanner::TokenType) -> bool { 1025 | if self.is_at_end() { 1026 | return false; 1027 | } 1028 | 1029 | self.peek().ty == ty 1030 | } 1031 | 1032 | fn advance(&mut self) -> &scanner::Token { 1033 | if !self.is_at_end() { 1034 | self.current += 1 1035 | } 1036 | 1037 | self.previous() 1038 | } 1039 | 1040 | fn is_at_end(&self) -> bool { 1041 | self.peek().ty == scanner::TokenType::Eof 1042 | } 1043 | 1044 | fn peek(&self) -> &scanner::Token { 1045 | &self.tokens[self.current] 1046 | } 1047 | 1048 | fn previous(&self) -> &scanner::Token { 1049 | &self.tokens[self.current - 1] 1050 | } 1051 | } 1052 | -------------------------------------------------------------------------------- /src/repl.rs: -------------------------------------------------------------------------------- 1 | use crate::error_formatting; 2 | use crate::expr; 3 | use crate::extensions; 4 | use crate::input; 5 | use crate::line_reader; 6 | use crate::parser; 7 | use crate::scanner; 8 | use crate::treewalk_interpreter; 9 | 10 | use std::sync::atomic::Ordering; 11 | 12 | const VERSION: &str = env!("CARGO_PKG_VERSION"); 13 | const AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); 14 | 15 | fn mk_interpreter() -> treewalk_interpreter::Interpreter { 16 | let interpreter: treewalk_interpreter::Interpreter = Default::default(); 17 | 18 | { 19 | let interrupt_clone = interpreter.interrupted.clone(); 20 | ctrlc::set_handler(move || { 21 | interrupt_clone.store(true, Ordering::Release); 22 | }) 23 | .expect("Error setting Ctrl-C handler"); 24 | } 25 | 26 | interpreter 27 | } 28 | 29 | fn eval_tokens( 30 | interpreter: &mut treewalk_interpreter::Interpreter, 31 | mut tokens: Vec, 32 | recursion_depth: i64, 33 | extensions: extensions::Extensions, 34 | line: &str, 35 | ) { 36 | let handle_err = |err| { 37 | error_formatting::format_parse_error( 38 | err, 39 | &input::Input { 40 | source: input::Source::Literal, 41 | content: line.to_string(), 42 | }, 43 | ); 44 | }; 45 | match parser::parse(extensions, tokens.clone()) { 46 | Ok(stmts) => { 47 | let stmts2: Vec = stmts 48 | .iter() 49 | .enumerate() 50 | .map(|(idx, stmt)| match stmt { 51 | expr::Stmt::Expr(expr) => { 52 | let var_sym = expr::Symbol { 53 | // hack!!! we should find a fresh varname from somewhere 54 | name: format!("isurehopethisisntusedelsewhere{}", idx), 55 | line: 0, 56 | col: 0, 57 | }; 58 | let var_expr = expr::Expr::Variable(var_sym.clone()); 59 | expr::Stmt::Block(vec![ 60 | expr::Stmt::VarDecl(var_sym, Some(expr.clone())), 61 | expr::Stmt::If( 62 | expr::Expr::Binary( 63 | Box::new(var_expr.clone()), 64 | expr::BinaryOp { 65 | ty: expr::BinaryOpTy::NotEqual, 66 | line: 0, 67 | col: 0, 68 | }, 69 | Box::new(expr::Expr::Literal(expr::Literal::Nil)), 70 | ), 71 | Box::new(expr::Stmt::Print(var_expr)), 72 | None, 73 | ), 74 | ]) 75 | } 76 | _ => stmt.clone(), 77 | }) 78 | .collect(); 79 | match interpreter.interpret(&stmts2) { 80 | Ok(()) => {} 81 | Err(err) => println!( 82 | "Runtime error: {}\n\n{}", 83 | err, 84 | interpreter.format_backtrace() 85 | ), 86 | } 87 | } 88 | Err( 89 | err 90 | @ 91 | parser::Error::TokenMismatch { 92 | expected: scanner::TokenType::Semicolon, 93 | found: 94 | scanner::Token { 95 | ty: scanner::TokenType::Eof, 96 | .. 97 | }, 98 | .. 99 | }, 100 | ) => { 101 | let expected_eof = tokens.pop().unwrap(); 102 | 103 | tokens.push(scanner::Token { 104 | ty: scanner::TokenType::Semicolon, 105 | lexeme: Vec::new(), 106 | literal: None, 107 | line: 0, 108 | col: -1, 109 | }); 110 | tokens.push(expected_eof); 111 | 112 | if recursion_depth > 0 { 113 | handle_err(&err) 114 | } else { 115 | eval_tokens(interpreter, tokens, recursion_depth + 1, extensions, line) 116 | } 117 | } 118 | Err(err) => handle_err(&err), 119 | } 120 | } 121 | 122 | pub fn run(extensions: extensions::Extensions) { 123 | let mut interpreter = mk_interpreter(); 124 | let mut line_reader = line_reader::LineReader::new(".repl-history.txt", ">>> "); 125 | println!( 126 | "===================================================\n\ 127 | Welcome to lox {}! Using tree-walk interpreter.\n\ 128 | \n\ 129 | Authors: {}\n\ 130 | ===================================================\n", 131 | VERSION, AUTHORS 132 | ); 133 | 134 | loop { 135 | let readline = line_reader.readline(); 136 | 137 | match readline { 138 | line_reader::LineReadStatus::Line(line) => match scanner::scan_tokens(line.clone()) { 139 | Ok(tokens) => eval_tokens(&mut interpreter, tokens, 0, extensions, &line), 140 | Err(err) => { 141 | error_formatting::format_lexical_error( 142 | &err, 143 | &input::Input { 144 | source: input::Source::Literal, 145 | content: line.to_string(), 146 | }, 147 | ); 148 | } 149 | }, 150 | line_reader::LineReadStatus::Done => break, 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/scanner.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt; 3 | 4 | #[derive(Eq, PartialEq, Debug, Copy, Clone)] 5 | pub enum TokenType { 6 | // Single-character tokens. 7 | LeftParen, 8 | RightParen, 9 | LeftBrace, 10 | RightBrace, 11 | LeftBracket, 12 | RightBracket, 13 | Comma, 14 | Dot, 15 | Minus, 16 | Plus, 17 | Semicolon, 18 | Slash, 19 | Star, 20 | 21 | // One or two character tokens. 22 | Bang, 23 | BangEqual, 24 | Equal, 25 | EqualEqual, 26 | Greater, 27 | GreaterEqual, 28 | Less, 29 | LessEqual, 30 | 31 | // Literals. 32 | Identifier, 33 | String, 34 | Number, 35 | 36 | // Keywords. 37 | And, 38 | Class, 39 | Else, 40 | False, 41 | Fun, 42 | For, 43 | If, 44 | Nil, 45 | Or, 46 | Print, 47 | Return, 48 | Super, 49 | This, 50 | True, 51 | Var, 52 | While, 53 | Lambda, 54 | 55 | Eof, 56 | } 57 | 58 | #[derive(Debug, Clone)] 59 | pub enum Literal { 60 | Identifier(String), 61 | Str(String), 62 | Number(f64), 63 | } 64 | 65 | #[derive(Clone)] 66 | pub struct Token { 67 | pub ty: TokenType, 68 | pub lexeme: Vec, 69 | pub literal: Option, 70 | pub line: usize, 71 | pub col: i64, 72 | } 73 | 74 | impl fmt::Debug for Token { 75 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 76 | write!( 77 | f, 78 | "Token {{ ty: {:?}, lexeme: \"{}\", literal: {:?}, line: {:?}, col: {:?}}}", 79 | self.ty, 80 | String::from_utf8(self.lexeme.clone()).unwrap(), 81 | self.literal, 82 | self.line, 83 | self.col 84 | ) 85 | } 86 | } 87 | 88 | pub fn scan_tokens(input: String) -> Result, Error> { 89 | let mut scanner: Scanner = Default::default(); 90 | 91 | scanner.scan_tokens(input); 92 | 93 | match scanner.err { 94 | Some(err) => Err(err), 95 | None => Ok(scanner.tokens), 96 | } 97 | } 98 | 99 | #[derive(Debug)] 100 | pub struct Error { 101 | pub what: String, 102 | pub line: usize, 103 | pub col: i64, 104 | } 105 | 106 | struct Scanner { 107 | source: Vec, 108 | tokens: Vec, 109 | err: Option, 110 | start: usize, 111 | current: usize, 112 | line: usize, 113 | col: i64, 114 | keywords: HashMap, 115 | } 116 | 117 | impl Default for Scanner { 118 | fn default() -> Scanner { 119 | Scanner { 120 | source: Vec::new(), 121 | tokens: Vec::new(), 122 | err: None, 123 | start: 0, 124 | current: 0, 125 | line: 1, 126 | col: -1, 127 | keywords: vec![ 128 | ("and", TokenType::And), 129 | ("class", TokenType::Class), 130 | ("else", TokenType::Else), 131 | ("false", TokenType::False), 132 | ("for", TokenType::For), 133 | ("fun", TokenType::Fun), 134 | ("if", TokenType::If), 135 | ("nil", TokenType::Nil), 136 | ("or", TokenType::Or), 137 | ("print", TokenType::Print), 138 | ("return", TokenType::Return), 139 | ("super", TokenType::Super), 140 | ("this", TokenType::This), 141 | ("true", TokenType::True), 142 | ("var", TokenType::Var), 143 | ("while", TokenType::While), 144 | ("lambda", TokenType::Lambda), 145 | ] 146 | .into_iter() 147 | .map(|(k, v)| (String::from(k), v)) 148 | .collect(), 149 | } 150 | } 151 | } 152 | 153 | impl Scanner { 154 | fn scan_tokens(&mut self, input: String) { 155 | self.source = input.into_bytes(); 156 | 157 | while !self.done() { 158 | self.start = self.current; 159 | self.scan_token(); 160 | } 161 | 162 | match self.err { 163 | Some(_) => {} 164 | None => self.tokens.push(Token { 165 | ty: TokenType::Eof, 166 | lexeme: Vec::new(), 167 | literal: None, 168 | line: self.line, 169 | col: self.col, 170 | }), 171 | } 172 | } 173 | 174 | fn advance(&mut self) -> char { 175 | self.current += 1; 176 | self.col += 1; 177 | 178 | char::from(self.source[self.current - 1]) 179 | } 180 | 181 | fn scan_token(&mut self) { 182 | let c = self.advance(); 183 | 184 | match c { 185 | '(' => self.add_token(TokenType::LeftParen), 186 | ')' => self.add_token(TokenType::RightParen), 187 | '{' => self.add_token(TokenType::LeftBrace), 188 | '}' => self.add_token(TokenType::RightBrace), 189 | '[' => self.add_token(TokenType::LeftBracket), 190 | ']' => self.add_token(TokenType::RightBracket), 191 | ',' => self.add_token(TokenType::Comma), 192 | '.' => self.add_token(TokenType::Dot), 193 | '-' => self.add_token(TokenType::Minus), 194 | '+' => self.add_token(TokenType::Plus), 195 | ';' => self.add_token(TokenType::Semicolon), 196 | '*' => self.add_token(TokenType::Star), 197 | '!' => { 198 | let matches_eq = self.matches('='); 199 | self.add_token(if matches_eq { 200 | TokenType::BangEqual 201 | } else { 202 | TokenType::Bang 203 | }) 204 | } 205 | '=' => { 206 | let matches_eq = self.matches('='); 207 | self.add_token(if matches_eq { 208 | TokenType::EqualEqual 209 | } else { 210 | TokenType::Equal 211 | }) 212 | } 213 | '<' => { 214 | let matches_eq = self.matches('='); 215 | self.add_token(if matches_eq { 216 | TokenType::LessEqual 217 | } else { 218 | TokenType::Less 219 | }) 220 | } 221 | '>' => { 222 | let matches_eq = self.matches('='); 223 | self.add_token(if matches_eq { 224 | TokenType::GreaterEqual 225 | } else { 226 | TokenType::Greater 227 | }) 228 | } 229 | '/' => { 230 | if self.matches('/') { 231 | while self.peek() != '\n' && !self.is_at_end() { 232 | self.advance(); 233 | } 234 | } else { 235 | self.add_token(TokenType::Slash) 236 | } 237 | } 238 | ' ' | '\r' | '\t' => {} 239 | '\n' => { 240 | self.line += 1; 241 | self.col = 0 242 | } 243 | '"' => self.string(), 244 | _ => { 245 | if Scanner::is_decimal_digit(c) { 246 | self.number() 247 | } else if Scanner::is_alpha(c) { 248 | self.identifier() 249 | } else { 250 | self.err = Some(Error { 251 | what: format!("scanner can't handle {}", c), 252 | line: self.line, 253 | col: self.col, 254 | }) 255 | } 256 | } 257 | } 258 | } 259 | 260 | fn is_alpha(c: char) -> bool { 261 | c.is_alphabetic() 262 | } 263 | 264 | fn is_decimal_digit(c: char) -> bool { 265 | c.is_ascii_digit() 266 | } 267 | 268 | fn is_alphanumeric(c: char) -> bool { 269 | Scanner::is_alpha(c) || Scanner::is_decimal_digit(c) 270 | } 271 | 272 | fn identifier(&mut self) { 273 | while Scanner::is_alphanumeric(self.peek()) { 274 | self.advance(); 275 | } 276 | 277 | let literal_val = 278 | String::from_utf8(self.source[self.start..self.current].to_vec()).unwrap(); 279 | 280 | let token_type = match self.keywords.get(&literal_val) { 281 | Some(kw_token_type) => *kw_token_type, 282 | None => TokenType::Identifier, 283 | }; 284 | 285 | match token_type { 286 | TokenType::Identifier => self.add_token_literal( 287 | TokenType::Identifier, 288 | Some(Literal::Identifier(literal_val)), 289 | ), // book doesn't do this. why not?} 290 | _ => self.add_token(token_type), 291 | } 292 | } 293 | 294 | fn number(&mut self) { 295 | while Scanner::is_decimal_digit(self.peek()) { 296 | self.advance(); 297 | } 298 | 299 | if self.peek() == '.' && Scanner::is_decimal_digit(self.peek_next()) { 300 | self.advance(); 301 | } 302 | 303 | while Scanner::is_decimal_digit(self.peek()) { 304 | self.advance(); 305 | } 306 | 307 | let val: f64 = String::from_utf8(self.source[self.start..self.current].to_vec()) 308 | .unwrap() 309 | .parse() 310 | .unwrap(); 311 | 312 | self.add_token_literal(TokenType::Number, Some(Literal::Number(val))) 313 | } 314 | 315 | fn string(&mut self) { 316 | while self.peek() != '"' && !self.is_at_end() { 317 | if self.peek() == '\n' { 318 | self.line += 1 319 | } 320 | self.advance(); 321 | } 322 | 323 | if self.is_at_end() { 324 | self.err = Some(Error { 325 | what: "Unterminated string".to_string(), 326 | line: self.line, 327 | col: self.col, 328 | }) 329 | } 330 | 331 | assert!(self.peek() == '"'); 332 | 333 | self.advance(); 334 | 335 | self.add_token_literal( 336 | TokenType::String, 337 | Some(Literal::Str( 338 | String::from_utf8(self.source[self.start + 1..self.current - 1].to_vec()).unwrap(), 339 | )), 340 | ) 341 | } 342 | 343 | fn peek_next(&self) -> char { 344 | if self.current + 1 >= self.source.len() { 345 | '\0' 346 | } else { 347 | char::from(self.source[self.current + 1]) 348 | } 349 | } 350 | 351 | fn peek(&self) -> char { 352 | if self.is_at_end() { 353 | '\0' 354 | } else { 355 | char::from(self.source[self.current]) 356 | } 357 | } 358 | 359 | fn matches(&mut self, c: char) -> bool { 360 | if self.is_at_end() { 361 | return true; 362 | } 363 | 364 | if char::from(self.source[self.current]) != c { 365 | return false; 366 | } 367 | 368 | self.current += 1; 369 | self.col += 1; 370 | true 371 | } 372 | 373 | fn add_token(&mut self, token_type: TokenType) { 374 | self.add_token_literal(token_type, None) 375 | } 376 | 377 | fn add_token_literal(&mut self, token_type: TokenType, literal: Option) { 378 | let text = self.source[self.start..self.current].to_vec(); 379 | 380 | self.tokens.push(Token { 381 | ty: token_type, 382 | lexeme: text, 383 | literal, 384 | line: self.line, 385 | col: self.col, 386 | }) 387 | } 388 | 389 | fn done(&self) -> bool { 390 | self.err.is_some() || self.is_at_end() 391 | } 392 | 393 | fn is_at_end(&self) -> bool { 394 | self.current >= self.source.len() 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /src/value.rs: -------------------------------------------------------------------------------- 1 | use crate::bytecode; 2 | use crate::bytecode_interpreter; 3 | use crate::gc; 4 | 5 | use std::cell::RefCell; 6 | use std::collections::HashMap; 7 | use std::rc::Rc; 8 | 9 | #[derive(Clone)] 10 | pub enum Upvalue { 11 | Open(usize), 12 | Closed(Value), 13 | } 14 | 15 | impl Upvalue { 16 | pub fn is_open(&self) -> bool { 17 | match self { 18 | Upvalue::Open(_) => true, 19 | Upvalue::Closed(_) => false, 20 | } 21 | } 22 | 23 | pub fn is_open_with_index(&self, index: usize) -> bool { 24 | match self { 25 | Upvalue::Open(idx) => index == *idx, 26 | Upvalue::Closed(_) => false, 27 | } 28 | } 29 | } 30 | 31 | #[derive(Default, Clone)] 32 | pub struct Closure { 33 | pub function: bytecode::Function, 34 | pub upvalues: Vec>>, 35 | } 36 | 37 | #[derive(Clone)] 38 | pub struct NativeFunction { 39 | pub arity: u8, 40 | pub name: String, 41 | pub func: fn(&mut bytecode_interpreter::Interpreter, &[Value]) -> Result, 42 | } 43 | 44 | #[derive(Clone)] 45 | pub struct Class { 46 | pub name: String, 47 | pub methods: HashMap, 48 | } 49 | 50 | #[derive(Clone)] 51 | pub struct Instance { 52 | pub class_id: gc::HeapId, 53 | pub fields: HashMap, 54 | } 55 | 56 | #[derive(Clone)] 57 | pub struct BoundMethod { 58 | pub instance_id: gc::HeapId, 59 | pub closure_id: gc::HeapId, 60 | } 61 | 62 | #[derive(Clone)] 63 | pub enum Value { 64 | Number(f64), 65 | Bool(bool), 66 | String(gc::HeapId), 67 | Function(gc::HeapId), 68 | Instance(gc::HeapId), 69 | BoundMethod(gc::HeapId), 70 | Class(gc::HeapId), 71 | NativeFunction(NativeFunction), 72 | Nil, 73 | List(gc::HeapId), 74 | } 75 | 76 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 77 | pub enum Type { 78 | Number, 79 | Bool, 80 | String, 81 | Function, 82 | NativeFunction, 83 | Class, 84 | BoundMethod, 85 | Instance, 86 | Nil, 87 | List, 88 | } 89 | 90 | pub fn type_of(value: &Value) -> Type { 91 | match value { 92 | Value::Number(_) => Type::Number, 93 | Value::Bool(_) => Type::Bool, 94 | Value::String(_) => Type::String, 95 | Value::Function(_) => Type::Function, 96 | Value::NativeFunction(_) => Type::NativeFunction, 97 | Value::BoundMethod(_) => Type::BoundMethod, 98 | Value::Class(_) => Type::Class, 99 | Value::Instance(_) => Type::Instance, 100 | Value::Nil => Type::Nil, 101 | Value::List(_) => Type::List, 102 | } 103 | } 104 | --------------------------------------------------------------------------------