diff --git a/src/compiler.rs b/src/compiler.rs index c3e45e0..4e0c7df 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,1031 +1,1168 @@ // COMPILER +use crate::parser::{ + Args, Block, Call, Chunk, Constructor, Expression, Function, LoadError, Name, Piece, Prefix, + Statement, VarArg, Variable, +}; +use crate::table::{Equivalent, Hashed, Hashes, Map, TableEntry}; +use crate::vm::{Code, Index, Machine, Offset, Prototype, Reference, Value}; use std::cmp::PartialEq; +use std::ops::Deref; use std::rc::Rc; -use crate::parser::{Piece,Expression,Statement,Name,Block,Chunk,Variable,VarArg,Call,Args,Function,Prefix,Constructor,LoadError,Number}; -use crate::vm::{Machine, Prototype, Code, Value, Index, Reference, Offset, MarsError}; -use crate::table::{Equivalent,Hashes,Map,Hashed,TableEntry}; pub(crate) struct Traversal<'a> { - // A 'cursor' of where we are in assumed execution - machine: &'a mut Machine, - contexts: Vec, // Stack of function prototypes being compiled + // A 'cursor' of where we are in assumed execution + machine: &'a mut Machine, + contexts: Vec, // Stack of function prototypes being compiled } pub(crate) struct Context { - // Everything known about a closure at a time - scopes: Vec, - vararg: Option>>, - constants: Map, // map some constant value to an index for not repeating constants - prototype: Prototype, + // Everything known about a closure at a time + scopes: Vec, + vararg: Option>>, + constants: Map, // map some constant value to an index for not repeating constants + prototype: Prototype, } #[derive(Clone, Debug)] -struct ConstantEntry(Value,Index); +struct ConstantEntry(Value, Index); impl Equivalent for ConstantEntry { - fn matches(&self, other: &Self) -> bool { - self.0 == other.0 - } + fn matches(&self, other: &Self) -> bool { + self.0 == other.0 + } } impl Equivalent for ConstantEntry { - fn matches(&self, other: &Value) -> bool { - self.0 == *other - } + fn matches(&self, other: &Value) -> bool { + self.0 == *other + } } impl Hashes for ConstantEntry { - fn hashed(&self) -> Hashed { - self.0.hashed() - } + fn hashed(&self) -> Hashed { + self.0.hashed() + } } impl TableEntry for ConstantEntry { - fn new_vacant() -> Self { - ConstantEntry(Value::Nil,0) - } - fn is_vacant(&self) -> bool { - matches!(self.0,Value::Nil) - } + fn new_vacant() -> Self { + ConstantEntry(Value::Nil, 0) + } + fn is_vacant(&self) -> bool { + matches!(self.0, Value::Nil) + } } #[derive(Clone, Debug)] enum BlindJump { - Break(usize), - Continue(usize), - Goto(String, usize), + Break(usize), + Continue(usize), + Goto(String, usize), } #[derive(Debug)] pub(crate) struct Scope { - index: Index, // Current index on stack - jumps: Vec, // todo: probably shouldn't have two vectors on each scope, they are used for temporaries too - labels: Vec<(String, usize)>, - symbol: Option, // If that index has a symbol - upvalue: bool, + index: Index, // Current index on stack + jumps: Vec, // todo: probably shouldn't have two vectors on each scope, they are used for temporaries too + labels: Vec<(String, usize)>, + symbol: Option, // If that index has a symbol + upvalue: bool, } impl Traversal<'_> { - fn compile(&mut self, it: &T) -> Result<(), LoadError> - where - T: Compile, - { - it.compile(self) - } - fn push_code(&mut self, it: Piece) -> usize { - match it.it { - Code::TableNew => { - self.temp_scope(); - } - Code::TableSet => { - self.consume_scope(3) // Value, Index, Table - } - Code::TableGet | Code::Binary(_) => { - self.consume_scope(2); // Index, Table - self.temp_scope(); // Result - } - Code::UpvalueGet(_) | Code::RegisterGet(_) | Code::Constant(_) | Code::Closure(_) => { - self.temp_scope(); - } - Code::Unary(_) => { - self.consume_scope(1); - self.temp_scope(); - } - Code::TableInsert(_) => { - self.consume_scope(2); // Value, Table - } - Code::Return(index) | Code::Call(index) => { - let diff = self.index().unwrap() - index; - self.consume_scope(diff + 1); - //assert_eq!(self.last_scope().index, index); - /* So note that Code::Call here doesn't do any temp_scope() magic, this is an edge-case for - Code::Discard (if it's not used then Code::Call(index) will eat everything up to index - and this consumption loop here won't do anything anyway */ - } - Code::Discard(_index) => { - // Unfortunately can't do any checks on the temporary scopes here, we don't know anything - /* while self.last_scope().index > index { // Shouldn't this not even be here? - self.consume_scope(1); + fn compile(&mut self, it: &T) -> Result<(), LoadError> + where + T: Compile, + { + it.compile(self) + } + fn push_code(&mut self, it: Piece) -> usize { + match it.it { + Code::TableNew => { + self.temp_scope(); + } + Code::TableSet => { + self.consume_scope(3) // Value, Index, Table + } + Code::TableGet | Code::Binary(_) => { + self.consume_scope(2); // Index, Table + self.temp_scope(); // Result + } + Code::UpvalueGet(_) | Code::RegisterGet(_) | Code::Constant(_) | Code::Closure(_) => { + self.temp_scope(); + } + Code::Unary(_) => { + self.consume_scope(1); + self.temp_scope(); + } + Code::TableInsert(_) => { + self.consume_scope(2); // Value, Table + } + Code::Return(index) | Code::Call(index) => { + let diff = self.index().unwrap() - index; + self.consume_scope(diff + 1); + //assert_eq!(self.last_scope().index, index); + /* So note that Code::Call here doesn't do any temp_scope() magic, this is an edge-case for + Code::Discard (if it's not used then Code::Call(index) will eat everything up to index + and this consumption loop here won't do anything anyway */ + } + Code::Discard(_index) => { + // Unfortunately can't do any checks on the temporary scopes here, we don't know anything + /* while self.last_scope().index > index { // Shouldn't this not even be here? + self.consume_scope(1); + } + while self.last_scope().index < index { + self.temp_scope(); + } */ + } + Code::VarArg(count) => { + for _ in 0..count { + self.temp_scope(); + } + /* This is also weird like Code::Call and Code::Discard in that for count == 0 any number + of vararg values are being pushed to the stack, but this is an edge-case that the compiler + promises it will only use in Code::Return and Code::Call where they won't loop anyway */ + } + Code::Skip | Code::UpvalueSet(_) | Code::RegisterSet(_) => { + self.consume_scope(1); + } + Code::Close(_) + | Code::Jump(_) + | Code::RangeLoop(_) + | Code::RangeBegin + | Code::IteratorLoop(_) + | Code::Comment(_) => {} } - while self.last_scope().index < index { - self.temp_scope(); - } */ - } - Code::VarArg(count) => { - for _ in 0..count { - self.temp_scope(); + let prototype = &mut self.contexts.last_mut().unwrap().prototype; + prototype.code.push(it.it); + prototype.pieces.push(it.unit()); + assert_eq!(prototype.code.len(), prototype.pieces.len()); + prototype.code.len() - 1 + } + fn insert_code(&mut self, location: usize, it: Code) { + // slightly dangerous since it doesn't consider scopes + self.last_context().prototype.code[location] = it; + } + fn push_constant(&mut self, it: Value) -> Index { + // todo: constants need pieces too!!! + // don't use constants that already exist + if let Some(entry) = &mut self + .contexts + .last_mut() + .unwrap() + .constants + .get_table(it.clone()) + { + entry.1 + } else { + let index = { + let constants = &mut self.contexts.last_mut().unwrap().prototype.constants; + constants.push(it.clone()); + constants.len() - 1 + } + .try_into() + .unwrap(); + self.contexts + .last_mut() + .unwrap() + .constants + .set_table(ConstantEntry(it, index)); + index } - /* This is also weird like Code::Call and Code::Discard in that for count == 0 any number - of vararg values are being pushed to the stack, but this is an edge-case that the compiler - promises it will only use in Code::Return and Code::Call where they won't loop anyway */ - } - Code::Skip | Code::UpvalueSet(_) | Code::RegisterSet(_) => { - self.consume_scope(1); - } - Code::Close(_) - | Code::Jump(_) - | Code::RangeLoop(_) - | Code::RangeBegin - | Code::IteratorLoop(_) - | Code::Comment(_) => {} } - let prototype = &mut self.contexts.last_mut().unwrap().prototype; - prototype.code.push(it.it); - prototype.pieces.push(it.unit()); - assert_eq!(prototype.code.len(), prototype.pieces.len()); - prototype.code.len() - 1 - } - fn insert_code(&mut self, location: usize, it: Code) { - self.last_context().prototype.code[location] = it; - } - fn push_constant(&mut self, it: Value) -> Index { - // todo: constants need pieces too!!! - // don't use constants that already exist - if let Some(entry) = &mut self.contexts.last_mut().unwrap().constants.get_table(it.clone()) { - entry.1 - } else { - let index = { - let constants = &mut self.contexts.last_mut().unwrap().prototype.constants; - constants.push(it.clone()); - constants.len() - 1 - }.try_into().unwrap(); - self.contexts.last_mut().unwrap().constants.set_table(ConstantEntry(it,index)); - index + fn push_literal(&mut self, it: Value, piece: Piece<()>) { + let constant = self.push_constant(it); + self.push_code(piece.swap(Code::Constant(constant))); } - } - fn push_literal(&mut self, it: Value, piece: Piece<()>) { - let constant = self.push_constant(it); - self.push_code(piece.swap(Code::Constant(constant))); - } - fn push_string(&mut self, string: String, piece: Piece<()>) -> Result<(),LoadError> { - match self.machine.new_string(string.clone().as_str()) { - Err(error) => Err(LoadError(error.0,piece)), - Ok(string) => Ok(self.push_literal(string, piece)), + fn push_string(&mut self, string: String, piece: Piece<()>) -> Result<(), LoadError> { + match self.machine.new_string(string.clone().as_str()) { + Err(error) => Err(LoadError(error.0, piece)), + Ok(string) => Ok(self.push_literal(string, piece)), + } } - } - fn new_scope(&mut self) { // Make some new scope - let index = self.last_scope().index; - self.contexts.last_mut().unwrap().scopes.push(Scope { - index, - jumps: vec![], - labels: vec![], - symbol: None, - upvalue: false, - }); - } - fn temp_scope(&mut self) -> Index { // Make a new scope with index++ - self.new_scope(); - if self.last_context().scopes.len() > 2 { // For the dummy scope - self.last_scope().index += 1; + fn new_scope(&mut self) { + // Make some new scope + let index = self.last_scope().index; + self.contexts.last_mut().unwrap().scopes.push(Scope { + index, + jumps: vec![], + labels: vec![], + symbol: None, + upvalue: false, + }); } - self.last_scope().index - } - fn last_scope(&mut self) -> &mut Scope { - self.last_context().scopes.last_mut().unwrap() - } - fn index(&mut self) -> Option { - if self.last_context().scopes.len() == 1 { - None - } else { - Some(self.last_context().scopes.last_mut().unwrap().index) + fn temp_scope(&mut self) -> Index { + // Make a new scope with index++ + self.new_scope(); + if self.last_context().scopes.len() > 2 { + // For the dummy scope + self.last_scope().index += 1; + } + self.last_scope().index } - } - fn code_length(&mut self) -> usize { - self.last_context().prototype.code.len() - } - fn close_scope(&mut self) { - // Handle exiting a variable register's scope - let mut last = self.last_context().scopes.pop().unwrap(); // Remove it - self.last_scope().jumps.append(&mut last.jumps); // Bubble up the orphaned blind jumps - // If this scope's declaration was an upvalue then the VM needs to close it at runtime - assert!(last.symbol.is_some()); - // Always have to pop off variable registers - if let Some(Code::Close(_)) = self.last_context().prototype.code.last() { - // Did we just close a scope? - let len = self.code_length(); // Ok, what's the last instruction index? - self.insert_code(len - 1, Code::Close(last.index)); // Push that Code::Close even further back to this register. + fn last_scope(&mut self) -> &mut Scope { + self.last_context().scopes.last_mut().unwrap() } - } - fn consume_scope(&mut self, times: u16) { - // Handle consuming a temporary on the stack - for _ in 0..times { - assert!(self.last_context().scopes.pop().unwrap().symbol.is_none()); // Remove it + fn index(&mut self) -> Option { + if self.last_context().scopes.len() == 1 { + None + } else { + Some(self.last_context().scopes.last_mut().unwrap().index) + } } - } - fn last_context(&mut self) -> &mut Context { - self.contexts.last_mut().unwrap() - } - pub(crate) fn close_context(&mut self) -> Result { - let mut context = self.contexts.pop().unwrap(); - for jump in context.scopes.pop().unwrap().jumps { // Get back the dummy one and error any jumps - return Err(LoadError::from_str(format!("{:?}",jump).as_str(), &Piece::<()>::null())) // todo: we need Vec or some append in LoadError and also BlindJumps need pieces! + fn code_length(&mut self) -> usize { + self.last_context().prototype.code.len() } - Ok(context.prototype) - } - pub(crate) fn new(machine: &mut Machine) -> Traversal { - Traversal { - machine, - contexts: vec![Context { - scopes: vec![Scope { // Dummy scope - index: 0, - jumps: vec![], - labels: vec![], - symbol: None, - upvalue: false, - }], - vararg: Some(Piece::::null().swap(None)), - constants: Map::new(), - prototype: Prototype { - args: 0, - vararg: true, - prototypes: vec![], - constants: vec![], - upvalues: vec![], - pieces: vec![], - code: vec![], - }, - }], + fn close_scope(&mut self) { + // Handle exiting a variable register's scope + let mut last = self.last_context().scopes.pop().unwrap(); // Remove it + self.last_scope().jumps.append(&mut last.jumps); // Bubble up the orphaned blind jumps + // If this scope's declaration was an upvalue then the VM needs to close it at runtime + assert!(last.symbol.is_some()); + // Always have to pop off variable registers + if let Some(Code::Close(_)) = self.last_context().prototype.code.last() { + // Did we just close a scope? + let len = self.code_length(); // Ok, what's the last instruction index? + self.insert_code(len - 1, Code::Close(last.index)); // Push that Code::Close even further back to this register. + } + } + fn consume_scope(&mut self, times: u16) { + // Handle consuming a temporary on the stack + for _ in 0..times { + assert!(self.last_context().scopes.pop().unwrap().symbol.is_none()); // Remove it + } + } + fn last_context(&mut self) -> &mut Context { + self.contexts.last_mut().unwrap() + } + pub(crate) fn close_context(&mut self) -> Result { + let mut context = self.contexts.pop().unwrap(); + for jump in context.scopes.pop().unwrap().jumps { + // Get back the dummy one and error any jumps + return Err(LoadError::from_str( + format!("{:?}", jump).as_str(), + &Piece::<()>::null(), + )); // todo: we need Vec or some append in LoadError and also BlindJumps need pieces! + } + Ok(context.prototype) + } + pub(crate) fn new(machine: &mut Machine) -> Traversal { + Traversal { + machine, + contexts: vec![Context { + scopes: vec![Scope { + // Dummy scope + index: 0, + jumps: vec![], + labels: vec![], + symbol: None, + upvalue: false, + }], + vararg: Some(Piece::::null().swap(None)), + constants: Map::new(), + prototype: Prototype { + args: 0, + vararg: true, + prototypes: vec![], + constants: vec![], + upvalues: vec![], + pieces: vec![], + code: vec![], + }, + }], + } } - } } // todo: not all impl Compile for Piece needs to be &T trait Compile { - fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError>; + fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError>; } fn compile_function( - this: &Piece<&Function>, - traversal: &mut Traversal, - method: bool, + this: &Piece<&Function>, + traversal: &mut Traversal, + method: bool, ) -> Result<(), LoadError> { - let mut self_arguments = Vec::new(); - if method { - self_arguments.push("self".to_string()); - } - self_arguments.append(&mut this.it.0.iter().map(|it| it.it.0.clone()).collect()); - let mut argument_scopes = vec![Scope { - // Dummy initial scope so the rest can start from index = 0 (since there can be zero arguments!!) - index: 0, - jumps: vec![], - labels: vec![], - symbol: None, - upvalue: false, - }]; - let mut index = 0; - for argument in self_arguments.iter().rev() { - argument_scopes.push(Scope { - index, - jumps: vec![], - labels: vec![], - symbol: Some(argument.clone()), - upvalue: false, + let mut self_arguments = Vec::new(); + if method { + self_arguments.push("self".to_string()); + } + self_arguments.append(&mut this.it.args.iter().map(|it| it.it.0.clone()).collect()); + let mut argument_scopes = vec![Scope { + // Dummy initial scope so the rest can start from index = 0 (since there can be zero arguments!!) + index: 0, + jumps: vec![], + labels: vec![], + symbol: None, + upvalue: false, + }]; + let mut index = 0; + for argument in self_arguments.iter().rev() { + argument_scopes.push(Scope { + index, + jumps: vec![], + labels: vec![], + symbol: Some(argument.clone()), + upvalue: false, + }); + index += 1; + } + traversal.contexts.push(Context { + vararg: this + .it + .vararg + .as_ref() + .map(|it| it.swap(it.clone().it.0.map(|string| string.0.clone()))), + scopes: argument_scopes, + prototype: Prototype { + args: this.it.args.len().try_into().unwrap(), + vararg: this.it.vararg.is_some(), + prototypes: vec![], + constants: vec![], + upvalues: vec![Reference::Upvalue(0)], // _ENV + pieces: vec![], + code: vec![], + }, + constants: Map::new(), }); - index += 1; - } - traversal.contexts.push(Context { - vararg: this - .it - .1 - .as_ref() - .map(|it| it.swap(it.clone().it.0.map(|string| string.0.clone()))), - scopes: argument_scopes, - prototype: Prototype { - args: this.it.0.len().try_into().unwrap(), - vararg: this.it.1.is_some(), - prototypes: vec![], - constants: vec![], - upvalues: vec![Reference::Upvalue(0)], // _ENV - pieces: vec![], - code: vec![], - }, - constants: Map::new(), - }); - traversal.compile(&this.it.2.inner_ref())?; // compile the block - let prototype = traversal.close_context()?; - let prototypes = &mut traversal.last_context().prototype.prototypes; // add this to the upper function's prototypes list - let index = prototypes.len().try_into().unwrap(); - prototypes.push(Rc::new(prototype)); - traversal.push_code(this.swap(Code::Closure(index))); // reference this closure - Ok(()) + traversal.compile(&this.it.block.inner_ref())?; // compile the block + let prototype = traversal.close_context()?; + let prototypes = &mut traversal.last_context().prototype.prototypes; // add this to the upper function's prototypes list + let index = prototypes.len().try_into().unwrap(); + prototypes.push(Rc::new(prototype)); + traversal.push_code(this.swap(Code::Closure(index))); // reference this closure + Ok(()) } enum Access { - Set, - Get, + Set, + Get, } fn compile_identifier( - name: Piece, - traversal: &mut Traversal, - access: Access, + name: Piece, + traversal: &mut Traversal, + access: Access, ) -> Result<(), LoadError> { - let length = traversal.contexts.len(); - for i in 0..length { - // For each context - let i = length - i - 1; // From top to bottom - if i == length - 1 { - // If this is our context - for scope in traversal.contexts[i].scopes.iter().rev() { - // Go through the scopes - if scope.symbol.as_ref().is_some_and(|it| it.eq(&name.it)) { - // Find it - let index = scope.index; - traversal.push_code(name.swap(match access { - Access::Set => Code::RegisterSet(index), - Access::Get => Code::RegisterGet(index), - })); - return Ok(()); // Then break out - } - } - } else { - // Otherwise it's another function's 'scope'(s) - let length = traversal.contexts[i].scopes.len(); - for j in 0..length { - // For each scope in that foreign context - let j = length - j - 1; // From top to bottom - if traversal.contexts[i].scopes[j] - .symbol - .as_ref() - .is_some_and(|it| it.eq(&name.it)) - { - // Go through... - // todo: fix this comment it's talking about something i ended up dropping - /* - So here we know this 'traversal.contexts[i]' is the function holding the upvalue - in 'scopes[j]', if it has an upvalue already made, we use its 'prototype.closing' - index and set our initial rolling variable 'reference' to Reference::Register('index'). - This is significant because this 'upvalue' MUST be made in this owning function's - prototype's closing list, but 'reference' also acts as a variable holding the upvalue - that the current function in the loop 'for k in j+1..length' produced so that the next - function context can reference it, this also means that the last 'reference' after the - loop is sort of vacuously a 'Reference::Upvalue' that is only storing our 'index' - for the eventual instruction itself. - */ - let register = traversal.contexts[i].scopes[j].index; - traversal.contexts[i].scopes[j].upvalue = true; - let mut reference = Reference::Closing(register); - // its important that a few conditions are held here e.g. length > 2, j < length + 1... - for k in j + 1..length { - // Ok now going from every context to the one wanting the upvalue - // set reference to what we found for the next context - reference = match traversal.contexts[k] - .prototype - .upvalues - .iter() - .position(|it| *it == reference) - { - Some(index) => Reference::Upvalue(index.try_into().unwrap()), - None => { - // we don't even have a reference to this in our upvalues so add it - let length = traversal.contexts[k].prototype.upvalues.len(); - traversal.contexts[k].prototype.upvalues.push(reference); - Reference::Upvalue(length.try_into().unwrap()) // Reference (child) to this reference to that reference (parent) for next context - } + let length = traversal.contexts.len(); + for i in 0..length { + // For each context + let i = length - i - 1; // From top to bottom + if i == length - 1 { + // If this is our context + for scope in traversal.contexts[i].scopes.iter().rev() { + // Go through the scopes + if scope.symbol.as_ref().is_some_and(|it| it.eq(&name.it)) { + // Find it + let index = scope.index; + traversal.push_code(name.swap(match access { + Access::Set => Code::RegisterSet(index), + Access::Get => Code::RegisterGet(index), + })); + return Ok(()); // Then break out + } + } + } else { + // Otherwise it's another function's 'scope'(s) + let length = traversal.contexts[i].scopes.len(); + for j in 0..length { + // For each scope in that foreign context + let j = length - j - 1; // From top to bottom + if traversal.contexts[i].scopes[j] + .symbol + .as_ref() + .is_some_and(|it| it.eq(&name.it)) + { + // Go through... + // todo: fix this comment it's talking about something i ended up dropping + /* + So here we know this 'traversal.contexts[i]' is the function holding the upvalue + in 'scopes[j]', if it has an upvalue already made, we use its 'prototype.closing' + index and set our initial rolling variable 'reference' to Reference::Register('index'). + This is significant because this 'upvalue' MUST be made in this owning function's + prototype's closing list, but 'reference' also acts as a variable holding the upvalue + that the current function in the loop 'for k in j+1..length' produced so that the next + function context can reference it, this also means that the last 'reference' after the + loop is sort of vacuously a 'Reference::Upvalue' that is only storing our 'index' + for the eventual instruction itself. + */ + let register = traversal.contexts[i].scopes[j].index; + traversal.contexts[i].scopes[j].upvalue = true; + let mut reference = Reference::Closing(register); + // its important that a few conditions are held here e.g. length > 2, j < length + 1... + for k in j + 1..length { + // Ok now going from every context to the one wanting the upvalue + // set reference to what we found for the next context + reference = match traversal.contexts[k] + .prototype + .upvalues + .iter() + .position(|it| *it == reference) + { + Some(index) => Reference::Upvalue(index.try_into().unwrap()), + None => { + // we don't even have a reference to this in our upvalues so add it + let length = traversal.contexts[k].prototype.upvalues.len(); + traversal.contexts[k].prototype.upvalues.push(reference); + Reference::Upvalue(length.try_into().unwrap()) // Reference (child) to this reference to that reference (parent) for next context + } + } + } + let index = match reference { + Reference::Closing(_) => panic!(), + Reference::Upvalue(index) => index, + }; + traversal.push_code(name.swap(match access { + Access::Set => Code::UpvalueSet(index), + Access::Get => Code::UpvalueGet(index), + })); + return Ok(()); + } } - } - let index = match reference { - Reference::Closing(_) => panic!(), - Reference::Upvalue(index) => index, - }; - traversal.push_code(name.swap(match access { - Access::Set => Code::UpvalueSet(index), - Access::Get => Code::UpvalueGet(index), - })); - return Ok(()); } - } } - } - // break 'search avoids this use of the _G table - traversal.push_string(name.it.clone(),name.unit())?; - traversal.push_code(name.swap(Code::UpvalueGet(0))); - traversal.push_code(name.swap(match access { - Access::Set => Code::TableSet, - Access::Get => Code::TableGet, - })); - Ok(()) + // break 'search avoids this use of the _G table + traversal.push_string(name.it.clone(), name.unit())?; + traversal.push_code(name.swap(Code::UpvalueGet(0))); + traversal.push_code(name.swap(match access { + Access::Set => Code::TableSet, + Access::Get => Code::TableGet, + })); + Ok(()) } fn compile_variable( - variable: Piece<&Variable>, - traversal: &mut Traversal, - access: Access, + variable: Piece<&Variable>, + traversal: &mut Traversal, + access: Access, ) -> Result<(), LoadError> { - match &variable.it { - Variable::Name(Name(name)) => { - compile_identifier(variable.swap(name.clone()), traversal, access)?; + match &variable.it { + Variable::Name(Name(name)) => { + compile_identifier(variable.swap(name.clone()), traversal, access)?; + } + Variable::Index(prefix, index) => { + // Compile the prefix expression, the index, and set + traversal.compile(&index.inner_ref())?; + traversal.compile(&prefix.as_ref().inner_ref())?; + traversal.push_code(prefix.unit().end().swap(match access { + Access::Set => Code::TableSet, + Access::Get => Code::TableGet, + })); + } + Variable::Register(index) => { + traversal.push_code(variable.swap(match access { + Access::Set => Code::RegisterSet(*index), + Access::Get => Code::RegisterGet(*index), + })); + } } - Variable::Index(prefix, index) => { - // Compile the prefix expression, the index, and set - traversal.compile(&index.inner_ref())?; - traversal.compile(&prefix.as_ref().inner_ref())?; - traversal.push_code(prefix.unit().end().swap(match access { - Access::Set => Code::TableSet, - Access::Get => Code::TableGet, - })); - } - Variable::Register(index) => { - traversal.push_code(variable.swap(match access { - Access::Set => Code::RegisterSet(*index), - Access::Get => Code::RegisterGet(*index), - })); - } - } - Ok(()) + Ok(()) } impl Compile for Piece<&Function> { - fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - compile_function(self, traversal, false) - } + fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + compile_function(self, traversal, false) + } } impl Compile for Piece<&Args> { - fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - let mut expressions_iter = self.it.0.iter().rev(); - if let Some(expression) = expressions_iter.next() { - let piece = expression.unit(); - match &expression.it { - Expression::Prefix(prefix) => match &**prefix { - Prefix::Call(call) => { - traversal.compile(&piece.swap(call))?; - } - prefix => { - traversal.compile(&piece.swap(prefix))?; - } - }, - Expression::VarArg(vararg) => { - traversal.compile(&piece.swap(vararg))?; - traversal.push_code(piece.swap(Code::VarArg(0))); // Dump all the varargs + fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + let mut expressions_iter = self.it.0.iter().rev(); + if let Some(expression) = expressions_iter.next() { + let piece = expression.unit(); + match &expression.it { + Expression::Prefix(prefix) => match &**prefix { + Prefix::Call(call) => { + traversal.compile(&piece.swap(call))?; + } + prefix => { + traversal.compile(&piece.swap(prefix))?; + } + }, + Expression::VarArg(vararg) => { + traversal.compile(&piece.swap(vararg))?; + traversal.push_code(piece.swap(Code::VarArg(0))); // Dump all the varargs + } + _ => { + traversal.compile(&expression.inner_ref())?; + } + } } - _ => { - traversal.compile(&expression.inner_ref())?; + while let Some(expression) = expressions_iter.next() { + traversal.compile(&expression.inner_ref())?; } - } + Ok(()) } - while let Some(expression) = expressions_iter.next() { - traversal.compile(&expression.inner_ref())?; - } - Ok(()) - } } impl Compile for Piece<&Call> { - fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - traversal.compile(&self.it.0.as_ref().inner_ref())?; // call prefix - match &self.it.1 { - Some(name) => { - traversal.push_string(name.it.0.clone(),name.unit())?; - traversal.push_code(name.swap(Code::TableGet)); - } - None => {} + fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + traversal.compile(&self.it.prefix.as_ref().inner_ref())?; // call prefix + match &self.it.method { + Some(name) => { + traversal.push_string(name.it.0.clone(), name.unit())?; + traversal.push_code(name.swap(Code::TableGet)); + } + None => {} + } + let index = traversal.index().unwrap(); + traversal.compile(&self.it.args.inner_ref())?; // arguments + traversal.push_code(self.it.prefix.unit().end().swap(Code::Call(index))); // Our responsibility to discard here + Ok(()) } - let index = traversal.index().unwrap(); - traversal.compile(&self.it.2.inner_ref())?; // arguments - traversal.push_code(self.it.0.unit().end().swap(Code::Call(index))); // Our responsibility to discard here - Ok(()) - } } impl Compile for Piece<&Prefix> { - fn compile<'a, 'b>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - match &self.it { - Prefix::Call(call) => { - let index = traversal.index().unwrap(); - traversal.compile(&self.swap(call))?; - traversal.push_code(self.swap(Code::Discard(index + 1)).end()); // produce 1 return value, or pad nil - } - Prefix::Variable(variable) => { - compile_variable(self.swap(variable), traversal, Access::Get)?; - } - Prefix::Expression(expression) => { - traversal.compile(&self.swap(expression))?; - } + fn compile<'a, 'b>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + match &self.it { + Prefix::Call(call) => { + let index = traversal.index().unwrap(); + traversal.compile(&self.swap(call))?; + traversal.push_code(self.swap(Code::Discard(index + 1)).end()); // produce 1 return value, or pad nil + } + Prefix::Variable(variable) => { + compile_variable(self.swap(variable), traversal, Access::Get)?; + } + Prefix::Expression(expression) => { + traversal.compile(&self.swap(expression))?; + } + } + Ok(()) } - Ok(()) - } } // for the sake of erroring alone impl Compile for Piece<&VarArg> { - fn compile<'a, 'b>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - match &traversal.contexts.last().unwrap().vararg { - Some(piece) => match &piece.it { - Some(that_name) => match &self.it.0 { - Some(Name(this_name)) => { - if that_name.eq(this_name) { - Ok(()) - } else { - Err(LoadError( + fn compile<'a, 'b>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + match &traversal.contexts.last().unwrap().vararg { + Some(piece) => match &piece.it { + Some(that_name) => match &self.it.0 { + Some(Name(this_name)) => { + if that_name.eq(this_name) { + Ok(()) + } else { + Err(LoadError( + format!( + "This context's only visible vararg parameter '{:?}' is not named '{:?}'", + that_name, this_name + ), + self.unit(), + )) + } + } + None => Err(LoadError( + format!( + "This context's only visible vararg parameter must be referred to by its name '{:?}'", + that_name + ), + self.unit(), + )), + }, + None => match &self.it.0 { + Some(name) => Err(LoadError( + format!( + "This context's only visible vararg parameter has no name '{:?}'", + name + ), + self.unit(), + )), + None => Ok(()), + }, + }, + None => Err(LoadError( format!( - "This context's only visible vararg parameter '{:?}' is not named '{:?}'", - that_name, this_name + "This context has no accessible vararg parameter '{:?}'", + self.it ), self.unit(), - )) - } - } - None => Err(LoadError( - format!( - "This context's only visible vararg parameter must be referred to by its name '{:?}'", - that_name - ), - self.unit(), - )), - }, - None => match &self.it.0 { - Some(name) => Err(LoadError( - format!( - "This context's only visible vararg parameter has no name '{:?}'", - name - ), - self.unit(), - )), - None => Ok(()), - }, - }, - None => Err(LoadError( - format!( - "This context has no accessible vararg parameter '{:?}'", - self.it - ), - self.unit(), - )), + )), + } } - } } impl Compile for Piece<&Constructor> { - fn compile<'a, 'b>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - traversal.push_code(self.swap(Code::TableNew)); - let index_table = traversal.index().unwrap(); - for field in self.it.0.iter() { - match &field.it.0 { - Some(index) => { - traversal.compile(&index.inner_ref())?; - traversal.push_code(field.it.1.swap(Code::RegisterGet(index_table)).start()); - traversal.push_code(field.it.1.swap(Code::TableSet)); - } - None => { - match &field.it.1.it { - Expression::VarArg(vararg) => { - traversal.compile(&field.it.1.swap(vararg))?; - traversal.push_code(field.it.1.swap(Code::VarArg(0))); + fn compile<'a, 'b>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + traversal.push_code(self.swap(Code::TableNew)); + let index_table = traversal.index().unwrap(); + for field in self.it.0.iter() { + match &field.it.index { + Some(index) => { + traversal.compile(&index.inner_ref())?; + traversal.push_code( + field + .it + .expression + .swap(Code::RegisterGet(index_table)) + .start(), + ); + traversal.push_code(field.it.expression.swap(Code::TableSet)); + } + None => { + match &field.it.expression.it { + Expression::VarArg(vararg) => { + traversal.compile(&field.it.expression.swap(vararg))?; + traversal.push_code(field.it.expression.swap(Code::VarArg(0))); + } + it => { + traversal.compile(&field.it.expression.swap(it))?; + } + } + let index = traversal + .contexts + .last() + .unwrap() + .scopes + .last() + .unwrap() + .index; + traversal.push_code( + field + .it + .expression + .swap(Code::RegisterGet(index_table)) + .start(), + ); + traversal.push_code(field.it.expression.swap(Code::TableInsert(index))); + } } - it => { - traversal.compile(&field.it.1.swap(it))?; - } - } - let index = traversal - .contexts - .last() - .unwrap() - .scopes - .last() - .unwrap() - .index; - traversal.push_code(field.it.1.swap(Code::RegisterGet(index_table)).start()); - traversal.push_code(field.it.1.swap(Code::TableInsert(index))); } - } + Ok(()) } - Ok(()) - } } impl Compile for Piece<&Expression> { - fn compile<'a>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - match self.it { - Expression::Nil => { - traversal.push_literal(Value::Nil, self.unit()); - } - Expression::True => { - traversal.push_literal(Value::Bool(true), self.unit()); - } - Expression::False => { - traversal.push_literal(Value::Bool(false), self.unit()); - } - Expression::Number(number) => { - let number = number - .0 - .parse::() - .map_err(|it| LoadError(it.to_string(), self.unit()))?; - traversal.push_literal(Value::Number(number), self.unit()); - } - Expression::String(string) => { - traversal.push_string(string.clone(),self.unit())?; - } - Expression::VarArg(vararg) => { - traversal.compile(&self.swap(vararg))?; - traversal.push_code(self.swap(Code::VarArg(1))); - } - Expression::Function(function) => { - traversal.compile(&self.swap(function))?; - } - Expression::Prefix(prefix) => { - traversal.compile(&self.swap(prefix.as_ref()))?; - } - Expression::Table(constructor) => { - traversal.compile(&self.swap(constructor))?; - } - Expression::Binary(left, op, right) => { - traversal.compile(&left.as_ref().inner_ref())?; - traversal.compile(&right.as_ref().inner_ref())?; - traversal.push_code(op.swap(Code::Binary(op.it))); - } - Expression::Unary(op, expression) => { - traversal.compile(&expression.as_ref().inner_ref())?; - traversal.push_code(op.swap(Code::Unary(op.it))); - } - }; - Ok(()) - } + fn compile<'a>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + match self.it { + Expression::Nil => { + traversal.push_literal(Value::Nil, self.unit()); + } + Expression::True => { + traversal.push_literal(Value::Bool(true), self.unit()); + } + Expression::False => { + traversal.push_literal(Value::Bool(false), self.unit()); + } + Expression::Number(number) => { + let number = number + .0 + .parse::() + .map(|it| Value::Integer(it)) + .unwrap_or(Value::Number( + number + .0 + .parse::() + .map_err(|it| LoadError(it.to_string(), self.unit()))?, + )); + traversal.push_literal(number, self.unit()); + } + Expression::String(string) => { + traversal.push_string(string.clone(), self.unit())?; + } + Expression::VarArg(vararg) => { + traversal.compile(&self.swap(vararg))?; + traversal.push_code(self.swap(Code::VarArg(1))); + } + Expression::Function(function) => { + traversal.compile(&self.swap(function))?; + } + Expression::Prefix(prefix) => { + traversal.compile(&self.swap(prefix.as_ref()))?; + } + Expression::Table(constructor) => { + traversal.compile(&self.swap(constructor))?; + } + Expression::Binary(left, op, right) => { + traversal.compile(&left.as_ref().inner_ref())?; + traversal.compile(&right.as_ref().inner_ref())?; + traversal.push_code(op.swap(Code::Binary(op.it))); + } + Expression::Unary(op, expression) => { + traversal.compile(&expression.as_ref().inner_ref())?; + traversal.push_code(op.swap(Code::Unary(op.it))); + } + }; + Ok(()) + } } fn jump_from(here: usize, there: usize) -> Result { - Ok((there as i64 - here as i64) as Offset) + Ok((there as i64 - here as i64) as Offset) } fn resolve_break(traversal: &mut Traversal, begin: usize, end: usize) -> Result<(), LoadError> { - for jump in std::mem::replace(&mut traversal.last_scope().jumps,Vec::new()) { - // ? - match jump { - BlindJump::Continue(index) => { - traversal.insert_code(index, Code::Jump(jump_from(index, begin)?)); - } - BlindJump::Break(index) => { - traversal.insert_code(index, Code::Jump(jump_from(index, end)?)); - } - _ => traversal.last_scope().jumps.push(jump), + for jump in std::mem::replace(&mut traversal.last_scope().jumps, Vec::new()) { + // ? + match jump { + BlindJump::Continue(index) => { + traversal.insert_code(index, Code::Jump(jump_from(index, begin)?)); + } + BlindJump::Break(index) => { + traversal.insert_code(index, Code::Jump(jump_from(index, end)?)); + } + _ => traversal.last_scope().jumps.push(jump), + } } - } - Ok(()) + Ok(()) } fn compile_assignment( - traversal: &mut Traversal, - variables: &Vec>, - expressions: &Vec>, + traversal: &mut Traversal, + variables: &Vec>, + expressions: &Vec>, ) -> Result<(), LoadError> { - let mut variables_iter = variables.iter().peekable(); - let mut expressions_iter = expressions.iter().peekable(); - while let Some(expression) = expressions_iter.next() { - let compile_variable_expression = | // Compile a variable normally with one value from an expression - traversal: &mut Traversal, - variable: Option<&Piece>, - expression: &Piece<&Expression> - | - -> Result<(), LoadError> { - let index = traversal.index().unwrap(); - traversal.compile(expression)?; - if let Some(variable) = variable { - compile_variable(variable.inner_ref(), traversal, Access::Set)?; - } else { - traversal.push_code(expression.swap(Code::Discard(index))); - } - Ok(()) - }; - if expressions_iter.peek().is_none() { - // If this is the last expression it CAN have multiplicity - match &expression.it { - Expression::Prefix(prefix) => { - match &**prefix { - Prefix::Call(call) => { - // multiple - let mut index = traversal.index().unwrap(); - traversal.compile(&expression.swap(call))?; - let index_discard = traversal.push_code(expression.swap(Code::UNSURE)); - while let Some(variable) = variables_iter.next() { - index += 1; // The index we would need to pad nil to or restrict to - compile_variable(variable.inner_ref(), traversal, Access::Set)?; // Pops each return value off the stack - } - traversal.insert_code(index_discard, Code::Discard(index.try_into().unwrap())); + let mut variables_iter = variables.iter().peekable(); + let mut expressions_iter = expressions.iter().peekable(); + while let Some(expression) = expressions_iter.next() { + let compile_variable_expression = |// Compile a variable normally with one value from an expression + traversal: &mut Traversal, + variable: Option<&Piece>, + expression: &Piece<&Expression>| + -> Result<(), LoadError> { + let index = traversal.index().unwrap(); + traversal.compile(expression)?; + if let Some(variable) = variable { + compile_variable(variable.inner_ref(), traversal, Access::Set)?; + } else { + traversal.push_code(expression.swap(Code::Discard(index))); } - prefix => { - if let Some(variable) = variables_iter.next() { - traversal.compile(&expression.swap(prefix))?; - compile_variable(variable.inner_ref(), traversal, Access::Set)? - } + Ok(()) + }; + if expressions_iter.peek().is_none() { + // If this is the last expression it CAN have multiplicity + match &expression.it { + Expression::Prefix(prefix) => { + match **prefix { + Prefix::Call(ref call) => { + // multiple + let mut index = traversal.index().unwrap(); + traversal.compile(&expression.swap(call))?; + let index_discard = traversal.push_code(expression.swap(Code::UNSURE)); + while let Some(variable) = variables_iter.next() { + index += 1; // The index we would need to pad nil to or restrict to + compile_variable(variable.inner_ref(), traversal, Access::Set)?; // Pops each return value off the stack + } + traversal.insert_code( + index_discard, + Code::Discard(index.try_into().unwrap()), + ); + } + ref prefix => { + if let Some(variable) = variables_iter.next() { + traversal.compile(&expression.swap(prefix))?; + compile_variable(variable.inner_ref(), traversal, Access::Set)? + } + } + } + } + Expression::VarArg(vararg) => { + traversal.compile(&expression.swap(vararg))?; // Does nothing, error check + if variables_iter.peek().is_some() { + let mut count = 0; + let index_vararg = traversal.push_code(expression.swap(Code::VarArg(0))); + for variable in variables_iter.clone() { + count += 1; + compile_variable(variable.inner_ref(), traversal, Access::Set)?; + } + traversal + .insert_code(index_vararg, Code::VarArg(count.try_into().unwrap())); + } + } + _ => { + compile_variable_expression( + traversal, + variables_iter.next(), + &expression.inner_ref(), + )?; + } } - } + } else { + // otherwise treat it normally and consume one variable + compile_variable_expression(traversal, variables_iter.next(), &expression.inner_ref())?; } - Expression::VarArg(vararg) => { - traversal.compile(&expression.swap(vararg))?; // Does nothing, error check - if variables_iter.peek().is_some() { - let mut count = 0; - let index_vararg = traversal.push_code(expression.swap(Code::VarArg(0))); - for variable in variables_iter.clone() { - count += 1; - compile_variable(variable.inner_ref(), traversal, Access::Set)?; - } - traversal.insert_code(index_vararg, Code::VarArg(count.try_into().unwrap())); - } - } - _ => { - compile_variable_expression( - traversal, - variables_iter.next(), - &expression.inner_ref(), - )?; - } - } - } else { - // otherwise treat it normally and consume one variable - compile_variable_expression(traversal, variables_iter.next(), &expression.inner_ref())?; } - } - while let Some(variable) = variables_iter.next() { - // Set the rest of the variables to nil - traversal.push_literal(Value::Nil, variable.unit()); - compile_variable(variable.inner_ref(), traversal, Access::Set)?; - } - Ok(()) + while let Some(variable) = variables_iter.next() { + // Set the rest of the variables to nil + traversal.push_literal(Value::Nil, variable.unit()); + compile_variable(variable.inner_ref(), traversal, Access::Set)?; + } + Ok(()) } impl Compile for Piece<&Block> { - fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - let last_scope_index = traversal.index().unwrap_or(0); - let mut depth = 0; // Counter for 'dangling' scopes produced by any declarations to be closed. - let mut var_scope = |traversal: &mut Traversal, symbol: String| -> Index { - let index = traversal.temp_scope(); - traversal.last_scope().symbol = Some(symbol); - depth += 1; - index - }; - // todo: for some reason, register indices are called "_index" and code indices "index_"? fix it - for statement in self.it.0.iter() { - let piece = statement.unit(); - match &statement.it { - Statement::Semicolon => {} - Statement::Assignment(variables, expressions) => { - compile_assignment(traversal, variables, expressions)?; - } - Statement::Call(call) => { - let index = traversal.index().unwrap_or(0); - traversal.compile(&self.swap(call))?; - traversal.push_code(self.swap(Code::Discard(index))); - } - Statement::Label(label) => { - let index_label = traversal.code_length() - 1; - traversal - .last_scope() - .labels - .push((label.it.0.clone(), index_label)); - let mut jumps = Vec::new(); - for jump in traversal.last_scope().jumps.clone().iter().rev() { - match jump { - BlindJump::Goto(name, index) => { - if name.eq(&label.it.0) { - traversal.insert_code( - *index, - Code::Jump(jump_from(*index, index_label)?), - ) - } else { - jumps.push(jump); + fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + let last_scope_index = traversal.index().unwrap_or(0); + let mut depth = 0; // Counter for 'dangling' scopes produced by any declarations to be closed. + let mut var_scope = |traversal: &mut Traversal, symbol: String| -> Index { + let index = traversal.temp_scope(); + traversal.last_scope().symbol = Some(symbol); + depth += 1; + index + }; + // todo: for some reason, register indices are called "_index" and code indices "index_"? fix it + // todo: maybe refactor this so that there are less indents + for statement in self.it.statements.iter() { + let piece = statement.unit(); + match &statement.it { + Statement::Semicolon => {} + Statement::Assignment(variables, expressions) => { + compile_assignment(traversal, variables, expressions)?; } - } - _ => jumps.push(jump), - } - } - } - Statement::Break => { - let index = traversal.push_code(piece.swap(Code::UNSURE)); - traversal.last_scope().jumps.push(BlindJump::Break(index)); - } - Statement::Continue => { - let index = traversal.push_code(piece.swap(Code::UNSURE)); - traversal - .last_scope() - .jumps - .push(BlindJump::Continue(index)); - } - Statement::Goto(name) => { - let mut index = None; - for scope in traversal.contexts.last().unwrap().scopes.iter().rev() { - for (label_name, label_index) in scope.labels.iter().rev() { - if name.it.0 == *label_name { - index = Some(label_index.clone()); - break; - } - } - } - if let Some(index) = index { - let current = (traversal.last_context().prototype.code.len() - 1) as Offset; - traversal.push_code(piece.swap(Code::Jump(index as Offset - current))); - } else { - let index = traversal.push_code(piece.swap(Code::UNSURE)); - traversal - .last_scope() - .jumps - .push(BlindJump::Goto(name.it.0.clone(), index)); - } - } - Statement::Do(block) => { - traversal.compile(&self.swap(block))?; - } - Statement::While(condition, block) => { - let piece = condition.unit().end(); - let index_exp = traversal.code_length(); - traversal.compile(&condition.inner_ref())?; - traversal.push_code(piece.swap(Code::Skip)); - let index_exit = traversal.push_code(piece.swap(Code::UNSURE)); - traversal.compile(&self.swap(block))?; - let index_jump = traversal.code_length(); - resolve_break(traversal, index_exp, index_jump + 1)?; - traversal.push_code(piece.swap(Code::Jump(jump_from(index_jump, index_exp)?))); - traversal.insert_code( - index_exit, - Code::Jump(jump_from(index_exit, index_jump + 1)?), - ); - } - Statement::Repeat(block, condition) => { - let piece = condition.unit().end(); - let index_block = traversal.code_length(); - traversal.compile(&self.swap(block))?; - let index_exp = traversal.code_length(); - traversal.compile(&condition.inner_ref())?; - traversal.push_code(piece.swap(Code::Skip)); - let index_jump = traversal.code_length(); - resolve_break(traversal, index_exp, index_jump + 1)?; - traversal - .push_code(piece.swap(Code::Jump(jump_from(index_jump, index_block)?))); - } - Statement::If(conditions, blocks, otherwise) => { - let mut conditions = conditions.iter().peekable(); - let mut blocks = blocks.iter(); - assert_eq!(conditions.len(), blocks.len()); - let mut jumps = Vec::new(); - while let Some(condition) = conditions.next() { - let block = blocks.next().unwrap(); - traversal.compile(&condition.inner_ref())?; - traversal.push_code(condition.swap(Code::Skip)); - let index_next = traversal.push_code(condition.swap(Code::UNSURE)); // jump to the next branch - traversal.compile(&block.inner_ref())?; - if conditions.peek().is_some() || otherwise.is_some() { - // don't jump ahead by 1 if it's at the end already and there is no else block - jumps.push(traversal.push_code(condition.swap(Code::UNSURE))); // jump all the way to the end - } - let length = traversal.code_length(); - traversal - .insert_code(index_next, Code::Jump(jump_from(index_next, length)?)); - } - assert!(blocks.next().is_none()); - if let Some(otherwise) = otherwise { - traversal.compile(&otherwise.inner_ref())?; - } - for jump in jumps { - let length = traversal.code_length(); - traversal.insert_code(jump, Code::Jump(jump_from(jump, length)?)) - } - } - Statement::Range(var, init, limit, step, block) => { - let init_index = traversal.temp_scope(); // init - traversal.compile(&init.inner_ref())?; - traversal.push_code(init.swap(Code::RegisterSet(init_index))); + Statement::Call(call) => { + let index = traversal.index().unwrap_or(0); + traversal.compile(&self.swap(call))?; + traversal.push_code(self.swap(Code::Discard(index))); + } + Statement::Label(label) => { + let index_label = traversal.code_length() - 1; + traversal + .last_scope() + .labels + .push((label.it.0.clone(), index_label)); + let mut jumps = Vec::new(); + for jump in traversal.last_scope().jumps.clone().iter().rev() { + match jump { + BlindJump::Goto(name, index) => { + if name.eq(&label.it.0) { + traversal.insert_code( + *index, + Code::Jump(jump_from(*index, index_label)?), + ) + } else { + jumps.push(jump); + } + } + _ => jumps.push(jump), + } + } + } + Statement::Break => { + let index = traversal.push_code(piece.swap(Code::UNSURE)); + traversal.last_scope().jumps.push(BlindJump::Break(index)); + } + Statement::Continue => { + let index = traversal.push_code(piece.swap(Code::UNSURE)); + traversal + .last_scope() + .jumps + .push(BlindJump::Continue(index)); + } + Statement::Goto(name) => { + let mut index = None; + for scope in traversal.contexts.last().unwrap().scopes.iter().rev() { + for (label_name, label_index) in scope.labels.iter().rev() { + if name.it.0 == *label_name { + index = Some(label_index.clone()); + break; + } + } + } + if let Some(index) = index { + let current = (traversal.last_context().prototype.code.len() - 1) as Offset; + traversal.push_code(piece.swap(Code::Jump(index as Offset - current))); + } else { + let index = traversal.push_code(piece.swap(Code::UNSURE)); + traversal + .last_scope() + .jumps + .push(BlindJump::Goto(name.it.0.clone(), index)); + } + } + Statement::Do(block) => { + traversal.compile(&self.swap(block))?; + } + Statement::While(condition, block) => { + let piece = condition.unit().end(); + let index_exp = traversal.code_length(); + traversal.compile(&condition.inner_ref())?; + traversal.push_code(piece.swap(Code::Skip)); + let index_exit = traversal.push_code(piece.swap(Code::UNSURE)); + traversal.compile(&self.swap(block))?; + let index_jump = traversal.code_length(); + resolve_break(traversal, index_exp, index_jump + 1)?; + traversal.push_code(piece.swap(Code::Jump(jump_from(index_jump, index_exp)?))); + traversal.insert_code( + index_exit, + Code::Jump(jump_from(index_exit, index_jump + 1)?), + ); + } + Statement::Repeat(block, condition) => { + let piece = condition.unit().end(); + let index_block = traversal.code_length(); + traversal.compile(&self.swap(block))?; + let index_exp = traversal.code_length(); + traversal.compile(&condition.inner_ref())?; + traversal.push_code(piece.swap(Code::Skip)); + let index_jump = traversal.code_length(); + resolve_break(traversal, index_exp, index_jump + 1)?; + traversal + .push_code(piece.swap(Code::Jump(jump_from(index_jump, index_block)?))); + } + Statement::If(conditions, blocks, otherwise) => { + let mut conditions = conditions.iter().peekable(); + let mut blocks = blocks.iter(); + assert_eq!(conditions.len(), blocks.len()); + let mut jumps = Vec::new(); + while let Some(condition) = conditions.next() { + let block = blocks.next().unwrap(); + traversal.compile(&condition.inner_ref())?; + traversal.push_code(condition.swap(Code::Skip)); + let index_next = traversal.push_code(condition.swap(Code::UNSURE)); // jump to the next branch + traversal.compile(&block.inner_ref())?; + if conditions.peek().is_some() || otherwise.is_some() { + // don't jump ahead by 1 if it's at the end already and there is no else block + jumps.push(traversal.push_code(condition.swap(Code::UNSURE))); // jump all the way to the end + } + let length = traversal.code_length(); + traversal + .insert_code(index_next, Code::Jump(jump_from(index_next, length)?)); + } + assert!(blocks.next().is_none()); + if let Some(otherwise) = otherwise { + traversal.compile(&otherwise.inner_ref())?; + } + for jump in jumps { + let length = traversal.code_length(); + traversal.insert_code(jump, Code::Jump(jump_from(jump, length)?)) + } + } + Statement::Range(var, init, limit, step, block) => { + let init_index = traversal.temp_scope(); // init + traversal.compile(&init.inner_ref())?; + traversal.push_code(init.swap(Code::RegisterSet(init_index))); - let limit_index = traversal.temp_scope(); // limit - traversal.compile(&limit.inner_ref())?; - traversal.push_code(limit.swap(Code::RegisterSet(limit_index))); + let limit_index = traversal.temp_scope(); // limit + traversal.compile(&limit.inner_ref())?; + traversal.push_code(limit.swap(Code::RegisterSet(limit_index))); - let step_index = traversal.temp_scope(); // step; - match step { - Some(expression) => traversal.compile(&expression.inner_ref())?, - None => traversal.push_literal(Value::Integer(1), limit.unit().end()), - }; - let piece = match step { - Some(expression) => expression.unit().start(), - None => limit.unit().end(), - }; - traversal.push_code(piece.swap(Code::RegisterSet(step_index))); - let index_loop = - traversal.push_code(block.unit().start().swap(Code::RangeBegin)) + 1; - var_scope(traversal, var.it.0.clone()); - traversal.compile(&block.inner_ref())?; - traversal.close_scope(); // temporary for v - let index_jump = traversal.push_code(block.unit().start().swap(Code::UNSURE)); // Dummy NOP - traversal.insert_code( - index_jump, - Code::RangeLoop(jump_from(index_jump, index_loop)?), - ); // Reinsert into above - resolve_break(traversal, index_loop, index_jump + 1)?; - traversal.close_scope(); - traversal.close_scope(); - traversal.close_scope(); // init, limit, step + let step_index = traversal.temp_scope(); // step; + match step { + Some(expression) => traversal.compile(&expression.inner_ref())?, + None => traversal.push_literal(Value::Integer(1), limit.unit().end()), + }; + let piece = match step { + Some(expression) => expression.unit().start(), + None => limit.unit().end(), + }; + traversal.push_code(piece.swap(Code::RegisterSet(step_index))); + let index_loop = + traversal.push_code(block.unit().start().swap(Code::RangeBegin)) + 1; + var_scope(traversal, var.it.0.clone()); + traversal.compile(&block.inner_ref())?; + traversal.close_scope(); // temporary for v + let index_jump = traversal.push_code(block.unit().start().swap(Code::UNSURE)); // Dummy NOP + traversal.insert_code( + index_jump, + Code::RangeLoop(jump_from(index_jump, index_loop)?), + ); // Reinsert into above + resolve_break(traversal, index_loop, index_jump + 1)?; + traversal.close_scope(); + traversal.close_scope(); + traversal.close_scope(); // init, limit, step + } + Statement::Iterator(names, expressions, block) => { + let mut iterator_variables = Vec::new(); + for _ in 0..2 { + // f, s, var + traversal.new_scope(); + iterator_variables.push( + block + .swap(Variable::Register(traversal.index().unwrap())) + .start(), + ); + } + // So we put 'explist' into f, s, var as in https://www.lua.org/manual/5.3/manual.html#3.3.5 + compile_assignment(traversal, &iterator_variables, expressions)?; + let index_loop = traversal.push_code(block.swap(Code::UNSURE)); + // Discard to fill all names + let index = traversal.index().unwrap(); + traversal.push_code( + block + .swap(Code::Discard( + (index as usize + names.len()).try_into().unwrap(), + )) + .start(), + ); + for name in names.iter() { + traversal.new_scope(); + traversal.last_scope().symbol = Some(name.it.0.clone()); + } + traversal.compile(&block.inner_ref())?; + for _name in names.iter() { + traversal.close_scope(); + } + let index_jump = traversal.push_code(block.unit().end().swap(Code::UNSURE)); + traversal + .insert_code(index_jump, Code::Jump(jump_from(index_jump, index_loop)?)); + traversal.insert_code( + index_loop, + Code::IteratorLoop(jump_from(index_loop, index_jump + 1)?), + ); + resolve_break(traversal, index_loop, index_jump + 1)?; + traversal.close_scope(); + traversal.close_scope(); + traversal.close_scope(); // f, s, var + } + Statement::Function(names, method_name, function) => { + // todo: ideally make names an expression, change the parser for that too + let mut names_method = names.clone(); + let is_method = if let Some(method) = method_name { + // for use in compiling the function with 'self' as an argument + names_method.push(method.clone()); + true + } else { + false + }; + let mut names = names_method.iter().peekable(); + let first = names.next().unwrap(); + let var = first.swap(Variable::Name(first.it.clone())); + if !names.peek().is_some() { + compile_function(&self.swap(function), traversal, is_method)?; + compile_variable(var.inner_ref(), traversal, Access::Set)?; + } else { + compile_variable(var.inner_ref(), traversal, Access::Get)?; + while let Some(name) = names.next() { + if !names.peek().is_some() { + compile_function(&self.swap(function), traversal, is_method)?; + traversal.push_string(name.it.0.clone(), name.unit())?; + traversal.push_code(name.unit().end().swap(Code::TableSet)); + } else { + traversal.push_string(name.it.0.clone(), name.unit())?; + traversal.push_code(name.unit().end().swap(Code::TableGet)); + } + } + } + } + Statement::LocalFunction(name, function) => { + var_scope(traversal, name.it.0.clone()); + let index = traversal.index().unwrap(); + traversal.compile(&self.swap(function))?; + traversal.push_code(name.swap(Code::RegisterSet(index)).end()); + } + Statement::Declaration(names, expressions) => { + let mut expressions_iter = expressions.iter().peekable(); + let mut names_iter = names.iter().peekable(); + let compile_declaration = |traversal: &mut Traversal, + expression: &Piece, + name: &Piece| + -> Result<(), LoadError> { + traversal.compile(&expression.inner_ref())?; + traversal.last_scope().symbol = Some(name.it.0.clone()); + Ok(()) + }; + while names_iter.peek().is_some() { + match (expressions_iter.next(), expressions_iter.peek().is_none()) { + (Some(expression), true) => { + // expression is last, has multiplicity + match expression.it { + Expression::VarArg(ref vararg) => { + let names: Vec<&Piece> = names_iter.collect(); + traversal.compile(&expression.swap(vararg))?; // for error checking only + traversal.push_code( + expression.swap(Code::VarArg( + names.len().try_into().unwrap(), + )), + ); + let mut scopes = + traversal.last_context().scopes.iter_mut().rev(); + for name in names.iter().rev() { + scopes.next().unwrap().symbol = Some(name.it.0.clone()); + } + } + Expression::Prefix(ref prefix) => { + match prefix.deref() { + Prefix::Call(call) => { + let names: Vec<&Piece> = names_iter.collect(); + traversal.compile(&expression.swap(call))?; + let index = (traversal.index().unwrap_or(0) + as usize + + names.len()) + .try_into() + .unwrap(); + traversal.push_code( + expression.swap(Code::Discard(index)).end(), + ); // discard and extend to names + let mut scopes = traversal + .last_context() + .scopes + .iter_mut() + .rev(); + for name in names.iter().rev() { + scopes.next().unwrap().symbol = + Some(name.it.0.clone()); + } + } + _ => compile_declaration( + traversal, + expression, + names_iter.next().unwrap(), + )?, + } + } + _ => compile_declaration( + traversal, + expression, + names_iter.next().unwrap(), + )?, + } + break; + } + (Some(expression), false) => compile_declaration( + traversal, + expression, + names_iter.next().unwrap(), + )?, // expression is not last, just use it + (None, ..) => { + // no more expressions + let index = traversal.index().unwrap_or(0) as usize; + traversal.push_code( + names_iter + .next() + .unwrap() + .swap(Code::Discard( + (index + names_iter.count()).try_into().unwrap(), + )) + .end(), + ); + break; + } + } + } + let index = traversal.index().unwrap_or(0); + // clear up the remaining expressions and discard if they existed + if expressions_iter.peek().is_some() { + while let Some(expression) = expressions_iter.next() { + traversal.compile(&expression.inner_ref())? + } + traversal.push_code(Piece::<()>::null().swap(Code::Discard(index))); + } + } + } } - Statement::Iterator(names, expressions, block) => { - let mut iterator_variables = Vec::new(); - for _ in 0..2 { - // f, s, var - traversal.new_scope(); - iterator_variables.push( - block - .swap(Variable::Register(traversal.index().unwrap())) - .start(), - ); - } - // So we put 'explist' into f, s, var as in https://www.lua.org/manual/5.3/manual.html#3.3.5 - compile_assignment(traversal, &iterator_variables, expressions)?; - let index_loop = traversal.push_code(block.swap(Code::UNSURE)); - // Discard to fill all names - let index = traversal.index().unwrap(); - traversal.push_code( - block - .swap(Code::Discard((index as usize + names.len()).try_into().unwrap())) - .start(), - ); - for name in names.iter() { - traversal.new_scope(); - traversal.last_scope().symbol = Some(name.it.0.clone()); - } - traversal.compile(&block.inner_ref())?; - for _name in names.iter() { + // Any 'dangling' scopes that weren't closed (declarations) will be at the end of this block + if let Some(return_expressions) = &self.it.return_exp { + // arguments are backwards + for return_expression in return_expressions.iter().rev() { + traversal.compile(&return_expression.inner_ref())?; + } + } + for _ in 0..depth { traversal.close_scope(); - } - let index_jump = traversal.push_code(block.unit().end().swap(Code::UNSURE)); - traversal - .insert_code(index_jump, Code::Jump(jump_from(index_jump, index_loop)?)); - traversal.insert_code( - index_loop, - Code::IteratorLoop(jump_from(index_loop, index_jump + 1)?), - ); - resolve_break(traversal, index_loop, index_jump + 1)?; - traversal.close_scope(); - traversal.close_scope(); - traversal.close_scope(); // f, s, var } - Statement::Function(names, method_name, function) => { - // todo: ideally make names an expression, change the parser for that too - let mut names_method = names.clone(); - let is_method = if let Some(method) = method_name { - // for use in compiling the function with 'self' as an argument - names_method.push(method.clone()); - true - } else { - false - }; - let mut names = names_method.iter().peekable(); - let first = names.next().unwrap(); - let var = first.swap(Variable::Name(first.it.clone())); - if !names.peek().is_some() { - compile_function(&self.swap(function), traversal, is_method)?; - compile_variable(var.inner_ref(), traversal, Access::Set)?; - } else { - compile_variable(var.inner_ref(), traversal, Access::Get)?; - while let Some(name) = names.next() { - if !names.peek().is_some() { - compile_function(&self.swap(function), traversal, is_method)?; - traversal.push_string(name.it.0.clone(),name.unit())?; - traversal.push_code(name.unit().end().swap(Code::TableSet)); - } else { - traversal.push_string(name.it.0.clone(),name.unit())?; - traversal.push_code(name.unit().end().swap(Code::TableGet)); - } - } - } - } - Statement::LocalFunction(name, function) => { - var_scope(traversal, name.it.0.clone()); - let index = traversal.index().unwrap(); - traversal.compile(&self.swap(function))?; - traversal.push_code(name.swap(Code::RegisterSet(index)).end()); - } - Statement::Declaration(names, expressions) => { - let variables = &names - .iter() - .map(|name| { - var_scope(traversal, name.it.0.clone()); - name.swap(Variable::Name(name.it.clone())) - }) - .collect(); - compile_assignment(traversal, variables, expressions)?; - } - } + assert_eq!(traversal.index().unwrap_or(0), last_scope_index); + Ok(()) } - // Any 'dangling' scopes that weren't closed (declarations) will be at the end of this block - if let Some(return_expressions) = &self.it.1 { - // arguments are backwards - for return_expression in return_expressions.iter().rev() { - traversal.compile(&return_expression.inner_ref())?; - } - } - for _ in 0..depth { - traversal.close_scope(); - } - assert_eq!(traversal.index().unwrap_or(0), last_scope_index); - Ok(()) - } } impl Compile for Chunk { - fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { - traversal.compile(&self.0.inner_ref()) - } + fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + traversal.compile(&self.0.inner_ref()) + } } -pub(crate) fn compile(chunk: &Chunk, machine: &mut Machine) -> Result { - let mut traversal = Traversal::new(machine); - traversal.compile(chunk)?; - traversal.close_context() -} \ No newline at end of file +pub(crate) fn compile(chunk: &Chunk, machine: &mut Machine) -> Result { + let mut traversal = Traversal::new(machine); + traversal.compile(chunk)?; + traversal.close_context() +} diff --git a/src/parser.rs b/src/parser.rs index 59f875d..f5fc0f7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,258 +1,257 @@ // PARSER -use std::fmt::Formatter; -use std::hash::{DefaultHasher, Hash, Hasher}; -use std::ops::{Add, Deref, DerefMut}; use crate::vm::{Index, RunError}; +use std::fmt::Formatter; +use std::ops::Add; // TODO: Vec> is good but sometimes we either need at least one or none, current fix is just to check if there is one and if not skip it, this takes extra performance #[derive(Clone, Copy)] struct Reader<'a> { - // 'cursor' states that follow through parsed source - slice: &'a str, - full: &'a str, - white: bool, // Is the previous 'thing' whitespace? + // 'cursor' states that follow through parsed source + slice: &'a str, + full: &'a str, + white: bool, // Is the previous 'thing' whitespace? } pub struct LoadError(pub String, pub Piece<()>); // Any error returned by a machine loading code impl LoadError { - fn new(message: &str, reader: &Reader) -> Result { - Err(LoadError(message.to_string(), reader.marker())) - } - pub(crate) fn from_str(message: &str, piece: &Piece) -> LoadError { - LoadError(message.to_string(), piece.unit()) - } - pub(crate) fn msg(&self, reader: &str) -> String { - let mut roll = format!("Error: {} {}", self.1.index, self.0); - let mut begin = self.1.index; - let mut end = self.1.index + self.1.width; - let mut count = 0; - for line in reader.lines() { - // todo: improve this - count += 1; - if line.len() >= begin { - begin = 0; - roll = roll.add(format!("\n{}\t", count).as_str()); - roll = roll.add(line); - } else { - begin -= line.len(); - } - if line.len() > end { - break; - } else { - end -= line.len() - } + fn new(message: &str, reader: &Reader) -> Result { + Err(LoadError(message.to_string(), reader.marker())) + } + pub(crate) fn from_str(message: &str, piece: &Piece) -> LoadError { + LoadError(message.to_string(), piece.unit()) + } + pub(crate) fn msg(&self, reader: &str) -> String { + let mut roll = format!("Error: {} {}", self.1.index, self.0); + let mut begin = self.1.index; + let mut end = self.1.index + self.1.width; + let mut count = 0; + for line in reader.lines() { + // todo: improve this + count += 1; + if line.len() >= begin { + begin = 0; + roll = roll.add(format!("\n{}\t", count).as_str()); + roll = roll.add(line); + } else { + begin -= line.len(); + } + if line.len() > end { + break; + } else { + end -= line.len() + } + } + roll + } + fn from_runtime(piece: Piece<()>, error: RunError) -> LoadError { + LoadError(error.0, piece) } - roll - } - fn from_runtime(piece: Piece<()>, error: RunError) -> LoadError { - LoadError(error.0,piece) - } } impl std::fmt::Debug for LoadError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("Error: {} {}", self.0, self.1.index)) - } + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("Error: {} {}", self.0, self.1.index)) + } } type Comment = String; #[derive(Clone)] pub(crate) struct Piece { - // A wrapper of T providing a reference to source code, used in errors - comment: Comment, - index: usize, - width: usize, - pub(crate) it: T, + // A wrapper of T providing a reference to source code, used in errors + comment: Comment, + index: usize, + width: usize, + pub(crate) it: T, } impl std::fmt::Debug for Piece where - T: std::fmt::Debug, + T: std::fmt::Debug, { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.it.fmt(f) - } + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.it.fmt(f) + } } impl Piece { - fn of(it: T, reader: &Reader, width: usize) -> Piece { - Piece { - it, - index: reader.slice.as_ptr() as usize - reader.full.as_ptr() as usize, - width, - comment: String::new(), + fn of(it: T, reader: &Reader, width: usize) -> Piece { + Piece { + it, + index: reader.slice.as_ptr() as usize - reader.full.as_ptr() as usize, + width, + comment: String::new(), + } } - } - fn from(it: T, begin: &Piece, end: &Piece) -> Piece { - Piece { - it, - index: begin.index, - width: end.index + end.width - begin.index, - comment: begin.comment.clone(), + fn from(it: T, begin: &Piece, end: &Piece) -> Piece { + Piece { + it, + index: begin.index, + width: end.index + end.width - begin.index, + comment: begin.comment.clone(), + } } - } - pub(crate) fn swap(&self, it: A) -> Piece { - Piece { - it, - index: self.index, - width: self.width, - comment: self.comment.clone(), + pub(crate) fn swap(&self, it: A) -> Piece { + Piece { + it, + index: self.index, + width: self.width, + comment: self.comment.clone(), + } } - } - pub(crate) fn unit(&self) -> Piece<()> { - Piece { - it: (), - index: self.index, - width: self.width, - comment: self.comment.clone(), + pub(crate) fn unit(&self) -> Piece<()> { + Piece { + it: (), + index: self.index, + width: self.width, + comment: self.comment.clone(), + } } - } - pub(crate) fn null() -> Piece<()> { - Piece { - it: (), - index: 0, - width: 0, - comment: String::new(), + pub(crate) fn null() -> Piece<()> { + Piece { + it: (), + index: 0, + width: 0, + comment: String::new(), + } } - } - fn map(self, f: F) -> Piece - where - F: FnOnce(T) -> U, - { - let it = f(self.it); - Piece { - it, - index: self.index, - width: self.width, - comment: self.comment, // this is stupid + fn map(self, f: F) -> Piece + where + F: FnOnce(T) -> U, + { + let it = f(self.it); + Piece { + it, + index: self.index, + width: self.width, + comment: self.comment, // this is stupid + } } - } - fn new(it: T) -> Piece { - Piece { - it, - index: 0, - width: 0, - comment: String::new(), + fn new(it: T) -> Piece { + Piece { + it, + index: 0, + width: 0, + comment: String::new(), + } } - } - pub(crate) fn end(self) -> Piece { - Piece { - it: self.it, - index: self.index + self.width, - width: 0, - comment: self.comment, + pub(crate) fn end(self) -> Piece { + Piece { + it: self.it, + index: self.index + self.width, + width: 0, + comment: self.comment, + } } - } - pub(crate) fn start(self) -> Piece { - Piece { - it: self.it, - index: self.index, - width: 0, - comment: self.comment, + pub(crate) fn start(self) -> Piece { + Piece { + it: self.it, + index: self.index, + width: 0, + comment: self.comment, + } } - } - pub(crate) fn inner_ref(&self) -> Piece<&T> { - self.unit().swap(&self.it) - } // TODO: .as_ref() + pub(crate) fn inner_ref(&self) -> Piece<&T> { + self.unit().swap(&self.it) + } // TODO: .as_ref() } impl<'a> From<&'a str> for Reader<'a> { - fn from(str: &'a str) -> Self { - Reader { - full: str, - slice: str, - white: true, + fn from(str: &'a str) -> Self { + Reader { + full: str, + slice: str, + white: true, + } } - } } impl<'a> Reader<'a> { - fn trim(&mut self) -> Result { - let start = self.slice.as_ptr() as usize; - self.slice = self.slice.trim_start(); - if self.slice.starts_with("--") { - let comment = if self.slice[2..].starts_with("[[") { - match self.slice.find("]]") { - Some(i) => { - let comment = &self.slice[4..i + 2]; - self.slice = &self.slice[i + 2..].trim(); - self.white = true; - Ok(comment) - } - _ => self.error("Unterminated multi-line comment"), - } - } else { - let comment; - if let Some(i) = self.slice.find("\n") { - self.slice = &self.slice[i + 1..].trim(); - comment = &self.slice[2..i + 1]; - self.white = true; + fn trim(&mut self) -> Result { + let start = self.slice.as_ptr() as usize; + self.slice = self.slice.trim_start(); + if self.slice.starts_with("--") { + let comment = if self.slice[2..].starts_with("[[") { + match self.slice.find("]]") { + Some(i) => { + let comment = &self.slice[4..i + 2]; + self.slice = &self.slice[i + 2..].trim(); + self.white = true; + Ok(comment) + } + _ => self.error("Unterminated multi-line comment"), + } + } else { + let comment; + if let Some(i) = self.slice.find("\n") { + self.slice = &self.slice[i + 1..].trim(); + comment = &self.slice[2..i + 1]; + self.white = true; + } else { + self.slice = &self.slice[..self.slice.len() - 1]; + comment = &self.slice[2..]; + self.white = false; + } + Ok(comment) + }?; + self.trim().map(|it| { + // Try another comment and append them to each other, just in case + it + "\n" + comment + }) } else { - self.slice = &self.slice[..self.slice.len() - 1]; - comment = &self.slice[2..]; - self.white = false; + if start < self.slice.as_ptr() as usize { + self.white = true; + } + Ok(String::new()) } - Ok(comment) - }?; - self.trim().map(|it| { - // Try another comment and append them to each other, just in case - it + "\n" + comment - }) - } else { - if start < self.slice.as_ptr() as usize { - self.white = true; - } - Ok(String::new()) } - } - fn white(&mut self) -> Result<&mut Self, LoadError> { - if self.white { - Ok(self) - } else { - self.error("Expected whitespace") + fn white(&mut self) -> Result<&mut Self, LoadError> { + if self.white { + Ok(self) + } else { + self.error("Expected whitespace") + } } - } - fn consume(&mut self, start: &str) -> Result<&mut Self, LoadError> { - self.trim()?; - if self.slice.starts_with(start) { - self.slice = &self.slice[start.len()..]; - Ok(self) - } else { - self.error(format!("Expected '{}'", start).as_str()) + fn consume(&mut self, start: &str) -> Result<&mut Self, LoadError> { + self.trim()?; + if self.slice.starts_with(start) { + self.slice = &self.slice[start.len()..]; + Ok(self) + } else { + self.error(format!("Expected '{}'", start).as_str()) + } } - } - // Consume but require whitespace before - fn white_consume(&mut self, start: &str) -> Result<&mut Self, LoadError> { - if self.white { - self.consume(start) - } else { - self.error(format!("Expected whitespace before parsing {}", start).as_str()) + // Consume but require whitespace before + fn white_consume(&mut self, start: &str) -> Result<&mut Self, LoadError> { + if self.white { + self.consume(start) + } else { + self.error(format!("Expected whitespace before parsing {}", start).as_str()) + } + } + // Consume but set whitespace after + fn consume_white(&mut self, start: &str) -> Result<&mut Self, LoadError> { + let result = self.consume(start)?; + result.white = true; + Ok(result) + } + fn take(&mut self) -> Result, LoadError> + where + T: Parse, + { + T::consume(self) + } + fn finished(&self) -> bool { + self.slice.is_empty() + } + fn error(&self, message: &str) -> Result { + LoadError::new(message, self) + } + fn marker(&self) -> Piece<()> { + Piece::of((), self, 0) } - } - // Consume but set whitespace after - fn consume_white(&mut self, start: &str) -> Result<&mut Self, LoadError> { - let result = self.consume(start)?; - result.white = true; - Ok(result) - } - fn take(&mut self) -> Result, LoadError> - where - T: Parse, - { - T::consume(self) - } - fn finished(&self) -> bool { - self.slice.is_empty() - } - fn error(&self, message: &str) -> Result { - LoadError::new(message, self) - } - fn marker(&self) -> Piece<()> { - Piece::of((), self, 0) - } } #[derive(Debug)] @@ -264,961 +263,999 @@ pub(crate) struct Name(pub(crate) String); // - ??? // - The reader may have not been trimmed trait Parse { - fn consume(reader: &mut Reader) -> Result, LoadError> - where - Self: Sized; + fn consume(reader: &mut Reader) -> Result, LoadError> + where + Self: Sized; } static KEYWORDS: &[&str] = &[ - "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "func", "global", - "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", - "while", + "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "func", "global", + "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", + "while", ]; impl Parse for Name { - fn consume(reader: &mut Reader) -> Result, LoadError> - where - Self: Sized, - { - reader.trim()?; - reader.white()?; - let mut chars = reader.slice.chars(); - let mut end = 1; - match chars.next() { - None => { - return reader.error("Expected identifier"); - } - Some(c) => { - if !(c.is_alphabetic() || c == '_') { - return reader.error("Identifier must begin with alphabetic character"); + fn consume(reader: &mut Reader) -> Result, LoadError> + where + Self: Sized, + { + reader.trim()?; + reader.white()?; + let mut chars = reader.slice.chars(); + let mut end = 1; + match chars.next() { + None => { + return reader.error("Expected identifier"); + } + Some(c) => { + if !(c.is_alphabetic() || c == '_') { + return reader.error("Identifier must begin with alphabetic character"); + } + } + }; + end += chars + .take_while(|c| c.is_alphanumeric() || *c == '_') + .count(); + let name = reader.slice[..end].to_string(); + if KEYWORDS.contains(&name.as_str()) { + return reader.error(format!("Expected name, got keyword {}", name).as_str()); } - } - }; - end += chars - .take_while(|c| c.is_alphanumeric() || *c == '_') - .count(); - let name = reader.slice[..end].to_string(); - if KEYWORDS.contains(&name.as_str()) { - return reader.error(format!("Expected name, got keyword {}", name).as_str()); + let result = Ok(Piece::of(Name(name), reader, end)); + reader.slice = &reader.slice[end..]; + result } - let result = Ok(Piece::of(Name(name), reader, end)); - reader.slice = &reader.slice[end..]; - result - } } impl Parse for Number { - fn consume(reader: &mut Reader) -> Result, LoadError> - where - Self: Sized, - { - reader.trim()?; - reader.white()?; - if !reader.white { - return reader.error("Expected whitespace before parsing number"); + fn consume(reader: &mut Reader) -> Result, LoadError> + where + Self: Sized, + { + reader.trim()?; + reader.white()?; + if !reader.white { + return reader.error("Expected whitespace before parsing number"); + } + let mut end; + if reader.slice.starts_with("0x") { + end = reader.slice[2..] + .chars() + .take_while(|c| c.is_digit(16)) + .count() + + 2; + if end == 2 { + end = 0 + } + } else { + end = reader + .slice + .chars() + .take_while(|c| c.is_digit(10) || *c == '.') + .count(); + } + if end == 0 { + reader.error("Could not parse number".into()) + } else { + let number = reader.slice[..end].to_string(); + reader.slice = &reader.slice[end..]; + Ok(Piece::of(Number(number), reader, end)) + } } - let mut end; - if reader.slice.starts_with("0x") { - end = reader.slice[2..] - .chars() - .take_while(|c| c.is_digit(16)) - .count() - + 2; - if end == 2 { - end = 0 - } - } else { - end = reader - .slice - .chars() - .take_while(|c| c.is_digit(10) || *c == '.') - .count(); - } - if end == 0 { - reader.error("Could not parse number".into()) - } else { - reader.slice = &reader.slice[end..]; - Ok(Piece::of( - Number(reader.slice[..end].to_string()), - reader, - end, - )) - } - } } impl Parse for String { - fn consume(reader: &mut Reader) -> Result, LoadError> - where - Self: Sized, - { - reader.trim()?; - let chars: &mut std::str::Chars = &mut reader.slice.chars(); - let mut string = String::new(); - let term1: char; - let term2: Option; - let extra; - match chars.next() { - Some('"') => { - term1 = '"'; - term2 = None; - extra = 2; - } - Some('\'') => { - term1 = '\''; - term2 = None; - extra = 2; - } - Some('[') if chars.next().is_some_and(|it| it == '[') => { - term1 = ']'; - term2 = Some(']'); - extra = 4; - } - _ => { - return reader.error("Could not parse string"); - } - } - loop { - match chars.next() { - Some(c) => { - match c { - '\\' => match chars.next() { - Some(c) => match c { - 'n' => string.push('\n'), - 'r' => string.push('\r'), - 't' => string.push('\t'), - '"' => string.push('"'), - '\'' => string.push('\''), - '\\' => string.push('\\'), - it => { - string.push(it); - } - }, - None => {} - }, - '\r' => {} // todo: ? - '\n' if term2.is_none() => { - return reader.error("Found newline while parsing string"); + fn consume(reader: &mut Reader) -> Result, LoadError> + where + Self: Sized, + { + reader.trim()?; + let chars: &mut std::str::Chars = &mut reader.slice.chars(); + let mut string = String::new(); + let term1: char; + let term2: Option; + let extra; + match chars.next() { + Some('"') => { + term1 = '"'; + term2 = None; + extra = 2; } - term if term == term1 => { - // If the second terminator exists and is the next char, or there is no second terminator - if !term2.is_some() - || chars.next().is_some_and(|it| it == term2.unwrap()) - { - let length = string.len(); - reader.slice = &reader.slice[length + extra..]; - return Ok(Piece::of(string, reader, length)); - // There is a second terminator and it wasn't the next char - } else { - string.push(term) - } + Some('\'') => { + term1 = '\''; + term2 = None; + extra = 2; + } + Some('[') if chars.next().is_some_and(|it| it == '[') => { + term1 = ']'; + term2 = Some(']'); + extra = 4; } _ => { - string.push(c); + return reader.error("Could not parse string"); } - } } - None => { - return reader.error("Found EOF while parsing string"); + loop { + match chars.next() { + Some(c) => { + match c { + '\\' => match chars.next() { + Some(c) => match c { + 'n' => string.push('\n'), + 'r' => string.push('\r'), + 't' => string.push('\t'), + '"' => string.push('"'), + '\'' => string.push('\''), + '\\' => string.push('\\'), + it => { + string.push(it); + } + }, + None => {} + }, + '\r' => {} // todo: ? + '\n' if term2.is_none() => { + return reader.error("Found newline while parsing string"); + } + term if term == term1 => { + // If the second terminator exists and is the next char, or there is no second terminator + if !term2.is_some() + || chars.next().is_some_and(|it| it == term2.unwrap()) + { + let length = string.len(); + reader.slice = &reader.slice[length + extra..]; + return Ok(Piece::of(string, reader, length)); + // There is a second terminator and it wasn't the next char + } else { + string.push(term) + } + } + _ => { + string.push(c); + } + } + } + None => { + return reader.error("Found EOF while parsing string"); + } + } } - } } - } } // AST #[derive(Debug)] -pub(crate) struct Block(pub(crate) Vec>, pub(crate) Option>>); // +pub(crate) struct Block { + pub(crate) statements: Vec>, + pub(crate) return_exp: Option>>, +} // #[derive(Debug)] pub(crate) struct Chunk(pub(crate) Piece); #[derive(Debug)] pub(crate) enum Statement { - Semicolon, - Assignment(Vec>, Vec>), - Call(Call), - Label(Piece), - Break, - Continue, - Goto(Piece), - Do(Block), - While(Piece, Block), - Repeat(Block, Piece), - If( - Vec>, - Vec>, - Option>, - ), - Range( - Piece, - Piece, - Piece, - Option>, - Piece, - ), - Iterator(Vec>, Vec>, Piece), - // TODO: Maybe make this work on just Piece,Option> maybe - Function(Vec>, Option>, Function), - LocalFunction(Piece, Function), - Declaration(Vec>, Vec>), + Semicolon, + Assignment(Vec>, Vec>), + Call(Call), + Label(Piece), + Break, + Continue, + Goto(Piece), + Do(Block), + While(Piece, Block), + Repeat(Block, Piece), + If( + Vec>, + Vec>, + Option>, + ), + Range( + Piece, + Piece, + Piece, + Option>, + Piece, + ), + Iterator(Vec>, Vec>, Piece), + // TODO: Maybe make this work on just Piece,Option> maybe + Function(Vec>, Option>, Function), + LocalFunction(Piece, Function), + Declaration(Vec>, Vec>), } #[derive(Debug)] pub(crate) enum Variable { - Name(Name), - Index(Box>, Piece), - Register(Index), // todo: this is kind of bad because the parser and the compiler should be separate. a wrapper could be used instead! + Name(Name), + Index(Box>, Piece), + Register(Index), // todo: this is kind of bad because the parser and the compiler should be separate. a wrapper could be used instead! } #[derive(Debug)] pub(crate) enum Expression { - Nil, - True, - False, - Number(Number), - String(String), - VarArg(VarArg), - Function(Function), - Prefix(Box), - Table(Constructor), - Binary( - Box>, - Piece, - Box>, - ), - Unary(Piece, Box>), + Nil, + True, + False, + Number(Number), + String(String), + VarArg(VarArg), + Function(Function), + Prefix(Box), + Table(Constructor), + Binary( + Box>, + Piece, + Box>, + ), + Unary(Piece, Box>), } #[derive(Debug)] pub(crate) struct Constructor(pub(crate) Vec>); #[derive(Debug)] pub(crate) enum Prefix { - Variable(Variable), - Call(Call), - Expression(Expression), + Variable(Variable), + Call(Call), + Expression(Expression), } #[derive(Debug, Clone)] pub(crate) struct VarArg(pub(crate) Option); #[derive(Debug)] -pub(crate) struct Call(pub(crate) Box>, pub(crate) Option>, pub(crate) Piece); +pub(crate) struct Call { + pub(crate) prefix: Box>, + pub(crate) method: Option>, + pub(crate) args: Piece, +} #[derive(Debug)] pub(crate) struct Args(pub(crate) Vec>); #[derive(Debug)] -pub(crate) struct Function(pub(crate) Vec>, pub(crate) Option>, pub(crate) Piece); +pub(crate) struct Function { + pub(crate) args: Vec>, + pub(crate) vararg: Option>, + pub(crate) block: Piece, +} #[derive(Debug)] -pub(crate) struct Field(pub(crate) Option>, pub(crate) Piece); +pub(crate) struct Field { + pub(crate) index: Option>, + pub(crate) expression: Piece, +} #[derive(Debug)] pub(crate) enum FieldSep { - Comma, - Semicolon, + Comma, + Semicolon, } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] pub(crate) enum BinaryOp { - Or, - And, - Less, - Greater, - LessEqual, - GreatEqual, - Equivalent, - NotEqual, - Pipe, - Tilde, - Ampersand, - ShiftLeft, - ShiftRight, - Concat, - Plus, - Minus, - Mul, - Divide, - DivFloor, - Modulo, - Caret, + Or, + And, + Less, + Greater, + LessEqual, + GreatEqual, + Equivalent, + NotEqual, + Pipe, + Tilde, + Ampersand, + ShiftLeft, + ShiftRight, + Concat, + Plus, + Minus, + Mul, + Divide, + DivFloor, + Modulo, + Caret, } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] pub(crate) enum UnaryOp { - Negate, - Not, - Ampersand, - Tilde, + Negate, + Not, + Ampersand, + Tilde, } impl Parse for Vec> { - fn consume(reader: &mut Reader) -> Result>>, LoadError> - where - Self: Sized, - { - let mut result: Vec> = Vec::new(); - reader.trim()?; - result.push(reader.take::()?); - while reader.consume_white(",").is_ok() { - result.push(reader.take::()?); + fn consume(reader: &mut Reader) -> Result>>, LoadError> + where + Self: Sized, + { + let mut result: Vec> = Vec::new(); + reader.trim()?; + result.push(reader.take::()?); + while reader.consume_white(",").is_ok() { + result.push(reader.take::()?); + } + let first = result.first().unwrap().unit(); + let last = result.last().unwrap().unit(); + Ok(Piece::from(result, &first, &last)) } - let first = result.first().unwrap().unit(); - let last = result.last().unwrap().unit(); - Ok(Piece::from(result, &first, &last)) - } } impl Parse for BinaryOp { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - let mut chars = reader.slice.chars(); - if let Some(char) = chars.next() { - let mut count = 1; - let op = match char { - '+' => BinaryOp::Plus, - '-' => BinaryOp::Minus, - '*' => BinaryOp::Mul, - '/' => { - if let Some('/') = chars.next() { - count += 1; - BinaryOp::DivFloor - } else { - BinaryOp::Divide - } + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + let mut chars = reader.slice.chars(); + if let Some(char) = chars.next() { + let mut count = 1; + let op = match char { + '+' => BinaryOp::Plus, + '-' => BinaryOp::Minus, + '*' => BinaryOp::Mul, + '/' => { + if let Some('/') = chars.next() { + count += 1; + BinaryOp::DivFloor + } else { + BinaryOp::Divide + } + } + '^' => BinaryOp::Caret, + '%' => BinaryOp::Modulo, + '&' => BinaryOp::Ampersand, + '~' => match chars.next() { + Some('=') => { + count += 1; + BinaryOp::NotEqual + } + _ => BinaryOp::Tilde, + }, + '|' => BinaryOp::Pipe, + '>' => match chars.next() { + Some('>') => { + count += 1; + BinaryOp::ShiftRight + } + Some('=') => { + count += 1; + BinaryOp::GreatEqual + } + _ => BinaryOp::Greater, + }, + '<' => match chars.next() { + Some('<') => { + count += 1; + BinaryOp::ShiftLeft + } + Some('=') => { + count += 1; + BinaryOp::LessEqual + } + _ => BinaryOp::Less, + }, + '.' => { + if let Some('.') = chars.next() { + count += 1; + BinaryOp::Concat + } else { + return reader.error("Expected '.' for concatenation"); + } + } + '=' => { + if let Some('=') = chars.next() { + count += 1; + BinaryOp::Equivalent + } else { + return reader.error("Expected '=' for equality"); + } + } + _ => { + if reader.white_consume("and").is_ok() { + count += 2; + BinaryOp::And + } else if reader.white_consume("or").is_ok() { + count += 1; + BinaryOp::Or + } else { + return reader.error("Expected binary operation"); + } + } + }; + if !matches!(op, BinaryOp::And | BinaryOp::Or) { + reader.white = true; + } + let result = Ok(Piece::of(op, reader, count)); + reader.slice = &reader.slice[count..]; + result + } else { + reader.error("Expected binary operand, got EOF") } - '^' => BinaryOp::Caret, - '%' => BinaryOp::Modulo, - '&' => BinaryOp::Ampersand, - '~' => match chars.next() { - Some('=') => { - count += 1; - BinaryOp::NotEqual - } - _ => BinaryOp::Tilde, - }, - '|' => BinaryOp::Pipe, - '>' => match chars.next() { - Some('>') => { - count += 1; - BinaryOp::ShiftRight - } - Some('=') => { - count += 1; - BinaryOp::GreatEqual - } - _ => BinaryOp::Greater, - }, - '<' => match chars.next() { - Some('<') => { - count += 1; - BinaryOp::ShiftLeft - } - Some('=') => { - count += 1; - BinaryOp::LessEqual - } - _ => BinaryOp::Less, - }, - '.' => { - if let Some('.') = chars.next() { - count += 1; - BinaryOp::Concat - } else { - return reader.error("Expected '.' for concatenation"); - } - } - '=' => { - if let Some('=') = chars.next() { - count += 1; - BinaryOp::Equivalent - } else { - return reader.error("Expected '=' for equality"); - } - } - _ => { - if reader.white_consume("and").is_ok() { - count += 2; - BinaryOp::And - } else if reader.white_consume("or").is_ok() { - count += 1; - BinaryOp::Or - } else { - return reader.error("Expected binary operation"); - } - } - }; - if !matches!(op, BinaryOp::And | BinaryOp::Or) { - reader.white = true; - } - let result = Ok(Piece::of(op, reader, count)); - reader.slice = &reader.slice[count..]; - result - } else { - reader.error("Expected binary operand, got EOF") } - } } impl Parse for UnaryOp { - fn consume(reader: &mut Reader) -> Result, LoadError> { - let start = &reader.marker(); - reader.trim()?; - let op = if reader.consume("-").is_ok() { - UnaryOp::Negate - } else if reader.white_consume("not").is_ok() { - UnaryOp::Not - } else if reader.consume("#").is_ok() { - UnaryOp::Ampersand - } else if reader.consume("~").is_ok() { - UnaryOp::Tilde - } else { - return reader.error("Expected unary operand"); - }; - if !matches!(op, UnaryOp::Not) { - reader.white = true; + fn consume(reader: &mut Reader) -> Result, LoadError> { + let start = &reader.marker(); + reader.trim()?; + let op = if reader.consume("-").is_ok() { + UnaryOp::Negate + } else if reader.white_consume("not").is_ok() { + UnaryOp::Not + } else if reader.consume("#").is_ok() { + UnaryOp::Ampersand + } else if reader.consume("~").is_ok() { + UnaryOp::Tilde + } else { + return reader.error("Expected unary operand"); + }; + if !matches!(op, UnaryOp::Not) { + reader.white = true; + } + Ok(Piece::from(op, &start, &reader.marker())) } - Ok(Piece::from(op, &start, &reader.marker())) - } } impl Parse for Function { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - let start = reader.marker(); - reader.consume_white("(")?; - let mut pre_parameters: Vec> = Vec::new(); - let mut vararg = None; - loop { - if let Ok(name) = reader.take::() { - if vararg.is_some() { - return reader.error("Unexpected extra argument"); - } else { - pre_parameters.push(name); + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + let start = reader.marker(); + reader.consume_white("(")?; + let mut pre_parameters: Vec> = Vec::new(); + let mut vararg = None; + loop { + if let Ok(name) = reader.take::() { + if vararg.is_some() { + return reader.error("Unexpected extra argument"); + } else { + pre_parameters.push(name); + } + } else if let Ok(new_vararg) = reader.take::() { + if vararg.is_some() { + return reader.error("Unexpected extra vararg"); + } else { + vararg = Some(new_vararg); + } + } else { + break; + } + if !reader.consume_white(",").is_ok() { + // rust can we has `repeat` pls + break; + } } - } else if let Ok(new_vararg) = reader.take::() { - if vararg.is_some() { - return reader.error("Unexpected extra vararg"); - } else { - vararg = Some(new_vararg); - } - } else { - break; - } - if !reader.consume_white(",").is_ok() { - // rust can we has `repeat` pls - break; - } + reader.consume_white(")")?; + let end = reader.marker(); + let block = reader.take::()?; + reader.white_consume("end")?; + Ok(Piece::from( + Function { + args: pre_parameters, + vararg: vararg, + block: block, + }, + &start, + &end, + )) } - reader.consume_white(")")?; - let end = reader.marker(); - let block = reader.take::()?; - reader.white_consume("end")?; - Ok(Piece::from( - Function(pre_parameters, vararg, block), - &start, - &end, - )) - } } impl Parse for VarArg { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - let start = reader.marker(); - reader.white()?.consume_white("...")?; - let name = reader.take::().ok(); - let end; - if let Some(name) = name { - let end = name.unit(); - Ok(Piece::from(VarArg(Some(name.it)), &start, &end)) - } else { - end = reader.marker(); - Ok(Piece::from( - VarArg(name.map(|piece| piece.it)), - &start, - &end, - )) + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + let start = reader.marker(); + reader.white()?.consume_white("...")?; + let name = reader.take::().ok(); + let end; + if let Some(name) = name { + let end = name.unit(); + Ok(Piece::from(VarArg(Some(name.it)), &start, &end)) + } else { + end = reader.marker(); + Ok(Piece::from( + VarArg(name.map(|piece| piece.it)), + &start, + &end, + )) + } } - } } impl BinaryOp { - fn compare(&self, other: &BinaryOp) -> bool { - self < other - } - fn compare_unary(&self) -> bool { - match self { - BinaryOp::Caret => true, - _ => false, + fn compare(&self, other: &BinaryOp) -> bool { + self < other + } + fn compare_unary(&self) -> bool { + match self { + BinaryOp::Caret => true, + _ => false, + } } - } } fn inject( - current: Piece, - op: Piece, - next: Piece, + current: Piece, + op: Piece, + next: Piece, ) -> Piece { - let start = current.unit(); - if let Expression::Binary(left, op2, right) = current.it { - if op.it.compare(&op2.it) { - let start = left.unit(); - let new_right = Box::new(inject(*right, op, next)); - let end = new_right.unit(); - Piece::from(Expression::Binary(left, op2, new_right), &start, &end) - } else { - let start2 = start.unit(); - let end = next.unit(); - Piece::from( - Expression::Binary( - Box::new(start.map(|_| Expression::Binary(left, op2, right))), - op, - Box::new(next), - ), - &start2, - &end, - ) - } - } else if let Expression::Unary(op2, inner) = current.it { - if op.it.compare_unary() { - let start = op2.unit(); - let inner = Box::new(inject(*inner, op, next)); - let end = inner.unit(); - Piece::from(Expression::Unary(op2, inner), &start, &end) - } else { - let start2 = start.unit(); - let end = next.unit(); - Piece::from( - Expression::Binary( - Box::new(start.map(|_| Expression::Unary(op2, inner))), - op, - Box::new(next), - ), - &start2, - &end, - ) - } - } else { let start = current.unit(); - let end = next.unit(); - Piece::from( - Expression::Binary(Box::new(current), op, Box::new(next)), - &start, - &end, - ) - } + if let Expression::Binary(left, op2, right) = current.it { + if op.it.compare(&op2.it) { + let start = left.unit(); + let new_right = Box::new(inject(*right, op, next)); + let end = new_right.unit(); + Piece::from(Expression::Binary(left, op2, new_right), &start, &end) + } else { + let start2 = start.unit(); + let end = next.unit(); + Piece::from( + Expression::Binary( + Box::new(start.map(|_| Expression::Binary(left, op2, right))), + op, + Box::new(next), + ), + &start2, + &end, + ) + } + } else if let Expression::Unary(op2, inner) = current.it { + if op.it.compare_unary() { + let start = op2.unit(); + let inner = Box::new(inject(*inner, op, next)); + let end = inner.unit(); + Piece::from(Expression::Unary(op2, inner), &start, &end) + } else { + let start2 = start.unit(); + let end = next.unit(); + Piece::from( + Expression::Binary( + Box::new(start.map(|_| Expression::Unary(op2, inner))), + op, + Box::new(next), + ), + &start2, + &end, + ) + } + } else { + let start = current.unit(); + let end = next.unit(); + Piece::from( + Expression::Binary(Box::new(current), op, Box::new(next)), + &start, + &end, + ) + } } impl Parse for Expression { - fn consume(reader: &mut Reader) -> Result, LoadError> { - let taker = |reader: &mut Reader| { - let start = reader.marker(); - reader.trim()?; - let result = if reader.white_consume("nil").is_ok() { - Expression::Nil - } else if reader.white_consume("true").is_ok() { - Expression::True - } else if reader.white_consume("false").is_ok() { - Expression::False - } else if let Ok(vararg) = reader.take::() { - Expression::VarArg(vararg.it) - } else if let Ok(number) = reader.take::() { - Expression::Number(number.it) - } else if let Ok(string) = reader.take::() { - Expression::String(string.it) - } else if reader.white_consume("function").is_ok() - || reader.white_consume("func").is_ok() - { - Expression::Function(reader.take::()?.it) - } else if let Ok(table) = reader.take::() { - Expression::Table(table.it) - } else if let Ok(unary) = reader.take::() { - Expression::Unary(unary, Box::new(reader.take::()?)) - } else { - Expression::Prefix(Box::new(reader.take::()?.it)) - }; - Ok(Piece::from(result, &start, &reader.marker())) - }; - let mut current = taker(reader)?; - while let Ok(binary) = reader.take::() { - let next = taker(reader)?; - current = inject(current, binary, next); + fn consume(reader: &mut Reader) -> Result, LoadError> { + let taker = |reader: &mut Reader| { + let start = reader.marker(); + reader.trim()?; + let result = if reader.white_consume("nil").is_ok() { + Expression::Nil + } else if reader.white_consume("true").is_ok() { + Expression::True + } else if reader.white_consume("false").is_ok() { + Expression::False + } else if let Ok(vararg) = reader.take::() { + Expression::VarArg(vararg.it) + } else if let Ok(number) = reader.take::() { + Expression::Number(number.it) + } else if let Ok(string) = reader.take::() { + Expression::String(string.it) + } else if reader.white_consume("function").is_ok() + || reader.white_consume("func").is_ok() + { + Expression::Function(reader.take::()?.it) + } else if let Ok(table) = reader.take::() { + Expression::Table(table.it) + } else if let Ok(unary) = reader.take::() { + Expression::Unary(unary, Box::new(reader.take::()?)) + } else { + Expression::Prefix(Box::new(reader.take::()?.it)) + }; + Ok(Piece::from(result, &start, &reader.marker())) + }; + let mut current = taker(reader)?; + while let Ok(binary) = reader.take::() { + let next = taker(reader)?; + current = inject(current, binary, next); + } + Ok(current) } - Ok(current) - } } impl Parse for Call { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - let prefix = reader.take::()?; - let piece = prefix.unit(); - if let Prefix::Call(call) = prefix.it { - Ok(piece.map(|_| call)) - } else { - reader.error("Expected variable, found expression.") + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + let prefix = reader.take::()?; + let piece = prefix.unit(); + if let Prefix::Call(call) = prefix.it { + Ok(piece.map(|_| call)) + } else { + reader.error("Expected variable, found expression.") + } } - } } impl Parse for Field { - fn consume(reader: &mut Reader) -> Result, LoadError> { - let start = reader.marker(); - reader.trim()?; - let result = if reader.consume_white("[").is_ok() { - let index = reader.take::()?; - reader.consume_white("=")?; - let value = reader.take::()?; - reader.consume_white("]")?; - Field(Some(index), value) - } else if let Ok(name) = reader.take::() { - reader.consume_white("=")?; - let index = name.map(|it| Expression::String(it.0)); - let value = reader.take::()?; - Field(Some(index), value) - } else { - Field(None, reader.take::()?) - }; - Ok(Piece::from(result, &start, &reader.marker())) - } + fn consume(reader: &mut Reader) -> Result, LoadError> { + let start = reader.marker(); + reader.trim()?; + let result = if reader.consume_white("[").is_ok() { + let index = reader.take::()?; + reader.consume_white("=")?; + let value = reader.take::()?; + reader.consume_white("]")?; + Field { + index: Some(index), + expression: value, + } + } else if let Ok(name) = reader.take::() { + reader.consume_white("=")?; + let index = name.map(|it| Expression::String(it.0)); + let value = reader.take::()?; + Field { + index: Some(index), + expression: value, + } + } else { + Field { + index: None, + expression: reader.take::()?, + } + }; + Ok(Piece::from(result, &start, &reader.marker())) + } } impl Parse for Constructor { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - reader.consume_white("{")?; - let fields: Piece>>; - if reader.clone().take::().is_ok() { - fields = reader.take::>>()?; - } else { - fields = Piece::from(Vec::new(), &reader.marker(), &reader.marker()); + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + reader.consume_white("{")?; + let fields: Piece>>; + if reader.clone().take::().is_ok() { + fields = reader.take::>>()?; + } else { + fields = Piece::from(Vec::new(), &reader.marker(), &reader.marker()); + } + reader.consume_white("}")?; + Ok(fields.map(|it| Constructor(it))) } - reader.consume_white("}")?; - Ok(fields.map(|it| Constructor(it))) - } } impl Parse for Args { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - let start = reader.marker(); - let result = if reader.consume_white("(").is_ok() { - let expressions = reader.take::>>()?; - reader.consume_white(")")?; - Args(expressions.it) - } else if let Ok(table) = reader.take::() { - Args(vec![table.map(|it| Expression::Table(it))]) - } else if let Ok(string) = reader.take::() { - Args(vec![string.map(|it| Expression::String(it))]) - } else { - return reader.error("Expected arguments"); - }; - Ok(Piece::from(result, &start, &reader.marker())) - } + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + let start = reader.marker(); + let result = if reader.consume_white("(").is_ok() { + let expressions = reader.take::>>()?; + reader.consume_white(")")?; + Args(expressions.it) + } else if let Ok(table) = reader.take::() { + Args(vec![table.map(|it| Expression::Table(it))]) + } else if let Ok(string) = reader.take::() { + Args(vec![string.map(|it| Expression::String(it))]) + } else { + return reader.error("Expected arguments"); + }; + Ok(Piece::from(result, &start, &reader.marker())) + } } impl Parse for Prefix { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - let start = reader.marker(); - let mut current: Box> = if reader.consume_white("(").is_ok() { - let exp = reader.take::()?; - reader.consume_white(")")?; - Box::new(Piece::from( - Prefix::Expression(exp.it), - &start, - &reader.marker(), - )) - } else if let Ok(name) = reader.take::() { - Box::new(Piece::from( - Prefix::Variable(Variable::Name(name.it)), - &start, - &reader.marker(), - )) - } else { - return reader.error("Expected expression"); - }; - loop { - let start = reader.marker(); - let result: Prefix = if reader.consume_white("[").is_ok() { - let exp = reader.take::()?; - reader.consume_white("]")?; - Prefix::Variable(Variable::Index(current, exp)) - } else if reader.consume_white(".").is_ok() { - let field = reader.take::()?; - Prefix::Variable(Variable::Index( - current, - field.map(|it| Expression::String(it.0)), - )) - } else if reader.consume_white(":").is_ok() { - let field = reader.take::()?; - let args = reader.take::()?; - Prefix::Call(Call(current, Some(field), args)) - } else if let Ok(args) = reader.take::() { - Prefix::Call(Call(current, None, args)) - } else { - break; - }; - current = Box::new(Piece::from(*Box::new(result), &start, &reader.marker())); + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + let start = reader.marker(); + let mut current: Box> = if reader.consume_white("(").is_ok() { + let exp = reader.take::()?; + reader.consume_white(")")?; + Box::new(Piece::from( + Prefix::Expression(exp.it), + &start, + &reader.marker(), + )) + } else if let Ok(name) = reader.take::() { + Box::new(Piece::from( + Prefix::Variable(Variable::Name(name.it)), + &start, + &reader.marker(), + )) + } else { + return reader.error("Expected expression"); + }; + loop { + let start = reader.marker(); + let result: Prefix = if reader.consume_white("[").is_ok() { + let exp = reader.take::()?; + reader.consume_white("]")?; + Prefix::Variable(Variable::Index(current, exp)) + } else if reader.consume_white(".").is_ok() { + let field = reader.take::()?; + Prefix::Variable(Variable::Index( + current, + field.map(|it| Expression::String(it.0)), + )) + } else if reader.consume_white(":").is_ok() { + let field = reader.take::()?; + let args = reader.take::()?; + Prefix::Call(Call { + prefix: current, + method: Some(field), + args: args, + }) + } else if let Ok(args) = reader.take::() { + Prefix::Call(Call { + prefix: current, + method: None, + args: args, + }) + } else { + break; + }; + current = Box::new(Piece::from(*Box::new(result), &start, &reader.marker())); + } + Ok(*current) } - Ok(*current) - } } impl Parse for Variable { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - let prefix = reader.take::()?; - let piece = prefix.unit(); - if let Prefix::Variable(var) = prefix.it { - Ok(piece.map(|_| var)) - } else { - reader.error("Expected variable, found expression.") + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + let prefix = reader.take::()?; + let piece = prefix.unit(); + if let Prefix::Variable(var) = prefix.it { + Ok(piece.map(|_| var)) + } else { + reader.error("Expected variable, found expression.") + } } - } } impl Parse for Statement { - fn consume(reader: &mut Reader) -> Result, LoadError> { - reader.trim()?; - let start = reader.marker(); - // todo: it is safer to pass back the new reader in the Ok, and then map it out (in fact, something else changed too) - if reader.white_consume("break").is_ok() { - Ok(Piece::from(Statement::Break, &start, &reader.marker())) - } else if reader.white_consume("continue").is_ok() { - Ok(Piece::from(Statement::Continue, &start, &reader.marker())) - } else if reader.consume_white(";").is_ok() { - Ok(Piece::from(Statement::Semicolon, &start, &reader.marker())) - } else if reader.white_consume("local").is_ok() { - if reader.white_consume("function").is_ok() || reader.white_consume("func").is_ok() { - let name = reader.take::()?; - let function = reader.take::()?; - *reader = *reader; - Ok(Piece::from( - Statement::LocalFunction(name, function.it), - &start, - &reader.marker(), - )) - } else { - let names = reader.take::>>()?.it; - let expressions = if reader.consume_white("=").is_ok() { - reader.take::>>()?.it + fn consume(reader: &mut Reader) -> Result, LoadError> { + reader.trim()?; + let start = reader.marker(); + // todo: it is safer to pass back the new reader in the Ok, and then map it out (in fact, something else changed too) + if reader.white_consume("break").is_ok() { + Ok(Piece::from(Statement::Break, &start, &reader.marker())) + } else if reader.white_consume("continue").is_ok() { + Ok(Piece::from(Statement::Continue, &start, &reader.marker())) + } else if reader.consume_white(";").is_ok() { + Ok(Piece::from(Statement::Semicolon, &start, &reader.marker())) + } else if reader.white_consume("local").is_ok() { + if reader.white_consume("function").is_ok() || reader.white_consume("func").is_ok() { + let name = reader.take::()?; + let function = reader.take::()?; + *reader = *reader; + Ok(Piece::from( + Statement::LocalFunction(name, function.it), + &start, + &reader.marker(), + )) + } else { + let names = reader.take::>>()?.it; + let expressions = if reader.consume_white("=").is_ok() { + reader.take::>>()?.it + } else { + Vec::new() + }; + *reader = *reader; // todo: what are these + Ok(Piece::from( + Statement::Declaration(names, expressions), + &start, + &reader.marker(), + )) + } + } else if reader.white_consume("function").is_ok() || reader.white_consume("func").is_ok() { + let mut names = Vec::new(); + loop { + if let Ok(name) = reader.take::() { + names.push(name); + if !reader.consume_white(".").is_ok() { + break; + } + } + } + let mut member = None; + if reader.consume_white(":").is_ok() { + member = Some(reader.take::()?); + } + let function = reader.take::()?; + *reader = *reader; + Ok(Piece::from( + Statement::Function(names, member, function.it), + &start, + &reader.marker(), + )) + } else if reader.white_consume("for").is_ok() { + let names = reader.take::>>()?.it; + let result = if names.len() < 1 { + let name = names.first().unwrap(); + reader.consume_white("=")?; + let begin = reader.take::()?; + reader.consume_white(",")?; + let finish = reader.take::()?; + let delta = if reader.consume(",").is_ok() { + Some(reader.take::()?) + } else { + None + }; + reader.white_consume("do")?; + let block = reader.take::()?; + reader.white_consume("end")?; + Ok(Piece::from( + Statement::Range( + Piece { + it: name.it.clone(), + width: name.width, + index: name.index, + comment: name.comment.clone(), + }, + begin, + finish, + delta, + block, + ), + &start, + &reader.marker(), + )) + } else { + reader.white_consume("in")?; + let expressions = reader.take::>>()?.it; + reader.white_consume("do")?; + let block = reader.take::()?; + reader.white_consume("end")?; + Ok(Piece::from( + Statement::Iterator(names, expressions, block), + &start, + &reader.marker(), + )) + }; + *reader = *reader; + result + } else if reader.white_consume("while").is_ok() { + let condition = reader.take::()?; + reader.white_consume("do")?; + let block = reader.take::()?; + reader.white_consume("end")?; + *reader = *reader; + Ok(Piece::from( + Statement::While(condition, block.it), + &start, + &reader.marker(), + )) + } else if reader.white_consume("if").is_ok() { + let mut conditions = Vec::new(); + let mut blocks = Vec::new(); + let mut branch = |reader: &mut Reader| -> Result<(), LoadError> { + conditions.push(reader.take::()?); + reader.white_consume("then")?; + blocks.push(reader.take::()?); + Ok(()) + }; + branch(reader)?; + let mut block = None; + while reader.white_consume("else").is_ok() { + if reader.consume("if").is_ok() { + branch(reader)?; + } else { + block = Some(reader.take::()?); + break; + } + } + reader.white_consume("end")?; + *reader = *reader; + Ok(Piece::from( + Statement::If(conditions, blocks, block), + &start, + &reader.marker(), + )) + } else if reader.white_consume("goto").is_ok() { + let name = reader.take::()?; + *reader = *reader; + Ok(Piece::from(Statement::Goto(name), &start, &reader.marker())) + } else if reader.white_consume("do").is_ok() { + let block = reader.take::()?; + *reader = *reader; + Ok(Piece::from( + Statement::Do(block.it), + &start, + &reader.marker(), + )) + } else if reader.white_consume("repeat").is_ok() { + reader.white_consume("repeat")?; + let block = reader.take::()?; + reader.white_consume("until")?; + let condition = reader.take::()?; + *reader = *reader; + Ok(Piece::from( + Statement::Repeat(block.it, condition), + &start, + &reader.marker(), + )) + } else if reader.consume_white("::").is_ok() { + let name = reader.take::()?; + reader.consume_white("::")?; + *reader = *reader; + Ok(Piece::from( + Statement::Label(name), + &start, + &reader.marker(), + )) } else { - Vec::new() - }; - *reader = *reader; // todo: what are these - Ok(Piece::from( - Statement::Declaration(names, expressions), - &start, - &reader.marker(), - )) - } - } else if reader.white_consume("function").is_ok() || reader.white_consume("func").is_ok() { - let mut names = Vec::new(); - loop { - if let Ok(name) = reader.take::() { - names.push(name); - if !reader.consume_white(".").is_ok() { - break; - } + let mut clone = reader.clone(); + if let Ok(call) = clone.take::() { + *reader = clone; + Ok(call.map(|it| Statement::Call(it))) + } else { + let mut clone = reader.clone(); + let vars = clone.take::>>()?; + clone.consume("=")?; + let expressions = clone.take::>>()?; + *reader = clone; + Ok(Piece::from( + Statement::Assignment(vars.it, expressions.it), + &start, + &reader.marker(), + )) + } } - } - let mut member = None; - if reader.consume_white(":").is_ok() { - member = Some(reader.take::()?); - } - let function = reader.take::()?; - *reader = *reader; - Ok(Piece::from( - Statement::Function(names, member, function.it), - &start, - &reader.marker(), - )) - } else if reader.white_consume("for").is_ok() { - let names = reader.take::>>()?.it; - let result = if names.len() < 1 { - let name = names.first().unwrap(); - reader.consume_white("=")?; - let begin = reader.take::()?; - reader.consume_white(",")?; - let finish = reader.take::()?; - let delta = if reader.consume(",").is_ok() { - Some(reader.take::()?) - } else { - None - }; - reader.white_consume("do")?; - let block = reader.take::()?; - reader.white_consume("end")?; - Ok(Piece::from( - Statement::Range( - Piece { - it: name.it.clone(), - width: name.width, - index: name.index, - comment: name.comment.clone(), - }, - begin, - finish, - delta, - block, - ), - &start, - &reader.marker(), - )) - } else { - reader.white_consume("in")?; - let expressions = reader.take::>>()?.it; - reader.white_consume("do")?; - let block = reader.take::()?; - reader.white_consume("end")?; - Ok(Piece::from( - Statement::Iterator(names, expressions, block), - &start, - &reader.marker(), - )) - }; - *reader = *reader; - result - } else if reader.white_consume("while").is_ok() { - let condition = reader.take::()?; - reader.white_consume("do")?; - let block = reader.take::()?; - reader.white_consume("end")?; - *reader = *reader; - Ok(Piece::from( - Statement::While(condition, block.it), - &start, - &reader.marker(), - )) - } else if reader.white_consume("if").is_ok() { - let mut conditions = Vec::new(); - let mut blocks = Vec::new(); - let mut branch = |reader: &mut Reader| -> Result<(), LoadError> { - conditions.push(reader.take::()?); - reader.white_consume("then")?; - blocks.push(reader.take::()?); - Ok(()) - }; - branch(reader)?; - let mut block = None; - while reader.white_consume("else").is_ok() { - if reader.consume("if").is_ok() { - branch(reader)?; - } else { - block = Some(reader.take::()?); - break; - } - } - reader.white_consume("end")?; - *reader = *reader; - Ok(Piece::from( - Statement::If(conditions, blocks, block), - &start, - &reader.marker(), - )) - } else if reader.white_consume("goto").is_ok() { - let name = reader.take::()?; - *reader = *reader; - Ok(Piece::from(Statement::Goto(name), &start, &reader.marker())) - } else if reader.white_consume("do").is_ok() { - let block = reader.take::()?; - *reader = *reader; - Ok(Piece::from( - Statement::Do(block.it), - &start, - &reader.marker(), - )) - } else if reader.white_consume("repeat").is_ok() { - reader.white_consume("repeat")?; - let block = reader.take::()?; - reader.white_consume("until")?; - let condition = reader.take::()?; - *reader = *reader; - Ok(Piece::from( - Statement::Repeat(block.it, condition), - &start, - &reader.marker(), - )) - } else if reader.consume_white("::").is_ok() { - let name = reader.take::()?; - reader.consume_white("::")?; - *reader = *reader; - Ok(Piece::from( - Statement::Label(name), - &start, - &reader.marker(), - )) - } else { - let mut clone = reader.clone(); - if let Ok(call) = clone.take::() { - *reader = clone; - Ok(call.map(|it| Statement::Call(it))) - } else { - let mut clone = reader.clone(); - let vars = clone.take::>>()?; - clone.consume("=")?; - let expressions = clone.take::>>()?; - *reader = clone; - Ok(Piece::from( - Statement::Assignment(vars.it, expressions.it), - &start, - &reader.marker(), - )) - } } - } } impl Parse for Block { - fn consume(reader: &mut Reader) -> Result, LoadError> - where - Self: Sized, - { - let mut statements = Vec::new(); - let start = reader.marker(); - while let Ok(statement) = reader.take::() { - statements.push(statement); + fn consume(reader: &mut Reader) -> Result, LoadError> + where + Self: Sized, + { + let mut statements = Vec::new(); + let start = reader.marker(); + while let Ok(statement) = reader.take::() { + statements.push(statement); + } + let expressions = if reader.consume("return").is_ok() { + if reader.clone().take::().is_ok() { + // TODO: make this dirty check less silly + let result = reader.take::>>()?; + reader.consume_white(";").ok(); + Some(result.it) + } else { + Some(Vec::new()) + } + } else { + None + }; + Ok(Piece::from( + Block { + statements: statements, + return_exp: expressions, + }, + &start, + &reader.marker(), + )) } - let expressions = if reader.consume("return").is_ok() { - if reader.clone().take::().is_ok() { - // TODO: make this dirty check less silly - let result = reader.take::>>()?; - reader.consume_white(";").ok(); - Some(result.it) - } else { - Some(Vec::new()) - } - } else { - None - }; - Ok(Piece::from( - Block(statements, expressions), - &start, - &reader.marker(), - )) - } } impl Parse for Chunk { - fn consume(reader: &mut Reader) -> Result, LoadError> - where - Self: Sized, - { - let mut statements = Vec::new(); - let start = reader.marker(); - while !reader.finished() { - let statement = reader.take::()?; - statements.push(statement); - reader.trim()?; + fn consume(reader: &mut Reader) -> Result, LoadError> + where + Self: Sized, + { + let mut statements = Vec::new(); + let start = reader.marker(); + while !reader.finished() { + let statement = reader.take::()?; + statements.push(statement); + reader.trim()?; + } + let expressions = if reader.white_consume("return").is_ok() { + let result = reader.take::>>()?; + reader.consume_white(";").ok(); + Some(result.it) + } else { + None + }; + Ok(Piece::from( + Chunk(Piece::from( + Block { + statements: statements, + return_exp: expressions, + }, + &start, + &reader.marker(), + )), + &start, + &reader.marker(), + )) } - let expressions = if reader.white_consume("return").is_ok() { - let result = reader.take::>>()?; - reader.consume_white(";").ok(); - Some(result.it) - } else { - None - }; - Ok(Piece::from( - Chunk(Piece::from( - Block(statements, expressions), - &start, - &reader.marker(), - )), - &start, - &reader.marker(), - )) - } } pub fn parse(str: &str) -> Result { - let mut reader = Reader::from(str); - reader.take::().map(|it| it.it) + let mut reader = Reader::from(str); + reader.take::().map(|it| it.it) } diff --git a/src/table.rs b/src/table.rs index b63f425..8eaad6c 100644 --- a/src/table.rs +++ b/src/table.rs @@ -25,16 +25,19 @@ Notes: type Displacement = u8; -#[cfg(feature="bighash")] +#[cfg(feature = "bighash")] pub type Hashed = u64; -#[cfg(not(feature="bighash"))] +#[cfg(not(feature = "bighash"))] pub type Hashed = u32; pub trait Equivalent: Sized { fn matches(&self, other: &T) -> bool; } -impl Equivalent for T where T: PartialEq { +impl Equivalent for T +where + T: PartialEq, +{ fn matches(&self, other: &T) -> bool { self == other } @@ -75,7 +78,13 @@ impl TableEntry for KeyValue { } } fn is_vacant(&self) -> bool { - matches!(self,KeyValue { index: Value::Nil, .. }) + matches!( + self, + KeyValue { + index: Value::Nil, + .. + } + ) } } @@ -87,7 +96,8 @@ struct Entry { } #[derive(Clone, Debug)] -pub struct Map { // default representing vacancy! +pub struct Map { + // default representing vacancy! map: Vec>, map_bounds: std::ops::Range, map_count: usize, // number of elements in table @@ -95,14 +105,19 @@ pub struct Map { // default representing vacancy! impl Map { pub(crate) fn string_cache() { // todo: this isn't a clean way, maybe make a generic Map and use a specific one for the cache and the rest of the language - } fn exchange_table(&mut self, len: usize) { - let old = std::mem::replace(&mut self.map, vec![Entry { - entry: E::new_vacant(), - home: 0, - displacement: 0, - }; len]); + let old = std::mem::replace( + &mut self.map, + vec![ + Entry { + entry: E::new_vacant(), + home: 0, + displacement: 0, + }; + len + ], + ); for Entry { entry, .. } in old { if entry.is_vacant() { self.set_table(entry) @@ -202,7 +217,11 @@ impl Map { self.set_table(entry); } } - pub(crate) fn rem_table(&mut self, index: K) where E: Equivalent, K: Hashes { + pub(crate) fn rem_table(&mut self, index: K) + where + E: Equivalent, + K: Hashes, + { if self.map.len() == 0 { return; } @@ -256,9 +275,12 @@ impl Map { } } pub(crate) fn get_table(&mut self, index: K) -> Option<&E> - where E: Equivalent, K: Hashes { + where + E: Equivalent, + K: Hashes, + { if self.map.len() == 0 { - return None + return None; } let location = index.hashed() as usize % self.map.len(); let home = &self.map[location]; @@ -377,7 +399,7 @@ impl Table { } else { self.table.set_table(KeyValue { index: Value::Integer(index), - value: item + value: item, }) } } @@ -387,25 +409,28 @@ impl Table { Value::Nil => Err(RunError( "Attempt to set new index of table with key: nil".to_string(), )), - index => Ok(self.table.set_table(KeyValue { - index, - value - })), + index => Ok(self.table.set_table(KeyValue { index, value })), } } pub fn get(&mut self, index: Value) -> Result { match index { Value::Integer(index) => Ok(self .array - .get(index as usize) + .get(index as usize - 1) .unwrap_or(&Value::Nil) .clone()), Value::Nil => Err(RunError("Attempt to index table with key: nil".to_string())), - index => { // todo: move this into the Map - Ok(self.table.get_table(index).unwrap_or(&KeyValue { - index: Value::Nil, - value: Value::Nil, - }).value.clone()) + index => { + // todo: move this into the Map + Ok(self + .table + .get_table(index) + .unwrap_or(&KeyValue { + index: Value::Nil, + value: Value::Nil, + }) + .value + .clone()) } } } @@ -419,4 +444,4 @@ impl Table { meta: None, } } -} \ No newline at end of file +} diff --git a/src/tests/script.lua b/src/tests/script.lua index f82b4b1..0fde1d9 100644 --- a/src/tests/script.lua +++ b/src/tests/script.lua @@ -1 +1,2 @@ -local table = {} \ No newline at end of file +local table = { "hello", "friend" } +print(table[1], table[2]) diff --git a/src/vm.rs b/src/vm.rs index 323b417..6d4acd3 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,190 +1,188 @@ // MACHINE +use crate::parser::{BinaryOp, Piece, UnaryOp, parse}; +use crate::table::{Equivalent, Hashed, Hashes, Map, Table, TableEntry}; use std::any::Any; use std::fmt::Formatter; use std::hash::{DefaultHasher, Hash, Hasher}; use std::ops::{Deref, DerefMut}; use std::rc::Rc; -use crate::table::{Equivalent, Hashed, Hashes, Map, Table, TableEntry}; -use crate::parser::{Piece, BinaryOp, UnaryOp, parse}; // Rust function to call pub struct Native(fn(&mut Machine, &mut Needle, usize) -> Result<(), RunError>); // A native function in Rust #[derive(Clone, Debug, Copy, PartialEq)] pub(crate) enum Reference { - Closing(Index), // This is actually an index to a register the parent's stack frame! - Upvalue(Index), // This is an index to the upvalues list in the closure + Closing(Index), // This is actually an index to a register the parent's stack frame! + Upvalue(Index), // This is an index to the upvalues list in the closure } #[derive(Clone)] pub struct Prototype { - // A function prototype - pub args: Index, - pub vararg: bool, // Does this function receive varargs? - pub prototypes: Vec>, // List of other prototypes this Prototype can make a Closure from - pub constants: Vec, // List of objects statically attached to this Prototype - pub upvalues: Vec, // Location of upvalues in (parent closure's upvalue or VM's closing) list - pub pieces: Vec>, // List of all pieces corresponding to it's equivalently indexed code - pub code: Vec, + // A function prototype + pub args: Index, + pub vararg: bool, // Does this function receive varargs? + pub prototypes: Vec>, // List of other prototypes this Prototype can make a Closure from + pub constants: Vec, // List of objects statically attached to this Prototype + pub upvalues: Vec, // Location of upvalues in (parent closure's upvalue or VM's closing) list + pub pieces: Vec>, // List of all pieces corresponding to it's equivalently indexed code + pub code: Vec, } impl std::fmt::Debug for Prototype { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!(f, " Prototype:")?; - writeln!( - f, - " Arguments: Count({}) Vararg({})", - self.args, self.vararg - )?; - writeln!(f, " Prototypes: {}", self.prototypes.len())?; - writeln!(f, " Constants: ")?; - for (index, constant) in self.constants.iter().enumerate() { - writeln!(f, " [{}] {:?}", index, constant)?; + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!(f, " Prototype:")?; + writeln!( + f, + " Arguments: Count({}) Vararg({})", + self.args, self.vararg + )?; + writeln!(f, " Prototypes: {}", self.prototypes.len())?; + writeln!(f, " Constants: ")?; + for (index, constant) in self.constants.iter().enumerate() { + writeln!(f, " [{}] {:?}", index, constant)?; + } + writeln!(f, " References: ")?; + for (index, upvalue) in self.upvalues.iter().enumerate() { + writeln!(f, " [{}] {:?}", index, upvalue)?; + } + writeln!(f, " Code: ")?; + for (index, code) in self.code.iter().enumerate() { + writeln!(f, " [{}] {:?}", index, code)?; // todo: pieces (print the line relevant) + } + Ok(()) } - writeln!(f, " References: ")?; - for (index, upvalue) in self.upvalues.iter().enumerate() { - writeln!(f, " [{}] {:?}", index, upvalue)?; - } - writeln!(f, " Code: ")?; - for (index, code) in self.code.iter().enumerate() { - writeln!(f, " [{}] {:?}", index, code)?; // todo: pieces (print the line relevant) - } - Ok(()) - } } #[derive(Clone, Debug)] enum Upvalue { - Stack(usize), // But this is an actual index to the stack - Heap(Value), // So this is Gc allocated + Stack(usize), // But this is an actual index to the stack + Heap(Value), // So this is Gc allocated } #[derive(Clone)] pub struct Closure { - // An actual callable function - pub(crate) prototype: Rc, - upvalues: Vec>, // List of upvalues associated with this function + // An actual callable function + pub(crate) prototype: Rc, + upvalues: Vec>, // List of upvalues associated with this function } impl std::fmt::Debug for Closure { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Closure:")?; - writeln!(f, " Upvalues:")?; - for (index, upvalue) in self.upvalues.iter().enumerate() { - writeln!(f, " [{}] {:?}", index, upvalue.borrow().deref())?; + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!(f, "Closure:")?; + writeln!(f, " Upvalues:")?; + for (index, upvalue) in self.upvalues.iter().enumerate() { + writeln!(f, " [{}] {:?}", index, upvalue.borrow().deref())?; + } + write!(f, "{:?}", self.prototype) } - write!(f, "{:?}", self.prototype) - } } impl Traverse for Upvalue { - fn traverse(&self) { - if let Upvalue::Heap(object) = self { - object.traverse() + fn traverse(&self) { + if let Upvalue::Heap(object) = self { + object.traverse() + } } - } } #[derive(Clone)] pub enum Callable { - Rust(Rc), - Mars(Gc), + Rust(Rc), + Mars(Gc), } impl Traverse for Callable { - fn traverse(&self) { - match self { - Callable::Rust(_) => {} - Callable::Mars(closure) => { - closure.traverse(); - } + fn traverse(&self) { + match self { + Callable::Rust(_) => {} + Callable::Mars(closure) => { + closure.traverse(); + } + } } - } } impl Traverse for Closure { - fn traverse(&self) { - for upvalue in self.upvalues.iter() { - upvalue.traverse() + fn traverse(&self) { + for upvalue in self.upvalues.iter() { + upvalue.traverse() + } } - } } impl PartialEq for Callable { - fn eq(&self, other: &Self) -> bool { - match self { - Callable::Rust(a) => match other { - Callable::Rust(b) => Rc::ptr_eq(a, b), - Callable::Mars(_) => false, - }, - Callable::Mars(a) => match other { - Callable::Mars(b) => a == b, - Callable::Rust(_) => false, - }, + fn eq(&self, other: &Self) -> bool { + match self { + Callable::Rust(a) => match other { + Callable::Rust(b) => Rc::ptr_eq(a, b), + Callable::Mars(_) => false, + }, + Callable::Mars(a) => match other { + Callable::Mars(b) => a == b, + Callable::Rust(_) => false, + }, + } } - } } impl std::fmt::Debug for Callable { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Callable::Rust(_) => f.write_str("Native"), - Callable::Mars(closure) => write!(f, "{:?}", closure.borrow().deref()), + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Callable::Rust(_) => f.write_str("Native"), + Callable::Mars(closure) => write!(f, "{:?}", closure.borrow().deref()), + } } - } } #[derive(Debug)] pub struct RunError(pub(crate) String); pub trait Object: std::fmt::Debug { - fn meta_string(&mut self) -> Result { - Ok(Value::Nil) - } - fn meta_number(&mut self) -> Result { - Ok(Value::Nil) - } - fn meta_new_index(&mut self, index: Value, item: Value) -> Result<(), RunError> { - Err(RunError(format!("Cannot set index in {:?}", &self))) - } - fn meta_index(&mut self, index: Value) -> Result { - Err(RunError(format!("Cannot get index in {:?}", &self))) - } - fn meta_eq(&mut self, other: &Value) -> Result { - Ok(Value::Nil) - } + fn meta_string(&mut self) -> Result { + Ok(Value::Nil) + } + fn meta_number(&mut self) -> Result { + Ok(Value::Nil) + } + fn meta_new_index(&mut self, index: Value, item: Value) -> Result<(), RunError> { + Err(RunError(format!("Cannot set index in {:?}", &self))) + } + fn meta_index(&mut self, index: Value) -> Result { + Err(RunError(format!("Cannot get index in {:?}", &self))) + } + fn meta_eq(&mut self, other: &Value) -> Result { + Ok(Value::Nil) + } } -impl Value { - -} +impl Value {} pub trait Userdata: Traverse + std::fmt::Debug + Any + Object {} pub struct Anything(dyn Userdata); // can't impl PartialEq for Rc impl std::fmt::Debug for Anything { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } } impl Traverse for Anything { - fn traverse(&self) { - self.0.traverse() - } + fn traverse(&self) { + self.0.traverse() + } } +use crate::compiler::compile; +use crate::gc::{Allocator, Gc, Traverse}; #[cfg(feature = "vector3")] use glam::Vec3; -use crate::gc::{Allocator, Gc, Traverse}; -use crate::compiler::{Traversal, Context, Scope, compile}; #[derive(Clone, Debug, PartialEq)] struct Phrase { - bytes: [u8; PHRASE_LEN], - hash: usize, + bytes: [u8; PHRASE_LEN], + hash: usize, } // Any value in the language @@ -194,172 +192,176 @@ pub(crate) struct CachedString(Rc, pub(crate) Hashed); #[derive(Clone, Debug)] struct CachedStringEntry(Option); impl Hashes for &str { - fn hashed(&self) -> Hashed { - let mut hasher = DefaultHasher::new(); - self[..self.len().min(6)].hash(&mut hasher); - hasher.finish() as Hashed - } + fn hashed(&self) -> Hashed { + let mut hasher = DefaultHasher::new(); + self[..self.len().min(6)].hash(&mut hasher); + hasher.finish() as Hashed + } } impl Hashes for CachedStringEntry { - fn hashed(&self) -> Hashed { - self.0.as_ref().unwrap().0.deref().hashed() - } + fn hashed(&self) -> Hashed { + self.0.as_ref().unwrap().0.deref().hashed() + } } -impl Equivalent for CachedStringEntry { // redundant? - fn matches(&self, other: &Self) -> bool { - match self.0 { - Some(ref entry) => match other.0 { - Some(ref other) => entry.0.deref() == other.0.deref(), - None => false, - }, - None => false, +impl Equivalent for CachedStringEntry { + // redundant? + fn matches(&self, other: &Self) -> bool { + match self.0 { + Some(ref entry) => match other.0 { + Some(ref other) => entry.0.deref() == other.0.deref(), + None => false, + }, + None => false, + } } - } } impl TableEntry for CachedStringEntry { - fn new_vacant() -> Self { - CachedStringEntry(None) - } - fn is_vacant(&self) -> bool { - self.0.is_none() - } + fn new_vacant() -> Self { + CachedStringEntry(None) + } + fn is_vacant(&self) -> bool { + self.0.is_none() + } } impl Equivalent<&str> for CachedStringEntry { - fn matches(&self, string: &&str) -> bool { - match self.0 { - Some(ref entry) => entry.0.deref() == *string, - None => false + fn matches(&self, string: &&str) -> bool { + match self.0 { + Some(ref entry) => entry.0.deref() == *string, + None => false, + } } - } } const PHRASE_LEN: usize = 16; #[derive(Debug, Clone)] pub enum Value { - Nil, // Empty value - Bool(bool), - Number(f64), - Integer(u64), // 64 maybe we should use signed integers... - CachedString(CachedString), - String(Rc, Hashed), - Table(Gc), - Object(Gc), - Function(Callable), - #[cfg(feature = "vector3")] - Vector(Vec3), + Nil, // Empty value + Bool(bool), + Number(f64), + Integer(u64), // 64 maybe we should use signed integers... + CachedString(CachedString), + String(Rc, Hashed), + Table(Gc
), + Object(Gc), + Function(Callable), + #[cfg(feature = "vector3")] + Vector(Vec3), } impl Value { - fn bool(&mut self) -> bool { - match self { - Value::Nil => false, - Value::Bool(false) => false, - _ => true, + fn bool(&mut self) -> bool { + match self { + Value::Nil => false, + Value::Bool(false) => false, + _ => true, + } } - } - fn unwrap_str(&mut self) -> Rc { - match self { - Value::CachedString(cached) => cached.0.clone(), - Value::String(string,_hash) => string.clone(), - _ => panic!() + fn unwrap_str(&mut self) -> Rc { + match self { + Value::CachedString(cached) => cached.0.clone(), + Value::String(string, _hash) => string.clone(), + _ => panic!(), + } } - } } impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - match self { - Value::Nil => match other { - Value::Nil => true, - _ => false, - } - Value::Bool(this) => match other { - Value::Bool(other) => this == other, - _ => false, - } - Value::Number(this) => match other { - Value::Number(other) => this == other, - Value::Integer(other) => *this == *other as f64, - _ => false, - } - Value::Integer(this) => match other { - Value::Number(other) => *this as f64 == *other, // are these conversions ok? - Value::Integer(other) => this == other, - _ => false, - } - Value::String(string, hash) => match other { - Value::CachedString(other) => - if *hash == other.1 { - other.0.deref() == string.deref() - } else { - false - } - Value::String(other_string, other_hash) => - if hash == other_hash { - string == other_string - } else { - false - } - _ => false - } - Value::CachedString(string) => match other { - Value::CachedString(other) => other.0 == string.0, // pointer equality - Value::String(other_string, other_hash) => - if string.1 == *other_hash { - string.0.deref() == other_string.deref() - } else { - false - } - _ => false - } - Value::Table(this) => match other { - Value::Table(other) => other == this, - _ => false - } - Value::Object(this) => match other { - Value::Object(other) => other == this, - _ => false - } - Value::Function(this) => match other { - Value::Function(other) => other == this, - _ => false - } + fn eq(&self, other: &Self) -> bool { + match self { + Value::Nil => match other { + Value::Nil => true, + _ => false, + }, + Value::Bool(this) => match other { + Value::Bool(other) => this == other, + _ => false, + }, + Value::Number(this) => match other { + Value::Number(other) => this == other, + Value::Integer(other) => *this == *other as f64, + _ => false, + }, + Value::Integer(this) => match other { + Value::Number(other) => *this as f64 == *other, // are these conversions ok? + Value::Integer(other) => this == other, + _ => false, + }, + Value::String(string, hash) => match other { + Value::CachedString(other) => { + if *hash == other.1 { + other.0.deref() == string.deref() + } else { + false + } + } + Value::String(other_string, other_hash) => { + if hash == other_hash { + string == other_string + } else { + false + } + } + _ => false, + }, + Value::CachedString(string) => match other { + Value::CachedString(other) => other.0 == string.0, // pointer equality + Value::String(other_string, other_hash) => { + if string.1 == *other_hash { + string.0.deref() == other_string.deref() + } else { + false + } + } + _ => false, + }, + Value::Table(this) => match other { + Value::Table(other) => other == this, + _ => false, + }, + Value::Object(this) => match other { + Value::Object(other) => other == this, + _ => false, + }, + Value::Function(this) => match other { + Value::Function(other) => other == this, + _ => false, + }, + } } - } } impl Traverse for Value { - fn traverse(&self) { - match self { - Value::Table(table) => { - table.traverse(); - } - Value::Object(anything) => { - anything.traverse(); - } - Value::Function(callable) => callable.traverse(), - _ => {} + fn traverse(&self) { + match self { + Value::Table(table) => { + table.traverse(); + } + Value::Object(anything) => { + anything.traverse(); + } + Value::Function(callable) => callable.traverse(), + _ => {} + } } - } } // Frame for calling a function pub struct Frame { - vararg: usize, // Where varargs start - offset: usize, // Where arguments start - counter: usize, // Which instruction we are at - closure: Gc, // The function that was called on this frame + vararg: usize, // Where varargs start + offset: usize, // Where arguments start + counter: usize, // Which instruction we are at + closure: Gc, // The function that was called on this frame } // Machine for executing functions pub struct Machine { - global: Gc
, - allocator: Allocator, - cache: Map // todo: better to use a generic version of Map + global: Gc
, + allocator: Allocator, + cache: Map, // todo: better to use a generic version of Map } /* @@ -370,35 +372,35 @@ Also, I had a premonition I may need this for multithreading later on! */ #[derive(Clone)] pub struct Register { - value: Value, - upvalue: Option>, + value: Value, + upvalue: Option>, } impl Register { - const NIL: Register = Register { - value: Value::Nil, - upvalue: None, - }; + const NIL: Register = Register { + value: Value::Nil, + upvalue: None, + }; } pub struct Needle { - frames: Vec, // Delineation of the stack and execution state for individual functions - stack: Vec, // Temporary storage for programs + frames: Vec, // Delineation of the stack and execution state for individual functions + stack: Vec, // Temporary storage for programs } impl Needle { - fn pop(&mut self) -> Value { - self.stack.pop().unwrap().value - } - fn push(&mut self, value: Value) { - self.stack.push(Register { - value, - upvalue: None, - }) - } - fn index(&self, index: Index, frame: &Frame) -> &Register { - &self.stack[frame.offset + index as usize] - } + fn pop(&mut self) -> Value { + self.stack.pop().unwrap().value + } + fn push(&mut self, value: Value) { + self.stack.push(Register { + value, + upvalue: None, + }) + } + fn index(&self, index: Index, frame: &Frame) -> &Register { + &self.stack[frame.offset + index as usize] + } } pub(crate) type Index = u16; // Vector index @@ -409,593 +411,602 @@ pub(crate) type Offset = i16; // Jump to offset #[derive(Debug, Clone, Copy)] #[repr(u32)] pub(crate) enum Code { - TableNew, - TableSet, // consume: value, index, table, - TableGet, // consume: index, table; push: result - TableInsert(Index), // consume: table, value - UpvalueGet(Index), // push: U[I] - UpvalueSet(Index), // consume: value - RegisterGet(Index), // push: R[I] - RegisterSet(Index), // consume: value - Constant(Index), // push: C[I] - Call(Index), // consume: R[I...] push: ... (all results) - Discard(Index), // consume: R[I...] (used with above to cull results or pad nil) - VarArg(Count), // push: VA[1 -> count] OR VA[all] - Jump(Offset), // PC += offset - Close(Index), // Raise R[I...].upvalue from Upvalue::Stack to Upvalue::Heap, 'closing' the register, same effect as Discard for None upvalues - Skip, // consume: condition; if condition then PC++ (and naturally ++ again) - Return(Index), // consume: R[I...] (move arguments around and finish) - Binary(BinaryOp), // consume: fst, snd; push: result TODO: just use direct instructions? - Unary(UnaryOp), // consume: value; push: result - Closure(Index), // push: closure constructed from prototypes[I] - IteratorLoop(Offset), - RangeBegin, // - RangeLoop(Offset), - Comment(Index), + TableNew, + TableSet, // consume: value, index, table, + TableGet, // consume: index, table; push: result + TableInsert(Index), // consume: table, value + UpvalueGet(Index), // push: U[I] + UpvalueSet(Index), // consume: value + RegisterGet(Index), // push: R[I] + RegisterSet(Index), // consume: value + Constant(Index), // push: C[I] + Call(Index), // consume: R[I...] push: ... (all results) + Discard(Index), // consume: R[I...] (used with above to cull results or pad nil) + VarArg(Count), // push: VA[1 -> count] OR VA[all] + Jump(Offset), // PC += offset + Close(Index), // Raise R[I...].upvalue from Upvalue::Stack to Upvalue::Heap, 'closing' the register, same effect as Discard for None upvalues + Skip, // consume: condition; if condition then PC++ (and naturally ++ again) + Return(Index), // consume: R[I...] (move arguments around and finish) + Binary(BinaryOp), // consume: fst, snd; push: result TODO: just use direct instructions? + Unary(UnaryOp), // consume: value; push: result + Closure(Index), // push: closure constructed from prototypes[I] + IteratorLoop(Offset), + RangeBegin, // + RangeLoop(Offset), + Comment(Index), } impl Code { - const NO_OP: Code = Code::Jump(1); - pub(crate) const UNSURE: Code = Code::Jump(0); + const NO_OP: Code = Code::Jump(1); + pub(crate) const UNSURE: Code = Code::Jump(0); } impl Machine { - pub(crate) fn new_string(&mut self, string: &str) -> Result { - if string.len() < SHORT_STRING_LEN { - let existing = self.cache.get_table(string); - match existing { - Some(ref entry) => { - Ok(Value::CachedString(entry.0.clone().unwrap())) - }, - None => { - let cached = CachedString(Rc::from(string),string.hashed()); - self.cache.set_table(CachedStringEntry(Some(cached.clone()))); - Ok(Value::CachedString(cached)) - } - } - } else { - Ok(Value::String(Rc::from(string), string.hashed())) - } - } - fn try_number(&mut self, value: &mut Value) -> Result { - match value { - integer @ Value::Integer(_) => Ok(integer.clone()), - number @ Value::Number(_) => Ok(number.clone()), - Value::Object(object) => object.borrow_mut().0.meta_number(), - Value::Table(table) => { - let mut table = table.borrow_mut(); - if let Some(_metatable) = &table.meta { - Err(RunError("Metatables unimplemented".to_string())) + pub(crate) fn new_string(&mut self, string: &str) -> Result { + if string.len() < SHORT_STRING_LEN { + let existing = self.cache.get_table(string); + match existing { + Some(ref entry) => Ok(Value::CachedString(entry.0.clone().unwrap())), + None => { + let cached = CachedString(Rc::from(string), string.hashed()); + self.cache + .set_table(CachedStringEntry(Some(cached.clone()))); + Ok(Value::CachedString(cached)) + } + } } else { - Ok(Value::Nil) + Ok(Value::String(Rc::from(string), string.hashed())) } - } - _ => Ok(Value::Nil), } - } - fn try_string(&mut self, value: &mut Value) -> Result { - Ok(match value { - Value::Nil => self.new_string("nil".to_string().as_str())?, - Value::Bool(bool) => self.new_string(format!("{}", bool).as_str())?, - Value::Integer(integer) => self.new_string(format!("{}", integer).as_str())?, - Value::Number(number) => self.new_string(format!("{}", number).as_str())?, - it @ Value::String(..) => return Ok(it.clone()), - it @ Value::CachedString(..) => return Ok(it.clone()), - #[cfg(feature = "vector3")] - Value::Vector(vector) => format!("{}", vector), - Value::Table(table) => { - let mut table = table.borrow_mut(); - if let Some(_metatable) = &table.meta { - return Err(RunError("Metatables unimplemented".to_string())); - } else { - self.new_string("{...}".to_string().as_str())? - } - } - Value::Object(object) => match object.borrow_mut().0.meta_string()? { - string @ Value::String(..) => return Ok(string), - it => return Err(RunError(format!("Expected string but got {:?}", it))), - }, - Value::Function(callable) => self.new_string(format!("{:?}", callable).as_str())?, - }) - } - fn set(&mut self, subject: Value, index: Value, value: Value) -> Result<(), RunError> { - match subject { - Value::Nil => Err(RunError("Cannot get from nil".to_string())), - Value::Bool(bool) => Err(RunError(format!("Cannot index {:?}", bool))), - Value::Integer(_integer) => Err(RunError("Integer index unimplemented".to_string())), - Value::Number(_number) => Err(RunError("Number index unimplemented".to_string())), - Value::String(.. ) | Value::CachedString(.. ) => { - Err(RunError("String index unimplemented".to_string())) - } - #[cfg(feature = "vector3")] - Value::Vector(_vector) => Err(RunError("Vector index unimplemented".to_string())), - Value::Table(mut table) => { - let mut table = table.borrow_mut(); - if let Some(_metatable) = &table.meta { - Err(RunError("Metatables unimplemented".to_string())) - } else { - table.set(index, value) - } - } - Value::Object(mut object) => object.borrow_mut().0.meta_new_index(index, value), - Value::Function(_callable) => Err(RunError("Function index unimplemented".to_string())), - } - } - fn get(&mut self, subject: Value, index: Value) -> Result { - match subject { - Value::Nil => Err(RunError("Cannot set to nil".to_string())), - Value::Bool(bool) => Err(RunError(format!("Cannot index {:?}", bool))), - Value::Integer(_integer) => Err(RunError("Integer index unimplemented".to_string())), - Value::Number(_number) => Err(RunError("Number index unimplemented".to_string())), - Value::String(..) | Value::CachedString(.. ) => { - Err(RunError("String index unimplemented".to_string())) - } - #[cfg(feature = "vector3")] - Value::Vector(_vector) => Err(RunError("Vector index unimplemented".to_string())), - Value::Table(mut table) => { - let mut table = table.borrow_mut(); - if let Some(_metatable) = &table.meta { - Err(RunError("Metatables unimplemented".to_string())) - } else { - table.get(index.clone()) - } - } - Value::Object(mut object) => object.borrow_mut().0.meta_index(index.clone()), - Value::Function(_callable) => Err(RunError("Function index unimplemented".to_string())), - } - } - /*fn equal(&mut self, lhs: &mut Value, rhs: &mut Value) -> Result { // with respect to metamethods - Ok(match lhs { - Value::Nil => match rhs { - Value::Nil => true, - Value::Object(object) => object.borrow_mut().0.meta_eq(rhs)?.bool(), - _ => false, - } - Value::Bool(this) => match rhs { - Value::Bool(other) => this == other, - _ => false, - } - Value::Number(this) => match rhs { - Value::Number(other) => this == other, - Value::Integer(other) => *this == *other as f64, - _ => false, - } - Value::Integer(this) => match rhs { - Value::Number(other) => *this as f64 == *other, // are these conversions ok? - Value::Integer(other) => this == other, - _ => false, - } - Value::String(string, hash) => match rhs { - Value::CachedString(other) => - if *hash == other.1 { - other.0.deref() == (*string).deref() - } else { - false - } - Value::String(other_string, other_hash) => - if hash == other_hash { - string == other_string - } else { - false - } - _ => false - } - Value::CachedString(string) => match rhs { - Value::CachedString(other) => other.0 == string.0, // pointer equality - Value::String(other_string, other_hash) => { - if string.1 == *other_hash { - string.0.deref() == (*other_string).deref() - } else { - false - } - } - _ => false - } - Value::Table(this) => match rhs { - Value::Table(other) => other == this, - _ => false - } - Value::Object(this) => match rhs { - Value::Object(other) => other == this, - _ => false - } - Value::Function(this) => match rhs { - Value::Function(other) => other == this, - _ => false - } - }) - }*/ - pub(crate) fn load(&mut self, source: &str) -> Result, MarsError> { - let chunk = match parse(source) { - Ok(parsed) => parsed, - Err(error) => return Err(MarsError(error.msg(source))), - }; - - println!("{:?}", chunk); - - let prototype = match compile(&chunk, self) { - Ok(prototype) => prototype, - Err(error) => return Err(MarsError(error.msg(source))), - }; - - let global = self.global.clone(); - let upvalues = vec![self.allocator.alloc(Upvalue::Heap(Value::Table(global)))]; - Ok(self.allocator.alloc(Closure { - prototype: Rc::new(prototype), - upvalues, - })) - } - fn dispatch(&mut self, needle: &mut Needle) -> Result<(), RunError> { - let mut frame: Frame = needle - .frames - .pop() - .ok_or(RunError("No frames in needle!".to_string()))?; - let mut call = |machine: &mut Machine, - needle: &mut Needle, - mut frame: Frame, - index: Index| - -> Result { - frame.counter += 1; // return to this frame at the next instruction - let offset = frame.offset; - match needle.stack[offset + index as usize].value.clone() { - Value::Function(callable) => { - match callable { - Callable::Rust(function) => { - function.0(machine, needle, offset + index as usize + 1)?; - Ok(frame) // nothing changes - } - Callable::Mars(closure) => { - needle.frames.push(frame); - let nargs = closure.borrow().prototype.args; - needle - .stack - .resize(offset + index as usize + nargs as usize, Register::NIL); - Ok(Frame { - // where to find the function, what about missing arguments?, - vararg: offset + index as usize + 1, // start of frame points to the register after the function - offset: offset + index as usize + 1 + nargs as usize, // points to first argument (or last vararg if nargs = zero) - counter: 0, - closure, - }) - } - } - } - _ => { - return Err(RunError( - "Calling non-function types are unimplemented".to_string(), - )); - } - } - }; - let mut jump = |frame: &mut Frame, offset: Offset| { - if offset < 0 { - frame.counter -= -(offset) as usize - } else { - frame.counter += offset as usize - } - }; - loop { - if needle.stack.len() > 65536 { - return Err(RunError("Soft stack limit of 65536 reached".to_string())); - } - let code = frame.closure.borrow_mut().prototype.code.get(frame.counter).cloned(); - let code = match code { - Some(code) => code, - None => { - if let Some(upper) = needle.frames.pop() { - frame = upper; - } else { - break; - } - continue; - } - }; - match code { - Code::Comment(number) => { - eprintln!("{}", number) - } - Code::TableNew => { - needle.push(Value::Table(self.allocator.alloc(Table::new()))) - } - Code::TableSet => { - let table = needle.pop(); - let index = needle.pop(); - let value = needle.pop(); - self.set(table, index, value)?; - } - Code::TableGet => { - let table = needle.pop(); - let index = needle.pop(); - needle.push(self.get(table, index)?); - } - Code::TableInsert(index) => { - match needle.pop() { - Value::Table(mut table) => { - for i in frame.offset + index as usize..needle.stack.len() { - table.borrow_mut().append(needle.stack[i].value.clone()) - } - } - _ => { - return Err(RunError( - "Inserting into non-table types is not implemented".to_string(), - )); // todo! - } - } - } - Code::UpvalueGet(index) => { - match frame.closure.borrow_mut().upvalues[index as usize] - .borrow_mut() - .deref() - { - Upvalue::Stack(stack) => needle.push(needle.stack[*stack].value.clone()), - Upvalue::Heap(object) => needle.push(object.clone()), - } - } - Code::UpvalueSet(index) => { - match frame.closure.borrow_mut().upvalues[index as usize] - .borrow_mut() - .deref_mut() - { - Upvalue::Stack(register) => needle.stack[*register].value = needle.pop(), - Upvalue::Heap(it) => *it = needle.pop(), - } - } - Code::RegisterGet(index) => { - needle.push(needle.stack[frame.vararg + index as usize].value.clone()); - } - Code::RegisterSet(index) => { - needle.stack[frame.vararg + index as usize].value = needle.pop(); - } - Code::Constant(constant) => { - needle.push( - frame.closure.borrow_mut().prototype.constants[constant as usize].clone(), - ); - } - Code::Call(index) => { - frame = call(self, needle, frame, index)?; - continue; - } - Code::Discard(index) => { - needle - .stack - .resize(frame.offset + index as usize, Register::NIL); - } - Code::VarArg(count) => { - if count == 0 { - for i in frame.vararg..frame.offset { - needle.push(needle.stack[i].value.clone()); - } - } else { - for i in 0..count as usize { - if frame.offset - i - 1 < frame.vararg { - needle.push(Value::Nil); - } else { - needle.push(needle.stack[frame.offset - i - 1].value.clone()); - } - } - } - } - Code::Jump(offset) => { - #[cfg(feature = "assertions")] - assert_ne!(offset, 0); - jump(&mut frame, offset); - continue; // Skip the extra offset++ - } - Code::Skip => { - if needle.pop().bool() { - frame.counter += 1; - } - } - Code::Return(index) => { - // Settle the return arguments to where this frame was started originally - for i in frame.offset + index as usize..needle.stack.len() { - needle.stack[frame.vararg + i - 1] = needle.stack[i].clone(); - } - if let Some(upper) = needle.frames.pop() { - frame = upper; - } else { - break; - } - continue; // todo: is this needed? - } - Code::Binary(op) => { - return Err(RunError( - "Binary operations are not implemented".to_string(), - )); - } - Code::Unary(op) => { - return Err(RunError("Unary operations are not implemented".to_string())); - } - Code::Close(index) => { - for i in frame.offset + index as usize..needle.stack.len() { - match &mut needle.stack[i] { - Register { - value, - upvalue: Some(upvalue), - } => { - if matches!(upvalue.borrow().deref(), Upvalue::Stack(_)) { - upvalue.replace(Upvalue::Heap(value.clone())) + fn try_number(&mut self, value: &mut Value) -> Result { + match value { + integer @ Value::Integer(_) => Ok(integer.clone()), + number @ Value::Number(_) => Ok(number.clone()), + Value::Object(object) => object.borrow_mut().0.meta_number(), + Value::Table(table) => { + let mut table = table.borrow_mut(); + if let Some(_metatable) = &table.meta { + Err(RunError("Metatables unimplemented".to_string())) } else { - panic!() // Because it's on the stack since it's right here! + Ok(Value::Nil) } - } - Register { upvalue: None, .. } => {} } - } - needle - .stack - .resize(frame.offset + index as usize, Register::NIL); // As with Code::Discard + _ => Ok(Value::Nil), } - Code::Closure(index) => { - let prototype = - frame.closure.borrow().prototype.prototypes[index as usize].clone(); - let mut upvalues = Vec::new(); - for reference in prototype.upvalues.iter() { - upvalues.push(match reference { - Reference::Closing(index) => { - let index = frame.offset + *index as usize; - match &mut needle.stack[index].upvalue { - Some(upvalue) => upvalue.clone(), - it => { - let upvalue = self.allocator.alloc(Upvalue::Stack(index)); - *it = Some(upvalue.clone()); - upvalue - } + } + fn try_string(&mut self, value: &mut Value) -> Result { + Ok(match value { + Value::Nil => self.new_string("nil".to_string().as_str())?, + Value::Bool(bool) => self.new_string(format!("{}", bool).as_str())?, + Value::Integer(integer) => self.new_string(format!("{}", integer).as_str())?, + Value::Number(number) => self.new_string(format!("{}", number).as_str())?, + it @ Value::String(..) => return Ok(it.clone()), + it @ Value::CachedString(..) => return Ok(it.clone()), + #[cfg(feature = "vector3")] + Value::Vector(vector) => format!("{}", vector), + Value::Table(table) => { + let mut table = table.borrow_mut(); + if let Some(_metatable) = &table.meta { + return Err(RunError("Metatables unimplemented".to_string())); + } else { + self.new_string("{...}".to_string().as_str())? } - } - Reference::Upvalue(index) => { - frame.closure.borrow_mut().upvalues[*index as usize].clone() - } - }); - } - needle.push(Value::Function(Callable::Mars(self.allocator.alloc( - Closure { - prototype, - upvalues, + } + Value::Object(object) => match object.borrow_mut().0.meta_string()? { + string @ Value::String(..) => return Ok(string), + it => return Err(RunError(format!("Expected string but got {:?}", it))), }, - )))); - } - Code::RangeBegin => { - let len = needle.stack.len(); - let init = len - 2; - let limit = len - 1; - let step = len; - let init_value = self.try_number(&mut needle.stack[init].value)?; - let limit_value = self.try_number(&mut needle.stack[limit].value)?; - let step_value = self.try_number(&mut needle.stack[step].value)?; - if matches!(init_value, Value::Integer(_)) - && matches!(limit_value, Value::Integer(_)) - && matches!(step_value, Value::Integer(_)) - { - let get = |value: Value| match value { - Value::Integer(integer) => integer.clone(), - _ => panic!(), - }; - // All integers so we can carry this out nicely - needle.stack[init].value = init_value.clone(); - // https://www.lua.org/source/5.5/lvm.c.html#floatforloop - // but vmcase(OP_FORLOOP) actually preempts the number of iterations for integers! - needle.stack[limit].value = Value::Integer( - (get(limit_value) - get(init_value)) / get(step_value.clone()), - ); // todo: is this actually correct? - needle.stack[step].value = step_value; - } else { - // Make them all as floats - let cast = |value: Value| match value { - Value::Integer(integer) => Value::Number(integer as f64), - number @ Value::Number(_) => number, - _ => panic!(), - }; - needle.stack[init].value = cast(init_value); - needle.stack[limit].value = cast(limit_value); - needle.stack[step].value = cast(step_value); - } - needle.push(needle.stack[init].value.clone()); - } - Code::RangeLoop(offset) => { - let len = needle.stack.len(); - let init_index = len - 2; - let limit_index = len - 1; - let step_index = len; - let init_value = self.try_number(&mut needle.stack[init_index].value)?; - let limit_value = self.try_number(&mut needle.stack[limit_index].value)?; - let step_value = self.try_number(&mut needle.stack[step_index].value)?; - match init_value { - Value::Integer(init) => { - let step = match step_value { - Value::Integer(it) => it, - _ => panic!(), - }; - let limit = match limit_value { - Value::Integer(it) => it, - _ => panic!(), - }; - if limit == 0 { - jump(&mut frame, offset); - } else { - needle.stack[init_index].value = Value::Integer(init + step); - needle.stack[limit_index].value = Value::Integer(limit - 1); - needle.push(Value::Integer(init)); - } + Value::Function(callable) => self.new_string(format!("{:?}", callable).as_str())?, + }) + } + fn set(&mut self, subject: Value, index: Value, value: Value) -> Result<(), RunError> { + match subject { + Value::Nil => Err(RunError("Cannot get from nil".to_string())), + Value::Bool(bool) => Err(RunError(format!("Cannot index {:?}", bool))), + Value::Integer(_integer) => Err(RunError("Integer index unimplemented".to_string())), + Value::Number(_number) => Err(RunError("Number index unimplemented".to_string())), + Value::String(..) | Value::CachedString(..) => { + Err(RunError("String index unimplemented".to_string())) } - Value::Number(init) => { - let step = match step_value { - Value::Number(it) => it, - _ => panic!(), - }; - let limit = match limit_value { - Value::Number(it) => it, - _ => panic!(), - }; - if (step >= 0.0 && init > limit) || (step < 0.0 && init < limit) { - jump(&mut frame, offset); - } else { - needle.stack[init_index].value = Value::Number(init + step); - needle.push(Value::Number(init)); - } + #[cfg(feature = "vector3")] + Value::Vector(_vector) => Err(RunError("Vector index unimplemented".to_string())), + Value::Table(mut table) => { + let mut table = table.borrow_mut(); + if let Some(_metatable) = &table.meta { + Err(RunError("Metatables unimplemented".to_string())) + } else { + table.set(index, value) + } } - _ => panic!(), - } + Value::Object(mut object) => object.borrow_mut().0.meta_new_index(index, value), + Value::Function(_callable) => Err(RunError("Function index unimplemented".to_string())), } - Code::IteratorLoop(offset) => { - let len = needle.stack.len(); - let function = needle.stack[len - 2].value.clone(); - let state = needle.stack[len - 1].value.clone(); - let var = needle.stack[len].value.clone(); - needle.push(function); - needle.push(state); - needle.push(var); - let frame_offset = frame.offset; - frame = call( - self, - needle, - frame, - Index::try_from(needle.stack.len() - frame_offset - 2).unwrap(), - )?; - if matches!( + } + fn get(&mut self, subject: Value, index: Value) -> Result { + match subject { + Value::Nil => Err(RunError("Cannot set to nil".to_string())), + Value::Bool(bool) => Err(RunError(format!("Cannot index {:?}", bool))), + Value::Integer(_integer) => Err(RunError("Integer index unimplemented".to_string())), + Value::Number(_number) => Err(RunError("Number index unimplemented".to_string())), + Value::String(..) | Value::CachedString(..) => { + Err(RunError("String index unimplemented".to_string())) + } + #[cfg(feature = "vector3")] + Value::Vector(_vector) => Err(RunError("Vector index unimplemented".to_string())), + Value::Table(mut table) => { + let mut table = table.borrow_mut(); + if let Some(_metatable) = &table.meta { + Err(RunError("Metatables unimplemented".to_string())) + } else { + table.get(index.clone()) + } + } + Value::Object(mut object) => object.borrow_mut().0.meta_index(index.clone()), + Value::Function(_callable) => Err(RunError("Function index unimplemented".to_string())), + } + } + /*fn equal(&mut self, lhs: &mut Value, rhs: &mut Value) -> Result { // with respect to metamethods + Ok(match lhs { + Value::Nil => match rhs { + Value::Nil => true, + Value::Object(object) => object.borrow_mut().0.meta_eq(rhs)?.bool(), + _ => false, + } + Value::Bool(this) => match rhs { + Value::Bool(other) => this == other, + _ => false, + } + Value::Number(this) => match rhs { + Value::Number(other) => this == other, + Value::Integer(other) => *this == *other as f64, + _ => false, + } + Value::Integer(this) => match rhs { + Value::Number(other) => *this as f64 == *other, // are these conversions ok? + Value::Integer(other) => this == other, + _ => false, + } + Value::String(string, hash) => match rhs { + Value::CachedString(other) => + if *hash == other.1 { + other.0.deref() == (*string).deref() + } else { + false + } + Value::String(other_string, other_hash) => + if hash == other_hash { + string == other_string + } else { + false + } + _ => false + } + Value::CachedString(string) => match rhs { + Value::CachedString(other) => other.0 == string.0, // pointer equality + Value::String(other_string, other_hash) => { + if string.1 == *other_hash { + string.0.deref() == (*other_string).deref() + } else { + false + } + } + _ => false + } + Value::Table(this) => match rhs { + Value::Table(other) => other == this, + _ => false + } + Value::Object(this) => match rhs { + Value::Object(other) => other == this, + _ => false + } + Value::Function(this) => match rhs { + Value::Function(other) => other == this, + _ => false + } + }) + }*/ + pub(crate) fn load(&mut self, source: &str) -> Result, MarsError> { + let chunk = match parse(source) { + Ok(parsed) => parsed, + Err(error) => return Err(MarsError(error.msg(source))), + }; + + println!("{:?}", chunk); + + let prototype = match compile(&chunk, self) { + Ok(prototype) => prototype, + Err(error) => return Err(MarsError(error.msg(source))), + }; + + let global = self.global.clone(); + let upvalues = vec![self.allocator.alloc(Upvalue::Heap(Value::Table(global)))]; + Ok(self.allocator.alloc(Closure { + prototype: Rc::new(prototype), + upvalues, + })) + } + fn dispatch(&mut self, needle: &mut Needle) -> Result<(), RunError> { + let mut frame: Frame = needle + .frames + .pop() + .ok_or(RunError("No frames in needle!".to_string()))?; + let mut call = |machine: &mut Machine, + needle: &mut Needle, + mut frame: Frame, + index: Index| + -> Result { + frame.counter += 1; // return to this frame at the next instruction + let offset = frame.offset; + match needle.stack[offset + index as usize].value.clone() { + Value::Function(callable) => { + match callable { + Callable::Rust(function) => { + function.0(machine, needle, offset + index as usize + 1)?; + Ok(frame) // nothing changes + } + Callable::Mars(closure) => { + needle.frames.push(frame); + let nargs = closure.borrow().prototype.args; + needle + .stack + .resize(offset + index as usize + nargs as usize, Register::NIL); + Ok(Frame { + // where to find the function, what about missing arguments?, + vararg: offset + index as usize + 1, // start of frame points to the register after the function + offset: offset + index as usize + 1 + nargs as usize, // points to first argument (or last vararg if nargs = zero) + counter: 0, + closure, + }) + } + } + } + _ => { + return Err(RunError( + "Calling non-function types are unimplemented".to_string(), + )); + } + } + }; + let mut jump = |frame: &mut Frame, offset: Offset| { + if offset < 0 { + frame.counter -= -(offset) as usize + } else { + frame.counter += offset as usize + } + }; + loop { + if needle.stack.len() > 65536 { + return Err(RunError("Soft stack limit of 65536 reached".to_string())); + } + let code = frame + .closure + .borrow_mut() + .prototype + .code + .get(frame.counter) + .cloned(); + let code = match code { + Some(code) => code, + None => { + if let Some(upper) = needle.frames.pop() { + frame = upper; + } else { + break; + } + continue; + } + }; + match code { + Code::Comment(number) => { + eprintln!("{}", number) + } + Code::TableNew => needle.push(Value::Table(self.allocator.alloc(Table::new()))), + Code::TableSet => { + let table = needle.pop(); + let index = needle.pop(); + let value = needle.pop(); + self.set(table, index, value)?; + } + Code::TableGet => { + let table = needle.pop(); + let index = needle.pop(); + needle.push(self.get(table, index)?); + } + Code::TableInsert(index) => { + match needle.pop() { + Value::Table(mut table) => { + for i in frame.offset + index as usize..needle.stack.len() { + table.borrow_mut().append(needle.pop()) + } + } + _ => { + return Err(RunError( + "Inserting into non-table types is not implemented".to_string(), + )); // todo! + } + } + } + Code::UpvalueGet(index) => { + match frame.closure.borrow_mut().upvalues[index as usize] + .borrow_mut() + .deref() + { + Upvalue::Stack(stack) => needle.push(needle.stack[*stack].value.clone()), + Upvalue::Heap(object) => needle.push(object.clone()), + } + } + Code::UpvalueSet(index) => { + match frame.closure.borrow_mut().upvalues[index as usize] + .borrow_mut() + .deref_mut() + { + Upvalue::Stack(register) => needle.stack[*register].value = needle.pop(), + Upvalue::Heap(it) => *it = needle.pop(), + } + } + Code::RegisterGet(index) => { + needle.push(needle.stack[frame.vararg + index as usize].value.clone()); + } + Code::RegisterSet(index) => { + needle.stack[frame.vararg + index as usize].value = needle.pop(); + } + Code::Constant(constant) => { + needle.push( + frame.closure.borrow_mut().prototype.constants[constant as usize].clone(), + ); + } + Code::Call(index) => { + frame = call(self, needle, frame, index)?; + continue; + } + Code::Discard(index) => { + needle + .stack + .resize(frame.offset + index as usize, Register::NIL); + } + Code::VarArg(count) => { + if count == 0 { + for i in frame.vararg..frame.offset { + needle.push(needle.stack[i].value.clone()); + } + } else { + for i in 0..count as usize { + if frame.offset - i - 1 < frame.vararg { + needle.push(Value::Nil); + } else { + needle.push(needle.stack[frame.offset - i - 1].value.clone()); + } + } + } + } + Code::Jump(offset) => { + #[cfg(feature = "assertions")] + assert_ne!(offset, 0); + jump(&mut frame, offset); + continue; // Skip the extra offset++ + } + Code::Skip => { + if needle.pop().bool() { + frame.counter += 1; + } + } + Code::Return(index) => { + // Settle the return arguments to where this frame was started originally + for i in frame.offset + index as usize..needle.stack.len() { + needle.stack[frame.vararg + i - 1] = needle.stack[i].clone(); + } + if let Some(upper) = needle.frames.pop() { + frame = upper; + } else { + break; + } + continue; // todo: is this needed? + } + Code::Binary(op) => { + return Err(RunError( + "Binary operations are not implemented".to_string(), + )); + } + Code::Unary(op) => { + return Err(RunError("Unary operations are not implemented".to_string())); + } + Code::Close(index) => { + for i in frame.offset + index as usize..needle.stack.len() { + match &mut needle.stack[i] { + Register { + value, + upvalue: Some(upvalue), + } => { + if matches!(upvalue.borrow().deref(), Upvalue::Stack(_)) { + upvalue.replace(Upvalue::Heap(value.clone())) + } else { + panic!() // Because it's on the stack since it's right here! + } + } + Register { upvalue: None, .. } => {} + } + } + needle + .stack + .resize(frame.offset + index as usize, Register::NIL); // As with Code::Discard + } + Code::Closure(index) => { + let prototype = + frame.closure.borrow().prototype.prototypes[index as usize].clone(); + let mut upvalues = Vec::new(); + for reference in prototype.upvalues.iter() { + upvalues.push(match reference { + Reference::Closing(index) => { + let index = frame.offset + *index as usize; + match &mut needle.stack[index].upvalue { + Some(upvalue) => upvalue.clone(), + it => { + let upvalue = self.allocator.alloc(Upvalue::Stack(index)); + *it = Some(upvalue.clone()); + upvalue + } + } + } + Reference::Upvalue(index) => { + frame.closure.borrow_mut().upvalues[*index as usize].clone() + } + }); + } + needle.push(Value::Function(Callable::Mars(self.allocator.alloc( + Closure { + prototype, + upvalues, + }, + )))); + } + Code::RangeBegin => { + let len = needle.stack.len(); + let init = len - 2; + let limit = len - 1; + let step = len; + let init_value = self.try_number(&mut needle.stack[init].value)?; + let limit_value = self.try_number(&mut needle.stack[limit].value)?; + let step_value = self.try_number(&mut needle.stack[step].value)?; + if matches!(init_value, Value::Integer(_)) + && matches!(limit_value, Value::Integer(_)) + && matches!(step_value, Value::Integer(_)) + { + let get = |value: Value| match value { + Value::Integer(integer) => integer.clone(), + _ => panic!(), + }; + // All integers so we can carry this out nicely + needle.stack[init].value = init_value.clone(); + // https://www.lua.org/source/5.5/lvm.c.html#floatforloop + // but vmcase(OP_FORLOOP) actually preempts the number of iterations for integers! + needle.stack[limit].value = Value::Integer( + (get(limit_value) - get(init_value)) / get(step_value.clone()), + ); // todo: is this actually correct? + needle.stack[step].value = step_value; + } else { + // Make them all as floats + let cast = |value: Value| match value { + Value::Integer(integer) => Value::Number(integer as f64), + number @ Value::Number(_) => number, + _ => panic!(), + }; + needle.stack[init].value = cast(init_value); + needle.stack[limit].value = cast(limit_value); + needle.stack[step].value = cast(step_value); + } + needle.push(needle.stack[init].value.clone()); + } + Code::RangeLoop(offset) => { + let len = needle.stack.len(); + let init_index = len - 2; + let limit_index = len - 1; + let step_index = len; + let init_value = self.try_number(&mut needle.stack[init_index].value)?; + let limit_value = self.try_number(&mut needle.stack[limit_index].value)?; + let step_value = self.try_number(&mut needle.stack[step_index].value)?; + match init_value { + Value::Integer(init) => { + let step = match step_value { + Value::Integer(it) => it, + _ => panic!(), + }; + let limit = match limit_value { + Value::Integer(it) => it, + _ => panic!(), + }; + if limit == 0 { + jump(&mut frame, offset); + } else { + needle.stack[init_index].value = Value::Integer(init + step); + needle.stack[limit_index].value = Value::Integer(limit - 1); + needle.push(Value::Integer(init)); + } + } + Value::Number(init) => { + let step = match step_value { + Value::Number(it) => it, + _ => panic!(), + }; + let limit = match limit_value { + Value::Number(it) => it, + _ => panic!(), + }; + if (step >= 0.0 && init > limit) || (step < 0.0 && init < limit) { + jump(&mut frame, offset); + } else { + needle.stack[init_index].value = Value::Number(init + step); + needle.push(Value::Number(init)); + } + } + _ => panic!(), + } + } + Code::IteratorLoop(offset) => { + let len = needle.stack.len(); + let function = needle.stack[len - 2].value.clone(); + let state = needle.stack[len - 1].value.clone(); + let var = needle.stack[len].value.clone(); + needle.push(function); + needle.push(state); + needle.push(var); + let frame_offset = frame.offset; + frame = call( + self, + needle, + frame, + Index::try_from(needle.stack.len() - frame_offset - 2).unwrap(), + )?; + if matches!( needle.stack.get(len + 1).unwrap_or(&Register::NIL).value, Value::Nil, ) { - jump(&mut frame, offset); - }; - } - } - frame.counter += 1; - } - Ok(()) - } - pub(crate) fn enter(&mut self, closure: Gc) -> Result<(), RunError> { - let mut needle = Needle { - frames: vec![Frame { - vararg: 1, // Both 1 since there is a single NIL on the stack - offset: 1, - counter: 0, - closure, - }], - stack: vec![Register::NIL], // When a function gets called, it expects to be able to place its return values over the value in the stack too - }; - self.dispatch(&mut needle) - } - pub fn new() -> Result { - let mut allocator = Allocator::new(); - let mut machine = Machine { - global: allocator.alloc(Table::new()), - allocator, - cache: Map::new(), - }; - let string = machine.new_string("print").unwrap(); - machine.global.borrow_mut().set( - string, - Value::Function(Callable::Rust(Rc::from(Native(|machine: &mut Machine, needle: &mut Needle, index: usize| -> Result<(), RunError> { - for i in index..needle.stack.len() { - println!("{}",machine.try_string(&mut needle.pop())?.unwrap_str()) + jump(&mut frame, offset); + }; + } + } + frame.counter += 1; } Ok(()) - })))) - )?; - Ok(machine) - } + } + pub(crate) fn enter(&mut self, closure: Gc) -> Result<(), RunError> { + let mut needle = Needle { + frames: vec![Frame { + vararg: 1, // Both 1 since there is a single NIL on the stack + offset: 1, + counter: 0, + closure, + }], + stack: vec![Register::NIL], // When a function gets called, it expects to be able to place its return values over the value in the stack too + }; + self.dispatch(&mut needle) + } + pub fn new() -> Result { + let mut allocator = Allocator::new(); + let mut machine = Machine { + global: allocator.alloc(Table::new()), + allocator, + cache: Map::new(), + }; + let string = machine.new_string("print").unwrap(); + machine.global.borrow_mut().set( + string, + Value::Function(Callable::Rust(Rc::from(Native( + |machine: &mut Machine, + needle: &mut Needle, + index: usize| + -> Result<(), RunError> { + for i in index..needle.stack.len() { + print!("{} ", machine.try_string(&mut needle.pop())?.unwrap_str()) + } + println!(); + Ok(()) + }, + )))), + )?; + Ok(machine) + } } #[derive(Debug, Clone)] -pub struct MarsError(String); \ No newline at end of file +pub struct MarsError(String);