use std::fmt::{Write, Debug, Display};
use crate::lexer::{ TokenWithLocation, Token };
#[derive(Debug, Clone, PartialEq)]
pub enum Statement {
Expression(Expression),
Let {
ident: String,
expression: Expression
},
Assign {
assignable: Assignable,
expression: Expression
},
If {
cond: Expression,
body: Vec<Self>,
r#else: Option<Vec<Self>>
},
DoWhile {
body: Vec<Self>,
cond: Expression
},
While {
cond: Expression,
body: Vec<Self>
},
For {
init: Box<Self>,
cond: Expression,
update: Box<Self>,
body: Vec<Self>
},
Return(Option<Expression>),
FuncDecl(Function)
}
#[derive(Debug, Clone, PartialEq)]
pub struct Function {
pub ident: String,
pub params: Vec<String>,
pub body: Vec<Statement>
}
impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}({}) {{{}}}", &self.ident, join(&self.params, ", "), join(&self.body, " "))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Prefix {
op: PrefixOp,
expression: Box<Self>,
},
Infix {
op: InfixOp,
left: Box<Self>,
right: Box<Self>
},
Group(Box<Self>),
FuncCall {
func: Assignable,
params: Vec<Self>
},
Assignable(Assignable),
Literal(Literal)
}
#[derive(Debug, Clone, PartialEq)]
pub enum Assignable {
Var(String),
PropIndex {
obj: Box<Self>,
index: Box<Expression>
},
ObjectProp {
obj: Box<Self>,
prop: String
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
ArrayLit(Vec<Expression>),
ObjectLit(Vec<(String, Expression)>),
StringLit(String),
NumberLit(i64),
Bool(bool),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PrefixOp {
Neg,
Bang
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum InfixOp {
Add,
Sub,
Mult,
Div,
Lt,
Gt,
Eq,
NotEq
}
#[derive(Debug, PartialEq)]
pub struct TokenNotInfixOpErr(TokenWithLocation);
impl TryFrom<TokenWithLocation> for InfixOp {
type Error = TokenNotInfixOpErr;
fn try_from(value: TokenWithLocation) -> Result<Self, Self::Error> {
match value.clone().to_token() {
Token::PLUS => Ok(Self::Add),
Token::MINUS => Ok(Self::Sub),
Token::ASTERISK => Ok(Self::Mult),
Token::SLASH => Ok(Self::Div),
Token::LT => Ok(Self::Lt),
Token::GT => Ok(Self::Gt),
Token::EQ => Ok(Self::Eq),
Token::NOTEQ => Ok(Self::NotEq),
_ => Err(TokenNotInfixOpErr(value))
}
}
}
impl Display for TokenNotInfixOpErr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Could not translate token {} to Infix Operand", self.0.ref_token())
}
}
impl Display for PrefixOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Neg => write!(f, "-"),
Self::Bang => write!(f, "!")
}
}
}
impl Display for InfixOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Add => f.write_char('+'),
Self::Sub => f.write_char('-'),
Self::Mult => f.write_char('*'),
Self::Div => f.write_char('/'),
Self::Lt => f.write_char('<'),
Self::Gt => f.write_char('>'),
Self::Eq => f.write_str("=="),
Self::NotEq => f.write_str("!=")
}
}
}
impl Display for Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NumberLit(num) => write!(f, "{num}"),
Self::ArrayLit(arr) => {
write!(f, "[{}]", join(arr, ", "))
},
Self::StringLit(string) => f.write_str(string),
Self::ObjectLit(obj) => {
let obj = obj.iter().map(|(ident, value)| {
let mut output = ident.clone();
output.push_str(": ");
output.push_str(&value.to_string());
output
}).collect::<Vec<String>>().join(", ");
write!(f, "{{{obj}}}")
},
Self::Bool(bool) => write!(f, "{}", bool),
}
}
}
impl Display for Assignable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Var(var) => write!(f, "{var}"),
Self::PropIndex { obj, index } => write!(f, "{obj}[{index}]"),
Self::ObjectProp { obj, prop } => write!(f, "{obj}.{prop}")
}
}
}
impl Display for Expression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Prefix { op, expression } => write!(f, "{op}{expression}"),
Self::Infix { op, left, right } => write!(f, "({left} {op} {right})"),
Self::Group(exp) => write!(f, "({exp})"),
Self::FuncCall { func, params } => {
write!(f, "{func}({})", join(params, ", "))
},
Self::Assignable(assignable) => write!(f, "{assignable}"),
Self::Literal(lit) => write!(f, "{lit}")
}
}
}
impl Display for Statement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Expression(e) => write!(f, "{e}"),
Self::Let { ident, expression } => write!(f, "let {ident} = {expression};"),
Self::Assign { assignable, expression } => write!(f, "{assignable} = {expression};"),
Self::Return(value) => {
match value {
Some(value) => write!(f, "return {value};"),
None => write!(f, "return;"),
}
},
Self::If { cond, body, r#else } => {
let body = join(body, " ");
write!(f, "if {cond} {{{body}}}")?;
if let Some(block) = r#else {
write!(f, " else {}", join(block, " "))?;
}
Ok(())
},
Self::DoWhile { body, cond } => write!(f, "do {{{}}} while {cond}", join(body, " ")),
Self::While { cond, body } => write!(f, "while {cond} {{{}}}", join(body, " ")),
Self::For { init, cond, update, body } => write!(f, "for({init} {cond}; {update}){{{}}}", join(body, " ")),
Self::FuncDecl(func) => {
write!(f, "{func}")
}
}
}
}
pub fn join<'t, T: std::fmt::Display + 't>(vals: impl IntoIterator<Item = &'t T>, separator: &str) -> String {
let mut output = String::new();
let mut vals = vals.into_iter();
if let Some(val) = vals.next() {
write!(output, "{}", &val).unwrap();
};
for val in vals {
write!(output, "{separator}{val}").unwrap();
}
output
}