use self::super::{
Error as ASTError, Result,
lexer::{Result as LexerResult, Token}
};
use itertools::Itertools;
use std::{
convert::{TryFrom, TryInto},
error::Error as STDError,
fmt::{Display, Formatter, Result as FMTResult},
iter::{Peekable, from_fn}
};
macro_rules! expression {
($($(#[$($attrib:tt)*])* $name:ident($next:ident)
{$($token:ident => $bin_op:ident),*}),*) => {
$(
$(#[$($attrib)*])*
fn $name<I>(iter: &mut TokenIterator<I>) -> Result<Expression>
where I: Iterator<Item = LexerResult<Token>> {
let mut expression = $next(iter)?;
loop {
match iter.peek().transpose()? {
$(Some(Token::$token) => {
iter.eat();
expression = Expression::BinaryOperation {
left: Box::new(expression),
operator: BinaryOperator::$bin_op,
right: Box::new($next(iter)?)
}
}),*
_ => break Ok(expression)
}
}
}
)*
}
}
macro_rules! expect {
($value:expr, $type:pat) => {
match $value {
Some(Err(error)) => return Err(ASTError::Lexer(error)),
Some(Ok($type)) => (),
Some(Ok(value)) => return Err(ASTError::Parser(Error(Some(value)))),
None => return Err(ASTError::Parser(Error(None)))
}
}
}
macro_rules! iter_expect {
($value:expr, $type:pat) => {
match $value {
Some(Err(error)) => return Some(Err(ASTError::Lexer(error))),
Some(Ok($type)) => (),
Some(Ok(value)) => return Some(Err(ASTError::Parser(Error(Some(value))))),
None => return Some(Err(ASTError::Parser(Error(None))))
}
}
}
macro_rules! iter_throw {
($value:expr) => {
match $value {
Ok(value) => value,
Err(error) => return Some(Err(error))
}
}
}
#[derive(Clone, Debug)]
pub struct Error(pub Option<Token>);
impl STDError for Error {}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> FMTResult {
match &self.0 {
Some(token) => write!(f, "unexpected '{}'", token),
None => write!(f, "unexpected end of file")
}
}
}
pub struct TokenIterator<I>(pub Peekable<I>)
where I: Iterator<Item = LexerResult<Token>>;
impl<I> TokenIterator<I>
where I: Iterator<Item = LexerResult<Token>> {
fn eat(&mut self) {
self.next();
}
#[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> Option<LexerResult<Token>> {
loop {
match self.0.next() {
Some(Ok(Token::Comment(_))) => (),
token => break token
}
}
}
fn eat_peek(&mut self) -> Option<LexerResult<Token>> {
self.eat();
self.peek()
}
fn eat_next(&mut self) -> Option<LexerResult<Token>> {
self.eat();
self.next()
}
fn identifier(&mut self) -> String {
match self.next() {
Some(Ok(Token::Identifier(identifier))) => identifier,
_ => unreachable!()
}
}
fn string(&mut self) -> String {
match self.next() {
Some(Ok(Token::String(string))) => string,
_ => unreachable!()
}
}
fn integer(&mut self) -> i64 {
match self.next() {
Some(Ok(Token::Integer(integer))) => integer,
_ => unreachable!()
}
}
fn peek(&mut self) -> Option<LexerResult<Token>> {
match self.0.peek().cloned() {
Some(Ok(Token::Comment(_))) => {self.0.next(); self.peek()},
token => token
}
}
}
pub fn parse_block<I>(iter: &mut TokenIterator<I>) -> Result<Block>
where I: Iterator<Item = LexerResult<Token>> {
let mut statements = Vec::new();
loop {
match iter.peek().transpose()? {
Some(Token::SemiColon) => iter.eat(),
Some(Token::Identifier(_)) => match parse_expression(iter)? {
Expression::Call {function, arguments} =>
statements.push(Statement::FunctionCall {
function: *function, arguments}),
Expression::MethodCall {class, method, arguments} =>
statements.push(Statement::MethodCall {
class: *class, method, arguments}),
actor => {
let mut variables = Vec::new();
while let Some(Ok(Token::Comma)) = iter.peek()
{iter.eat(); variables.push(parse_expression(iter)?.try_into()?)}
let variables = (actor.try_into()?, variables);
let values = if let Some(Ok(Token::Assign)) = iter.peek() {
iter.eat();
let mut values = vec![parse_expression(iter)?];
while let Some(Ok(Token::Comma)) = iter.peek()
{iter.eat(); values.push(parse_expression(iter)?)}
values
} else {Vec::new()};
statements.push(Statement::Assign {variables, values})
}
},
Some(Token::KeywordLocal) => match iter.eat_peek().transpose()? {
Some(Token::Identifier(_)) => {
let actor = iter.identifier();
let mut variables = Vec::new();
while let Some(Ok(Token::Comma)) = iter.peek()
{iter.eat(); variables.push(iter.identifier())}
let variables = (actor, variables);
let values = if let Some(Ok(Token::Assign)) = iter.peek() {
iter.eat();
let mut values = vec![parse_expression(iter)?];
while let Some(Ok(Token::Comma)) = iter.peek()
{iter.eat(); values.push(parse_expression(iter)?)}
values
} else {Vec::new()};
statements.push(Statement::LocalAssign {variables, values})
},
Some(Token::KeywordFunction) =>
statements.push(parse_function_statement(iter, true)?),
_ => break Err(ASTError::Parser(Error(iter.next().transpose()?)))
},
Some(Token::KeywordFunction) =>
statements.push(parse_function_statement(iter, false)?),
Some(Token::KeywordIf) => statements.push(parse_if(iter)?),
Some(Token::KeywordFor) => statements.push(parse_for(iter)?),
Some(Token::KeywordWhile | Token::KeywordRepeat) =>
statements.push(parse_while(iter)?),
Some(Token::KeywordReturn) => {
iter.eat();
let mut values = Vec::new();
loop {
values.push(parse_expression(iter)?);
match iter.peek() {
Some(Ok(Token::Comma)) => iter.eat(),
_ => break
}
}
statements.push(Statement::Return {values})
},
_ => break Ok(Block(statements))
}
}
}
pub fn parse_expression<I>(iter: &mut TokenIterator<I>) -> Result<Expression>
where I: Iterator<Item = LexerResult<Token>> {
parse_expression_logical_or(iter)
}
expression! {
parse_expression_logical_or(parse_expression_logical_and) {
KeywordOr => LogicalOr
},
parse_expression_logical_and(parse_expression_comparison) {
KeywordAnd => LogicalAnd
},
parse_expression_comparison(parse_expression_bitwise_or) {
Equal => Equal,
NotEqual => NotEqual,
LessThan => LessThan,
GreaterThan => GreaterThan,
LessThanOrEqual => LessThanOrEqual,
GreaterThanOrEqual => GreaterThanOrEqual
},
parse_expression_bitwise_or(parse_expression_bitwise_xor) {
BitwiseOr => BitwiseOr
},
parse_expression_bitwise_xor(parse_expression_bitwise_and) {
BitwiseNotOrXOr => BitwiseXOr
},
parse_expression_bitwise_and(parse_expression_bitwise_shift) {
BitwiseAnd => BitwiseAnd
},
parse_expression_bitwise_shift(parse_expression_concat) {
ShiftLeft => ShiftLeft,
ShiftRight => ShiftRight
},
parse_expression_term(parse_expression_factor) {
Add => Add,
Minus => Subtract
},
parse_expression_factor(parse_expression_unary) {
Multiply => Multiply,
Divide => Divide,
FloorDivide => FloorDivide,
Modulo => Modulo
}
}
pub fn parse_expression_concat<I>(iter: &mut TokenIterator<I>)
-> Result<Expression> where I: Iterator<Item = LexerResult<Token>> {
let mut expression = parse_expression_term(iter)?;
loop {
if let Some(Ok(Token::Concat)) = iter.peek() {
iter.eat();
expression = Expression::BinaryOperation {
left: Box::new(expression),
operator: BinaryOperator::Concat,
right: Box::new(parse_expression_concat(iter)?)
}
} else {break Ok(expression)}
}
}
pub fn parse_expression_unary<I>(iter: &mut TokenIterator<I>)
-> Result<Expression> where I: Iterator<Item = LexerResult<Token>> {
Ok(match iter.peek() {
Some(Ok(Token::KeywordNot)) => {
iter.eat();
Expression::UnaryOperation {
operator: UnaryOperator::LogicalNot,
operand: Box::new(parse_expression_unary(iter)?)
}
},
Some(Ok(Token::Length)) => {
iter.eat();
Expression::UnaryOperation {
operator: UnaryOperator::Length,
operand: Box::new(parse_expression_unary(iter)?)
}
},
Some(Ok(Token::Minus)) => {
iter.eat();
Expression::UnaryOperation {
operator: UnaryOperator::Negate,
operand: Box::new(parse_expression_unary(iter)?)
}
},
Some(Ok(Token::BitwiseNotOrXOr)) => {
iter.eat();
Expression::UnaryOperation {
operator: UnaryOperator::BitwiseNot,
operand: Box::new(parse_expression_unary(iter)?)
}
},
_ => parse_expression_exponent(iter)?
})
}
pub fn parse_expression_exponent<I>(iter: &mut TokenIterator<I>)
-> Result<Expression> where I: Iterator<Item = LexerResult<Token>> {
let mut expression = parse_expression_primary(iter)?;
loop {
if let Some(Ok(Token::Exponent)) = iter.peek() {
iter.eat();
expression = Expression::BinaryOperation {
left: Box::new(expression),
operator: BinaryOperator::Exponent,
right: Box::new(parse_expression_exponent(iter)?)
}
} else {break Ok(expression)}
}
}
pub fn parse_expression_primary<I>(iter: &mut TokenIterator<I>)
-> Result<Expression> where I: Iterator<Item = LexerResult<Token>> {
Ok(match iter.peek().transpose()? {
Some(Token::Identifier(_)) => {
let identifier = iter.identifier(); parse_expression_inner(iter, Expression::Identifier(identifier))?
},
Some(Token::Integer(_)) => Expression::Integer(iter.integer()),
Some(Token::String(_)) => Expression::String(iter.string()),
Some(Token::LiteralNil) => {iter.eat(); Expression::Nil},
Some(Token::LiteralTrue) => {iter.eat(); Expression::True},
Some(Token::LiteralFalse) => {iter.eat(); Expression::False},
Some(Token::OpenParen) => {
iter.eat();
let expression = parse_expression(iter)?;
expect!(iter.next(), Token::CloseParen);
parse_expression_inner(iter, expression)?
},
Some(Token::OpenCurly) => parse_table(iter)?,
Some(Token::KeywordFunction) => parse_function_expression(iter)?,
_ => return Err(ASTError::Parser(Error(iter.next().transpose()?)))
})
}
pub fn parse_expression_inner<I>(iter: &mut TokenIterator<I>, actor: Expression)
-> Result<Expression> where I: Iterator<Item = LexerResult<Token>> {
match iter.peek().transpose()? {
Some(Token::OpenParen) => {
let mut first = true;
let arguments = from_fn(|| match iter.peek().transpose() {
Ok(Some(Token::OpenParen)) if first => {
iter.eat(); first = false;
if let Some(Ok(Token::CloseParen)) = iter.peek()
{iter.eat(); return None}
Some(parse_expression(iter))
}
Ok(Some(Token::Comma)) => {iter.eat(); Some(parse_expression(iter))},
Ok(Some(Token::CloseParen)) => {iter.eat(); None},
Ok(_) => Some(Err(ASTError::Parser(Error(
iter.next().transpose().unwrap())))),
Err(error) => Some(Err(ASTError::Lexer(error)))
}).try_collect()?;
let function = Box::new(actor);
parse_expression_inner(iter, Expression::Call {function, arguments})
},
Some(Token::String(_)) => {
let arguments = vec![Expression::String(iter.string())];
let function = Box::new(actor);
parse_expression_inner(iter, Expression::Call {function, arguments})
},
Some(Token::OpenCurly) => {
let arguments = vec![parse_table(iter)?];
let function = Box::new(actor);
parse_expression_inner(iter, Expression::Call {function, arguments})
},
Some(Token::Period) => match iter.eat_peek().transpose()? {
Some(Token::Identifier(_)) => {
let index = Box::new(Expression::String(iter.identifier()));
parse_expression_inner(iter, Expression::Index {
index, indexee: Box::new(actor)
})
},
_ => Err(ASTError::Parser(Error(iter.next().transpose()?)))
},
Some(Token::Colon) => match {iter.eat(); iter.next().transpose()?} {
Some(Token::Identifier(method)) => {
let mut first = true;
let arguments = from_fn(|| match iter.peek().transpose() {
Ok(Some(Token::OpenParen)) if first => {
iter.eat(); first = false;
if let Some(Ok(Token::CloseParen)) = iter.peek()
{iter.eat(); return None}
Some(parse_expression(iter))
},
Ok(Some(Token::Comma)) => {iter.eat(); Some(parse_expression(iter))},
Ok(Some(Token::CloseParen)) => {iter.eat(); None},
Ok(_) => Some(Err(ASTError::Parser(Error(
iter.next().transpose().unwrap())))),
Err(error) => Some(Err(ASTError::Lexer(error)))
}).try_collect()?;
let class = Box::new(actor);
parse_expression_inner(iter,
Expression::MethodCall {class, method, arguments})
},
token => Err(ASTError::Parser(Error(token)))
},
Some(Token::OpenBracket) => {
iter.eat();
let index = Box::new(parse_expression(iter)?);
let result = parse_expression_inner(iter, Expression::Index {
index, indexee: Box::new(actor)
})?;
match iter.next().transpose()? {
Some(Token::CloseBracket) => parse_expression_inner(iter, result),
token => Err(ASTError::Parser(Error(token)))
}
},
_ => Ok(actor)
}
}
pub fn parse_table<I>(iter: &mut TokenIterator<I>) -> Result<Expression>
where I: Iterator<Item = LexerResult<Token>> {
expect!(iter.next(), Token::OpenCurly);
let mut array = Vec::new();
let mut key_value = Vec::new();
let mut first = true;
loop {
match iter.peek().transpose()? {
Some(Token::OpenBracket) => {
iter.eat(); let key = parse_expression(iter)?;
expect!(iter.next(), Token::CloseBracket);
expect!(iter.next(), Token::Assign);
let value = parse_expression(iter)?;
match iter.next().transpose()? {
Some(Token::Comma) => key_value.push(KeyValue {key, value}),
Some(Token::CloseCurly) => {
key_value.push(KeyValue {key, value});
break Ok(Expression::Table {array, key_value})
},
token => break Err(ASTError::Parser(Error(token)))
}
},
Some(Token::Identifier(_)) => {
let key = Expression::String(iter.identifier());
match iter.next().transpose()? {
Some(Token::Comma) => array.push(key),
Some(Token::Assign) => {
let value = parse_expression(iter)?;
match iter.next().transpose()? {
Some(Token::Comma) => key_value.push(KeyValue {key, value}),
Some(Token::CloseCurly) => {
key_value.push(KeyValue {key, value});
break Ok(Expression::Table {array, key_value})
},
token => break Err(ASTError::Parser(Error(token)))
}
},
Some(Token::CloseCurly) => {
array.push(key);
break Ok(Expression::Table {array, key_value})
},
token => break Err(ASTError::Parser(Error(token)))
}
},
Some(Token::CloseCurly) if first =>
{iter.eat(); break Ok(Expression::Table {array, key_value})},
_ => {
array.push(parse_expression(iter)?);
match iter.next().transpose()? {
Some(Token::Comma) => continue,
Some(Token::CloseCurly) =>
break Ok(Expression::Table {array, key_value}),
token => break Err(ASTError::Parser(Error(token)))
}
}
}
first = false;
}
}
pub fn parse_if<I>(iter: &mut TokenIterator<I>) -> Result<Statement>
where I: Iterator<Item = LexerResult<Token>> {
expect!(iter.next(), Token::KeywordIf);
let condition = parse_expression(iter)?;
expect!(iter.next(), Token::KeywordThen);
let then = parse_block(iter)?;
let mut r#else = None;
let else_ifs = from_fn(|| match iter.next().transpose() {
Ok(Some(Token::KeywordEnd)) => None,
Ok(Some(Token::KeywordElseIf)) => {
let condition = iter_throw!(parse_expression(iter));
iter_expect!(iter.next(), Token::KeywordThen);
let then = iter_throw!(parse_block(iter));
Some(Ok(ElseIf {condition, then}))
},
Ok(Some(Token::KeywordElse)) => {
r#else = Some(iter_throw!(parse_block(iter)));
iter_expect!(iter.next(), Token::KeywordEnd);
None
},
Ok(token) => Some(Err(ASTError::Parser(Error(token)))),
Err(error) => Some(Err(ASTError::Lexer(error)))
}).try_collect()?;
Ok(Statement::If {
condition,
then,
else_ifs,
r#else
})
}
pub fn parse_for<I>(iter: &mut TokenIterator<I>) -> Result<Statement>
where I: Iterator<Item = LexerResult<Token>> {
expect!(iter.next(), Token::KeywordFor);
let variable = match iter.next().transpose()? {
Some(Token::Identifier(argument)) => argument,
token => return Err(ASTError::Parser(Error(token)))
};
match iter.next().transpose()? {
Some(Token::Assign) => {
let first = parse_expression(iter)?;
expect!(iter.next(), Token::Comma);
let limit = parse_expression(iter)?;
let step = match iter.next().transpose()? {
Some(Token::Comma) => {
let step = parse_expression(iter)?;
expect!(iter.next(), Token::KeywordDo);
step
},
Some(Token::KeywordDo) => Expression::Integer(1),
token => return Err(ASTError::Parser(Error(token)))
};
let r#do = parse_block(iter)?;
expect!(iter.next(), Token::KeywordEnd);
Ok(Statement::NumericFor {variable, first, limit, step, r#do})
},
Some(Token::KeywordIn) => {
let iterator = parse_expression(iter)?;
expect!(iter.next(), Token::KeywordDo);
let r#do = parse_block(iter)?;
expect!(iter.next(), Token::KeywordEnd);
Ok(Statement::GenericFor {variable, iterator, r#do})
},
token => Err(ASTError::Parser(Error(token)))
}
}
pub fn parse_while<I>(iter: &mut TokenIterator<I>) -> Result<Statement>
where I: Iterator<Item = LexerResult<Token>> {
Ok(match iter.next().transpose()? {
Some(Token::KeywordWhile) => {
let condition = parse_expression(iter)?;
expect!(iter.next(), Token::KeywordDo);
let block = parse_block(iter)?;
expect!(iter.next(), Token::KeywordEnd);
Statement::While {condition, block, run_first: false}
},
Some(Token::KeywordRepeat) => {
let block = parse_block(iter)?;
expect!(iter.next(), Token::KeywordUntil);
let condition = parse_expression(iter)?;
Statement::While {condition, block, run_first: true}
},
token => return Err(ASTError::Parser(Error(token)))
})
}
fn parse_tuple<'i, I>(iter: &'i mut TokenIterator<I>)
-> impl Iterator<Item = Result<String>> + 'i
where I: Iterator<Item = LexerResult<Token>> {
let mut first = true;
from_fn(move || match iter.peek().transpose() {
Ok(Some(Token::OpenParen)) if first => {
iter.eat(); first = false;
match iter.next().transpose() {
Ok(Some(Token::Identifier(argument))) => Some(Ok(argument)),
Ok(Some(Token::CloseParen)) => None,
Ok(token) => Some(Err(ASTError::Parser(Error(token)))),
Err(error) => Some(Err(ASTError::Lexer(error)))
}
},
Ok(Some(Token::Comma)) => {
iter.eat();
match iter.next().transpose() {
Ok(Some(Token::Identifier(argument))) => Some(Ok(argument)),
Ok(token) => Some(Err(ASTError::Parser(Error(token)))),
Err(error) => Some(Err(ASTError::Lexer(error)))
}
},
Ok(Some(Token::CloseParen)) => {iter.eat(); None},
Ok(_) => Some(Err(ASTError::Parser(Error(
iter.next().transpose().unwrap())))),
Err(error) => Some(Err(ASTError::Lexer(error)))
})
}
pub fn parse_function_statement<I>(iter: &mut TokenIterator<I>, local: bool)
-> Result<Statement> where I: Iterator<Item = LexerResult<Token>> {
expect!(iter.next(), Token::KeywordFunction);
let name_first = match iter.next().transpose()? {
Some(Token::Identifier(name)) => name,
token => return Err(ASTError::Parser(Error(token)))
};
let name_rest = (!local).then(|| {
let mut rest = Vec::new();
loop {
match iter.peek() {
Some(Ok(Token::Colon)) => match iter.eat_next().transpose()? {
Some(Token::Identifier(name)) => break Ok((rest, Some(name))),
token => return Err(ASTError::Parser(Error(token)))
},
Some(Ok(Token::Period)) => match iter.eat_next().transpose()? {
Some(Token::Identifier(name)) => rest.push(name),
token => return Err(ASTError::Parser(Error(token)))
},
_ => break Ok((rest, None))
}
}
}).transpose()?;
let arguments = parse_tuple(iter).try_collect()?;
let body = parse_block(iter)?;
expect!(iter.next(), Token::KeywordEnd);
Ok(match name_rest {
None =>
Statement::LocalFunction {name: name_first, arguments, body},
Some((name_rest, None)) =>
Statement::Function {name: (name_first, name_rest), arguments, body},
Some((name_rest, Some(name))) =>
Statement::Method {class: (name_first, name_rest), name, arguments, body}
})
}
pub fn parse_function_expression<I>(iter: &mut TokenIterator<I>)
-> Result<Expression> where I: Iterator<Item = LexerResult<Token>> {
expect!(iter.next(), Token::KeywordFunction);
let arguments = parse_tuple(iter).try_collect()?;
let body = parse_block(iter)?;
expect!(iter.next(), Token::KeywordEnd);
Ok(Expression::Function {arguments, body})
}
#[derive(Clone, Debug)]
pub struct Block(pub Vec<Statement>);
impl Display for Block {
fn fmt(&self, f: &mut Formatter) -> FMTResult {
self.0.iter().try_for_each(|stmt| writeln!(f, "{}", stmt))
}
}
#[derive(Clone, Debug)]
pub enum Statement {
If {
condition: Expression,
then: Block,
else_ifs: Vec<ElseIf>,
r#else: Option<Block>
},
GenericFor {
variable: String,
iterator: Expression,
r#do: Block
},
NumericFor {
variable: String,
first: Expression,
limit: Expression,
step: Expression,
r#do: Block
},
While {
condition: Expression,
block: Block,
run_first: bool
},
Return {
values: Vec<Expression>
},
Assign {
variables: (AssignmentTarget, Vec<AssignmentTarget>),
values: Vec<Expression>
},
LocalAssign {
variables: (String, Vec<String>),
values: Vec<Expression>
},
FunctionCall {
function: Expression,
arguments: Vec<Expression>
},
MethodCall {
class: Expression,
method: String,
arguments: Vec<Expression>
},
Function {
name: (String, Vec<String>),
arguments: Vec<String>,
body: Block
},
LocalFunction {
name: String,
arguments: Vec<String>,
body: Block
},
Method {
class: (String, Vec<String>),
name: String,
arguments: Vec<String>,
body: Block
}
}
impl Display for Statement {
fn fmt(&self, f: &mut Formatter) -> FMTResult {
match self {
Self::If {condition, then, r#else, else_ifs} => {
write!(f, "if {} then\n{}", condition, then)?;
else_ifs.iter().try_for_each(|ElseIf {condition, then}|
write!(f, "elseif {} then\n{}", condition, then))?;
if let Some(r#else) = r#else {write!(f, "else\n{}", r#else)?}
write!(f, "end")
},
Self::GenericFor {variable, iterator, r#do} =>
write!(f, "for {} in {} do\n{}end", variable, iterator, r#do),
Self::NumericFor {variable, first, limit, step, r#do} =>
write!(f, "for {} = {}, {}, {} do\n{}end", variable, first, limit,
step, r#do),
Self::While {condition, block, run_first: false} =>
write!(f, "while {} do\n{}end", condition, block),
Self::While {condition, block, run_first: true} =>
write!(f, "repeat\n{}until {}", block, condition),
Self::Return {values} => {
write!(f, "return ")?;
values.iter().enumerate()
.try_for_each(|(index, value)| if index == 0 {write!(f, "{}", value)}
else {write!(f, ", {}", value)})
},
Self::Assign {..} =>
todo!(),
Self::FunctionCall {function, arguments} => {
write!(f, "{}(", function)?;
arguments.iter().enumerate().try_for_each(|(index, expr)| {
if index == 0 {write!(f, "{}", expr)} else {write!(f, ", {}", expr)}
})?;
write!(f, ")")
},
_ => todo!()
}
}
}
#[derive(Clone, Debug)]
#[warn(clippy::large_enum_variant)]
pub enum Expression {
Identifier(String),
Nil,
True,
False,
Integer(i64),
String(String),
Table {
array: Vec<Expression>,
key_value: Vec<KeyValue>
},
Function {
arguments: Vec<String>,
body: Block
},
Call {
function: Box<Expression>,
arguments: Vec<Expression>
},
MethodCall {
class: Box<Expression>,
method: String,
arguments: Vec<Expression>
},
Index {
indexee: Box<Expression>,
index: Box<Expression>
},
BinaryOperation {
left: Box<Expression>,
operator: BinaryOperator,
right: Box<Expression>
},
UnaryOperation {
operator: UnaryOperator,
operand: Box<Expression>
}
}
impl Display for Expression {
fn fmt(&self, f: &mut Formatter) -> FMTResult {
match self {
Self::Identifier(identifier) => write!(f, "{}", identifier),
Self::Nil => write!(f, "nil"),
Self::True => write!(f, "true"),
Self::False => write!(f, "false"),
Self::Integer(integer) => write!(f, "{}", integer),
Self::String(string) => write!(f, "{:?}", string),
Self::Table {array, key_value} => {
write!(f, "{{")?;
let mut first = true;
let mut is_first = || {let value = first; first = false; value};
array.iter().try_for_each(|value| if is_first() {
write!(f, "{}", value)
} else {
write!(f, ", {}", value)
})?;
key_value.iter().try_for_each(|KeyValue {key, value}| if is_first() {
write!(f, "[{}] = {}", key, value)
} else {
write!(f, ", [{}] = {}", key, value)
})?;
write!(f, "}})")
},
Self::Function {arguments, body} => {
write!(f, "function(")?;
arguments.iter().enumerate().try_for_each(|(index, expr)| {
if index == 0 {write!(f, "{}", expr)} else {write!(f, ", {}", expr)}
})?;
write!(f, ")\n{}end", body)
},
Self::Call {function, arguments} => {
write!(f, "{}(", function)?;
arguments.iter().enumerate().try_for_each(|(index, expr)| {
if index == 0 {write!(f, "{}", expr)} else {write!(f, ", {}", expr)}
})?;
write!(f, ")")
},
Self::Index {indexee, index} => write!(f, "{}[{}]", indexee, index),
Self::BinaryOperation {left, operator, right} =>
write!(f, "{} {} {}", left, operator, right),
Self::UnaryOperation {operator: UnaryOperator::LogicalNot, operand} =>
write!(f, "not {}", operand),
Self::UnaryOperation {operator, operand} =>
write!(f, "{}{}", operator, operand),
_ => todo!()
}
}
}
#[derive(Clone, Debug)]
pub struct ElseIf {
pub condition: Expression,
pub then: Block
}
#[derive(Clone, Debug)]
pub enum AssignmentTarget {
Identifier(String),
Index {
indexee: Expression,
index: Expression
}
}
impl TryFrom<Expression> for AssignmentTarget {
type Error = ASTError;
fn try_from(value: Expression) -> Result<Self> {
Ok(match value {
Expression::Identifier(identifier) =>
Self::Identifier(identifier),
Expression::Index {indexee, index} =>
Self::Index {indexee: *indexee, index: *index},
_ => return Err(ASTError::Parser(Error(None))) })
}
}
#[derive(Clone, Debug)]
pub struct KeyValue {
pub key: Expression,
pub value: Expression
}
#[derive(Clone, Copy, Debug)]
pub enum BinaryOperator {
Add,
Subtract,
Multiply,
Divide,
FloorDivide,
Modulo,
Exponent,
BitwiseAnd,
BitwiseOr,
BitwiseXOr,
ShiftLeft,
ShiftRight,
Equal,
NotEqual,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
LogicalAnd,
LogicalOr,
Concat
}
impl Display for BinaryOperator {
fn fmt(&self, f: &mut Formatter) -> FMTResult {
match self {
Self::Add => write!(f, "+"),
Self::Subtract => write!(f, "-"),
Self::Multiply => write!(f, "*"),
Self::Divide => write!(f, "/"),
Self::FloorDivide => write!(f, "//"),
Self::Modulo => write!(f, "%"),
Self::Exponent => write!(f, "^"),
Self::BitwiseAnd => write!(f, "&"),
Self::BitwiseOr => write!(f, "|"),
Self::BitwiseXOr => write!(f, "~"),
Self::ShiftLeft => write!(f, "<<"),
Self::ShiftRight => write!(f, ">>"),
Self::Equal => write!(f, "=="),
Self::NotEqual => write!(f, "~="),
Self::LessThan => write!(f, "<"),
Self::LessThanOrEqual => write!(f, "<="),
Self::GreaterThan => write!(f, ">"),
Self::GreaterThanOrEqual => write!(f, ">="),
Self::LogicalAnd => write!(f, "and"),
Self::LogicalOr => write!(f, "or"),
Self::Concat => write!(f, "..")
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum UnaryOperator {
Negate,
BitwiseNot,
LogicalNot,
Length
}
impl Display for UnaryOperator {
fn fmt(&self, f: &mut Formatter) -> FMTResult {
match self {
Self::Negate => write!(f, "-"),
Self::BitwiseNot => write!(f, "~"),
Self::LogicalNot => write!(f, "not"),
Self::Length => write!(f, "#")
}
}
}