From f91d5a5091a8ffdfd31de57b2f27622fbaac9dfa Mon Sep 17 00:00:00 2001 From: paladin Date: Thu, 2 Jul 2026 00:43:49 +0100 Subject: [PATCH] Rewriting parser. --- Cargo.lock | 39 -- Cargo.toml | 1 - src/assets/script.lua | 7 + src/engine.rs | 1 - src/lang.rs | 859 +++++++++++++++++++++++------------------- src/lib.rs | 3 +- src/main.rs | 5 +- src/notes/old_lang.rs | 353 +++++++++++++++++ 8 files changed, 832 insertions(+), 436 deletions(-) create mode 100644 src/notes/old_lang.rs diff --git a/Cargo.lock b/Cargo.lock index d23e755..2a3d033 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,15 +358,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "convert_case" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -425,29 +416,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" -[[package]] -name = "derive_more" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", - "unicode-xid", -] - [[package]] name = "dispatch" version = "0.2.0" @@ -609,7 +577,6 @@ dependencies = [ "anyhow", "console_error_panic_hook", "console_log", - "derive_more", "env_logger", "log", "pollster", @@ -1976,12 +1943,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "utf8parse" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 0ae2500..81491de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ log = "0.4" wgpu = "29.0.3" pollster = "0.4.0" console_error_panic_hook = "0.1.7" -derive_more = { version = "2.1.1", features = ["display"] } [target.'cfg(target_arch = "wasm32")'.dependencies] console_error_panic_hook = "0.1.6" diff --git a/src/assets/script.lua b/src/assets/script.lua index e69de29..9aeeb13 100644 --- a/src/assets/script.lua +++ b/src/assets/script.lua @@ -0,0 +1,7 @@ +local all = { ... } +while true do + for index, item in pairs(all) do + dog:log(index, item) + end + return +end \ No newline at end of file diff --git a/src/engine.rs b/src/engine.rs index 31e602a..4806748 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,4 +1,3 @@ -#![recursion_limit = "256"] // Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu use std::sync::Arc; diff --git a/src/lang.rs b/src/lang.rs index 161d86b..4bce7c7 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -1,327 +1,171 @@ -use derive_more::{Display}; +#[derive(Debug, Clone)] +struct Reader<'a> { + slice: &'a str, + full: &'a str, +} -// State of 'cursor' that is reading through the text stream -// todo: implement locations for the 'cursor' through Piece -struct Reader<'a>(&'a str); +#[derive(Debug)] +struct Error(String); + +impl Error { + fn new(message: &str, reader: &Reader) -> Result { + Err(Error(message.to_string())) + } +} + +#[derive(Debug)] struct Piece { - line: usize, index: usize, - column: usize, - piece: T, + width: usize, + it: T, +} + +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 + } + } + fn from(it: T, begin: &Piece, end: &Piece) -> Piece { + Piece { + it, + index: begin.index, + width: end.index + end.width - begin.index + } + } + fn null(&self) -> Piece<()> { + Piece { + it: (), + index: self.index, + width: self.width + } + } } // Strips comments and whitespace -// todo: make this a Option<&str> and handle errors. // todo: implement comments returning for debugging. -fn trim(_str: &str) -> &str { - let str = _str.trim(); - if str.starts_with("--") { - if str[2..].starts_with("[[") { - match str.find("]]") { - Some(i) => { - &str[i+2..].trim() + +impl<'a> From<&'a str> for Reader<'a> { + fn from(str: &'a str) -> Self { + Reader { + full: str, + slice: str + } + } +} + +impl<'a> Reader<'a> { + fn trim(&mut self) -> Result<&Self,Error> { + self.slice = self.slice.trim_start(); + if self.slice.starts_with("--") { + if self.slice[2..].starts_with("[[") { + match self.slice.find("]]") { + Some(i) => { + self.slice = &self.slice[i+2..].trim(); + Ok(self) + } + _ => { + self.error("Unterminated multi-line comment") + } } - _ => { - "" + } else { + if let Some(i) = self.slice.find("\n") { + self.slice = &self.slice[i+1..].trim(); } + Ok(self) } } else { - match str.find("\n") { - Some(i) => { - &str[i+1..].trim() - } - _ => { - "" - } - } + Ok(self) } - } else { - str.trim() + } + 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 { + self.error(format!("Expected '{}'",start).as_str()) + } + } + fn take(&mut self) -> Result,Error> where T: Parse { + self.trim()?; + T::consume(self) + } + fn error(&self, message: &str) -> Result { + Error::new(message,self) + } + fn marker(&self) -> Piece<()> { + Piece::of((),self,0) } } -// Macro for expanding syntax form into a struct -macro_rules! definition { - {@build ($n:ident structure) ($($t:tt)*) null () } => { - #[derive(Display)] - struct $n ($($t)*); - }; - {@build ($n:ident enumeration new ($($f:tt)*) ($m:ident($($mt:tt)*)$($r:tt)*)) () null ()} => { - definition!{@build ($n enumeration ($($f)*) ($m($($mt)*)$($r)*)) () null () $($mt)*} - }; - {@build ($n:ident enumeration ($($f:tt)*) ($m:ident($($mt:tt)*)$($r:tt)*)) ($($t:tt)*) null ()} => { - definition!{@build ($n enumeration new ($($f)*$m($($t)*)) ($($r)*)) () null () } - }; - {@build ($n:ident enumeration new ($($m:ident($($mt:tt)*))*) ()) () null () } => { - definition!{@build ($n enumeration filter () ($($m($($mt)*))*))} - }; - {@build ($n:ident enumeration filter ($($e:tt)*) ($m:ident($($mt:tt)+)$($t:tt)*))} => { - definition!{@build ($n enumeration filter ($($e)*$m($($mt)*),) ($($t)*))} - }; - {@build ($n:ident enumeration filter ($($e:tt)*) ($m:ident()$($t:tt)*))} => { - definition!{@build ($n enumeration filter ($($e)*$m,) ($($t)*))} - }; - {@build ($n:ident enumeration filter ($($e:tt)*) ())} => { - #[derive(Display)] - enum $n { - $($e)* - } - }; - {@build $m:tt ($($t:tt)*) null () $l:literal $($r:tt)*} => { - definition!{@build $m ($($t)*) null () $($r)*} - }; - {@build $m:tt ($($t:tt)*) null () $i:ident $($r:tt)*} => { - definition!{@build $m ($($t)*Box<$i>,) null () $($r)*} - }; - {@build $m:tt ($($t:tt)*) option ($a:tt) () $($r:tt)*} => { - definition!{@build $m ($($t)*Option<$a>,) null () $($r)*} - }; - {@build $m:tt ($($t:tt)*) vector ($a:tt) () $($r:tt)*} => { - definition!{@build $m ($($t)*Vec<$a>,) null () $($r)*} - }; - {@build $m:tt ($($t:tt)*) option ($($a:tt)*) () $($r:tt)*} => { - definition!{@build $m ($($t)*Option<($($a),*)>,) null () $($r)*} - }; - {@build $m:tt ($($t:tt)*) vector ($($a:tt)*) () $($r:tt)*} => { - definition!{@build $m ($($t)*Vec<($($a),*)>,) null () $($r)*} - }; - {@build $m:tt ($($t:tt)*) null () [$($b:tt)*] $($r:tt)*} => { - definition!{@build $m ($($t)*) option () ($($b)*) $($r)*} - }; - {@build $m:tt ($($t:tt)*) null () {$($b:tt)*} $($r:tt)*} => { - definition!{@build $m ($($t)*) vector () ($($b)*) $($r)*} - }; - {@build $m:tt ($($t:tt)*) $i:ident ($($a:tt)*) ($l:literal $($b:tt)*) $($r:tt)*} => { - definition!{@build $m ($($t)*) $i ($($a)*) ($($b)*) $($r)*} - }; - {@build $m:tt ($($t:tt)*) $i:ident ($($a:tt)*) ($n:ident $($b:tt)*) $($r:tt)*} => { - definition!{@build $m ($($t)*) $i ($($a)*$n) ($($b)*) $($r)*} - }; -} -// Macro for expanding syntax form into an implementation of trait Parse -macro_rules! implement { - {@begin $n:ident structure $($t:tt)*} => { - implement!{@build (state result) (structure $n) {} {} $($t)*} - }; - {@begin $n:ident enumeration ($m:ident ($($t2:tt)*)$($t:tt)*)} => { - implement!{@build (state result) (enumeration $m {} ($($t)*) $n) {} {} $($t2)*} - }; - {@build ($st:ident $r:ident) $m:tt $f:tt {$($f2:tt)*} $s:literal $($t:tt)*} => { - implement!{@build ($st $r) $m $f { - $($f2)* - $st = $st.trim_start(); - if $st.starts_with($s) { - $st = &$st[$s.len()..] - } else { - return Err("error".to_string()) - } - } $($t)*} - }; - {@build ($s:ident $r:ident) $m:tt {$($f:tt)*} {$($f2:tt)*} $i:ident $($t:tt)*} => { - implement!{@build ($s $r) $m {$($f)*{$($f2)*}} { - let $r; - match $i::consume($s) { - Ok((r,s)) => { - $s = s; - $r = r; - } - Err(error) => { - return Err(error); - } - } - } $($t)*} - }; - {@build $va:tt ($($m:tt)*) {$($f:tt)*} {$($f2:tt)*} {$($r:tt)*} $($t:tt)*} => { - implement!{@build $va (vector {$($f)*{$($f2)*}} ($($t)*) $($m)*) {} {} $($r)*} - }; - {@build $va:tt ($($m:tt)*) {$($f:tt)*} {$($f2:tt)*} [$($r:tt)*] $($t:tt)*} => { - implement!{@build $va (option {$($f)*{$($f2)*}} ($($t)*) $($m)*) {} {} $($r)*} - }; - {@finish ($s:ident $re:ident) (option {$($l:tt)*} ($($t:tt)*) $($m:tt)*) {{$($f:tt)*}$({$($r:tt)*})*} } => { - implement!{@build ($s $re) ($($m)*) {$($l)*} { - let mut $re; - let taker = move |_state| { - let mut $s: &str = _state; - $($f)* - Ok((( - $({$($r)*$re}),* - ),$s)) - }; - match taker($s) { - Ok((r,s)) => { - $s = s; - $re = Some(r); - } - Err(error) => { - $re = None; - } - } - } $($t)*} - }; - {@finish ($s:ident $re:ident) (vector {$($l:tt)*} ($($t:tt)*) $($m:tt)*) {{$($f:tt)*}$({$($r:tt)*})*} } => { - implement!{@build ($s $re) ($($m)*) {$($l)*} { - let mut $re = Vec::new(); - let taker = move |_state| { - let mut $s: &str = _state; - $($f)* - Ok((( - $({$($r)*$re}),* - ),$s)) - }; - loop { - match taker($s) { - Ok((r,s)) => { - $s = s; - $re.push(r); - } - Err(error) => { - break; - } - }; - } - } $($t)*} - }; - {@build $va:tt $m:tt {$($r:tt)*} $r2:tt} => { - implement!{@finish $va $m {$($r)*$r2}} - }; - {@finish ($s:ident $re:ident) (structure $n:ident) {{$($f:tt)*}$({$($r:tt)*})*} } => { - impl Parse for $n { - fn consume(_state: &str) -> Result<(Self, &str), Error> where Self: Sized { - let mut $s: &str = _state; - $($f)* - Ok(( - $n($({$($r)*$re.into()}),*),$s - )) - } - } - }; - {@finish ($s:ident $re:ident) (enumeration $m2:ident {$($l:tt)*} ($m:ident ($($t2:tt)*)$($t:tt)*) $n:ident) {$f:tt$({$($r:tt)*})+} } => { - implement!{@build ($s $re) (enumeration $m {$($l)*{ - $f - Ok(( - $n::$m2($({$($r)*$re.into()}),+),$s - )) - }} ($($t)*) $n) {} {} $($t2)*} - }; - {@finish ($s:ident $re:ident) (enumeration $m3:ident {$($l:tt)*} ($m:ident ($($t2:tt)*)$($t:tt)*) $n:ident) {$f:tt} } => { - implement!{@build ($s $re) (enumeration $m {$($l)*{ - $f - Ok(( - $n::$m3,$s - )) - }} ($($t)*) $n) {} {} $($t2)*} - }; - {@finish ($s:ident $re:ident) (enumeration $m2:ident {$($l:tt)*} () $n:ident) {$f:tt$({$($r:tt)*})+}} => { - implement!{@finish ($s $re) (enumeration {$($l)*{ - $f - Ok(( - $n::$m2($({$($r)*$re.into()}),+),$s - )) - }} () $n)} // straight to below - }; - {@finish ($s:ident $re:ident) (enumeration $m2:ident {$($l:tt)*} () $n:ident) {$f:tt}} => { - implement!{@finish ($s $re) (enumeration {$($l)*{ - $f - Ok(( - $n::$m2,$s - )) - }} () $n)} // straight to below - }; - {@finish ($s:ident $re:ident) (enumeration {$($f:tt)*} () $n:ident)} => { - impl Parse for $n { - fn consume(_state: &str) -> Result<(Self, &str), Error> where Self: Sized { - let mut $s: &str = _state; - $( - let case = $f; - if case.is_ok() { - return case; - } - )* - Err("error".into()) - } - } - }; -} -macro_rules! class { - ($i:ident($($t:tt)*)) => { - definition!{@build ($i structure) () null () $($t)*} - implement!{@begin $i structure $($t)*} - }; - ($i:ident{$($n:ident($($t:tt)*)),*}) => { - definition!{@build ($i enumeration new () ($($n($($t)*))*)) () null ()} - implement!{@begin $i enumeration ($($n($($t)*))*)} - } -} -macro_rules! parser { - () => {}; - ($i:ident$t:tt;$($tail:tt)*) => { - class!($i$t); - parser!($($tail)*); - }; -} +#[derive(Debug)] struct Number(String); +#[derive(Debug)] struct Name(String); -type Error = 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(state: &str) -> Result<(Self, &str), Error> + fn consume(reader: &mut Reader) -> Result, Error> where Self: Sized; } - impl Parse for Name { - fn consume(_state: &str) -> Result<(Self, &str), Error> + fn consume(reader: &mut Reader) -> Result, Error> where Self: Sized { - let state = _state.trim_start(); - let mut chars = state.chars(); + reader.trim()?; + let mut chars = reader.slice.chars(); let mut end = 1; - match state.chars().next() { + match chars.next() { None => { - return Err("Expected identifier".into()) + return reader.error("Expected identifier"); } Some(c) => { if !(c.is_alphabetic() || c == '_') { - return Err("Identifier must begin with alphabetic character".into()) + return reader.error("Identifier must begin with alphabetic character") } } }; - end += state.chars().take_while(|c| { c.is_alphanumeric() || *c == '_' }).count(); - Ok((Name(state[..end].into()), &state[end..])) + 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 } } - impl Parse for Number { - fn consume(_state: &str) -> Result<(Self, &str), Error> + fn consume(reader: &mut Reader) -> Result, Error> where Self: Sized { - let state = _state.trim_start(); - let error = Err("Could not parse number".into()); - if state.starts_with("0x") { - let end = state[2..].chars().take_while(|c| c.is_digit(16)).count()+2; - if end == 0 { - error - } else { - Ok((Number(state[..end].into()),&state[end..])) - } + 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 { - let end = state.chars().take_while(|c| c.is_digit(10) || *c == '.').count(); - if end == 0 { - error - } else { - Ok((Number(state[..end].into()),&state[end..])) - } + 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(_state: &str) -> Result<(Self, &str), Error> + fn consume(reader: &mut Reader) -> Result, Error> where Self: Sized, { - let state = _state.trim_start(); - let chars: &mut std::str::Chars = &mut state.chars(); + reader.trim()?; + let chars: &mut std::str::Chars = &mut reader.slice.chars(); let mut string = String::new(); let term1: char; let term2: Option; @@ -339,7 +183,7 @@ impl Parse for String { term2 = Some(']'); } _ => { - return Err("Could not parse string".into()) + return reader.error("Could not parse string"); } } loop { @@ -366,12 +210,14 @@ impl Parse for String { } '\r' => {} // todo: ? '\n' if term2.is_none() => { - return Err("Found newline while parsing string".into()) + 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()) { - return Ok((string,chars.as_str())) + 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) @@ -383,122 +229,351 @@ impl Parse for String { } } None => { - return Err("Found EOF while parsing string".into()) + return reader.error("Found EOF while parsing string"); } } } } } -// todo: reimplement attrib here -// https://www.lua.org/manual/5.5/manual.html#9 -parser! { - // LiteralString -> "..." - // LiteralNumber -> 0x... 123.456 - Chunk ( Block ); - Block ( {Statement} [Return Name] ); - Statement { - Semicolon (";"), - Assignment (Variables "=" Expressions), - Call (FunctionCall), - Label (Label), - Break ("break"), - Goto ("goto" Name), - Do ("do" Block "end"), - While ("while" Expression "do" Block "end"), - Repeat ("repeat" Block "until" Expression), - If ("if" Expression "then" Block {"elseif" Expression "then" Block} ["else" Block] "end"), - ForRange ("for" Name "=" Expression "," Expression ["," Expression] "do" Block "end"), - ForIn ("for" Names "in" Expressions "do" Block "end"), - Function ("function" FunctionName FunctionBody), - LocalFunction ("local" "function" Name FunctionBody), - GlobalFunction ("global" "function" Name FunctionBody), - Declaration ("local" Names ["=" Expressions]), - Global ("global" Names) - }; - Return( "return" [Expressions] [";"] ); - Label( "::" Name "::" ); - FunctionName( Name {"." Name} [":" Name] ); - Variables( Variable {"," Variable} ); - Variable { - Name (Name), - Index (PrefixExpression "[" Expression "]"), - DotIndex (PrefixExpression "." Name) - }; - Names( Name {"," Name} ); - Expressions( Expression {"," Expression} ); - Expression { - Nil ("nil"), - False ("false"), - True ("true"), - Number (Number), - String (String), - VarArg ("..."), - FunctionDef (FunctionDef), - PrefixExpression (PrefixExpression), - Table (Table), - Binary (Expression BinaryOp Expression), - Unary (UnaryOp Expression) - }; - PrefixExpression { - Variable (Variable), - Call (FunctionCall), - Expression ("(" Expression ")") - }; - FunctionCall { - Normal (PrefixExpression Arguments), - Instanced (PrefixExpression ":" Name Arguments) - }; - Arguments { - Expressions ("(" [Expressions] ")"), - Table (Table), - String (String) - }; - FunctionDef( "function" FunctionBody ); - FunctionBody( "(" [Parameters] ")" Block "end" ); - Parameters { - Names (Names ["," VarArg]), - VarArg (VarArg) - }; - VarArg( "..." [Name] ); - Table( "{" [Fields] "}" ); - Fields( Field {FieldSep Field} [FieldSep] ); - Field { - ExpressionIndex ("[" Expression "]" "=" Expression), - Name (Name "=" Expression), - Expression (Expression) - }; - FieldSep { - Comma (","), - Semicolon (";") - }; - BinaryOp { - Plus ("+"), - Minus ("-"), - Mul ("*"), - Divide ("/"), - DivFloor ("//"), - Caret ("^"), - Modulo ("%"), - Ampersand ("&"), - Tilde ("~"), - Pipe ("|"), - ShiftRight (">>"), - ShiftLeft ("<<"), - Concat (".."), - Less ("<"), - LessEqual ("<="), - Greater (">"), - GreatEqual (">="), - Equivalent ("=="), - NotEqual ("~="), - And ("and"), - Or ("or") - }; - UnaryOp { - Negate ("-"), - Not ("!"), - Ampersand ("#"), - Tilde ("~") - }; +// AST +#[derive(Debug)] +struct Block(Vec>); +#[derive(Debug)] +enum Statement { + Semicolon, + Assignment(Vec>,Vec>), + Call(Call), + Label(Piece), + Break, + Continue, + Return(Vec>), + 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) +} +#[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) +} +#[derive(Debug)] +enum Prefix { + Variable(Variable), + Call(Call), + Expression(Expression), +} +#[derive(Debug)] +struct VarArg(Option); +#[derive(Debug)] +struct Call(Option,Vec); +#[derive(Debug)] +struct Function(Vec>,Option>,Piece); +#[derive(Debug)] +struct Field(Option,Expression); +#[derive(Debug)] +enum FieldSep { + Comma, + Semicolon +} +#[derive(Debug)] +enum BinaryOp { + Plus, + Minus, + Mul, + Divide, + DivFloor, + Caret, + Modulo, + Ampersand, + Tilde, + Pipe, + ShiftRight, + ShiftLeft, + Concat, + Less, + LessEqual, + Greater, + GreatEqual, + Equivalent, + NotEqual, + And, + Or +} +#[derive(Debug)] +enum UnaryOp { + Negate, + Not, + Ampersand, + Tilde +} + +impl Parse for Vec> { + fn consume(reader: &mut Reader) -> Result>>, Error> + where + Self: Sized, + { + let result: Vec> = Vec::new(); + reader.trim()?; + loop { + if let Ok(it) = reader.take::() { + 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)) + } +} + +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 { + reader.trim()?; + if let Ok(name) = reader.take::() { + parameters.push(name); + reader.trim()?; + if vararg.is_some() { + return reader.error("Unexpected argument after vararg '...'") + } + if !reader.consume(",").is_ok() { + break + } + } + vararg = reader.take::().ok() + } + reader.trim()?; + reader.consume(")")?; + reader.trim()?; + let end = reader.marker(); + let block = reader.take::()?; + 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)) + } + } +} + +impl Parse for Expression { + fn consume(reader: &mut Reader) -> Result, Error> { + + } +} + +// todo: WHY am i trimming everywhere... fix ts; its handled in take and consume already, comments can be stored in piece +impl Parse for Statement { + fn consume(mut reader: &mut Reader) -> Result, Error> { + reader.trim()?; + let start = reader.marker(); + let restore = |new: &mut Reader| { + reader = new + }; + if reader.consume("break").is_ok() { + Ok(Piece::from(Statement::Break,&start,&reader.marker())) + } else if reader.consume("continue").is_ok() { + Ok(Piece::from(Statement::Continue,&start,&reader.marker())) + } else if reader.consume(";").is_ok() { + Ok(Piece::from(Statement::Semicolon,&start,&reader.marker())) + } else if let Ok(mut reader) = reader.consume("local").cloned() { + reader.trim()?; + if reader.consume("function").is_ok() { + reader.trim()?; + let name = reader.take::()?; + reader.trim()?; + let function = reader.take::()?; + restore(&mut reader); + Ok(Piece::from(Statement::LocalFunction(name, function.it), &start, &function.null())) + } else { + let names = reader.take::>>()?.it; + reader.trim()?; + reader.consume("=")?; + reader.trim()?; + let expressions = reader.take::>>()?.it; + restore(&mut reader); + Ok(Piece::from(Statement::Declaration(names,expressions),&start,&reader.marker())) + } + } else if let Ok(mut reader) = reader.consume("function") { + let mut names = Vec::new(); + loop { + reader.trim()?; + if let Ok(name) = reader.take::() { + names.push(name); + reader.trim()?; + if !reader.consume(".").is_ok() { + break + } + } + } + let mut member = None; + if reader.consume(":").is_ok() { + reader.trim()?; + member = Some(reader.take::()?); + } + let function = reader.take::()?; + restore(&mut reader); + Ok(Piece::from(Statement::Function(names,member,function.it),&start,&reader.marker())) + } else if let Ok(mut reader) = reader.consume("for") { + reader.trim()?; + let names = reader.take::>>()?.it; reader.trim()?; + let result = if names.len() > 1 { + let name = *names.first().unwrap().clone(); + reader.consume("=")?; reader.trim()?; + let begin = reader.take::()?; reader.trim()?; + reader.consume(",")?; reader.trim()?; + let finish = reader.take::()?; reader.trim()?; + let delta = if reader.consume(",").is_ok() { + reader.trim()?; + Some(reader.take::()?) + } else { + None + }; + reader.consume("do")?; reader.trim()?; + let block = reader.take::()?; reader.trim()?; + reader.consume("end")?; + Ok(Piece::from(Statement::Range(name,begin,finish,delta,block.it),&start,&reader.marker())) + } else { + reader.consume("in")?; reader.trim()?; + let expressions = reader.take::>>()?.it; reader.trim()?; + reader.consume("do")?; reader.trim()?; + let block = reader.take::()?; reader.trim()?; + reader.consume("end")?; + Ok(Piece::from(Statement::Iterator(names,expressions,block.it),&start,&reader.marker())) + }; + restore(&mut reader); + result + } else if let Ok(mut reader) = reader.consume("while") { + reader.trim()?; + let condition = reader.take::()?; + reader.consume("do")?; reader.trim()?; + let block = reader.take::()?; reader.trim()?; + reader.consume("end")?; + restore(&mut reader); + Ok(Piece::from(Statement::While(condition,block.it),&start,&reader.marker())) + } else if let Ok(mut reader) = reader.consume("if") { + reader.trim()?; + let mut conditions = Vec::new(); + let mut blocks = Vec::new(); + let branch = || -> Result<(),Error> { + conditions.push(reader.take::()?); reader.trim()?; + reader.consume("then")?; reader.trim()?; + blocks.push(reader.take::()?.it); + Ok(()) + }; + branch()?; + while reader.consume("elseif").is_ok() { + reader.trim()?; + branch()?; + } + let block = if reader.consume("else").is_ok() { + reader.trim()?; + Some(reader.take::()?.it) + } else { + None + }; + reader.consume("end")?; + restore(&mut reader); + Ok(Piece::from(Statement::If(conditions,blocks,block),&start,&reader.marker())) + } else if let Ok(mut reader) = reader.consume("goto") { + reader.trim()?; + let name = reader.take::()?; + restore(&mut reader); + Ok(Piece::from(Statement::Goto(name),&start,&reader.marker())) + } else if let Ok(mut reader) = reader.consume("do") { + reader.trim()?; + let block = reader.take::()?; + restore(&mut reader); + Ok(Piece::from(Statement::Do(block.it),&start,&reader.marker())) + } else if let Ok(mut reader) = reader.consume("repeat") { + reader.trim()?; + reader.consume("repeat")?; reader.trim()?; + let block = reader.take::()?; reader.trim()?; + reader.consume("until")?; reader.trim()?; + let condition = reader.take::()?; + restore(&mut reader); + Ok(Piece::from(Statement::Repeat(block.it,condition),&start,&reader.marker())) + } else if let Ok(mut reader) = reader.consume("::") { + let name = reader.take::()?; + reader.consume("::")?; + restore(&mut reader); + Ok(Piece::from(Statement::Label(name),&start,&reader.marker())) + } else if let Ok(mut reader) = + } +} + +impl Parse for Block { + fn consume(reader: &mut Reader) -> Result, Error> + where + Self: Sized + { + let mut statements = Vec::new(); + while let Ok(statement) = reader.take::() { + statements.push(statement); + } + if statements.is_empty() { + Ok(Piece::of(Block(statements),reader,0)) + } else { + let first = statements.first().unwrap().null(); + let last = statements.last().unwrap().null(); + Ok(Piece::from(Block(statements),&first,&last)) + } + } +} + +fn parse(str: &str) -> Result { + Reader::from(str).take::().map(|piece| piece.it) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn simple() { + println!("{:?}",parse(include_str!("assets/script.lua")).unwrap()); + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 159e22c..911bacc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ +#![recursion_limit = "256"] pub mod engine; -mod lang; \ No newline at end of file +pub mod lang; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2cce76f..758c277 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ #![recursion_limit = "256"] -use game::engine::run; +use game::*; fn main() { - run().unwrap(); + + //engine::run().unwrap(); } diff --git a/src/notes/old_lang.rs b/src/notes/old_lang.rs new file mode 100644 index 0000000..afa743d --- /dev/null +++ b/src/notes/old_lang.rs @@ -0,0 +1,353 @@ +// Macro for expanding syntax form into a struct +macro_rules! definition { + {@build ($n:ident structure) ($($t:tt)*) null () } => { + #[allow(unused)] + #[derive(Debug)] + struct $n ($($t)*); + }; + {@build ($n:ident enumeration new ($($f:tt)*) ($m:ident($($mt:tt)*)$($r:tt)*)) () null ()} => { + definition!{@build ($n enumeration ($($f)*) ($m($($mt)*)$($r)*)) () null () $($mt)*} + }; + {@build ($n:ident enumeration ($($f:tt)*) ($m:ident($($mt:tt)*)$($r:tt)*)) ($($t:tt)*) null ()} => { + definition!{@build ($n enumeration new ($($f)*$m($($t)*)) ($($r)*)) () null () } + }; + {@build ($n:ident enumeration new ($($m:ident($($mt:tt)*))*) ()) () null () } => { + definition!{@build ($n enumeration filter () ($($m($($mt)*))*))} + }; + {@build ($n:ident enumeration filter ($($e:tt)*) ($m:ident($($mt:tt)+)$($t:tt)*))} => { + definition!{@build ($n enumeration filter ($($e)*$m($($mt)*),) ($($t)*))} + }; + {@build ($n:ident enumeration filter ($($e:tt)*) ($m:ident()$($t:tt)*))} => { + definition!{@build ($n enumeration filter ($($e)*$m,) ($($t)*))} + }; + {@build ($n:ident enumeration filter ($($e:tt)*) ())} => { + #[allow(unused)] + #[derive(Debug)] + enum $n { + $($e)* + } + }; + {@build $m:tt ($($t:tt)*) null () $l:literal $($r:tt)*} => { + definition!{@build $m ($($t)*) null () $($r)*} + }; + {@build $m:tt ($($t:tt)*) null () $i:ident $($r:tt)*} => { + definition!{@build $m ($($t)*Box<$i>,) null () $($r)*} + }; + {@build $m:tt ($($t:tt)*) option ($a:tt) () $($r:tt)*} => { + definition!{@build $m ($($t)*Option<$a>,) null () $($r)*} + }; + {@build $m:tt ($($t:tt)*) vector ($a:tt) () $($r:tt)*} => { + definition!{@build $m ($($t)*Vec<$a>,) null () $($r)*} + }; + {@build $m:tt ($($t:tt)*) option ($($a:tt)*) () $($r:tt)*} => { + definition!{@build $m ($($t)*Option<($($a),*)>,) null () $($r)*} + }; + {@build $m:tt ($($t:tt)*) vector ($($a:tt)*) () $($r:tt)*} => { + definition!{@build $m ($($t)*Vec<($($a),*)>,) null () $($r)*} + }; + {@build $m:tt ($($t:tt)*) null () [$($b:tt)*] $($r:tt)*} => { + definition!{@build $m ($($t)*) option () ($($b)*) $($r)*} + }; + {@build $m:tt ($($t:tt)*) null () {$($b:tt)*} $($r:tt)*} => { + definition!{@build $m ($($t)*) vector () ($($b)*) $($r)*} + }; + {@build $m:tt ($($t:tt)*) $i:ident ($($a:tt)*) ($l:literal $($b:tt)*) $($r:tt)*} => { + definition!{@build $m ($($t)*) $i ($($a)*) ($($b)*) $($r)*} + }; + {@build $m:tt ($($t:tt)*) $i:ident ($($a:tt)*) ($n:ident $($b:tt)*) $($r:tt)*} => { + definition!{@build $m ($($t)*) $i ($($a)*$n) ($($b)*) $($r)*} + }; +} +macro_rules! implement { + {@begin $n:ident structure $($t:tt)*} => { + implement!{@build (state result) (structure $n) {} {} $($t)*} + }; + {@begin $n:ident enumeration ($m:ident ($($t2:tt)*)$($t:tt)*)} => { + implement!{@build (state result) (enumeration $m {} ($($t)*) $n) {} {} $($t2)*} + }; + {@build ($st:ident $r:ident) $m:tt $f:tt {$($f2:tt)*} $s:literal $($t:tt)*} => { + implement!{@build ($st $r) $m $f { + $($f2)* + $st = $st.trim_start(); + if $st.starts_with($s) { + $st = &$st[$s.len()..] + } else { + return Err("error".to_string()) + } + } $($t)*} + }; + {@build ($s:ident $r:ident) $m:tt {$($f:tt)*} {$($f2:tt)*} $i:ident $($t:tt)*} => { + implement!{@build ($s $r) $m {$($f)*{$($f2)*}} { + let $r; + match $i::consume($s) { + Ok((r,s)) => { + $s = s; + $r = r; + } + Err(error) => { + return Err(error); + } + } + } $($t)*} + }; + {@build $va:tt ($($m:tt)*) {$($f:tt)*} {$($f2:tt)*} {$($r:tt)*} $($t:tt)*} => { + implement!{@build $va (vector {$($f)*{$($f2)*}} ($($t)*) $($m)*) {} {} $($r)*} + }; + {@build $va:tt ($($m:tt)*) {$($f:tt)*} {$($f2:tt)*} [$($r:tt)*] $($t:tt)*} => { + implement!{@build $va (option {$($f)*{$($f2)*}} ($($t)*) $($m)*) {} {} $($r)*} + }; + {@finish ($s:ident $re:ident) (option {$($l:tt)*} ($($t:tt)*) $($m:tt)*) {{$($f:tt)*}$({$($r:tt)*})*} } => { + implement!{@build ($s $re) ($($m)*) {$($l)*} { + let mut $re; + let taker = move |_state| { + let mut $s: &str = _state; + $($f)* + Ok((( + $({$($r)*$re}),* + ),$s)) + }; + match taker($s) { + Ok((r,s)) => { + $s = s; + $re = Some(r); + } + Err(_) => { + $re = None; + } + } + } $($t)*} + }; + {@finish ($s:ident $re:ident) (vector {$($l:tt)*} ($($t:tt)*) $($m:tt)*) {{$($f:tt)*}$({$($r:tt)*})*} } => { + implement!{@build ($s $re) ($($m)*) {$($l)*} { + let mut $re = Vec::new(); + let taker = move |_state| { + let mut $s: &str = _state; + $($f)* + Ok((( + $({$($r)*$re}),* + ),$s)) + }; + while !$s.is_empty() { + match taker($s) { + Ok((r,s)) => { + $s = s; + $re.push(r); + } + Err(error) => { + break; + } + }; + } + } $($t)*} + }; + {@build $va:tt $m:tt {$($r:tt)*} $r2:tt} => { + implement!{@finish $va $m {$($r)*$r2}} + }; + {@finish ($s:ident $re:ident) (structure $n:ident) {{$($f:tt)*}$({$($r:tt)*})*} } => { + #[allow(unused)] + impl Parse for $n { + fn consume(_state: &str) -> Result<(Self, &str), Error> where Self: Sized { + let mut $s: &str = _state; + $($f)* + Ok(( + $n($({$($r)*$re.into()}),*),$s + )) + } + } + }; + {@finish ($s:ident $re:ident) (enumeration $m2:ident {$($l:tt)*} ($m:ident ($($t2:tt)*)$($t:tt)*) $n:ident) {$f:tt$({$($r:tt)*})+} } => { + implement!{@build ($s $re) (enumeration $m {$($l)*{ + $f + Ok(( + $n::$m2($({$($r)*$re.into()}),+),$s + )) + }} ($($t)*) $n) {} {} $($t2)*} + }; + {@finish ($s:ident $re:ident) (enumeration $m3:ident {$($l:tt)*} ($m:ident ($($t2:tt)*)$($t:tt)*) $n:ident) {$f:tt} } => { + implement!{@build ($s $re) (enumeration $m {$($l)*{ + $f + Ok(( + $n::$m3,$s + )) + }} ($($t)*) $n) {} {} $($t2)*} + }; + {@finish ($s:ident $re:ident) (enumeration $m2:ident {$($l:tt)*} () $n:ident) {$f:tt$({$($r:tt)*})+}} => { + implement!{@finish ($s $re) (enumeration {$($l)*{ + $f + Ok(( + $n::$m2($({$($r)*$re.into()}),+),$s + )) + }} () $n)} // straight to below + }; + {@finish ($s:ident $re:ident) (enumeration $m2:ident {$($l:tt)*} () $n:ident) {$f:tt}} => { + implement!{@finish ($s $re) (enumeration {$($l)*{ + $f + Ok(( + $n::$m2,$s + )) + }} () $n)} // straight to below + }; + {@finish ($s:ident $re:ident) (enumeration {$({$($f:tt)*})*} () $n:ident)} => { + #[allow(unused)] + impl Parse for $n { + fn consume(_state: &str) -> Result<(Self, &str), Error> where Self: Sized { + let mut $s: &str = _state; + $( + let case = (||{ + let mut state: &str = _state; + $($f)* + })(); // put it into a closure and run it (makes returning easier) + if case.is_ok() { + return case; + } + )* + Err("error".into()) + } + } + }; +} +macro_rules! class { + ($i:ident($($t:tt)*)) => { + definition!{@build ($i structure) () null () $($t)*} + implement!{@begin $i structure $($t)*} + //display!{@begin $i structure $($t)*} + }; + ($i:ident{$($n:ident($($t:tt)*)),*}) => { + definition!{@build ($i enumeration new () ($($n($($t)*))*)) () null ()} + implement!{@begin $i enumeration ($($n($($t)*))*)} + //display!{@begin $i enumeration ($($n($($t)*))*)} + } +} +macro_rules! parser { + () => {}; + ($i:ident$t:tt;$($tail:tt)*) => { + class!($i$t); + parser!($($tail)*); + }; +} + +// todo: reimplement attrib here +// https://www.lua.org/manual/5.5/manual.html#9 +parser!{ + // LiteralString -> "..." + // LiteralNumber -> 0x... 123.456 + Chunk ( Block ); + Block ( {Statement} [Return] ); + Statement { + Semicolon (";"), + Assignment (Variables "=" Expressions), + Call (RootAtom CallChain), + Label (Label), + Break ("break"), + Goto ("goto" Name), + Do ("do" Block "end"), + While ("while" Expression "do" Block "end"), + Repeat ("repeat" Block "until" Expression), + If ("if" Expression "then" Block {"elseif" Expression "then" Block} ["else" Block] "end"), + ForRange ("for" Name "=" Expression "," Expression ["," Expression] "do" Block "end"), + ForIn ("for" Names "in" Expressions "do" Block "end"), + Function ("function" FunctionName FunctionBody), + LocalFunction ("local" "function" Name FunctionBody), + GlobalFunction ("global" "function" Name FunctionBody), + Declaration ("local" Names ["=" Expressions]), + Global ("global" Names) + }; + Return( "return" [Expressions] [";"] ); + Label( "::" Name "::" ); + FunctionName( Name {"." Name} [":" Name] ); + Variables( Variable {"," Variable} ); + Names( Name {"," Name} ); + Expressions( Expression {"," Expression} ); + // DEVIATION: This parser is greedy, so the manual's syntax breaks it. + RootAtom { + Variable (Name), + Expression ("(" Expression ")") + }; + IndexAtom { + Dot ("." Name), + Index ("[" Expression "]") + }; + CallAtom { + Normal (Arguments), + Method (":" Name Arguments) + }; + PrefixAtom { + Call (CallAtom), + Index (IndexAtom) + }; + VariableChain { + Link (PrefixAtom VariableChain), + Finish (IndexAtom) + }; + CallChain { + Link (PrefixAtom CallChain), + Finish (CallAtom) + }; + Variable (RootAtom VariableChain); + Expression { + Nil ("nil"), + False ("false"), + True ("true"), + VarArg ("..."), + Number (Number), + String (String), + FunctionDef (FunctionDef), + Prefix (RootAtom {PrefixAtom}), + Table (Table), + Binary (Expression BinaryOp Expression), // todo: . + Unary (UnaryOp Expression) + }; + // ----------------------- + Arguments { + Expressions ("(" [Expressions] ")"), + Table (Table), + String (String) + }; + FunctionDef( "function" FunctionBody ); + FunctionBody( "(" [Parameters] ")" Block "end" ); + Parameters { + Names (Names ["," VarArg]), + VarArg (VarArg) + }; + VarArg( "..." [Name] ); + Table( "{" [Fields] "}" ); + Fields( Field {FieldSep Field} [FieldSep] ); + Field { + ExpressionIndex ("[" Expression "]" "=" Expression), + Name (Name "=" Expression), + Expression (Expression) + }; + FieldSep { + Comma (","), + Semicolon (";") + }; + BinaryOp { + Plus ("+"), + Minus ("-"), + Mul ("*"), + Divide ("/"), + DivFloor ("//"), + Caret ("^"), + Modulo ("%"), + Ampersand ("&"), + Tilde ("~"), + Pipe ("|"), + ShiftRight (">>"), + ShiftLeft ("<<"), + Concat (".."), + Less ("<"), + LessEqual ("<="), + Greater (">"), + GreatEqual (">="), + Equivalent ("=="), + NotEqual ("~="), + And ("and"), + Or ("or") + }; + UnaryOp { + Negate ("-"), + Not ("not"), + Ampersand ("#"), + Tilde ("~") + }; +} \ No newline at end of file