fix(users/tazjin): rustfmt code with non-default settings
rustfmt only sometimes detects path-based nested config files (probably some kind of race?), so my users folder uses a separate formatting check for rustfmt to avoid flaky CI. Enough flakes around already ... Change-Id: Ifd862f9974f071b3a256643dd8e56c019116156a Reviewed-on: https://cl.tvl.fyi/c/depot/+/5242 Reviewed-by: tazjin <tazjin@tvl.su> Autosubmit: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI
This commit is contained in:
		
							parent
							
								
									8b8c98380e
								
							
						
					
					
						commit
						0d0b43ed88
					
				
					 16 changed files with 348 additions and 421 deletions
				
			
		|  | @ -63,9 +63,11 @@ enum Precedence { | |||
|     Equality,   // == !=
 | ||||
|     Comparison, // < > <= >=
 | ||||
|     Term,       // + -
 | ||||
|     Factor,     // * /
 | ||||
|     Unary,      // ! -
 | ||||
|     Call,       // . ()
 | ||||
|     Factor,     //
 | ||||
|     // 
 | ||||
|     // * /
 | ||||
|     Unary, // ! -
 | ||||
|     Call,  // . ()
 | ||||
|     Primary, | ||||
| } | ||||
| 
 | ||||
|  | @ -78,11 +80,7 @@ struct ParseRule<T: Iterator<Item = Token>> { | |||
| } | ||||
| 
 | ||||
| impl<T: Iterator<Item = Token>> ParseRule<T> { | ||||
|     fn new( | ||||
|         prefix: Option<ParseFn<T>>, | ||||
|         infix: Option<ParseFn<T>>, | ||||
|         precedence: Precedence, | ||||
|     ) -> Self { | ||||
|     fn new(prefix: Option<ParseFn<T>>, infix: Option<ParseFn<T>>, precedence: Precedence) -> Self { | ||||
|         ParseRule { | ||||
|             prefix, | ||||
|             infix, | ||||
|  | @ -105,18 +103,16 @@ impl Precedence { | |||
|             Precedence::Factor => Precedence::Unary, | ||||
|             Precedence::Unary => Precedence::Call, | ||||
|             Precedence::Call => Precedence::Primary, | ||||
|             Precedence::Primary => panic!( | ||||
|                 "invalid parser state: no higher precedence than Primary" | ||||
|             ), | ||||
|             Precedence::Primary => { | ||||
|                 panic!("invalid parser state: no higher precedence than Primary") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn rule_for<T: Iterator<Item = Token>>(token: &TokenKind) -> ParseRule<T> { | ||||
|     match token { | ||||
|         TokenKind::LeftParen => { | ||||
|             ParseRule::new(Some(Compiler::grouping), None, Precedence::None) | ||||
|         } | ||||
|         TokenKind::LeftParen => ParseRule::new(Some(Compiler::grouping), None, Precedence::None), | ||||
| 
 | ||||
|         TokenKind::Minus => ParseRule::new( | ||||
|             Some(Compiler::unary), | ||||
|  | @ -124,57 +120,33 @@ fn rule_for<T: Iterator<Item = Token>>(token: &TokenKind) -> ParseRule<T> { | |||
|             Precedence::Term, | ||||
|         ), | ||||
| 
 | ||||
|         TokenKind::Plus => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Term) | ||||
|         } | ||||
|         TokenKind::Plus => ParseRule::new(None, Some(Compiler::binary), Precedence::Term), | ||||
| 
 | ||||
|         TokenKind::Slash => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Factor) | ||||
|         } | ||||
|         TokenKind::Slash => ParseRule::new(None, Some(Compiler::binary), Precedence::Factor), | ||||
| 
 | ||||
|         TokenKind::Star => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Factor) | ||||
|         } | ||||
|         TokenKind::Star => ParseRule::new(None, Some(Compiler::binary), Precedence::Factor), | ||||
| 
 | ||||
|         TokenKind::Number(_) => { | ||||
|             ParseRule::new(Some(Compiler::number), None, Precedence::None) | ||||
|         } | ||||
|         TokenKind::Number(_) => ParseRule::new(Some(Compiler::number), None, Precedence::None), | ||||
| 
 | ||||
|         TokenKind::True => { | ||||
|             ParseRule::new(Some(Compiler::literal), None, Precedence::None) | ||||
|         } | ||||
|         TokenKind::True => ParseRule::new(Some(Compiler::literal), None, Precedence::None), | ||||
| 
 | ||||
|         TokenKind::False => { | ||||
|             ParseRule::new(Some(Compiler::literal), None, Precedence::None) | ||||
|         } | ||||
|         TokenKind::False => ParseRule::new(Some(Compiler::literal), None, Precedence::None), | ||||
| 
 | ||||
|         TokenKind::Nil => { | ||||
|             ParseRule::new(Some(Compiler::literal), None, Precedence::None) | ||||
|         } | ||||
|         TokenKind::Nil => ParseRule::new(Some(Compiler::literal), None, Precedence::None), | ||||
| 
 | ||||
|         TokenKind::Bang => { | ||||
|             ParseRule::new(Some(Compiler::unary), None, Precedence::None) | ||||
|         } | ||||
|         TokenKind::Bang => ParseRule::new(Some(Compiler::unary), None, Precedence::None), | ||||
| 
 | ||||
|         TokenKind::BangEqual => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Equality) | ||||
|         } | ||||
|         TokenKind::BangEqual => ParseRule::new(None, Some(Compiler::binary), Precedence::Equality), | ||||
| 
 | ||||
|         TokenKind::EqualEqual => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Equality) | ||||
|         } | ||||
|         TokenKind::EqualEqual => ParseRule::new(None, Some(Compiler::binary), Precedence::Equality), | ||||
| 
 | ||||
