diff --git a/mars-49d70575ae6f08.core b/mars-49d70575ae6f08.core new file mode 100644 index 0000000..40e21fd Binary files /dev/null and b/mars-49d70575ae6f08.core differ diff --git a/src/gc.rs b/src/gc.rs index 9ef4159..3562c33 100644 --- a/src/gc.rs +++ b/src/gc.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, Layout}; +use std::alloc::{Layout, alloc, dealloc}; use std::any::Any; use std::cell::{Ref, RefCell, RefMut}; use std::fmt::Debug; @@ -24,116 +24,131 @@ in the allocator ensure location is consistent #[derive(Debug)] pub struct Gc { - it: NonNull>> + it: NonNull>>, } pub struct Agc {} impl Clone for Gc { - fn clone(&self) -> Self { - Gc { it: self.it } - } + fn clone(&self) -> Self { + Gc { it: self.it } + } } impl Traverse for Gc { - fn traverse(&self) { - self.borrow().traverse() - } + fn traverse(&self) { + self.borrow().traverse() + } } impl PartialEq for Gc { - fn eq(&self, other: &Gc) -> bool { - self.it == other.it - } + fn eq(&self, other: &Gc) -> bool { + self.it == other.it + } } impl Gc { - pub fn borrow(&self) -> impl Deref { - Ref::map(unsafe { // ??? - (*self.it.as_ptr()).borrow() - },|it| &it.data) - } - pub fn borrow_mut(&mut self) -> impl DerefMut { - RefMut::map(unsafe { - (*self.it.as_mut()).borrow_mut() - },|it| &mut it.data) - } - - pub fn replace(&mut self, new: T) where T: Sized { - unsafe { - (*self.it.as_mut()).borrow_mut().data = new; + pub fn borrow(&self) -> impl Deref { + Ref::map( + unsafe { + // ??? + (*self.it.as_ptr()).borrow() + }, + |it| &it.data, + ) + } + pub fn borrow_mut(&mut self) -> impl DerefMut { + RefMut::map(unsafe { (*self.it.as_mut()).borrow_mut() }, |it| { + &mut it.data + }) } - } - pub fn addr(&self) -> usize { - self.it.as_ptr().addr() - } + pub fn replace(&mut self, new: T) + where + T: Sized, + { + unsafe { + (*self.it.as_mut()).borrow_mut().data = new; + } + } + + pub fn addr(&self) -> usize { + self.it.as_ptr().addr() + } } #[derive(Clone, Debug, Copy)] enum Color { - White, - Black, + White, + Black, } struct Header { - layout: Layout, - color: Color, // NOT for incremental tri-color right now; white == mark-free, black == mark-keep - data: T + layout: Layout, + color: Color, // NOT for incremental tri-color right now; white == mark-free, black == mark-keep + data: T, } pub struct Allocator { - // An array of pointers is used here since I did not want to use a compactor and larger types - // held on the GC (game objects) will most likely be massive anyway. - objects: Vec>>>, + // An array of pointers is used here since I did not want to use a compactor and larger types + // held on the GC (game objects) will most likely be massive anyway. + objects: Vec>>>>, } impl Allocator { - pub fn new() -> Allocator { - Allocator { - objects: Vec::new(), - } - } - pub fn alloc(&mut self, it: T) -> Gc { - let layout = Layout::new::>>(); - let pointer = unsafe { alloc(layout) as *mut RefCell> }; // todo: maybe use a compacting GC - assert!(!pointer.is_null()); // lol idk how to fix this rn - let mut header = unsafe { pointer.as_mut() }.unwrap().borrow_mut(); - header.layout = layout; - header.color = Color::Black; - header.data = it; - self.objects.push(Some(pointer as *mut RefCell>)); - Gc { - it: NonNull::new(pointer).unwrap(), - } - } - fn mark_white(&mut self) { - for i in 0..self.objects.len() { - if let Some(object) = self.objects[i] { - unsafe { (*object).borrow_mut().color = Color::White }; - } - } - } - fn collect(&mut self) { - self.objects.retain(|object| { - if let Some(object) = object { - let header = unsafe { (**object).borrow_mut() }; - match header.color { - Color::White => { - unsafe { dealloc(*object as *mut u8,header.layout); } - true - } - Color::Black => false + pub fn new() -> Allocator { + Allocator { + objects: Vec::new(), } - } else { - false - } - }); - } + } + pub fn alloc(&mut self, it: T) -> Gc { + let layout = Layout::new::>>(); + let pointer = unsafe { + let pointer = alloc(layout) as *mut RefCell>; + assert!(!pointer.is_null()); // lol idk how to fix this rn (gah use a result!!!) + pointer.write(RefCell::new(Header { + layout, + color: Color::Black, + data: it, + })); + pointer + }; // todo: maybe use a compacting GC + self.objects.push(NonNull::new(pointer)); + Gc { + it: NonNull::new(pointer).unwrap(), + } + } + fn mark_white(&mut self) { + for i in 0..self.objects.len() { + if let Some(object) = self.objects[i] { + unsafe { (*object.as_ptr()).borrow_mut().color = Color::White }; + } + } + } + fn collect(&mut self) { + self.mark_white(); + self.objects.retain(|object| { + if let Some(object) = object { + let header = unsafe { (*object.as_ptr()).borrow_mut() }; + match header.color { + Color::White => { + unsafe { + dealloc(object.as_ptr() as *mut u8, header.layout); + } + true + } + Color::Black => false, + } + } else { + false + } + }); + } } pub trait Traverse: Any + Debug { - fn traverse(&self) { // mark or grey - () - } -} \ No newline at end of file + fn traverse(&self) { + // mark or grey + () + } +} diff --git a/src/lib.rs b/src/lib.rs index 2ff46b2..2a18593 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,15 +5,17 @@ pub mod gc; mod table; -use std::fmt::{Formatter}; +use std::fmt::Formatter; +use std::hash::{DefaultHasher, Hash, Hasher}; use std::ops::{Add, Deref, DerefMut}; // 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? +struct Reader<'a> { + // 'cursor' states that follow through parsed source + slice: &'a str, + full: &'a str, + white: bool, // Is the previous 'thing' whitespace? } type Error = String; @@ -21,232 +23,239 @@ type Error = String; pub struct LoadError(String, 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())) - } - fn from(message: &str, piece: &Piece) -> LoadError { - LoadError(message.to_string(), piece.unit()) - } - 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())) + } + fn from(message: &str, piece: &Piece) -> LoadError { + LoadError(message.to_string(), piece.unit()) + } + 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 } - roll - } } 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)] -struct Piece { // A wrapper of T providing a reference to source code, used in errors - comment: Comment, - index: usize, - width: usize, - it: T, +struct Piece { + // A wrapper of T providing a reference to source code, used in errors + comment: Comment, + index: usize, + width: usize, + it: T, } -impl std::fmt::Debug for Piece where T: std::fmt::Debug { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.it.fmt(f) - } +impl std::fmt::Debug for Piece +where + T: std::fmt::Debug, +{ + 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(), + } } - } - fn swap(&self, it: A) -> Piece { - Piece { - it, - index: self.index, - width: self.width, - comment: self.comment.clone() + fn swap(&self, it: A) -> Piece { + Piece { + it, + index: self.index, + width: self.width, + comment: self.comment.clone(), + } } - } - fn unit(&self) -> Piece<()> { - Piece { - it: (), - index: self.index, - width: self.width, - comment: self.comment.clone() + fn unit(&self) -> Piece<()> { + Piece { + it: (), + index: self.index, + width: self.width, + comment: self.comment.clone(), + } } - } - fn null() -> Piece<()> { - Piece { - it: (), - index: 0, - width: 0, - comment: String::new() + 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(), + } } - } - fn end(self) -> Piece { - Piece { - it: self.it, - index: self.index + self.width, - width: 0, - comment: self.comment, + fn end(self) -> Piece { + Piece { + it: self.it, + index: self.index + self.width, + width: 0, + comment: self.comment, + } } - } - fn start(self) -> Piece { - Piece { - it: self.it, - index: self.index, - width: 0, - comment: self.comment, + fn start(self) -> Piece { + Piece { + it: self.it, + index: self.index, + width: 0, + comment: self.comment, + } } - } - fn inner_ref(&self) -> Piece<&T> { - self.unit().swap(&self.it) - } // TODO: .as_ref() + 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)] @@ -258,164 +267,164 @@ struct Name(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"]; +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", +]; 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 { + reader.slice = &reader.slice[end..]; + Ok(Piece::of( + Number(reader.slice[..end].to_string()), + 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 @@ -425,59 +434,67 @@ struct Block(Vec>, Option>>); // struct Chunk(Piece); #[derive(Debug)] 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)] 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)] 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)] struct Constructor(Vec>); #[derive(Debug)] enum Prefix { - Variable(Variable), - Call(Call), - Expression(Expression), + Variable(Variable), + Call(Call), + Expression(Expression), } -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] struct VarArg(Option); #[derive(Debug)] struct Call(Box>, Option>, Piece); @@ -489,1817 +506,1991 @@ struct Function(Vec>, Option>, Piece); struct Field(Option>, Piece); #[derive(Debug)] enum FieldSep { - Comma, - Semicolon, + Comma, + Semicolon, } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] 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)] 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 - } - }, - '^' => BinaryOp::Caret, - '%' => BinaryOp::Modulo, - '&' => BinaryOp::Ampersand, - '~' => { - match chars.next() { - Some('=') => { - count += 1; - BinaryOp::NotEqual - }, - _ => { - BinaryOp::Tilde + 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; } - } - }, - '|' => 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") - } + let result = Ok(Piece::of(op, reader, count)); + reader.slice = &reader.slice[count..]; + result + } else { + reader.error("Expected binary operand, got EOF") } - }; - 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(pre_parameters, vararg, 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) -> 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 { +fn inject( + current: Piece, + op: Piece, + next: Piece, +) -> Piece { 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(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())) + } } 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(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())); + } + 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, 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, 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) } // COMPILER +use crate::gc::*; use std::any::Any; use std::cmp::PartialEq; use std::rc::Rc; -use crate::gc::*; -struct Traversal { // A 'cursor' of where we are in assumed execution - contexts: Vec, // Stack of function prototypes being compiled +struct Traversal { + // A 'cursor' of where we are in assumed execution + contexts: Vec, // Stack of function prototypes being compiled } -struct Context { // Everything known about a closure at a time - code: Vec>, - scopes: Vec, - constants: Vec, - vararg: Option>>, - prototype: Prototype, +struct Context { + // Everything known about a closure at a time + scopes: Vec, + vararg: Option>>, + prototype: Prototype, } -#[derive(Clone)] +#[derive(Clone, Debug)] enum BlindJump { - Break(usize), - Continue(usize), - Goto(String,usize), + Break(usize), + Continue(usize), + Goto(String, usize), } +#[derive(Debug)] 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::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) => { - while self.last_scope().index > index { - self.consume_scope(1); // Pass Value + 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::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.last_scope().index - 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(_) => {} } - 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); + 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!!! + let constants = &mut self.contexts.last_mut().unwrap().prototype.constants; + let index; + if let Some(position) = constants.iter().position(|found| it.eq(found)) { + index = position; + } else { + index = constants.len(); } - while self.last_scope().index < index { - self.temp_scope(); - } */ - } - Code::VarArg(count) => { - for _ in 0..count { - self.temp_scope(); + constants.push(it); + index as 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 new_scope(&mut self) { + let context = &mut self.contexts.last_mut().unwrap(); + let scopes = &mut context.scopes; + let index = scopes.last().unwrap().index; + scopes.push(Scope { + index, + jumps: vec![], + labels: vec![], + symbol: None, + upvalue: false, + }); + } + fn temp_scope(&mut self) -> Index { + self.new_scope(); + let index = self.last_scope().index + 1; + self.last_scope().index = index; + index + } + fn last_scope(&mut self) -> &mut Scope { + self.last_context().scopes.last_mut().unwrap() + } + 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. } - /* 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(_) => {} } - self.contexts.last_mut().unwrap().code.push(it); - self.contexts.len() - 1 - } - fn insert_code(&mut self, location: usize, it: Code) { - let code = &mut self.last_context().code; - let piece = code[location].unit(); - code[location] = piece.swap(it); - } - fn push_constant(&mut self, it: Value) -> Index { - let it = match it { - Value::String(string) => { // todo! not great to construct a string then immediately destruct it - string.into() - }, - other => other, - }; - let constants = &mut self.contexts.last_mut().unwrap().constants; - let index; - if let Some(position) = constants.iter().position(|found| it.eq(found)) { - index = position; - } else { - index = constants.len(); + 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 + } } - constants.push(it); - index as 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 new_scope(&mut self) { - let context = &mut self.contexts.last_mut().unwrap(); - let scopes = &mut context.scopes; - let index = scopes.last().unwrap().index; - scopes.push(Scope { - index, - jumps: vec![], - labels: vec![], - symbol: None, - upvalue: false, - }); - } - fn temp_scope(&mut self) -> Index { - self.new_scope(); - let index = self.last_scope().index + 1; - self.last_scope().index = index; - index - } - fn last_scope(&mut self) -> &mut Scope { - self.last_context().scopes.last_mut().unwrap() - } - fn code_length(&mut self) -> usize { - self.last_context().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(Piece {it: Code::Close(_), ..}) = self.last_context().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_context(&mut self) -> &mut Context { + self.contexts.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 close_context(&mut self) -> Result { + let context = self.contexts.pop().unwrap(); + Ok(context.prototype) } - } - fn last_context(&mut self) -> &mut Context { - self.contexts.last_mut().unwrap() - } - fn close_context(&mut self) -> Result { - let context = self.contexts.pop().unwrap(); - Ok(context.prototype) - } } // 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) -> 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, +fn compile_function( + 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, + }); + 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() as Index, + vararg: this.it.1.is_some(), + prototypes: vec![], + constants: vec![], + upvalues: vec![Reference::Upvalue(0)], // _ENV + pieces: vec![], + code: vec![], + }, }); - 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()))), - constants: vec![], - code: vec![], - scopes: argument_scopes, - prototype: Prototype { - args: this.it.0.len() as Index, - vararg: this.it.1.is_some(), - prototypes: vec![], - constants: vec![], - upvalues: vec![Reference::Upvalue(0)], // _ENV - pieces: vec![], - code: vec![], - }, - }); - traversal.compile(&this.it.2.inner_ref())?; - let prototype = traversal.close_context()?; - let prototypes = &mut traversal.last_context().prototype.prototypes; - let index = prototypes.len() as Index; - prototypes.push(Rc::new(prototype)); - traversal.push_code(this.swap(Code::Closure(index))); - Ok(()) + 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() as Index; + 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) -> Result<(), LoadError> { - let length = traversal.contexts.len(); - 'search: 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), - })); - break 'search; // 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 as Index), - 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 as Index) // Reference (child) to this reference to that reference (parent) for next context - } +fn compile_identifier( + name: Piece, + traversal: &mut Traversal, + access: Access, +) -> Result<(), LoadError> { + let length = traversal.contexts.len(); + 'search: 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), + })); + break 'search; // 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 as Index), + 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 as Index) // 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), + })); + break 'search; + } } - } - 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), - })); - break 'search } - } - // break 'search avoids this use of the _G table - traversal.push_literal(Value::String(name.it.clone()), name.unit()); - traversal.push_code(name.swap(Code::UpvalueGet(0))); - traversal.push_code(name.swap(match access { + } + // break 'search avoids this use of the _G table + traversal.push_literal(name.it.clone().into(), 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(()) + })); + Ok(()) } -fn compile_variable(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)?; +fn compile_variable( + 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)?; + } + 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))?; + 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())?; + } } - 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())?; + 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())?; - match &self.it.1 { - Some(name) => { - traversal.push_literal(Value::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.0.as_ref().inner_ref())?; // call prefix + match &self.it.1 { + Some(name) => { + traversal.push_literal(name.it.0.clone().into(), name.unit()); + traversal.push_code(name.swap(Code::TableGet)); + } + None => {} + } + let index = traversal.last_scope().index; + 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(()) } - let index = traversal.last_scope().index; - 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.last_scope().index; - 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.last_scope().index; + 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(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(()) - } - } - }, + 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 has no accessible vararg parameter '{:?}'", + self.it + ), + self.unit(), + )), } - - }, - 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> { - 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::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))); - }, - it => { - traversal.compile(&field.it.1.swap(it))?; + fn compile<'a, 'b>(&self, traversal: &mut Traversal) -> Result<(), LoadError> { + 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::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))); + } + 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::TableInsert(index))); + } } - } - let index = traversal.contexts.last().unwrap().scopes.last().unwrap().index; - 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_literal(Value::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_err(|it| LoadError(it.to_string(), self.unit()))?; + traversal.push_literal(Value::Number(number), self.unit()); + } + Expression::String(string) => { + traversal.push_literal(string.clone().into(), 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) - 1) as Offset) + Ok((there as i64 - here as i64) as Offset) } fn resolve_break(traversal: &mut Traversal, begin: usize, end: usize) -> Result<(), LoadError> { - let mut jumps = Vec::new(); - for jump in traversal.last_scope().jumps.clone() { // ? - 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)?)); - }, - _ => jumps.push(jump) + let mut jumps = Vec::new(); + for jump in traversal.last_scope().jumps.clone() { + // ? + 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)?)); + } + _ => jumps.push(jump), + } } - } - traversal.last_scope().jumps = jumps; - Ok(()) + traversal.last_scope().jumps = jumps; + 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.last_scope().index; - 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.last_scope().index; - 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 as Index)); - }, - prefix => { - if let Some(variable) = variables_iter.next() { - traversal.compile(&expression.swap(prefix))?; - compile_variable(variable.inner_ref(),traversal,Access::Set)? - } + 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.last_scope().index; + 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))); } - } - }, - 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)?; + 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.last_scope().index; + 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 as Index)); + } + 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 as Index)); + } + } + _ => { + compile_variable_expression( + traversal, + variables_iter.next(), + &expression.inner_ref(), + )?; + } } - traversal.insert_code(index_vararg,Code::VarArg(count as Index)); - } + } else { + // otherwise treat it normally and consume one variable + compile_variable_expression(traversal, variables_iter.next(), &expression.inner_ref())?; } - _ => { - 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.last_scope().index; - 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.last_scope().index; - 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.last_scope().index; + 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)?; } - } - _ => 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().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(); - let mut blocks = blocks.iter(); - 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)); - traversal.compile(&block.inner_ref())?; - jumps.push(traversal.push_code(condition.swap(Code::UNSURE))); - 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.last_scope().index; + 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 - }, - 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.last_scope().index)).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.last_scope().index; - traversal.push_code(block.swap(Code::Discard(index + names.len() as Index)).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_literal(Value::String(name.it.0.clone()), name.unit()); - traversal.push_code(name.unit().end().swap(Code::TableSet)); - } else { - traversal.push_literal(Value::String(name.it.0.clone()), name.unit()); - traversal.push_code(name.unit().end().swap(Code::TableGet)); - } + 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.last_scope().index)) + .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.last_scope().index; + traversal.push_code( + block + .swap(Code::Discard(index + names.len() as Index)) + .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_literal(name.it.0.clone().into(), name.unit()); + traversal.push_code(name.unit().end().swap(Code::TableSet)); + } else { + traversal.push_literal(name.it.0.clone().into(), 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.last_scope().index; + 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)?; + } } - } - }, - Statement::LocalFunction(name,function) => { - var_scope(traversal, name.it.0.clone()); - let index = traversal.last_scope().index; - 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)?; } - } + // 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(); + } + if traversal.last_scope().index != last_scope_index { + println!("{:?}", traversal.last_scope()) + } + assert_eq!(traversal.last_scope().index, 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.last_scope().index, 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()) + } } // MACHINE -use crate::table::Table; +use crate::table::{Hashed, Table}; // Rust function to call struct Native(dyn Fn(&mut Machine, &mut Needle) -> Result<(), RunError>); // A native function in Rust #[derive(Clone, Debug, Copy, PartialEq)] enum Reference { - Closing(Index), - Upvalue(Index), -} - -#[derive(Clone, Debug)] -pub struct Prototype { // A function prototype - args: Index, - vararg: bool, // Does this function receive varargs? - prototypes: Vec>, // List of other prototypes this Prototype can make a Closure from - constants: Vec, // List of objects statically attached to this Prototype - upvalues: Vec, // Location of upvalues in (parent closure's upvalue or VM's closing) list - pieces: Vec>, // List of all pieces corresponding to it's equivalently indexed code - code: Vec, -} - -#[derive(Clone, Debug)] -enum Upvalue { // Do we REALLY have to store each Index in the Rc> too? - Stack(usize), - Heap(Value), + 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 Closure { // An actual callable function - prototype: Rc, - upvalues: Vec>, // List of upvalues associated with this function +pub struct Prototype { + // A function prototype + args: Index, + vararg: bool, // Does this function receive varargs? + prototypes: Vec>, // List of other prototypes this Prototype can make a Closure from + constants: Vec, // List of objects statically attached to this Prototype + upvalues: Vec, // Location of upvalues in (parent closure's upvalue or VM's closing) list + pieces: Vec>, // List of all pieces corresponding to it's equivalently indexed code + 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)?; + } + 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 +} + +#[derive(Clone)] +pub struct Closure { + // An actual callable function + 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 { - for upvalue in self.upvalues.iter() { - write!(f,"{:?}",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 + 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, + }, } - }, - 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()), + } } - } } struct RunError(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 { - 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 { + Ok(Value::Nil) + } + fn meta_eq(&mut self, other: &Value) -> Result { + Ok(Value::Nil) + } } impl From for Value { - fn from(string: String) -> Self { - let bytes = string.as_bytes(); - if bytes.len() < PHRASE_LEN - 1 { - let array: [u8; PHRASE_LEN] = bytes.try_into().unwrap(); - let hash = table::hash(&Value::String(string)); - Value::Phrase((array,hash)) - } else { - Value::String(string) + fn from(string: String) -> Self { + let mut hasher = DefaultHasher::new(); + string.hash(&mut hasher); + Value::String(Rc::from(string.as_str()), hasher.finish() as Hashed) } - } } impl Value { - fn number(&mut self) -> Result { - match self { - 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 { - Ok(Value::Nil) + fn number(&mut self) -> Result { + match self { + 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 { + Ok(Value::Nil) + } + } + _ => Ok(Value::Nil), } - } - _ => Ok(Value::Nil), } - } - fn string(&mut self) -> Result { - Ok(match self { - Value::Nil => "nil".to_string(), - Value::Bool(bool) => format!("{}", bool), - Value::Integer(integer) => format!("{}", integer), - Value::Number(number) => format!("{}", number), - Value::Phrase(phrase) => format!("{}", String::from_utf8_lossy(&phrase.0)), - Value::String(string) => format!("{}", string), - #[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 { - "{...}".to_string() + fn string(&mut self) -> Result { + Ok(match self { + Value::Nil => "nil".to_string(), + Value::Bool(bool) => format!("{}", bool), + Value::Integer(integer) => format!("{}", integer), + Value::Number(number) => format!("{}", number), + it @ Value::String(..) => 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 { + "{...}".to_string() + } + } + 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) => format!("{:?}", callable), } - }, - Value::Object(object) => match object.borrow_mut().0.meta_string()? { - Value::String(string) => string, - it => return Err(RunError(format!("Expected string but got {:?}",it))) - }, - Value::Function(callable) => format!("{:?}",callable), - }.into()) - } - fn set(&mut self, index: Value, item: Value) -> Result<(),RunError> { - match self { - Value::Nil => Err(RunError("Cannot index 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::Phrase(_phrase) => Err(RunError("Phrase index unimplemented".to_string())), - Value::String(_string) => Err(RunError("String index unimplemented".to_string())), - #[cfg(feature = "vector3")] - Value::Vector(_vector) => Err(RunError("Vector index unimplemented".to_string())), - Value::Table(table) => { - let mut table = table.borrow_mut(); - if let Some(_metatable) = &table.meta { - Err(RunError("Metatables unimplemented".to_string())) - } else { - table.set(index,item) - } - }, - Value::Object(object) => object.borrow_mut().0.meta_new_index(index,item), - Value::Function(_callable) => Err(RunError("Function index unimplemented".to_string())), + .into()) } - } - fn get(&mut self, index: Value) -> Result { - match self { - Value::Nil => Err(RunError("Cannot index 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::Phrase(_phrase) => Err(RunError("Phrase index unimplemented".to_string())), - Value::String(_string) => Err(RunError("String index unimplemented".to_string())), - #[cfg(feature = "vector3")] - Value::Vector(_vector) => Err(RunError("Vector index unimplemented".to_string())), - Value::Table(table) => { - let table = table.borrow_mut(); - if let Some(_metatable) = &table.meta { - Err(RunError("Metatables unimplemented".to_string())) - } else { - table.get(index) + fn set(&mut self, index: Value, item: Value) -> Result<(), RunError> { + match self { + Value::Nil => Err(RunError("Cannot index 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(_string, _hash) => { + Err(RunError("String index unimplemented".to_string())) + } + #[cfg(feature = "vector3")] + Value::Vector(_vector) => Err(RunError("Vector index unimplemented".to_string())), + Value::Table(table) => { + let mut table = table.borrow_mut(); + if let Some(_metatable) = &table.meta { + Err(RunError("Metatables unimplemented".to_string())) + } else { + table.set(index, item) + } + } + Value::Object(object) => object.borrow_mut().0.meta_new_index(index, item), + Value::Function(_callable) => Err(RunError("Function index unimplemented".to_string())), + } + } + fn get(&mut self, index: Value) -> Result { + match self { + Value::Nil => Err(RunError("Cannot index 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(_string, _hash) => { + Err(RunError("String index unimplemented".to_string())) + } + #[cfg(feature = "vector3")] + Value::Vector(_vector) => Err(RunError("Vector index unimplemented".to_string())), + Value::Table(table) => { + let table = table.borrow_mut(); + if let Some(_metatable) = &table.meta { + Err(RunError("Metatables unimplemented".to_string())) + } else { + table.get(index) + } + } + Value::Object(object) => object.borrow_mut().0.meta_index(index), + Value::Function(_callable) => Err(RunError("Function index unimplemented".to_string())), } - }, - Value::Object(object) => object.borrow_mut().0.meta_index(index), - Value::Function(_callable) => Err(RunError("Function index unimplemented".to_string())), } - } } -trait Userdata: Traverse + std::fmt::Debug + Any + Object {} +pub trait Userdata: Traverse + std::fmt::Debug + Any + Object {} -struct Anything(dyn Userdata); // can't impl PartialEq for Rc +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() + } } #[cfg(feature = "vector3")] use glam::Vec3; +#[derive(Clone, Debug, PartialEq)] +struct Phrase { + bytes: [u8; PHRASE_LEN], + hash: usize, +} + // Any value in the language const PHRASE_LEN: usize = 16; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] +// 120 - 8 - 64 -> 56 pub enum Value { - Nil, // Empty value - Bool(bool), - Number(f64), - Integer(u64), // maybe we should use signed integers... - Phrase(([u8; 16],usize)), // "VeryShortString" + hash - String(String), - Table(Gc), - Object(Gc), - Function(Callable), - #[cfg(feature = "vector3")] - Vector(Vec3), + // 32 bytes!!! + Nil, // Empty value + Bool(bool), + Number(f64), + Integer(u64), // 64 maybe we should use signed integers... + String(Rc, Hashed), + Table(Gc
), + Object(Gc), + Function(Callable), + #[cfg(feature = "vector3")] + Vector(Vec3), } 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, + global: Gc
, + allocator: Allocator, } /* @@ -2310,35 +2501,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] + } } type Index = u16; // Vector index @@ -2349,367 +2540,438 @@ type Offset = i16; // Jump to offset #[derive(Debug, Clone, Copy)] #[repr(u32)] enum Code { - 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), + 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); - const UNSURE: Code = Code::Jump(0); + const NO_OP: Code = Code::Jump(1); + const UNSURE: Code = Code::Jump(0); } impl Machine { - fn load(&mut self, source: &str) -> Result { - let parsed = match parse(source) { - Ok(parsed) => parsed, - Err(error) => return Err(error.msg(source)) - }; + fn load(&mut self, source: &str) -> Result { + let parsed = match parse(source) { + Ok(parsed) => parsed, + Err(error) => return Err(error.msg(source)), + }; - let mut traversal = Traversal{contexts: vec![Context { - scopes: vec![Scope { // Dummy initial scope so the rest can start from index = 0 - index: 0, - jumps: vec![], - labels: vec![], - symbol: None, - upvalue: false, - }], - code: vec![], - vararg: Some(Piece::::null().swap(None)), - constants: vec![], - prototype: Prototype { - args: 0, - vararg: true, - prototypes: vec![], - constants: vec![], - upvalues: vec![], - pieces: vec![], - code: vec![], - }, - }]}; + println!("{:?}", parsed); - match parsed.compile(&mut traversal) { - Ok(compiled) => compiled, - Err(error) => return Err(error.msg(source)) - }; + let mut traversal = Traversal { + contexts: vec![Context { + scopes: vec![Scope { + // Dummy initial scope so the rest can start from index = 0 + index: 0, + jumps: vec![], + labels: vec![], + symbol: None, + upvalue: false, + }], + vararg: Some(Piece::::null().swap(None)), + prototype: Prototype { + args: 0, + vararg: true, + prototypes: vec![], + constants: vec![], + upvalues: vec![], + pieces: vec![], + code: vec![], + }, + }], + }; - let prototype = match traversal.close_context() { - Ok(compiled) => compiled, - Err(error) => return Err(error.msg(source)) - }; + match parsed.compile(&mut traversal) { + Ok(compiled) => compiled, + Err(error) => return Err(error.msg(source)), + }; - let global = self.global.clone(); - let upvalues = vec![self.allocator.alloc(Upvalue::Heap(Value::Table(global)))]; - Ok(Callable::Mars(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)?; - 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) + let prototype = match traversal.close_context() { + Ok(compiled) => compiled, + Err(error) => return Err(error.msg(source)), + }; + + let global = self.global.clone(); + let upvalues = vec![self.allocator.alloc(Upvalue::Heap(Value::Table(global)))]; + Ok(Callable::Mars(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)?; + 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 not yet implemented".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[frame.counter]; + match code { + Code::Comment(number) => { + eprintln!("{}", number) + } + Code::TableSet => { + let value = needle.pop(); + let index = needle.pop(); + let mut table = needle.pop(); + table.set(index, value)?; + } + Code::TableGet => { + let index = needle.pop(); + let mut table = needle.pop(); + needle.push(table.get(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); + } + Code::Skip => { + if matches!(needle.pop(), Value::Nil | Value::Bool(false)) { + 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; + } + } + 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 = needle.stack[init].value.number()?; + let limit_value = needle.stack[limit].value.number()?; + let step_value = needle.stack[step].value.number()?; + 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 = needle.stack[init_index].value.number()?; + let limit_value = needle.stack[limit_index].value.number()?; + let step_value = needle.stack[step_index].value.number()?; + 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(()) + } + fn enter(&mut self, closure: Gc) -> Result<(), RunError> { + let mut needle = Needle { + frames: vec![Frame { + vararg: 0, + offset: 0, counter: 0, closure, - }) - } - } - } - _ => { - return Err(RunError("Calling non-function types are not yet implemented".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[frame.counter]; - match code { - Code::TableSet => { - let value = needle.pop(); - let index = needle.pop(); - let mut table = needle.pop(); - table.set(index,value)?; - } - Code::TableGet => { - let index = needle.pop(); - let mut table = needle.pop(); - needle.push(table.get(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); - } - Code::Skip => { - if matches!(needle.pop(),Value::Nil | Value::Bool(false)) { - 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; - } - } - 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 = needle.stack[init].value.number()?; - let limit_value = needle.stack[limit].value.number()?; - let step_value = needle.stack[step].value.number()?; - 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 = needle.stack[init_index].value.number()?; - let limit_value = needle.stack[limit_index].value.number()?; - let step_value = needle.stack[step_index].value.number()?; - 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 needle.stack.get(len + 1).unwrap_or(&Register::NIL).value == Value::Nil { - jump(&mut frame, offset); - }; - } - } - frame.counter += 1; + }], + 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) } - Ok(()) - } - fn enter(&mut self, closure: Gc) -> Result<(), RunError> { - let mut needle = Needle { - frames: vec![Frame { - vararg: 0, - offset: 0, - 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) - } - fn new() -> Machine { - let mut allocator = Allocator::new(); - Machine { - global: allocator.alloc(Table::new()), - allocator, + fn new() -> Machine { + let mut allocator = Allocator::new(); + Machine { + global: allocator.alloc(Table::new()), + allocator, + } } - } } #[cfg(test)] mod tests { - use super::*; - #[test] - fn simple() { - let mut machine = Machine::new(); - let result = machine.load(include_str!("tests/script.lua")); - match result { - Err(error) => println!("{}",error), - Ok(result) => println!("{:?}",result) + use super::*; + #[test] + fn simple() { + let mut machine = Machine::new(); + let result = machine.load(include_str!("tests/script.lua")); + match result { + Err(error) => println!("{}", error), + Ok(result) => println!("{:?}", result), + } } - } -} \ No newline at end of file +} diff --git a/src/table.rs b/src/table.rs index e795d75..6df39b0 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,7 +1,6 @@ -use std::hash::{DefaultHasher, Hash, Hasher}; -use std::rc::Rc; use crate::gc::{Gc, Traverse}; use crate::{Callable, RunError, Value}; +use std::rc::Rc; // I've already spent 2 months on this interpreter, and I'm tired, so I've cut a few corners... /* See some of Lua's notes on this table: https://www.lua.org/source/5.5/ltable.c.html @@ -25,316 +24,318 @@ Notes: */ type Displacement = u8; +pub type Hashed = usize; #[derive(Debug, Clone)] struct Entry { - index: Value, - item: Value, - home: usize, - displacement: Displacement, + index: Value, + item: Value, + home: usize, + displacement: Displacement, } impl Default for Entry { - fn default() -> Self { - Entry { - index: Value::Nil, - item: Value::Nil, - home: 0, - displacement: 0, + fn default() -> Self { + Entry { + index: Value::Nil, + item: Value::Nil, + home: 0, + displacement: 0, + } } - } } -pub fn hash(value: &Value) -> usize { - match value { - Value::Nil => { 0 } - Value::Bool(boolean) => { if *boolean { 1 } else { 0 } } - Value::String(string) => { - let mut hasher = DefaultHasher::new(); - string.hash(&mut hasher); - hasher.finish() as usize - } - Value::Phrase(phrase) => { - phrase.1 - } - Value::Function(callable) => { - match callable { - Callable::Rust(native) => { - Rc::as_ptr(native).addr() +pub fn hash(value: &Value) -> Hashed { + match value { + Value::Nil => 0, + Value::Bool(boolean) => { + if *boolean { + 1 + } else { + 0 + } } - Callable::Mars(closure) => { - closure.addr() + Value::String(_string, hash) => *hash, + Value::Function(callable) => match callable { + Callable::Rust(native) => Rc::as_ptr(native).addr(), + Callable::Mars(closure) => closure.addr(), + }, + Value::Integer(integer) => *integer as usize, + Value::Number(number) => { + if number.is_nan() { + 0 + } else { + number.to_bits() as usize + } + } + Value::Table(table) => table.addr(), + Value::Object(object) => object.addr(), + #[cfg(feature = "vector3")] + Value::Vector(vec) => { + let mut hasher = DefaultHasher::new(); + vec.as_u64vec3().hash(&mut hasher); + hasher.finish() as usize } - } } - Value::Integer(integer) => { - *integer as usize - } - Value::Number(number) => { - if number.is_nan() { - 0 - } else { - number.to_bits() as usize - } - } - Value::Table(table) => { - table.addr() - } - Value::Object(object) => { - object.addr() - } - #[cfg(feature = "vector3")] - Value::Vector(vec) => { - let mut hasher = DefaultHasher::new(); - vec.as_u64vec3().hash(&mut hasher); - hasher.finish() as usize - } - } } // todo: displaced items don't ever get shuffled closer to their homes unless the table is resized #[derive(Debug, Clone)] pub struct Table { - table: Vec, - array: Vec, - table_bounds: std::ops::Range, - table_count: usize, // number of elements in table - pub meta: Option> + table: Vec, + array: Vec, + table_bounds: std::ops::Range, + table_count: usize, // number of elements in table + pub meta: Option>, } impl Traverse for Table { - fn traverse(&self) { - for Entry { index, item, .. } in self.table.iter() { - if !matches!(index,Value::Nil) { - index.traverse(); - item.traverse(); - } + fn traverse(&self) { + for Entry { index, item, .. } in self.table.iter() { + if !matches!(index, Value::Nil) { + index.traverse(); + item.traverse(); + } + } + for item in self.array.iter() { + item.traverse() + } } - for item in self.array.iter() { - item.traverse() - } - } } impl Table { - fn exchange_table(&mut self, len: usize) { - let old = std::mem::replace(&mut self.table, vec![Entry::default(); len]); - for Entry { index, item, .. } in old { - if index != Value::Nil { - self.set_table(index,item) - } - } - } - pub fn resize_table(&mut self, len: usize) { - self.exchange_table(len.max(self.table_count + (self.table_count / 3))); - self.table_bounds = 0..self.table_upper(); - } - pub fn resize_array(&mut self, len: usize) { - self.array.resize(len,Value::Nil) - } - fn table_upper(&self) -> usize { - (self.table.len() / 4) * 3 - } - fn table_lower(&self) -> usize { - self.table.len() / 3 - } - fn ensure_table(&mut self) { - if self.table_count > self.table_upper() { // free space is short - self.exchange_table((self.table.len() + 4) * 2); - } else if self.table_count < self.table_lower() { // too much free space - self.exchange_table(self.table.len() / 2) - } - self.table_bounds = self.table_lower()..self.table_upper() - } - fn set_table(&mut self, index: Value, item: Value) { - #[cfg(feature = "assertions")] - assert_ne!(index,Value::Nil); - #[cfg(feature = "assertions")] - assert_ne!(item,Value::Nil); - if !self.table_bounds.contains(&self.table_count) { // make sure the table is appropriately sized - self.ensure_table(); - } - let range = self.table.len(); - let home = hash(&index) % range; - if self.table[home].index == Value::Nil { // attempt to place it directly in an empty space - // INSERT - self.table[home].home = home; - self.table[home].item = item; // home.item.soft_drop() - self.table[home].index = index; - self.table[home].displacement = self.table[home].displacement.max(0); - self.table_count += 1; - } else if self.table[home].index == index { // attempt to replace it directly - // REPLACE - self.table[home].item = item; // home.item.soft_drop() - } else { - // attempt to replace it in a collided neighbour location - for i in 1..self.table[home].displacement + 1 { - let neighbour = &mut self.table[(home + i as usize) % range]; // todo: is mod expensive? - if neighbour.index == index { // found where it was displaced to - // REPLACE - neighbour.item = item; - return; - } - } - // at this point it must be added, probe to place in an empty space - for j in self.table[home].displacement + 1..Displacement::MAX - 1 { - let neighbour = &mut self.table[(home + j as usize) % range]; - if neighbour.index == Value::Nil { // new empty slot hooray! - // INSERT - neighbour.home = home; - neighbour.item = item; - neighbour.index = index; - self.table[home].displacement = j; - self.table_count += 1; - return; - } - } - // impossible but this still needs to be complete - #[cfg(feature = "messages")] - eprintln!("Large table collision, are the hashes ok?\n\tBrute-force probing..."); - let mut free: Option = None; - for k in 0..self.table.len() { - let neighbour = &mut self.table[k]; - if neighbour.index == Value::Nil && free.is_none() { - free = Some(k); - } else if neighbour.index == index { - // REPLACE - neighbour.item = item; - return; - } - } - if let Some(k) = free { - // INSERT - self.table[k].home = home; - self.table[k].index = index; - self.table[k].item = item; - self.table[home].displacement = Displacement::MAX; - self.table_count += 1; - return; - } - // must resize - #[cfg(feature = "messages")] - eprintln!("\n\tResizing..."); - self.resize_table((self.table.len() + 4) * 2); - self.set_table(index,item); - } - } - fn rem_table(&mut self, index: Value) { - let range = self.table.len(); - let home = hash(&index) % range; - if self.table[home].index == index { - self.table[home].index = Value::Nil; - self.table[home].item = Value::Nil; // is this necessary? - self.table_count -= 1; - } else { - if self.table[home].displacement != Displacement::MAX { - let mut largest = 0; - for i in 1..self.table[home].displacement { - let neighbour = &mut self.table[(home + i as usize) % range]; - if neighbour.index == index { - neighbour.index = Value::Nil; - neighbour.item = Value::Nil; - self.table_count -= 1; - if i == self.table[home].displacement { - self.table[home].displacement = largest + fn exchange_table(&mut self, len: usize) { + let old = std::mem::replace(&mut self.table, vec![Entry::default(); len]); + for Entry { index, item, .. } in old { + if index != Value::Nil { + self.set_table(index, item) } - return; - } else if neighbour.index != Value::Nil && neighbour.home == home { - largest = i; - } } - } else { - let mut largest = 0; - let mut finished = false; // what - for k in 0..self.table.len() { - let neighbour = &mut self.table[k]; - if neighbour.index == index { - neighbour.index = Value::Nil; - neighbour.item = Value::Nil; - self.table_count -= 1; - #[cfg(feature = "assertions")] - assert!(!finished); - finished = true; - } - if neighbour.home == home && neighbour.index != Value::Nil { - largest = largest.max(if k < home { - k + self.table.len() - home - 1 // ? - } else { - k - home - }) - } + } + pub fn resize_table(&mut self, len: usize) { + self.exchange_table(len.max(self.table_count + (self.table_count / 3))); + self.table_bounds = 0..self.table_upper(); + } + pub fn resize_array(&mut self, len: usize) { + self.array.resize(len, Value::Nil) + } + fn table_upper(&self) -> usize { + (self.table.len() / 4) * 3 + } + fn table_lower(&self) -> usize { + self.table.len() / 3 + } + fn ensure_table(&mut self) { + if self.table_count > self.table_upper() { + // free space is short + self.exchange_table((self.table.len() + 4) * 2); + } else if self.table_count < self.table_lower() { + // too much free space + self.exchange_table(self.table.len() / 2) } - self.table[home].displacement = if largest > Displacement::MAX as usize { - Displacement::MAX + self.table_bounds = self.table_lower()..self.table_upper() + } + fn set_table(&mut self, index: Value, item: Value) { + #[cfg(feature = "assertions")] + assert_ne!(index, Value::Nil); + #[cfg(feature = "assertions")] + assert_ne!(item, Value::Nil); + if !self.table_bounds.contains(&self.table_count) { + // make sure the table is appropriately sized + self.ensure_table(); + } + let range = self.table.len(); + let home = hash(&index) % range; + if self.table[home].index == Value::Nil { + // attempt to place it directly in an empty space + // INSERT + self.table[home].home = home; + self.table[home].item = item; // home.item.soft_drop() + self.table[home].index = index; + self.table[home].displacement = self.table[home].displacement.max(0); + self.table_count += 1; + } else if self.table[home].index == index { + // attempt to replace it directly + // REPLACE + self.table[home].item = item; // home.item.soft_drop() } else { - largest as Displacement - } - } - } - } - pub fn set(&mut self, index: Value, item: Value) -> Result<(),RunError> { - match index { - Value::Integer(index) => { // This is an integer index, try the array first - match item { - Value::Nil => { - if (0..self.array.len() + 1).contains(&(index as usize)) { - if self.array.len() == index as usize { - self.array.pop(); - } else { - self.array[index as usize + 1] = Value::Nil - } + // attempt to replace it in a collided neighbour location + for i in 1..self.table[home].displacement + 1 { + let neighbour = &mut self.table[(home + i as usize) % range]; // todo: is mod expensive? + if neighbour.index == index { + // found where it was displaced to + // REPLACE + neighbour.item = item; + return; + } } - self.rem_table(Value::Integer(index)); - }, - item => { - if (0..self.array.len() + 1).contains(&(index as usize)) { - if self.array.len() == index as usize { - self.array.push(item) - } else { - self.array[index as usize + 1] = item; - } - } else { - self.set_table(Value::Integer(index),item) + // at this point it must be added, probe to place in an empty space + for j in self.table[home].displacement + 1..Displacement::MAX - 1 { + let neighbour = &mut self.table[(home + j as usize) % range]; + if neighbour.index == Value::Nil { + // new empty slot hooray! + // INSERT + neighbour.home = home; + neighbour.item = item; + neighbour.index = index; + self.table[home].displacement = j; + self.table_count += 1; + return; + } } - } + // impossible but this still needs to be complete + #[cfg(feature = "messages")] + eprintln!("Large table collision, are the hashes ok?\n\tBrute-force probing..."); + let mut free: Option = None; + for k in 0..self.table.len() { + let neighbour = &mut self.table[k]; + if neighbour.index == Value::Nil && free.is_none() { + free = Some(k); + } else if neighbour.index == index { + // REPLACE + neighbour.item = item; + return; + } + } + if let Some(k) = free { + // INSERT + self.table[k].home = home; + self.table[k].index = index; + self.table[k].item = item; + self.table[home].displacement = Displacement::MAX; + self.table_count += 1; + return; + } + // must resize + #[cfg(feature = "messages")] + eprintln!("\n\tResizing..."); + self.resize_table((self.table.len() + 4) * 2); + self.set_table(index, item); } - Ok(()) - }, - Value::Nil => Err(RunError("Attempt to set new index of tabel with key: nil".to_string())), - index => Ok(self.set_table(index,item)) } - } - pub fn get(&self, index: Value) -> Result { - match index { - Value::Integer(index) => Ok(self.array.get(index as usize).unwrap_or(&Value::Nil).clone()), - Value::Nil => Err(RunError("Attempt to index table with key: nil".to_string())), - index => { - let location = hash(&index) % self.table.len(); - let home = &self.table[location]; - if home.index == index { - Ok(home.item.clone()) + fn rem_table(&mut self, index: Value) { + let range = self.table.len(); + let home = hash(&index) % range; + if self.table[home].index == index { + self.table[home].index = Value::Nil; + self.table[home].item = Value::Nil; // is this necessary? + self.table_count -= 1; } else { - for i in 1..home.displacement as usize { - let neighbour = &self.table[location + i]; - if neighbour.index == index { - return Ok(neighbour.item.clone()) + if self.table[home].displacement != Displacement::MAX { + let mut largest = 0; + for i in 1..self.table[home].displacement { + let neighbour = &mut self.table[(home + i as usize) % range]; + if neighbour.index == index { + neighbour.index = Value::Nil; + neighbour.item = Value::Nil; + self.table_count -= 1; + if i == self.table[home].displacement { + self.table[home].displacement = largest + } + return; + } else if neighbour.index != Value::Nil && neighbour.home == home { + largest = i; + } + } + } else { + let mut largest = 0; + let mut finished = false; // what + for k in 0..self.table.len() { + let neighbour = &mut self.table[k]; + if neighbour.index == index { + neighbour.index = Value::Nil; + neighbour.item = Value::Nil; + self.table_count -= 1; + #[cfg(feature = "assertions")] + assert!(!finished); + finished = true; + } + if neighbour.home == home && neighbour.index != Value::Nil { + largest = largest.max(if k < home { + k + self.table.len() - home - 1 // ? + } else { + k - home + }) + } + } + self.table[home].displacement = if largest > Displacement::MAX as usize { + Displacement::MAX + } else { + largest as Displacement + } } - } - Ok(Value::Nil) } - } } - } - pub fn append(&mut self, item: Value) { - self.array.push(item) - } - pub fn new() -> Self { - Table { - table: Vec::new(), - array: Vec::new(), - table_count: 0, - table_bounds: (0..0).into(), - meta: None + pub fn set(&mut self, index: Value, item: Value) -> Result<(), RunError> { + match index { + Value::Integer(index) => { + // This is an integer index, try the array first + match item { + Value::Nil => { + if (0..self.array.len() + 1).contains(&(index as usize)) { + if self.array.len() == index as usize { + self.array.pop(); + } else { + self.array[index as usize + 1] = Value::Nil + } + } + self.rem_table(Value::Integer(index)); + } + item => { + if (0..self.array.len() + 1).contains(&(index as usize)) { + if self.array.len() == index as usize { + self.array.push(item) + } else { + self.array[index as usize + 1] = item; + } + } else { + self.set_table(Value::Integer(index), item) + } + } + } + Ok(()) + } + Value::Nil => Err(RunError( + "Attempt to set new index of tabel with key: nil".to_string(), + )), + index => Ok(self.set_table(index, item)), + } } - } -} \ No newline at end of file + pub fn get(&self, index: Value) -> Result { + match index { + Value::Integer(index) => Ok(self + .array + .get(index as usize) + .unwrap_or(&Value::Nil) + .clone()), + Value::Nil => Err(RunError("Attempt to index table with key: nil".to_string())), + index => { + let location = hash(&index) % self.table.len(); + let home = &self.table[location]; + if home.index == index { + Ok(home.item.clone()) + } else { + for i in 1..home.displacement as usize { + let neighbour = &self.table[location + i]; + if neighbour.index == index { + return Ok(neighbour.item.clone()); + } + } + Ok(Value::Nil) + } + } + } + } + pub fn append(&mut self, item: Value) { + self.array.push(item) + } + pub fn new() -> Self { + Table { + table: Vec::new(), + array: Vec::new(), + table_count: 0, + table_bounds: (0..0).into(), + meta: None, + } + } +} diff --git a/src/tests/script.lua b/src/tests/script.lua index ace0f14..36d8fd4 100644 --- a/src/tests/script.lua +++ b/src/tests/script.lua @@ -1 +1,5 @@ -do end \ No newline at end of file +if true then + print("whats good") +else + print("oh no") +end