Majority of untested implementation of Statement; Some changes to parser structure and code style; Added .gitignore

This commit is contained in:
Adebimpe Lincoln
2026-07-10 20:59:17 +01:00
parent f91d5a5091
commit a894fc6689
2 changed files with 541 additions and 459 deletions
+1
View File
@@ -0,0 +1 @@
target
+224 -143
View File
@@ -1,4 +1,4 @@
#[derive(Debug, Clone)]
#[derive(Clone)]
struct Reader<'a> {
slice: &'a str,
full: &'a str,
@@ -8,13 +8,16 @@ struct Reader<'a> {
struct Error(String);
impl Error {
fn new<T>(message: &str, reader: &Reader) -> Result<T,Error> {
fn new<T>(message: &str, _reader: &Reader) -> Result<T, Error> {
Err(Error(message.to_string()))
}
}
type Comment = String;
#[derive(Debug)]
struct Piece<T> {
comment: Comment,
index: usize,
width: usize,
it: T,
@@ -25,21 +28,24 @@ impl<T> Piece<T> {
Piece {
it,
index: reader.slice.as_ptr() as usize - reader.full.as_ptr() as usize,
width
width,
comment: String::new()
}
}
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
width: end.index + end.width - begin.index,
comment: String::new()
}
}
fn null(&self) -> Piece<()> {
Piece {
it: (),
index: self.index,
width: self.width
width: self.width,
comment: String::new()
}
}
}
@@ -51,33 +57,40 @@ impl<'a> From<&'a str> for Reader<'a> {
fn from(str: &'a str) -> Self {
Reader {
full: str,
slice: str
slice: str,
}
}
}
impl<'a> Reader<'a> {
fn trim(&mut self) -> Result<&Self,Error> {
fn trim(&mut self) -> Result<Comment, Error> {
self.slice = self.slice.trim_start();
if self.slice.starts_with("--") {
if self.slice[2..].starts_with("[[") {
let comment = if self.slice[2..].starts_with("[[") {
match self.slice.find("]]") {
Some(i) => {
let comment = &self.slice[4..i + 2];
self.slice = &self.slice[i + 2..].trim();
Ok(self)
}
_ => {
self.error("Unterminated multi-line comment")
Ok(comment)
}
_ => self.error("Unterminated multi-line comment"),
}
} else {
let comment;
if let Some(i) = self.slice.find("\n") {
self.slice = &self.slice[i + 1..].trim();
}
Ok(self)
}
comment = &self.slice[2..i+1];
} else {
Ok(self)
self.slice = &self.slice[..self.slice.len() - 1];
comment = &self.slice[2..];
}
Ok(comment)
}?;
self.trim().map(|it| {
it + comment
})
} else {
Ok(String::new())
}
}
fn consume(&mut self, start: &str) -> Result<&Self, Error> {
@@ -89,7 +102,10 @@ impl<'a> Reader<'a> {
self.error(format!("Expected '{}'", start).as_str())
}
}
fn take<T>(&mut self) -> Result<Piece<T>,Error> where T: Parse {
fn take<T>(&mut self) -> Result<Piece<T>, Error>
where
T: Parse,
{
self.trim()?;
T::consume(self)
}
@@ -111,12 +127,13 @@ struct Name(String);
// - The reader may have not been trimmed
trait Parse {
fn consume(reader: &mut Reader) -> Result<Piece<Self>, Error>
where Self: Sized;
where
Self: Sized;
}
impl Parse for Name {
fn consume(reader: &mut Reader) -> Result<Piece<Self>, Error>
where
Self: Sized
Self: Sized,
{
reader.trim()?;
let mut chars = reader.slice.chars();
@@ -127,12 +144,18 @@ impl Parse for Name {
}
Some(c) => {
if !(c.is_alphabetic() || c == '_') {
return reader.error("Identifier must begin with alphabetic character")
return reader.error("Identifier must begin with alphabetic character");
}
}
};
end += chars.take_while(|c| { c.is_alphanumeric() || *c == '_' }).count();
let result = Ok(Piece::of(Name(reader.slice[..end].to_string()),reader,end));
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
}
@@ -140,21 +163,35 @@ impl Parse for Name {
impl Parse for Number {
fn consume(reader: &mut Reader) -> Result<Piece<Number>, Error>
where
Self: Sized
Self: Sized,
{
reader.trim()?;
let mut end;
if reader.slice.starts_with("0x") {
end = reader.slice[2..].chars().take_while(|c| c.is_digit(16)).count()+2;
if end == 2 { end = 0 }
end = reader.slice[2..]
.chars()
.take_while(|c| c.is_digit(16))
.count()
+ 2;
if end == 2 {
end = 0
}
} else {
end = reader.slice.chars().take_while(|c| c.is_digit(10) || *c == '.').count();
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))
Ok(Piece::of(
Number(reader.slice[..end].to_string()),
reader,
end,
))
}
}
}
@@ -173,7 +210,7 @@ impl Parse for String {
Some('"') => {
term1 = '"';
term2 = None;
},
}
Some('\'') => {
term1 = '\'';
term2 = None;
@@ -190,10 +227,8 @@ impl Parse for String {
match chars.next() {
Some(c) => {
match c {
'\\' => {
match chars.next() {
Some(c) => {
match c {
'\\' => match chars.next() {
Some(c) => match c {
'n' => string.push('\n'),
'r' => string.push('\r'),
't' => string.push('\t'),
@@ -203,21 +238,21 @@ impl Parse for String {
it => {
string.push(it);
}
}
}
},
None => {}
}
}
},
'\r' => {} // todo: ?
'\n' if term2.is_none() => {
return reader.error("Found newline while parsing string");
}
term if term == term1 => {
// If the second terminator exists and is the next char, or there is no second terminator
if !term2.is_some() || chars.next().is_some_and(|it| it == term2.unwrap()) {
if !term2.is_some()
|| chars.next().is_some_and(|it| it == term2.unwrap())
{
let length = string.len();
reader.slice = &reader.slice[length..];
return Ok(Piece::of(string,reader,length))
return Ok(Piece::of(string, reader, length));
// There is a second terminator and it wasn't the next char
} else {
string.push(term)
@@ -238,7 +273,7 @@ impl Parse for String {
// AST
#[derive(Debug)]
struct Block(Vec<Piece<Statement>>);
struct Block(Vec<Piece<Statement>>, Vec<Piece<Expression>>);
#[derive(Debug)]
enum Statement {
Semicolon,
@@ -247,22 +282,27 @@ enum Statement {
Label(Piece<Name>),
Break,
Continue,
Return(Vec<Piece<Expression>>),
Goto(Piece<Name>),
Do(Block),
While(Piece<Expression>, Block),
Repeat(Block, Piece<Expression>),
If(Vec<Piece<Expression>>, Vec<Block>, Option<Block>),
Range(Piece<Name>,Piece<Expression>,Piece<Expression>,Option<Piece<Expression>>,Block),
Range(
Piece<Name>,
Piece<Expression>,
Piece<Expression>,
Option<Piece<Expression>>,
Block,
),
Iterator(Vec<Piece<Name>>, Vec<Piece<Expression>>, Block),
Function(Vec<Piece<Name>>, Option<Piece<Name>>, Function),
LocalFunction(Piece<Name>, Function),
Declaration(Vec<Piece<Name>>,Vec<Piece<Expression>>)
Declaration(Vec<Piece<Name>>, Vec<Piece<Expression>>),
}
#[derive(Debug)]
enum Variable {
Name(Name),
Index(Box<Prefix>,Box<Expression>)
Index(Box<Prefix>, Box<Expression>),
}
#[derive(Debug)]
enum Expression {
@@ -276,7 +316,7 @@ enum Expression {
Prefix(Box<Prefix>),
Table(Vec<Field>),
Binary(Box<Expression>, BinaryOp, Box<Expression>),
Unary(UnaryOp,Box<Expression>)
Unary(UnaryOp, Box<Expression>),
}
#[derive(Debug)]
enum Prefix {
@@ -295,7 +335,7 @@ struct Field(Option<Expression>,Expression);
#[derive(Debug)]
enum FieldSep {
Comma,
Semicolon
Semicolon,
}
#[derive(Debug)]
enum BinaryOp {
@@ -319,14 +359,14 @@ enum BinaryOp {
Equivalent,
NotEqual,
And,
Or
Or,
}
#[derive(Debug)]
enum UnaryOp {
Negate,
Not,
Ampersand,
Tilde
Tilde,
}
impl<T: Parse> Parse for Vec<Piece<T>> {
@@ -334,13 +374,14 @@ impl<T: Parse> Parse for Vec<Piece<T>> {
where
Self: Sized,
{
let result: Vec<Piece<T>> = Vec::new();
let mut result: Vec<Piece<T>> = Vec::new();
reader.trim()?;
loop {
if let Ok(it) = reader.take::<T>() {
result.push(it);
reader.trim()?;
if !reader.consume(",").is_ok() {
break
break;
}
}
}
@@ -361,25 +402,25 @@ impl Parse for Function {
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 '...'")
return reader.error("Unexpected argument after vararg '...'");
}
if !reader.consume(",").is_ok() {
break
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))
Ok(Piece::from(
Function(parameters, vararg, block),
&start,
&end,
))
}
}
@@ -395,173 +436,213 @@ impl Parse for VarArg {
Ok(Piece::from(VarArg(Some(name.it)), &start, &end))
} else {
end = reader.marker();
Ok(Piece::from(VarArg(name.map(|piece| piece.it)), &start, &end))
Ok(Piece::from(
VarArg(name.map(|piece| piece.it)),
&start,
&end,
))
}
}
}
impl Parse for Expression {
fn consume(reader: &mut Reader) -> Result<Piece<Self>, Error> {
reader.trim()?;
}
}
impl Parse for Call {
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()?;
fn consume(initial: &mut Reader) -> Result<Piece<Statement>, Error> {
initial.trim()?;
let start = initial.marker();
// todo: it is safer to pass back the new reader in the Ok, and then map it out
if initial.consume("break").is_ok() {
Ok(Piece::from(Statement::Break, &start, &initial.marker()))
} else if initial.consume("continue").is_ok() {
Ok(Piece::from(Statement::Continue, &start, &initial.marker()))
} else if initial.consume(";").is_ok() {
Ok(Piece::from(Statement::Semicolon, &start, &initial.marker()))
} else if let Ok(mut reader) = initial.clone().consume("local") {
if reader.consume("function").is_ok() {
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()))
*initial = *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()))
*initial = *reader;
Ok(Piece::from(
Statement::Declaration(names, expressions),
&start,
&reader.marker(),
))
}
} else if let Ok(mut reader) = reader.consume("function") {
} else if let Ok(mut reader) = initial.clone().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
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()?;
*initial = *reader;
Ok(Piece::from(
Statement::Function(names, member, function.it),
&start,
&reader.marker(),
))
} else if let Ok(mut reader) = initial.clone().consume("for") {
let names = reader.take::<Vec<Piece<Name>>>()?.it;
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()?;
reader.consume("=")?;
let begin = reader.take::<Expression>()?;
reader.consume(",")?;
let finish = reader.take::<Expression>()?;
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("do")?;
let block = reader.take::<Block>()?;
reader.consume("end")?;
Ok(Piece::from(Statement::Range(name,begin,finish,delta,block.it),&start,&reader.marker()))
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("in")?;
let expressions = reader.take::<Vec<Piece<Expression>>>()?.it;
reader.consume("do")?;
let block = reader.take::<Block>()?;
reader.consume("end")?;
Ok(Piece::from(Statement::Iterator(names,expressions,block.it),&start,&reader.marker()))
Ok(Piece::from(
Statement::Iterator(names, expressions, block.it),
&start,
&reader.marker(),
))
};
restore(&mut reader);
*initial = *reader;
result
} else if let Ok(mut reader) = reader.consume("while") {
reader.trim()?;
} else if let Ok(mut reader) = initial.clone().consume("while") {
let condition = reader.take::<Expression>()?;
reader.consume("do")?; reader.trim()?;
let block = reader.take::<Block>()?; reader.trim()?;
reader.consume("do")?;
let block = reader.take::<Block>()?;
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()?;
*initial = *reader;
Ok(Piece::from(
Statement::While(condition, block.it),
&start,
&reader.marker(),
))
} else if let Ok(mut reader) = initial.clone().consume("if") {
let mut conditions = Vec::new();
let mut blocks = Vec::new();
let branch = || -> Result<(), Error> {
conditions.push(reader.take::<Expression>()?); reader.trim()?;
reader.consume("then")?; reader.trim()?;
conditions.push(reader.take::<Expression>()?);
reader.consume("then")?;
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()?;
*initial = *reader;
Ok(Piece::from(
Statement::If(conditions, blocks, block),
&start,
&reader.marker(),
))
} else if let Ok(mut reader) = initial.clone().consume("goto") {
let name = reader.take::<Name>()?;
restore(&mut reader);
*initial = *reader;
Ok(Piece::from(Statement::Goto(name), &start, &reader.marker()))
} else if let Ok(mut reader) = reader.consume("do") {
reader.trim()?;
} else if let Ok(mut reader) = initial.clone().consume("do") {
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()?;
*initial = *reader;
Ok(Piece::from(
Statement::Do(block.it),
&start,
&reader.marker(),
))
} else if let Ok(mut reader) = initial.clone().consume("repeat") {
reader.consume("repeat")?;
let block = reader.take::<Block>()?;
reader.consume("until")?;
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("::") {
*initial = *reader;
Ok(Piece::from(
Statement::Repeat(block.it, condition),
&start,
&reader.marker(),
))
} else if let Ok(mut reader) = initial.clone().consume("::") {
let name = reader.take::<Name>()?;
reader.consume("::")?;
restore(&mut reader);
Ok(Piece::from(Statement::Label(name),&start,&reader.marker()))
} else if let Ok(mut reader) =
*initial = *reader;
Ok(Piece::from(
Statement::Label(name),
&start,
&reader.marker(),
))
} else {
reader.take::<Call>().map(|call| Statement::Call(call)).or_else(|| reader.take::)
}
}
}
impl Parse for Block {
fn consume(reader: &mut Reader) -> Result<Piece<Block>, Error>
where
Self: Sized
Self: Sized,
{
let mut statements = Vec::new();
let start = reader.marker();
while let Ok(statement) = reader.take::<Statement>() {
statements.push(statement);
}
if statements.is_empty() {
Ok(Piece::of(Block(statements),reader,0))
let expressions = if reader.consume("return").is_ok() {
let result = reader.take::<Vec<Piece<Expression>>>()?;
reader.consume(";").ok();
result.it
} else {
let first = statements.first().unwrap().null();
let last = statements.last().unwrap().null();
Ok(Piece::from(Block(statements),&first,&last))
}
Vec::new()
};
Ok(Piece::from(
Block(statements, expressions),
&start,
&reader.marker(),
))
}
}