Rewriting parser.

This commit is contained in:
paladin
2026-07-02 00:43:49 +01:00
parent d2e89dae3e
commit f91d5a5091
8 changed files with 832 additions and 436 deletions
Generated
-39
View File
@@ -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"
-1
View File
@@ -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"
+7
View File
@@ -0,0 +1,7 @@
local all = { ... }
while true do
for index, item in pairs(all) do
dog:log(index, item)
end
return
end
-1
View File
@@ -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
View File
@@ -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
View File
@@ -1,2 +1,3 @@
#![recursion_limit = "256"]
pub mod engine; pub mod engine;
mod lang; pub mod lang;
+3 -2
View File
@@ -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();
} }
+353
View File
@@ -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 ("~")
};
}