|         TokenKind::Greater => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison) | ||||
|         } | ||||
|         TokenKind::Greater => ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison), | ||||
| 
 | ||||
|         TokenKind::GreaterEqual => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison) | ||||
|         } | ||||
| 
 | ||||
|         TokenKind::Less => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison) | ||||
|         } | ||||
|         TokenKind::Less => ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison), | ||||
| 
 | ||||
|         TokenKind::LessEqual => { | ||||
|             ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison) | ||||
|  | @ -184,9 +156,7 @@ fn rule_for<T: Iterator<Item = Token>>(token: &TokenKind) -> ParseRule<T> { | |||
|             ParseRule::new(Some(Compiler::variable), None, Precedence::None) | ||||
|         } | ||||
| 
 | ||||
|         TokenKind::String(_) => { | ||||
|             ParseRule::new(Some(Compiler::string), None, Precedence::None) | ||||
|         } | ||||
|         TokenKind::String(_) => ParseRule::new(Some(Compiler::string), None, Precedence::None), | ||||
| 
 | ||||
|         _ => ParseRule::new(None, None, Precedence::None), | ||||
|     } | ||||
|  | @ -236,9 +206,7 @@ impl<T: Iterator<Item = Token>> Compiler<T> { | |||
| 
 | ||||
|     fn define_variable(&mut self, var: Option<ConstantIdx>) -> LoxResult<()> { | ||||
|         if self.locals.scope_depth == 0 { | ||||
|             self.emit_op(OpCode::OpDefineGlobal( | ||||
|                 var.expect("should be global"), | ||||
|             )); | ||||
|             self.emit_op(OpCode::OpDefineGlobal(var.expect("should be global"))); | ||||
|         } else { | ||||
|             self.locals | ||||
|                 .locals | ||||
|  | @ -305,9 +273,7 @@ impl<T: Iterator<Item = Token>> Compiler<T> { | |||
|     } | ||||
| 
 | ||||
|     fn block(&mut self) -> LoxResult<()> { | ||||
|         while !self.check(&TokenKind::RightBrace) | ||||
|             && !self.check(&TokenKind::Eof) | ||||
|         { | ||||
|         while !self.check(&TokenKind::RightBrace) && !self.check(&TokenKind::Eof) { | ||||
|             self.declaration()?; | ||||
|         } | ||||
| 
 | ||||
|  | @ -712,9 +678,8 @@ impl<T: Iterator<Item = Token>> Compiler<T> { | |||
| 
 | ||||
| pub fn compile(code: &str) -> Result<(Interner, Chunk), Vec<Error>> { | ||||
|     let chars = code.chars().collect::<Vec<char>>(); | ||||
|     let tokens = scanner::scan(&chars).map_err(|errors| { | ||||
|         errors.into_iter().map(Into::into).collect::<Vec<Error>>() | ||||
|     })?; | ||||
|     let tokens = scanner::scan(&chars) | ||||
|         .map_err(|errors| errors.into_iter().map(Into::into).collect::<Vec<Error>>())?; | ||||
| 
 | ||||
|     let mut compiler = Compiler { | ||||
|         tokens: tokens.into_iter().peekable(), | ||||
|  |  | |||
|  | @ -23,10 +23,7 @@ impl crate::Lox for Interpreter { | |||
|         Interpreter {} | ||||
|     } | ||||
| 
 | ||||
|     fn interpret( | ||||
|         &mut self, | ||||
|         code: String, | ||||
|     ) -> Result<Self::Value, Vec<Self::Error>> { | ||||
|     fn interpret(&mut self, code: String) -> Result<Self::Value, Vec<Self::Error>> { | ||||
|         let (strings, chunk) = compiler::compile(&code)?; | ||||
|         vm::interpret(strings, chunk).map_err(|e| vec![e]) | ||||
|     } | ||||
|  |  | |||
|  | @ -118,12 +118,7 @@ impl VM { | |||
| 
 | ||||
|                 OpCode::OpNegate => { | ||||
|                     let v = self.pop(); | ||||
|                     with_type!( | ||||
|                         self, | ||||
|                         v, | ||||
|                         Value::Number(num), | ||||
|                         self.push(Value::Number(-num)) | ||||
|                     ); | ||||
|                     with_type!(self, v, Value::Number(num), self.push(Value::Number(-num))); | ||||
|                 } | ||||
| 
 | ||||
|                 OpCode::OpSubtract => binary_op!(self, Number, -), | ||||
|  | @ -141,15 +136,18 @@ impl VM { | |||
|                             self.push(Value::String(new_s.into())); | ||||
|                         } | ||||
| 
 | ||||
|                         (Value::Number(n_a), Value::Number(n_b)) => | ||||
|                             self.push(Value::Number(n_a + n_b)), | ||||
|                         (Value::Number(n_a), Value::Number(n_b)) => { | ||||
|                             self.push(Value::Number(n_a + n_b)) | ||||
|                         } | ||||
| 
 | ||||
|                         _ => return Err(Error { | ||||
|                             line: self.chunk.get_line(self.ip - 1), | ||||
|                             kind: ErrorKind::TypeError( | ||||
|                                 "'+' operator only works on strings and numbers".into() | ||||
|                             ), | ||||
|                         }) | ||||
|                         _ => { | ||||
|                             return Err(Error { | ||||
|                                 line: self.chunk.get_line(self.ip - 1), | ||||
|                                 kind: ErrorKind::TypeError( | ||||
|                                     "'+' operator only works on strings and numbers".into(), | ||||
|                                 ), | ||||
|                             }) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|  | @ -205,8 +203,7 @@ impl VM { | |||
|                         self.stack.len() > local_idx.0, | ||||
|                         "stack is not currently large enough for local" | ||||
|                     ); | ||||
|                     self.stack[local_idx.0] = | ||||
|                         self.stack.last().unwrap().clone(); | ||||
|                     self.stack[local_idx.0] = self.stack.last().unwrap().clone(); | ||||
|                 } | ||||
| 
 | ||||
|                 OpCode::OpJumpPlaceholder(_) => { | ||||
|  | @ -255,9 +252,7 @@ impl VM { | |||
|     fn print_value(&self, val: Value) -> String { | ||||
|         match val { | ||||
|             Value::String(LoxString::Heap(s)) => s, | ||||
|             Value::String(LoxString::Interned(id)) => { | ||||
|                 self.strings.lookup(id).into() | ||||
|             } | ||||
|             Value::String(LoxString::Interned(id)) => self.strings.lookup(id).into(), | ||||
|             _ => format!("{:?}", val), | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -1,8 +1,5 @@ | |||
| use std::env; | ||||
| use std::fs; | ||||
| use std::io; | ||||
| use std::io::Write; | ||||
| use std::process; | ||||
| use std::{env, fs, io, process}; | ||||
| 
 | ||||
| mod bytecode; | ||||
| mod scanner; | ||||
|  | @ -15,10 +12,7 @@ pub trait Lox { | |||
|     type Error: std::fmt::Display; | ||||
| 
 | ||||
|     fn create() -> Self; | ||||
|     fn interpret( | ||||
|         &mut self, | ||||
|         source: String, | ||||
|     ) -> Result<Self::Value, Vec<Self::Error>>; | ||||
|     fn interpret(&mut self, source: String) -> Result<Self::Value, Vec<Self::Error>>; | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
|  | @ -29,9 +23,7 @@ fn main() { | |||
|     } | ||||
| 
 | ||||
|     match env::var("LOX_INTERPRETER").as_ref().map(String::as_str) { | ||||
|         Ok("treewalk") => { | ||||
|             pick::<treewalk::interpreter::Interpreter>(args.nth(1)) | ||||
|         } | ||||
|         Ok("treewalk") => pick::<treewalk::interpreter::Interpreter>(args.nth(1)), | ||||
|         _ => pick::<bytecode::Interpreter>(args.nth(1)), | ||||
|     } | ||||
| } | ||||
|  | @ -46,8 +38,7 @@ fn pick<I: Lox>(file_arg: Option<String>) { | |||
| 
 | ||||
| // Run Lox code from a file and print results to stdout
 | ||||
| fn run_file<I: Lox>(file: &str) { | ||||
|     let contents = | ||||
|         fs::read_to_string(file).expect("failed to read the input file"); | ||||
|     let contents = fs::read_to_string(file).expect("failed to read the input file"); | ||||
|     let mut lox = I::create(); | ||||
|     run(&mut lox, contents); | ||||
| } | ||||
|  |  | |||
|  | @ -106,15 +106,9 @@ impl<'a> Scanner<'a> { | |||
| 
 | ||||
|             // possible multi-character tokens
 | ||||
|             '!' => self.add_if_next('=', TokenKind::BangEqual, TokenKind::Bang), | ||||
|             '=' => { | ||||
|                 self.add_if_next('=', TokenKind::EqualEqual, TokenKind::Equal) | ||||
|             } | ||||
|             '=' => self.add_if_next('=', TokenKind::EqualEqual, TokenKind::Equal), | ||||
|             '<' => self.add_if_next('=', TokenKind::LessEqual, TokenKind::Less), | ||||
|             '>' => self.add_if_next( | ||||
|                 '=', | ||||
|                 TokenKind::GreaterEqual, | ||||
|                 TokenKind::Greater, | ||||
|             ), | ||||
|             '>' => self.add_if_next('=', TokenKind::GreaterEqual, TokenKind::Greater), | ||||
| 
 | ||||
|             '/' => { | ||||
|                 // support comments until EOL by discarding characters
 | ||||
|  | @ -234,8 +228,7 @@ impl<'a> Scanner<'a> { | |||
|             self.advance(); | ||||
|         } | ||||
| 
 | ||||
|         let ident: String = | ||||
|             self.source[self.start..self.current].iter().collect(); | ||||
|         let ident: String = self.source[self.start..self.current].iter().collect(); | ||||
| 
 | ||||
|         // Determine whether this is an identifier, or a keyword:
 | ||||
|         let token_kind = match ident.as_str() { | ||||
|  |  | |||
|  | @ -34,11 +34,7 @@ impl Callable { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn call( | ||||
|         &self, | ||||
|         lox: &mut Interpreter, | ||||
|         args: Vec<Value>, | ||||
|     ) -> Result<Value, Error> { | ||||
|     fn call(&self, lox: &mut Interpreter, args: Vec<Value>) -> Result<Value, Error> { | ||||
|         match self { | ||||
|             Callable::Builtin(builtin) => builtin.call(args), | ||||
| 
 | ||||
|  | @ -50,10 +46,8 @@ impl Callable { | |||
|                     fn_env.define(param, value)?; | ||||
|                 } | ||||
| 
 | ||||
|                 let result = lox.interpret_block_with_env( | ||||
|                     Some(Rc::new(RwLock::new(fn_env))), | ||||
|                     &func.body, | ||||
|                 ); | ||||
|                 let result = | ||||
|                     lox.interpret_block_with_env(Some(Rc::new(RwLock::new(fn_env))), &func.body); | ||||
| 
 | ||||
|                 match result { | ||||
|                     // extract returned values if applicable
 | ||||
|  | @ -109,22 +103,13 @@ pub struct Environment { | |||
| } | ||||
| 
 | ||||
| impl Environment { | ||||
|     fn define( | ||||
|         &mut self, | ||||
|         name: &scanner::Token, | ||||
|         value: Value, | ||||
|     ) -> Result<(), Error> { | ||||
|     fn define(&mut self, name: &scanner::Token, value: Value) -> Result<(), Error> { | ||||
|         let ident = identifier_str(name)?; | ||||
|         self.values.insert(ident.into(), value); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn get( | ||||
|         &self, | ||||
|         ident: &str, | ||||
|         line: usize, | ||||
|         depth: usize, | ||||
|     ) -> Result<Value, Error> { | ||||
|     fn get(&self, ident: &str, line: usize, depth: usize) -> Result<Value, Error> { | ||||
|         if depth > 0 { | ||||
|             match &self.enclosing { | ||||
|                 None => { | ||||
|  | @ -137,9 +122,7 @@ impl Environment { | |||
|                     }) | ||||
|                 } | ||||
|                 Some(parent) => { | ||||
|                     let env = parent | ||||
|                         .read() | ||||
|                         .expect("fatal: environment lock poisoned"); | ||||
|                     let env = parent.read().expect("fatal: environment lock poisoned"); | ||||
|                     return env.get(ident, line, depth - 1); | ||||
|                 } | ||||
|             } | ||||
|  | @ -154,11 +137,7 @@ impl Environment { | |||
|             }) | ||||
|     } | ||||
| 
 | ||||
|     fn assign( | ||||
|         &mut self, | ||||
|         name: &scanner::Token, | ||||
|         value: Value, | ||||
|     ) -> Result<(), Error> { | ||||
|     fn assign(&mut self, name: &scanner::Token, value: Value) -> Result<(), Error> { | ||||
|         let ident = identifier_str(name)?; | ||||
| 
 | ||||
|         match self.values.get_mut(ident) { | ||||
|  | @ -242,22 +221,14 @@ impl Lox for Interpreter { | |||
| 
 | ||||
| impl Interpreter { | ||||
|     // Environment modification helpers
 | ||||
|     fn define_var( | ||||
|         &mut self, | ||||
|         name: &scanner::Token, | ||||
|         value: Value, | ||||
|     ) -> Result<(), Error> { | ||||
|     fn define_var(&mut self, name: &scanner::Token, value: Value) -> Result<(), Error> { | ||||
|         self.env | ||||
|             .write() | ||||
|             .expect("environment lock is poisoned") | ||||
|             .define(name, value) | ||||
|     } | ||||
| 
 | ||||
|     fn assign_var( | ||||
|         &mut self, | ||||
|         name: &scanner::Token, | ||||
|         value: Value, | ||||
|     ) -> Result<(), Error> { | ||||
|     fn assign_var(&mut self, name: &scanner::Token, value: Value) -> Result<(), Error> { | ||||
|         self.env | ||||
|             .write() | ||||
|             .expect("environment lock is poisoned") | ||||
|  | @ -271,11 +242,10 @@ impl Interpreter { | |||
|             kind: ErrorKind::UndefinedVariable(ident.into()), | ||||
|         })?; | ||||
| 
 | ||||
|         self.env.read().expect("environment lock is poisoned").get( | ||||
|             ident, | ||||
|             var.name.line, | ||||
|             depth, | ||||
|         ) | ||||
|         self.env | ||||
|             .read() | ||||
|             .expect("environment lock is poisoned") | ||||
|             .get(ident, var.name.line, depth) | ||||
|     } | ||||
| 
 | ||||
|     /// Interpret the block in the supplied environment. If no
 | ||||
|  | @ -324,16 +294,10 @@ impl Interpreter { | |||
|                 Value::Literal(Literal::String(output)) | ||||
|             } | ||||
|             Statement::Var(var) => return self.interpret_var(var), | ||||
|             Statement::Block(block) => { | ||||
|                 return self.interpret_block_with_env(None, block) | ||||
|             } | ||||
|             Statement::Block(block) => return self.interpret_block_with_env(None, block), | ||||
|             Statement::If(if_stmt) => return self.interpret_if(if_stmt), | ||||
|             Statement::While(while_stmt) => { | ||||
|                 return self.interpret_while(while_stmt) | ||||
|             } | ||||
|             Statement::Function(func) => { | ||||
|                 return self.interpret_function(func.clone()) | ||||
|             } | ||||
|             Statement::While(while_stmt) => return self.interpret_while(while_stmt), | ||||
|             Statement::Function(func) => return self.interpret_function(func.clone()), | ||||
|             Statement::Return(ret) => { | ||||
|                 return Err(Error { | ||||
|                     line: 0, | ||||
|  | @ -348,9 +312,7 @@ impl Interpreter { | |||
|     fn interpret_var(&mut self, var: &parser::Var) -> Result<Value, Error> { | ||||
|         let init = var.initialiser.as_ref().ok_or_else(|| Error { | ||||
|             line: var.name.line, | ||||
|             kind: ErrorKind::InternalError( | ||||
|                 "missing variable initialiser".into(), | ||||
|             ), | ||||
|             kind: ErrorKind::InternalError("missing variable initialiser".into()), | ||||
|         })?; | ||||
|         let value = self.eval(init)?; | ||||
|         self.define_var(&var.name, value.clone())?; | ||||
|  | @ -369,10 +331,7 @@ impl Interpreter { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn interpret_while( | ||||
|         &mut self, | ||||
|         stmt: &parser::While, | ||||
|     ) -> Result<Value, Error> { | ||||
|     fn interpret_while(&mut self, stmt: &parser::While) -> Result<Value, Error> { | ||||
|         let mut value = Value::Literal(Literal::Nil); | ||||
|         while eval_truthy(&self.eval(&stmt.condition)?) { | ||||
|             value = self.interpret_stmt(&stmt.body)?; | ||||
|  | @ -381,10 +340,7 @@ impl Interpreter { | |||
|         Ok(value) | ||||
|     } | ||||
| 
 | ||||
|     fn interpret_function( | ||||
|         &mut self, | ||||
|         func: Rc<parser::Function>, | ||||
|     ) -> Result<Value, Error> { | ||||
|     fn interpret_function(&mut self, func: Rc<parser::Function>) -> Result<Value, Error> { | ||||
|         let name = func.name.clone(); | ||||
|         let value = Value::Callable(Callable::Function { | ||||
|             func, | ||||
|  | @ -414,9 +370,7 @@ impl Interpreter { | |||
|             (TokenKind::Minus, Value::Literal(Literal::Number(num))) => { | ||||
|                 Ok(Literal::Number(-num).into()) | ||||
|             } | ||||
|             (TokenKind::Bang, right) => { | ||||
|                 Ok(Literal::Boolean(!eval_truthy(&right)).into()) | ||||
|             } | ||||
|             (TokenKind::Bang, right) => Ok(Literal::Boolean(!eval_truthy(&right)).into()), | ||||
| 
 | ||||
|             (op, right) => Err(Error { | ||||
|                 line: expr.operator.line, | ||||
|  | @ -478,10 +432,7 @@ impl Interpreter { | |||
|         Ok(value) | ||||
|     } | ||||
| 
 | ||||
|     fn eval_logical( | ||||
|         &mut self, | ||||
|         logical: &parser::Logical, | ||||
|     ) -> Result<Value, Error> { | ||||
|     fn eval_logical(&mut self, logical: &parser::Logical) -> Result<Value, Error> { | ||||
|         let left = eval_truthy(&self.eval(&logical.left)?); | ||||
|         let right = eval_truthy(&self.eval(&logical.right)?); | ||||
| 
 | ||||
|  | @ -490,10 +441,7 @@ impl Interpreter { | |||
|             TokenKind::Or => Ok(Literal::Boolean(left || right).into()), | ||||
|             kind => Err(Error { | ||||
|                 line: logical.operator.line, | ||||
|                 kind: ErrorKind::InternalError(format!( | ||||
|                     "Invalid logical operator: {:?}", | ||||
|                     kind | ||||
|                 )), | ||||
|                 kind: ErrorKind::InternalError(format!("Invalid logical operator: {:?}", kind)), | ||||
|             }), | ||||
|         } | ||||
|     } | ||||
|  | @ -504,10 +452,7 @@ impl Interpreter { | |||
|             Value::Literal(v) => { | ||||
|                 return Err(Error { | ||||
|                     line: call.paren.line, | ||||
|                     kind: ErrorKind::RuntimeError(format!( | ||||
|                         "not callable: {:?}", | ||||
|                         v | ||||
|                     )), | ||||
|                     kind: ErrorKind::RuntimeError(format!("not callable: {:?}", v)), | ||||
|                 }) | ||||
|             } | ||||
|         }; | ||||
|  | @ -546,10 +491,7 @@ fn eval_truthy(lit: &Value) -> bool { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| fn set_enclosing_env( | ||||
|     this: &RwLock<Environment>, | ||||
|     parent: Rc<RwLock<Environment>>, | ||||
| ) { | ||||
| fn set_enclosing_env(this: &RwLock<Environment>, parent: Rc<RwLock<Environment>>) { | ||||
|     this.write() | ||||
|         .expect("environment lock is poisoned") | ||||
|         .enclosing = Some(parent); | ||||
|  |  | |||
|  | @ -124,56 +124,54 @@ pub enum Statement { | |||
| 
 | ||||
| // Parser
 | ||||
| 
 | ||||
| /* | ||||
| program        → declaration* EOF ; | ||||
| 
 | ||||
| declaration    → funDecl | ||||
|                | varDecl | ||||
|                | statement ; | ||||
| 
 | ||||
| funDecl        → "fun" function ; | ||||
| function       → IDENTIFIER "(" parameters? ")" block ; | ||||
| parameters     → IDENTIFIER ( "," IDENTIFIER )* ; | ||||
| 
 | ||||
| 
 | ||||
| statement      → exprStmt | ||||
|                | forStmt | ||||
|                | ifStmt | ||||
|                | printStmt | ||||
|                | returnStmt | ||||
|                | whileStmt | ||||
|                | block ; | ||||
| 
 | ||||
| forStmt        → "for" "(" ( varDecl | exprStmt | ";" ) | ||||
|                  expression? ";" | ||||
|                  expression? ")" statement ; | ||||
| 
 | ||||
| returnStmt     → "return" expression? ";" ; | ||||
| 
 | ||||
| whileStmt      → "while" "(" expression ")" statement ; | ||||
| 
 | ||||
| exprStmt       → expression ";" ; | ||||
| 
 | ||||
| ifStmt         → "if" "(" expression ")" statement | ||||
|                ( "else" statement )? ; | ||||
| 
 | ||||
| printStmt      → "print" expression ";" ; | ||||
| 
 | ||||
| expression     → assignment ; | ||||
| assignment     → IDENTIFIER "=" assignment | ||||
|                | logic_or ; | ||||
| logic_or       → logic_and ( "or" logic_and )* ; | ||||
| logic_and      → equality ( "and" equality )* ; | ||||
| equality       → comparison ( ( "!=" | "==" ) comparison )* ; | ||||
| comparison     → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; | ||||
| term           → factor ( ( "-" | "+" ) factor )* ; | ||||
| factor         → unary ( ( "/" | "*" ) unary )* ; | ||||
| unary          → ( "!" | "-" ) unary | call ; | ||||
| call           → primary ( "(" arguments? ")" )* ; | ||||
| arguments      → expression ( "," expression )* ; | ||||
| primary        → NUMBER | STRING | "true" | "false" | "nil" | ||||
|                | "(" expression ")" ; | ||||
| */ | ||||
| // program        → declaration* EOF ;
 | ||||
| //
 | ||||
| // declaration    → funDecl
 | ||||
| // | varDecl
 | ||||
| // | statement ;
 | ||||
| //
 | ||||
| // funDecl        → "fun" function ;
 | ||||
| // function       → IDENTIFIER "(" parameters? ")" block ;
 | ||||
| // parameters     → IDENTIFIER ( "," IDENTIFIER )* ;
 | ||||
| //
 | ||||
| //
 | ||||
| // statement      → exprStmt
 | ||||
| // | forStmt
 | ||||
| // | ifStmt
 | ||||
| // | printStmt
 | ||||
| // | returnStmt
 | ||||
| // | whileStmt
 | ||||
| // | block ;
 | ||||
| //
 | ||||
| // forStmt        → "for" "(" ( varDecl | exprStmt | ";" )
 | ||||
| // expression? ";"
 | ||||
| // expression? ")" statement ;
 | ||||
| //
 | ||||
| // returnStmt     → "return" expression? ";" ;
 | ||||
| //
 | ||||
| // whileStmt      → "while" "(" expression ")" statement ;
 | ||||
| //
 | ||||
| // exprStmt       → expression ";" ;
 | ||||
| //
 | ||||
| // ifStmt         → "if" "(" expression ")" statement
 | ||||
| // ( "else" statement )? ;
 | ||||
| //
 | ||||
| // printStmt      → "print" expression ";" ;
 | ||||
| //
 | ||||
| // expression     → assignment ;
 | ||||
| // assignment     → IDENTIFIER "=" assignment
 | ||||
| // | logic_or ;
 | ||||
| // logic_or       → logic_and ( "or" logic_and )* ;
 | ||||
| // logic_and      → equality ( "and" equality )* ;
 | ||||
| // equality       → comparison ( ( "!=" | "==" ) comparison )* ;
 | ||||
| // comparison     → term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
 | ||||
| // term           → factor ( ( "-" | "+" ) factor )* ;
 | ||||
| // factor         → unary ( ( "/" | "*" ) unary )* ;
 | ||||
| // unary          → ( "!" | "-" ) unary | call ;
 | ||||
| // call           → primary ( "(" arguments? ")" )* ;
 | ||||
| // arguments      → expression ( "," expression )* ;
 | ||||
| // primary        → NUMBER | STRING | "true" | "false" | "nil"
 | ||||
| // | "(" expression ")" ;
 | ||||
| 
 | ||||
| struct Parser { | ||||
|     tokens: Vec<Token>, | ||||
|  | @ -213,9 +211,7 @@ impl Parser { | |||
|                 if params.len() >= 255 { | ||||
|                     return Err(Error { | ||||
|                         line: self.peek().line, | ||||
|                         kind: ErrorKind::InternalError( | ||||
|                             "255 parameter limit exceeded.".into(), | ||||
|                         ), | ||||
|                         kind: ErrorKind::InternalError("255 parameter limit exceeded.".into()), | ||||
|                     }); | ||||
|                 } | ||||
| 
 | ||||
|  | @ -429,10 +425,7 @@ impl Parser { | |||
| 
 | ||||
|             return Err(Error { | ||||
|                 line: equals.line, | ||||
|                 kind: ErrorKind::InvalidAssignmentTarget(format!( | ||||
|                     "{:?}", | ||||
|                     equals | ||||
|                 )), | ||||
|                 kind: ErrorKind::InvalidAssignmentTarget(format!("{:?}", equals)), | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|  | @ -495,9 +488,7 @@ impl Parser { | |||
|     } | ||||
| 
 | ||||
|     fn unary(&mut self) -> ExprResult { | ||||
|         if self.match_token(&TokenKind::Bang) | ||||
|             || self.match_token(&TokenKind::Minus) | ||||
|         { | ||||
|         if self.match_token(&TokenKind::Bang) || self.match_token(&TokenKind::Minus) { | ||||
|             return Ok(Expr::Unary(Unary { | ||||
|                 operator: self.previous().clone(), | ||||
|                 right: Box::new(self.unary()?), | ||||
|  | @ -557,10 +548,7 @@ impl Parser { | |||
| 
 | ||||
|             TokenKind::LeftParen => { | ||||
|                 let expr = self.expression()?; | ||||
|                 self.consume( | ||||
|                     &TokenKind::RightParen, | ||||
|                     ErrorKind::UnmatchedParens, | ||||
|                 )?; | ||||
|                 self.consume(&TokenKind::RightParen, ErrorKind::UnmatchedParens)?; | ||||
|                 return Ok(Expr::Grouping(Grouping(Box::new(expr)))); | ||||
|             } | ||||
| 
 | ||||
|  | @ -632,11 +620,7 @@ impl Parser { | |||
|         &self.tokens[self.current - 1] | ||||
|     } | ||||
| 
 | ||||
|     fn consume( | ||||
|         &mut self, | ||||
|         kind: &TokenKind, | ||||
|         err: ErrorKind, | ||||
|     ) -> Result<Token, Error> { | ||||
|     fn consume(&mut self, kind: &TokenKind, err: ErrorKind) -> Result<Token, Error> { | ||||
|         if self.check_token(kind) { | ||||
|             return Ok(self.advance()); | ||||
|         } | ||||
|  |  | |||
|  | @ -56,13 +56,14 @@ impl<'a> Resolver<'a> { | |||
|                 // The resolver does not clone references, so unless
 | ||||
|                 // the interpreter is called before the resolver this
 | ||||
|                 // case should never happen.
 | ||||
|                 None => return Err(Error { | ||||
|                     line: 0, | ||||
|                     kind: ErrorKind::InternalError( | ||||
|                         "multiple function references before interpretation" | ||||
|                             .into(), | ||||
|                     ), | ||||
|                 }), | ||||
|                 None => { | ||||
|                     return Err(Error { | ||||
|                         line: 0, | ||||
|                         kind: ErrorKind::InternalError( | ||||
|                             "multiple function references before interpretation".into(), | ||||
|                         ), | ||||
|                     }) | ||||
|                 } | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
|  | @ -79,10 +80,7 @@ impl<'a> Resolver<'a> { | |||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn resolve_function( | ||||
|         &mut self, | ||||
|         func: &'a mut parser::Function, | ||||
|     ) -> Result<(), Error> { | ||||
|     fn resolve_function(&mut self, func: &'a mut parser::Function) -> Result<(), Error> { | ||||
|         self.declare(&func.name.lexeme); | ||||
|         self.define(&func.name.lexeme); | ||||
| 
 | ||||
|  | @ -123,17 +121,13 @@ impl<'a> Resolver<'a> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn resolve_variable( | ||||
|         &mut self, | ||||
|         var: &'a mut parser::Variable, | ||||
|     ) -> Result<(), Error> { | ||||
|     fn resolve_variable(&mut self, var: &'a mut parser::Variable) -> Result<(), Error> { | ||||
|         if let Some(scope) = self.scopes.last_mut() { | ||||
|             if let Some(false) = scope.get(var.name.lexeme.as_str()) { | ||||
|                 return Err(Error { | ||||
|                     line: var.name.line, | ||||
|                     kind: ErrorKind::StaticError( | ||||
|                         "can't read local variable in its own initialiser" | ||||
|                             .into(), | ||||
|                         "can't read local variable in its own initialiser".into(), | ||||
|                     ), | ||||
|                 }); | ||||
|             } | ||||
|  | @ -143,10 +137,7 @@ impl<'a> Resolver<'a> { | |||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn resolve_assign( | ||||
|         &mut self, | ||||
|         assign: &'a mut parser::Assign, | ||||
|     ) -> Result<(), Error> { | ||||
|     fn resolve_assign(&mut self, assign: &'a mut parser::Assign) -> Result<(), Error> { | ||||
|         self.resolve_expr(&mut assign.value)?; | ||||
|         assign.depth = self.resolve_local(&assign.name); | ||||
|         Ok(()) | ||||
|  | @ -162,10 +153,7 @@ impl<'a> Resolver<'a> { | |||
|         None | ||||
|     } | ||||
| 
 | ||||
|     fn resolve_call( | ||||
|         &mut self, | ||||
|         call: &'a mut parser::Call, | ||||
|     ) -> Result<(), Error> { | ||||
|     fn resolve_call(&mut self, call: &'a mut parser::Call) -> Result<(), Error> { | ||||
|         self.resolve_expr(&mut call.callee)?; | ||||
| 
 | ||||
|         for arg in call.args.iter_mut() { | ||||
|  | @ -198,10 +186,7 @@ impl<'a> Resolver<'a> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn resolve( | ||||
|     globals: &[String], | ||||
|     block: &mut parser::Block, | ||||
| ) -> Result<(), Error> { | ||||
| pub fn resolve(globals: &[String], block: &mut parser::Block) -> Result<(), Error> { | ||||
|     let mut resolver: Resolver = Default::default(); | ||||
| 
 | ||||
|     // Scope for static globals only starts, never ends.
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue