From eba41e43304d1fe4dff8f132907d6ee295240e73 Mon Sep 17 00:00:00 2001 From: paladin Date: Sat, 18 Jul 2026 15:15:51 +0100 Subject: [PATCH] Implementing compiler. --- src/assets/script.lua | 15 +- src/lang.rs | 1659 ++++++++++++++++++++++++++++------------- 2 files changed, 1131 insertions(+), 543 deletions(-) diff --git a/src/assets/script.lua b/src/assets/script.lua index 9aeeb13..73a6987 100644 --- a/src/assets/script.lua +++ b/src/assets/script.lua @@ -1,7 +1,12 @@ -local all = { ... } -while true do - for index, item in pairs(all) do - dog:log(index, item) +local two +do + local one + if something then + local three + print(something) + end + local four + if something2 then + end - return end \ No newline at end of file diff --git a/src/lang.rs b/src/lang.rs index c01d8f7..e882a55 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -1,660 +1,1243 @@ -#[derive(Clone)] +use std::any::Any; +use std::collections::HashMap; +use std::fmt::Formatter; +use std::ops::Add; +use std::rc::Rc; +// 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> { - slice: &'a str, - full: &'a str, + slice: &'a str, + full: &'a str, + white: bool, // Is the previous 'thing' whitespace? } -#[derive(Debug)] -struct Error(String); +struct Error(String,Piece<()>); impl Error { - fn new(message: &str, _reader: &Reader) -> Result { - Err(Error(message.to_string())) - } + fn new(message: &str, reader: &Reader) -> Result { + Err(Error(message.to_string(), reader.marker())) + } + fn msg(&self, reader: &Reader) -> String { + self.0.clone().add(reader.slice) + } } +impl std::fmt::Debug for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("Error: {} {}", self.0, self.1.index)) + } +} + + type Comment = String; -#[derive(Debug)] struct Piece { - comment: Comment, - index: usize, - width: usize, - it: T, + 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 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: 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 null(&self) -> Piece<()> { - Piece { - it: (), - index: self.index, - width: self.width, - comment: String::new() - } + } + fn unit(&self) -> Piece<()> { + Piece { + it: (), + index: self.index, + width: self.width, + comment: self.comment.clone() } + } + 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() + } + } } // Strips comments and whitespace // todo: implement comments returning for debugging. impl<'a> From<&'a str> for Reader<'a> { - fn from(str: &'a str) -> Self { - Reader { - full: str, - slice: str, - } + fn from(str: &'a str) -> Self { + Reader { + full: str, + slice: str, + white: true, } + } } impl<'a> Reader<'a> { - fn trim(&mut self) -> Result { - 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(); - 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]; - } else { - self.slice = &self.slice[..self.slice.len() - 1]; - comment = &self.slice[2..]; - } - Ok(comment) - }?; - self.trim().map(|it| { - it + comment - }) - } else { - Ok(String::new()) + 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"), } - } - fn consume(&mut self, start: &str) -> Result<&Self, Error> { - self.trim()?; - if self.slice.starts_with(start) { - self.slice = &self.slice[start.len()..]; - Ok(self) + } 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.error(format!("Expected '{}'", start).as_str()) + 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 { + if start < self.slice.as_ptr() as usize { + self.white = true; + } + Ok(String::new()) } - fn take(&mut self) -> Result, Error> - where - T: Parse, - { - self.trim()?; - T::consume(self) + } + fn white(&mut self) -> Result<&mut Self, Error> { + if self.white { + Ok(self) + } else { + self.error("Expected whitespace") } - fn error(&self, message: &str) -> Result { - Error::new(message, self) + } + fn consume(&mut self, start: &str) -> Result<&mut Self, Error> { + 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 marker(&self) -> Piece<()> { - Piece::of((), self, 0) + } + // Consume but require whitespace before + fn white_consume(&mut self, start: &str) -> Result<&mut Self, Error> { + 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, Error> { + let result = self.consume(start)?; + result.white = true; + Ok(result) + } + fn take(&mut self) -> Result, Error> + where + T: Parse, + { + T::consume(self) + } + fn finished(&self) -> bool { + self.slice.is_empty() + } + fn error(&self, message: &str) -> Result { + Error::new(message, self) + } + fn marker(&self) -> Piece<()> { + Piece::of((), self, 0) + } } #[derive(Debug)] struct Number(String); -#[derive(Debug)] +#[derive(Debug, Clone)] struct Name(String); // Requirements for Parse: // - The reader.slice must be pushed to the end of the consumed text (or restored in an error) // - ??? // - The reader may have not been trimmed trait Parse { - fn consume(reader: &mut Reader) -> Result, Error> - where - Self: Sized; + fn consume(reader: &mut Reader) -> Result, Error> + 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"]; impl Parse for Name { - fn consume(reader: &mut Reader) -> Result, Error> - where - Self: Sized, - { - reader.trim()?; - 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 result = Ok(Piece::of( - Name(reader.slice[..end].to_string()), - reader, - end, - )); - reader.slice = &reader.slice[end..]; - result + fn consume(reader: &mut Reader) -> Result, Error> + 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(); + // TODO: do we need to check if this is a keyword here? + 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 + } } impl Parse for Number { - fn consume(reader: &mut Reader) -> Result, Error> - where - Self: Sized, - { - reader.trim()?; - 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, - )) - } + fn consume(reader: &mut Reader) -> Result, Error> + 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, + )) + } + } } impl Parse for String { - fn consume(reader: &mut Reader) -> Result, Error> - 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; - match chars.next() { - Some('"') => { - term1 = '"'; - term2 = None; + fn consume(reader: &mut Reader) -> Result, Error> + 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"); } - Some('\'') => { - term1 = '\''; - term2 = None; - } - Some('[') if chars.next().is_some_and(|it| it == '[') => { - term1 = ']'; - term2 = Some(']'); + 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) + } } _ => { - return reader.error("Could not parse string"); + string.push(c); } + } } - 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..]; - 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"); - } - } + None => { + return reader.error("Found EOF while parsing string"); } + } } + } } // AST #[derive(Debug)] -struct Block(Vec>, Vec>); +struct Block(Vec>, Vec>); // +#[derive(Debug)] +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>, - Block, - ), - Iterator(Vec>, Vec>, Block), - 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>, + Block, + ), + Iterator(Vec>, Vec>, Block), + Function(Vec>, Option>, Function), + LocalFunction(Piece, Function), + Declaration(Vec>, Vec>), } #[derive(Debug)] enum Variable { - Name(Name), - Index(Box, Box), + Name(Name), + Index(Box>, Piece), } #[derive(Debug)] enum Expression { - Nil, - True, - False, - Number(Number), - String(String), - VarArg(VarArg), - Function(Function), - Prefix(Box), - Table(Vec), - Binary(Box, BinaryOp, Box), - Unary(UnaryOp, 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), + Ident(Variable), + Call(Call), + Expression(Piece), } #[derive(Debug)] struct VarArg(Option); #[derive(Debug)] -struct Call(Option, Vec); +struct Call(Box>, Option>, Piece); +#[derive(Debug)] +struct Args(Vec>); #[derive(Debug)] struct Function(Vec>, Option>, Piece); #[derive(Debug)] -struct Field(Option, Expression); +struct Field(Option>, Piece); #[derive(Debug)] enum FieldSep { - Comma, - Semicolon, + Comma, + Semicolon, } -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)] enum BinaryOp { - Plus, - Minus, - Mul, - Divide, - DivFloor, - Caret, - Modulo, - Ampersand, - Tilde, - Pipe, - ShiftRight, - ShiftLeft, - Concat, - Less, - LessEqual, - Greater, - GreatEqual, - Equivalent, - NotEqual, - And, - Or, + Or, + And, + Less, + Greater, + LessEqual, + GreatEqual, + Equivalent, + NotEqual, + Pipe, + Tilde, + Ampersand, + ShiftLeft, + ShiftRight, + Concat, + Plus, + Minus, + Mul, + Divide, + DivFloor, + Modulo, + Caret, } -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)] enum UnaryOp { - Negate, - Not, - Ampersand, - Tilde, + Negate, + Not, + Ampersand, + Tilde } impl Parse for Vec> { - fn consume(reader: &mut Reader) -> Result>>, Error> - where - Self: Sized, - { - let mut result: Vec> = Vec::new(); - reader.trim()?; - loop { - if let Ok(it) = reader.take::() { - result.push(it); - reader.trim()?; - if !reader.consume(",").is_ok() { - break; - } - } - } - if result.is_empty() { - return reader.error(format!("Expected {}s", std::any::type_name::()).as_str()); - } - let first = result.first().unwrap().null(); - let last = result.last().unwrap().null(); - Ok(Piece::from(result, &first, &last)) + fn consume(reader: &mut Reader) -> Result>>, Error> + 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)) + } +} + +impl Parse for BinaryOp { + fn consume(reader: &mut Reader) -> Result, Error> { + reader.trim()?; + let mut chars = reader.slice.chars(); + if let Some(char) = chars.next() { + let mut count = 1; + let op = match char { + '+' => BinaryOp::Plus, + '-' => BinaryOp::Minus, + '*' => BinaryOp::Mul, + '/' => { + if let Some('/') = chars.next() { + count += 1; + BinaryOp::DivFloor + } else { + BinaryOp::Divide + } + }, + '^' => BinaryOp::Caret, + '%' => BinaryOp::Modulo, + '&' => BinaryOp::Ampersand, + '~' => { + match chars.next() { + Some('=') => { + count += 1; + BinaryOp::NotEqual + }, + _ => { + BinaryOp::Tilde + } + } + }, + '|' => BinaryOp::Pipe, + '>' => { + match chars.next() { + Some('>') => { + count += 1; + BinaryOp::ShiftRight + }, + Some('=') => { + count += 1; + BinaryOp::GreatEqual + } + _ => { + BinaryOp::Greater + } + } + }, + '<' => { + match chars.next() { + Some('<') => { + count += 1; + BinaryOp::ShiftLeft + }, + Some('=') => { + count += 1; + BinaryOp::LessEqual + } + _ => { + BinaryOp::Less + } + } + }, + '.' => { + if let Some('.') = chars.next() { + count += 1; + BinaryOp::Concat + } else { + return reader.error("Expected '.' for concatenation") + } + }, + '=' => { + if let Some('=') = chars.next() { + count += 1; + BinaryOp::Equivalent + } else { + return reader.error("Expected '=' for equality") + } + }, + _ => { + if reader.white_consume("and").is_ok() { + count+=2; + BinaryOp::And + } else if reader.white_consume("or").is_ok() { + count+=1; + BinaryOp::Or + } else { + return reader.error("Expected binary operation") + } + } + }; + if !matches!(op,BinaryOp::And | BinaryOp::Or) { + reader.white = true; + } + let result = Ok(Piece::of(op,reader,count)); + reader.slice = &reader.slice[count..]; + result + } else { + reader.error("Expected binary operand, got EOF") + } + } +} + +impl Parse for UnaryOp { + fn consume(reader: &mut Reader) -> Result, Error> { + 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())) + } } impl Parse for Function { - fn consume(reader: &mut Reader) -> Result, Error> { - reader.trim()?; - let start = reader.marker(); - reader.consume("(")?; - let mut parameters: Vec> = Vec::new(); - let mut vararg = None; - loop { - if let Ok(name) = reader.take::() { - parameters.push(name); - if vararg.is_some() { - return reader.error("Unexpected argument after vararg '...'"); - } - if !reader.consume(",").is_ok() { - break; - } - } - vararg = reader.take::().ok() - } - reader.consume(")")?; - let end = reader.marker(); - let block = reader.take::()?; - Ok(Piece::from( - Function(parameters, vararg, block), - &start, - &end, - )) + fn consume(reader: &mut Reader) -> Result, Error> { + reader.trim()?; + let start = reader.marker(); + reader.consume_white("(")?; + let mut parameters: Vec> = Vec::new(); + let mut vararg = None; + while let Ok(name) = reader.take::() { + parameters.push(name); + if vararg.is_some() { + return reader.error("Unexpected argument after vararg '...'"); + } + if !reader.consume_white(",").is_ok() { + break; + } + vararg = reader.take::().ok() } + reader.consume_white(")")?; + let end = reader.marker(); + let block = reader.take::()?; + reader.white_consume("end")?; + Ok(Piece::from( + Function(parameters, vararg, block), + &start, + &end, + )) + } } impl Parse for VarArg { - fn consume(reader: &mut Reader) -> Result, Error> { - reader.trim()?; - let start = reader.marker(); - reader.consume("...")?; - let name = reader.take::().ok(); - let end; - if let Some(name) = name { - let end = name.null(); - 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, Error> { + 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 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 { + 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, Error> { - reader.trim()?; - + fn consume(reader: &mut Reader) -> Result, Error> { + 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) + } } impl Parse for Call { - fn consume(reader: &mut Reader) -> Result, Error> { - + fn consume(reader: &mut Reader) -> Result, Error> { + 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, Error> { + 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, Error> { + reader.trim()?; + let start = reader.marker(); + 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))) + } +} + +impl Parse for Args { + fn consume(reader: &mut Reader) -> Result, Error> { + 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, Error> { + 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),&start,&reader.marker())) + } else if let Ok(name) = reader.take::() { + Box::new(Piece::from(Prefix::Ident(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::Ident(Variable::Index(current, exp)) + } else if reader.consume_white(".").is_ok() { + let field = reader.take::()?; + Prefix::Ident(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) + } +} + +impl Parse for Variable { + fn consume(reader: &mut Reader) -> Result, Error> { + reader.trim()?; + let prefix = reader.take::()?; + let piece = prefix.unit(); + if let Prefix::Ident(var) = prefix.it { + Ok(piece.map(|_| var)) + } else { + reader.error("Expected variable, found expression.") + } + } } impl Parse for Statement { - fn consume(initial: &mut Reader) -> Result, Error> { - initial.trim()?; - let start = initial.marker(); - // todo: it is safer to pass back the new reader in the Ok, and then map it out - if initial.consume("break").is_ok() { - Ok(Piece::from(Statement::Break, &start, &initial.marker())) - } else if initial.consume("continue").is_ok() { - Ok(Piece::from(Statement::Continue, &start, &initial.marker())) - } else if initial.consume(";").is_ok() { - Ok(Piece::from(Statement::Semicolon, &start, &initial.marker())) - } else if let Ok(mut reader) = initial.clone().consume("local") { - if reader.consume("function").is_ok() { - let name = reader.take::()?; - let function = reader.take::()?; - *initial = *reader; - Ok(Piece::from( - Statement::LocalFunction(name, function.it), - &start, - &function.null(), - )) - } else { - let names = reader.take::>>()?.it; - reader.consume("=")?; - let expressions = reader.take::>>()?.it; - *initial = *reader; - Ok(Piece::from( - Statement::Declaration(names, expressions), - &start, - &reader.marker(), - )) - } - } else if let Ok(mut reader) = initial.clone().consume("function") { - let mut names = Vec::new(); - loop { - if let Ok(name) = reader.take::() { - names.push(name); - if !reader.consume(".").is_ok() { - break; - } - } - } - let mut member = None; - if reader.consume(":").is_ok() { - member = Some(reader.take::()?); - } - let function = reader.take::()?; - *initial = *reader; - Ok(Piece::from( - Statement::Function(names, member, function.it), - &start, - &reader.marker(), - )) - } else if let Ok(mut reader) = initial.clone().consume("for") { - let names = reader.take::>>()?.it; - let result = if names.len() > 1 { - let name = *names.first().unwrap().clone(); - reader.consume("=")?; - let begin = reader.take::()?; - reader.consume(",")?; - let finish = reader.take::()?; - let delta = if reader.consume(",").is_ok() { - Some(reader.take::()?) - } else { - None - }; - reader.consume("do")?; - let block = reader.take::()?; - reader.consume("end")?; - Ok(Piece::from( - Statement::Range(name, begin, finish, delta, block.it), - &start, - &reader.marker(), - )) - } else { - reader.consume("in")?; - let expressions = reader.take::>>()?.it; - reader.consume("do")?; - let block = reader.take::()?; - reader.consume("end")?; - Ok(Piece::from( - Statement::Iterator(names, expressions, block.it), - &start, - &reader.marker(), - )) - }; - *initial = *reader; - result - } else if let Ok(mut reader) = initial.clone().consume("while") { - let condition = reader.take::()?; - reader.consume("do")?; - let block = reader.take::()?; - reader.consume("end")?; - *initial = *reader; - Ok(Piece::from( - Statement::While(condition, block.it), - &start, - &reader.marker(), - )) - } else if let Ok(mut reader) = initial.clone().consume("if") { - let mut conditions = Vec::new(); - let mut blocks = Vec::new(); - let branch = || -> Result<(), Error> { - conditions.push(reader.take::()?); - reader.consume("then")?; - blocks.push(reader.take::()?.it); - Ok(()) - }; - branch()?; - while reader.consume("elseif").is_ok() { - branch()?; - } - let block = if reader.consume("else").is_ok() { - Some(reader.take::()?.it) - } else { - None - }; - reader.consume("end")?; - *initial = *reader; - Ok(Piece::from( - Statement::If(conditions, blocks, block), - &start, - &reader.marker(), - )) - } else if let Ok(mut reader) = initial.clone().consume("goto") { - let name = reader.take::()?; - *initial = *reader; - Ok(Piece::from(Statement::Goto(name), &start, &reader.marker())) - } else if let Ok(mut reader) = initial.clone().consume("do") { - let block = reader.take::()?; - *initial = *reader; - Ok(Piece::from( - Statement::Do(block.it), - &start, - &reader.marker(), - )) - } else if let Ok(mut reader) = initial.clone().consume("repeat") { - reader.consume("repeat")?; - let block = reader.take::()?; - reader.consume("until")?; - let condition = reader.take::()?; - *initial = *reader; - Ok(Piece::from( - Statement::Repeat(block.it, condition), - &start, - &reader.marker(), - )) - } else if let Ok(mut reader) = initial.clone().consume("::") { - let name = reader.take::()?; - reader.consume("::")?; - *initial = *reader; - Ok(Piece::from( - Statement::Label(name), - &start, - &reader.marker(), - )) - } else { - reader.take::().map(|call| Statement::Call(call)).or_else(|| reader.take::) + fn consume(reader: &mut Reader) -> Result, Error> { + reader.trim()?; + let start = reader.marker(); + // todo: it is safer to pass back the new reader in the Ok, and then map it out + 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; + reader.consume_white("=")?; + let expressions = reader.take::>>()?.it; + *reader = *reader; + 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.it), + &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.it), + &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<(), Error> { + conditions.push(reader.take::()?); + reader.white_consume("then")?; + blocks.push(reader.take::()?.it); + 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::()?.it); + 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, Error> - 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() { - let result = reader.take::>>()?; - reader.consume(";").ok(); - result.it - } else { - Vec::new() - }; - Ok(Piece::from( - Block(statements, expressions), - &start, - &reader.marker(), - )) + fn consume(reader: &mut Reader) -> Result, Error> + 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(); + result.it + } else { + Vec::new() + } + } else { + Vec::new() + }; + Ok(Piece::from( + Block(statements, expressions), + &start, + &reader.marker(), + )) + } } -fn parse(str: &str) -> Result { - Reader::from(str).take::().map(|piece| piece.it) +impl Parse for Chunk { + fn consume(reader: &mut Reader) -> Result, Error> + 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(); + result.it + } else { + Vec::new() + }; + Ok(Piece::from( + Chunk(Piece::from( + Block(statements, expressions), + &start, + &reader.marker(), + )), + &start, + &reader.marker(), + )) + } +} + +fn parse(str: &str) -> Result { + let mut reader = Reader::from(str); + reader.take::().map(|it| it.it) +} + +// COMPILER + +#[derive(Debug)] +struct Table(HashMap, Option>); + +#[derive(Debug, Clone)] +enum Object { + Nil, + Bool(bool), + Number(f64), + Table(Rc), + String(String), + Object(Rc,Option>), +} + +struct Frame<'a> { + begin: Index, // Where this frame begins in the stack (after this) + base: Index, // Where arguments begin (before this) + parent: &'a mut Frame<'a>, +} + +#[derive(Clone)] +enum Register { + Upvalue(Index), + Stack(Index), + Label(Index), + VarArg, +} + +struct Context<'a> { + code: Vec, + symbols: HashMap, + parent: Option<&'a mut Context<'a>>, +} + +impl<'a> Context<'a> { + fn new() -> Context<'a> { + Context { + code: Vec::new(), + symbols: HashMap::new(), + parent: None, + } + } + fn from(&'a mut self) -> Context<'a> { + Context { + code: Vec::new(), + symbols: HashMap::new(), + parent: Some(self) + } + } + fn commit(&mut self) { + + } + fn compile(&mut self, it: &T) -> Result<(), Error> where T: Compile { + it.compile(self) + } + fn function(self) -> Callable { + Callable::Function(self.code) + } +} + +struct Machine { + stack: [Object; 1024], +} + +#[derive(Clone)] +struct Native(Rc Result<(),Error>>); + +impl std::fmt::Debug for Native { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("") + } +} + +#[derive(Debug, Clone)] +enum Callable { + Rust(Native), + Function(Vec), + Closure(Vec,Vec>) +} + +type Index = i16; +type Count = i16; + +#[derive(Debug, Clone)] +enum Literal { + Nil, + Table, + Bool(bool), + Number(f64), + String(String), + Function(Callable), +} + +#[derive(Debug, Clone)] +enum Code { + Call(Callable,Count), + Literal(Literal), + Push(Index), + Binary(BinaryOp), + Unary(UnaryOp), + Up(Index), + Pop(Count), + Jump(Index), + Return(Count), +} + +trait Compile { + fn compile<'a>(&self, context: &mut Context<'a>) -> Result<(),Error>; +} + +impl Compile for Chunk { + fn compile<'a>(&self, context: &mut Context<'a>) -> Result<(), Error> { + Ok(()) + } +} + +impl Machine { + fn load(&self, source: &str) -> Result { + let chunk = parse(source)?; + let mut context = Context::new(); + context.compile(&chunk)?; + Ok(context.function()) + } + fn new() -> Machine { + Machine { + stack: [const {Object::Nil}; 1024] + } + } } #[cfg(test)] mod tests { - use super::*; - #[test] - fn simple() { - println!("{:?}", parse(include_str!("assets/script.lua")).unwrap()); - } -} + use super::*; + #[test] + fn simple() { + let mut machine = Machine::new(); + let result = machine.load(include_str!("assets/script.lua")); + println!("{:#?}", result); + } +} \ No newline at end of file