Rewriting parser.
This commit is contained in:
Generated
-39
@@ -358,15 +358,6 @@ dependencies = [
|
|||||||
"web-sys",
|
"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]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
@@ -425,29 +416,6 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
|
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]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -609,7 +577,6 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"console_log",
|
"console_log",
|
||||||
"derive_more",
|
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
"pollster",
|
"pollster",
|
||||||
@@ -1976,12 +1943,6 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ log = "0.4"
|
|||||||
wgpu = "29.0.3"
|
wgpu = "29.0.3"
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
console_error_panic_hook = "0.1.7"
|
console_error_panic_hook = "0.1.7"
|
||||||
derive_more = { version = "2.1.1", features = ["display"] }
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
console_error_panic_hook = "0.1.6"
|
console_error_panic_hook = "0.1.6"
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
local all = { ... }
|
||||||
|
while true do
|
||||||
|
for index, item in pairs(all) do
|
||||||
|
dog:log(index, item)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
@@ -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
|
// Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|||||||
+467
-392
@@ -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
|
#[derive(Debug)]
|
||||||
// todo: implement locations for the 'cursor' through Piece<T>
|
struct Error(String);
|
||||||
struct Reader<'a>(&'a str);
|
|
||||||
|
impl Error {
|
||||||
|
fn new<T>(message: &str, reader: &Reader) -> Result<T,Error> {
|
||||||
|
Err(Error(message.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Piece<T> {
|
struct Piece<T> {
|
||||||
line: usize,
|
|
||||||
index: usize,
|
index: usize,
|
||||||
column: usize,
|
width: usize,
|
||||||
piece: T,
|
it: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Piece<T> {
|
||||||
|
fn of(it: T, reader: &Reader, width: usize) -> Piece<T> {
|
||||||
|
Piece {
|
||||||
|
it,
|
||||||
|
index: reader.slice.as_ptr() as usize - reader.full.as_ptr() as usize,
|
||||||
|
width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn from<A,B>(it: T, begin: &Piece<A>, end: &Piece<B>) -> Piece<T> {
|
||||||
|
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
|
// Strips comments and whitespace
|
||||||
// todo: make this a Option<&str> and handle errors.
|
|
||||||
// todo: implement comments returning for debugging.
|
// todo: implement comments returning for debugging.
|
||||||
fn trim(_str: &str) -> &str {
|
|
||||||
let str = _str.trim();
|
impl<'a> From<&'a str> for Reader<'a> {
|
||||||
if str.starts_with("--") {
|
fn from(str: &'a str) -> Self {
|
||||||
if str[2..].starts_with("[[") {
|
Reader {
|
||||||
match str.find("]]") {
|
full: str,
|
||||||
Some(i) => {
|
slice: str
|
||||||
&str[i+2..].trim()
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
match str.find("\n") {
|
Ok(self)
|
||||||
Some(i) => {
|
|
||||||
&str[i+1..].trim()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} 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<T>(&mut self) -> Result<Piece<T>,Error> where T: Parse {
|
||||||
|
self.trim()?;
|
||||||
|
T::consume(self)
|
||||||
|
}
|
||||||
|
fn error<T>(&self, message: &str) -> Result<T,Error> {
|
||||||
|
Error::new(message,self)
|
||||||
|
}
|
||||||
|
fn marker(&self) -> Piece<()> {
|
||||||
|
Piece::of((),self,0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Macro for expanding syntax form into a struct
|
#[derive(Debug)]
|
||||||
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)*);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
struct Number(String);
|
struct Number(String);
|
||||||
|
#[derive(Debug)]
|
||||||
struct Name(String);
|
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 {
|
trait Parse {
|
||||||
fn consume(state: &str) -> Result<(Self, &str), Error>
|
fn consume(reader: &mut Reader) -> Result<Piece<Self>, Error>
|
||||||
where Self: Sized;
|
where Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Name {
|
impl Parse for Name {
|
||||||
fn consume(_state: &str) -> Result<(Self, &str), Error>
|
fn consume(reader: &mut Reader) -> Result<Piece<Self>, Error>
|
||||||
where
|
where
|
||||||
Self: Sized
|
Self: Sized
|
||||||
{
|
{
|
||||||
let state = _state.trim_start();
|
reader.trim()?;
|
||||||
let mut chars = state.chars();
|
let mut chars = reader.slice.chars();
|
||||||
let mut end = 1;
|
let mut end = 1;
|
||||||
match state.chars().next() {
|
match chars.next() {
|
||||||
None => {
|
None => {
|
||||||
return Err("Expected identifier".into())
|
return reader.error("Expected identifier");
|
||||||
}
|
}
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
if !(c.is_alphabetic() || 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();
|
end += chars.take_while(|c| { c.is_alphanumeric() || *c == '_' }).count();
|
||||||
Ok((Name(state[..end].into()), &state[end..]))
|
let result = Ok(Piece::of(Name(reader.slice[..end].to_string()),reader,end));
|
||||||
|
reader.slice = &reader.slice[end..];
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Number {
|
impl Parse for Number {
|
||||||
fn consume(_state: &str) -> Result<(Self, &str), Error>
|
fn consume(reader: &mut Reader) -> Result<Piece<Number>, Error>
|
||||||
where
|
where
|
||||||
Self: Sized
|
Self: Sized
|
||||||
{
|
{
|
||||||
let state = _state.trim_start();
|
reader.trim()?;
|
||||||
let error = Err("Could not parse number".into());
|
let mut end;
|
||||||
if state.starts_with("0x") {
|
if reader.slice.starts_with("0x") {
|
||||||
let end = state[2..].chars().take_while(|c| c.is_digit(16)).count()+2;
|
end = reader.slice[2..].chars().take_while(|c| c.is_digit(16)).count()+2;
|
||||||
if end == 0 {
|
if end == 2 { end = 0 }
|
||||||
error
|
|
||||||
} else {
|
|
||||||
Ok((Number(state[..end].into()),&state[end..]))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let end = state.chars().take_while(|c| c.is_digit(10) || *c == '.').count();
|
end = reader.slice.chars().take_while(|c| c.is_digit(10) || *c == '.').count();
|
||||||
if end == 0 {
|
}
|
||||||
error
|
if end == 0 {
|
||||||
} else {
|
reader.error("Could not parse number".into())
|
||||||
Ok((Number(state[..end].into()),&state[end..]))
|
} else {
|
||||||
}
|
reader.slice = &reader.slice[end..];
|
||||||
|
Ok(Piece::of(Number(reader.slice[..end].to_string()),reader,end))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for String {
|
impl Parse for String {
|
||||||
fn consume(_state: &str) -> Result<(Self, &str), Error>
|
fn consume(reader: &mut Reader) -> Result<Piece<String>, Error>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let state = _state.trim_start();
|
reader.trim()?;
|
||||||
let chars: &mut std::str::Chars = &mut state.chars();
|
let chars: &mut std::str::Chars = &mut reader.slice.chars();
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
let term1: char;
|
let term1: char;
|
||||||
let term2: Option<char>;
|
let term2: Option<char>;
|
||||||
@@ -339,7 +183,7 @@ impl Parse for String {
|
|||||||
term2 = Some(']');
|
term2 = Some(']');
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err("Could not parse string".into())
|
return reader.error("Could not parse string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
@@ -366,12 +210,14 @@ impl Parse for String {
|
|||||||
}
|
}
|
||||||
'\r' => {} // todo: ?
|
'\r' => {} // todo: ?
|
||||||
'\n' if term2.is_none() => {
|
'\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 => {
|
term if term == term1 => {
|
||||||
// If the second terminator exists and is the next char, or there is no second terminator
|
// 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()) {
|
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
|
// There is a second terminator and it wasn't the next char
|
||||||
} else {
|
} else {
|
||||||
string.push(term)
|
string.push(term)
|
||||||
@@ -383,122 +229,351 @@ impl Parse for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return Err("Found EOF while parsing string".into())
|
return reader.error("Found EOF while parsing string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: reimplement attrib here
|
// AST
|
||||||
// https://www.lua.org/manual/5.5/manual.html#9
|
#[derive(Debug)]
|
||||||
parser! {
|
struct Block(Vec<Piece<Statement>>);
|
||||||
// LiteralString -> "..."
|
#[derive(Debug)]
|
||||||
// LiteralNumber -> 0x... 123.456
|
enum Statement {
|
||||||
Chunk ( Block );
|
Semicolon,
|
||||||
Block ( {Statement} [Return Name] );
|
Assignment(Vec<Piece<Variable>>,Vec<Piece<Expression>>),
|
||||||
Statement {
|
Call(Call),
|
||||||
Semicolon (";"),
|
Label(Piece<Name>),
|
||||||
Assignment (Variables "=" Expressions),
|
Break,
|
||||||
Call (FunctionCall),
|
Continue,
|
||||||
Label (Label),
|
Return(Vec<Piece<Expression>>),
|
||||||
Break ("break"),
|
Goto(Piece<Name>),
|
||||||
Goto ("goto" Name),
|
Do(Block),
|
||||||
Do ("do" Block "end"),
|
While(Piece<Expression>,Block),
|
||||||
While ("while" Expression "do" Block "end"),
|
Repeat(Block,Piece<Expression>),
|
||||||
Repeat ("repeat" Block "until" Expression),
|
If(Vec<Piece<Expression>>,Vec<Block>,Option<Block>),
|
||||||
If ("if" Expression "then" Block {"elseif" Expression "then" Block} ["else" Block] "end"),
|
Range(Piece<Name>,Piece<Expression>,Piece<Expression>,Option<Piece<Expression>>,Block),
|
||||||
ForRange ("for" Name "=" Expression "," Expression ["," Expression] "do" Block "end"),
|
Iterator(Vec<Piece<Name>>,Vec<Piece<Expression>>,Block),
|
||||||
ForIn ("for" Names "in" Expressions "do" Block "end"),
|
Function(Vec<Piece<Name>>,Option<Piece<Name>>,Function),
|
||||||
Function ("function" FunctionName FunctionBody),
|
LocalFunction(Piece<Name>,Function),
|
||||||
LocalFunction ("local" "function" Name FunctionBody),
|
Declaration(Vec<Piece<Name>>,Vec<Piece<Expression>>)
|
||||||
GlobalFunction ("global" "function" Name FunctionBody),
|
}
|
||||||
Declaration ("local" Names ["=" Expressions]),
|
#[derive(Debug)]
|
||||||
Global ("global" Names)
|
enum Variable {
|
||||||
};
|
Name(Name),
|
||||||
Return( "return" [Expressions] [";"] );
|
Index(Box<Prefix>,Box<Expression>)
|
||||||
Label( "::" Name "::" );
|
}
|
||||||
FunctionName( Name {"." Name} [":" Name] );
|
#[derive(Debug)]
|
||||||
Variables( Variable {"," Variable} );
|
enum Expression {
|
||||||
Variable {
|
Nil,
|
||||||
Name (Name),
|
True,
|
||||||
Index (PrefixExpression "[" Expression "]"),
|
False,
|
||||||
DotIndex (PrefixExpression "." Name)
|
Number(Number),
|
||||||
};
|
String(String),
|
||||||
Names( Name {"," Name} );
|
VarArg(VarArg),
|
||||||
Expressions( Expression {"," Expression} );
|
Function(Function),
|
||||||
Expression {
|
Prefix(Box<Prefix>),
|
||||||
Nil ("nil"),
|
Table(Vec<Field>),
|
||||||
False ("false"),
|
Binary(Box<Expression>,BinaryOp,Box<Expression>),
|
||||||
True ("true"),
|
Unary(UnaryOp,Box<Expression>)
|
||||||
Number (Number),
|
}
|
||||||
String (String),
|
#[derive(Debug)]
|
||||||
VarArg ("..."),
|
enum Prefix {
|
||||||
FunctionDef (FunctionDef),
|
Variable(Variable),
|
||||||
PrefixExpression (PrefixExpression),
|
Call(Call),
|
||||||
Table (Table),
|
Expression(Expression),
|
||||||
Binary (Expression BinaryOp Expression),
|
}
|
||||||
Unary (UnaryOp Expression)
|
#[derive(Debug)]
|
||||||
};
|
struct VarArg(Option<Name>);
|
||||||
PrefixExpression {
|
#[derive(Debug)]
|
||||||
Variable (Variable),
|
struct Call(Option<Name>,Vec<Expression>);
|
||||||
Call (FunctionCall),
|
#[derive(Debug)]
|
||||||
Expression ("(" Expression ")")
|
struct Function(Vec<Piece<Name>>,Option<Piece<VarArg>>,Piece<Block>);
|
||||||
};
|
#[derive(Debug)]
|
||||||
FunctionCall {
|
struct Field(Option<Expression>,Expression);
|
||||||
Normal (PrefixExpression Arguments),
|
#[derive(Debug)]
|
||||||
Instanced (PrefixExpression ":" Name Arguments)
|
enum FieldSep {
|
||||||
};
|
Comma,
|
||||||
Arguments {
|
Semicolon
|
||||||
Expressions ("(" [Expressions] ")"),
|
}
|
||||||
Table (Table),
|
#[derive(Debug)]
|
||||||
String (String)
|
enum BinaryOp {
|
||||||
};
|
Plus,
|
||||||
FunctionDef( "function" FunctionBody );
|
Minus,
|
||||||
FunctionBody( "(" [Parameters] ")" Block "end" );
|
Mul,
|
||||||
Parameters {
|
Divide,
|
||||||
Names (Names ["," VarArg]),
|
DivFloor,
|
||||||
VarArg (VarArg)
|
Caret,
|
||||||
};
|
Modulo,
|
||||||
VarArg( "..." [Name] );
|
Ampersand,
|
||||||
Table( "{" [Fields] "}" );
|
Tilde,
|
||||||
Fields( Field {FieldSep Field} [FieldSep] );
|
Pipe,
|
||||||
Field {
|
ShiftRight,
|
||||||
ExpressionIndex ("[" Expression "]" "=" Expression),
|
ShiftLeft,
|
||||||
Name (Name "=" Expression),
|
Concat,
|
||||||
Expression (Expression)
|
Less,
|
||||||
};
|
LessEqual,
|
||||||
FieldSep {
|
Greater,
|
||||||
Comma (","),
|
GreatEqual,
|
||||||
Semicolon (";")
|
Equivalent,
|
||||||
};
|
NotEqual,
|
||||||
BinaryOp {
|
And,
|
||||||
Plus ("+"),
|
Or
|
||||||
Minus ("-"),
|
}
|
||||||
Mul ("*"),
|
#[derive(Debug)]
|
||||||
Divide ("/"),
|
enum UnaryOp {
|
||||||
DivFloor ("//"),
|
Negate,
|
||||||
Caret ("^"),
|
Not,
|
||||||
Modulo ("%"),
|
Ampersand,
|
||||||
Ampersand ("&"),
|
Tilde
|
||||||
Tilde ("~"),
|
}
|
||||||
Pipe ("|"),
|
|
||||||
ShiftRight (">>"),
|
impl<T: Parse> Parse for Vec<Piece<T>> {
|
||||||
ShiftLeft ("<<"),
|
fn consume(reader: &mut Reader) -> Result<Piece<Vec<Piece<T>>>, Error>
|
||||||
Concat (".."),
|
where
|
||||||
Less ("<"),
|
Self: Sized,
|
||||||
LessEqual ("<="),
|
{
|
||||||
Greater (">"),
|
let result: Vec<Piece<T>> = Vec::new();
|
||||||
GreatEqual (">="),
|
reader.trim()?;
|
||||||
Equivalent ("=="),
|
loop {
|
||||||
NotEqual ("~="),
|
if let Ok(it) = reader.take::<T>() {
|
||||||
And ("and"),
|
reader.trim()?;
|
||||||
Or ("or")
|
if !reader.consume(",").is_ok() {
|
||||||
};
|
break
|
||||||
UnaryOp {
|
}
|
||||||
Negate ("-"),
|
}
|
||||||
Not ("!"),
|
}
|
||||||
Ampersand ("#"),
|
if result.is_empty() {
|
||||||
Tilde ("~")
|
return reader.error(format!("Expected {}s",std::any::type_name::<T>()).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<Piece<Self>, Error> {
|
||||||
|
reader.trim()?;
|
||||||
|
let start = reader.marker();
|
||||||
|
reader.consume("(")?;
|
||||||
|
let mut parameters: Vec<Piece<Name>> = Vec::new();
|
||||||
|
let mut vararg = None;
|
||||||
|
loop {
|
||||||
|
reader.trim()?;
|
||||||
|
if let Ok(name) = reader.take::<Name>() {
|
||||||
|
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::<VarArg>().ok()
|
||||||
|
}
|
||||||
|
reader.trim()?;
|
||||||
|
reader.consume(")")?;
|
||||||
|
reader.trim()?;
|
||||||
|
let end = reader.marker();
|
||||||
|
let block = reader.take::<Block>()?;
|
||||||
|
Ok(Piece::from(Function(parameters,vararg,block),&start,&end))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for VarArg {
|
||||||
|
fn consume(reader: &mut Reader) -> Result<Piece<Self>, Error> {
|
||||||
|
reader.trim()?;
|
||||||
|
let start = reader.marker();
|
||||||
|
reader.consume("...")?;
|
||||||
|
let name = reader.take::<Name>().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<Piece<Self>, 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<Piece<Statement>, 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::<Name>()?;
|
||||||
|
reader.trim()?;
|
||||||
|
let function = reader.take::<Function>()?;
|
||||||
|
restore(&mut reader);
|
||||||
|
Ok(Piece::from(Statement::LocalFunction(name, function.it), &start, &function.null()))
|
||||||
|
} else {
|
||||||
|
let names = reader.take::<Vec<Piece<Name>>>()?.it;
|
||||||
|
reader.trim()?;
|
||||||
|
reader.consume("=")?;
|
||||||
|
reader.trim()?;
|
||||||
|
let expressions = reader.take::<Vec<Piece<Expression>>>()?.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::<Name>() {
|
||||||
|
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::<Name>()?);
|
||||||
|
}
|
||||||
|
let function = reader.take::<Function>()?;
|
||||||
|
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::<Vec<Piece<Name>>>()?.it; reader.trim()?;
|
||||||
|
let result = if names.len() > 1 {
|
||||||
|
let name = *names.first().unwrap().clone();
|
||||||
|
reader.consume("=")?; reader.trim()?;
|
||||||
|
let begin = reader.take::<Expression>()?; reader.trim()?;
|
||||||
|
reader.consume(",")?; reader.trim()?;
|
||||||
|
let finish = reader.take::<Expression>()?; reader.trim()?;
|
||||||
|
let delta = if reader.consume(",").is_ok() {
|
||||||
|
reader.trim()?;
|
||||||
|
Some(reader.take::<Expression>()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
reader.consume("do")?; reader.trim()?;
|
||||||
|
let block = reader.take::<Block>()?; 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::<Vec<Piece<Expression>>>()?.it; reader.trim()?;
|
||||||
|
reader.consume("do")?; reader.trim()?;
|
||||||
|
let block = reader.take::<Block>()?; 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::<Expression>()?;
|
||||||
|
reader.consume("do")?; reader.trim()?;
|
||||||
|
let block = reader.take::<Block>()?; 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::<Expression>()?); reader.trim()?;
|
||||||
|
reader.consume("then")?; reader.trim()?;
|
||||||
|
blocks.push(reader.take::<Block>()?.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::<Block>()?.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::<Name>()?;
|
||||||
|
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::<Block>()?;
|
||||||
|
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::<Block>()?; reader.trim()?;
|
||||||
|
reader.consume("until")?; reader.trim()?;
|
||||||
|
let condition = reader.take::<Expression>()?;
|
||||||
|
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::<Name>()?;
|
||||||
|
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<Piece<Block>, Error>
|
||||||
|
where
|
||||||
|
Self: Sized
|
||||||
|
{
|
||||||
|
let mut statements = Vec::new();
|
||||||
|
while let Ok(statement) = reader.take::<Statement>() {
|
||||||
|
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<Block,Error> {
|
||||||
|
Reader::from(str).take::<Block>().map(|piece| piece.it)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn simple() {
|
||||||
|
println!("{:?}",parse(include_str!("assets/script.lua")).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -1,2 +1,3 @@
|
|||||||
|
#![recursion_limit = "256"]
|
||||||
pub mod engine;
|
pub mod engine;
|
||||||
mod lang;
|
pub mod lang;
|
||||||
+3
-2
@@ -1,7 +1,8 @@
|
|||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
use game::engine::run;
|
use game::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
run().unwrap();
|
|
||||||
|
//engine::run().unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ("~")
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user