use std::fmt;
use crate::token;
#[derive(Debug, PartialEq, Eq)]
pub enum Node {
Program(Vec<Statement>),
Stmt(Statement),
Expr(Expression),
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Node::Program(stmts) => write!(f, "{}", display_statements(stmts)),
Node::Stmt(stmt) => write!(f, "{}", stmt),
Node::Expr(expr) => write!(f, "{}", expr),
}
}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Statement {
Let(String, Expression),
Return(Expression),
Expr(Expression),
}
impl fmt::Display for Statement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Statement::Let(id, expr) => write!(f, "let {} = {};", id, expr),
Statement::Return(expr) => write!(f, "return {};", expr),
Statement::Expr(expr) => write!(f, "{}", expr),
}
}
}
pub type BlockStatement = Vec<Statement>;
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Expression {
Identifier(String),
Lit(Literal),
Prefix(token::Token, Box<Expression>),
Infix(token::Token, Box<Expression>, Box<Expression>),
If(Box<Expression>, BlockStatement, Option<BlockStatement>),
Fn(Vec<String>, BlockStatement),
Call(Box<Expression>, Vec<Expression>),
Index(Box<Expression>, Box<Expression>),
}
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expression::Identifier(id) => write!(f, "{}", id),
Expression::Prefix(op, right) => write!(f, "({}{})", op, right),
Expression::Infix(op, left, right) => write!(f, "({} {} {})", left, op, right),
Expression::Lit(literal) => write!(f, "{}", literal),
Expression::If(condition, consequence, alternative) => {
if let Some(alternative) = alternative {
write!(
f,
"if {} {{ {} }} else {{ {} }}",
condition,
display_statements(consequence),
display_statements(alternative),
)
} else {
write!(
f,
"if {} {{ {} }}",
condition,
display_statements(consequence),
)
}
}
Expression::Fn(parameters, body) => {
write!(
f,
"fn({}) {{ {} }}",
parameters.join(", "),
display_statements(body)
)
}
Expression::Call(function_expr, arguments) => {
write!(f, "{}({})", function_expr, display_expressions(arguments))
}
Expression::Index(left, index) => write!(f, "({}[{}])", left, index),
}
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Literal {
Integer(i32),
Boolean(bool),
String(String),
Array(Vec<Expression>),
Hash(Vec<(Expression, Expression)>),
}
impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Literal::Integer(int) => write!(f, "{}", int),
Literal::Boolean(bool) => write!(f, "{}", bool),
Literal::String(str) => write!(f, "\"{}\"", str),
Literal::Array(expressions) => write!(f, "[{}]", display_expressions(expressions)),
Literal::Hash(entries) => {
let hash = entries
.iter()
.map(|(k, v)| format!("{}: {}", k, v))
.collect::<Vec<String>>()
.join(", ");
write!(f, "{{{}}}", hash)
}
}
}
}
pub fn display_statements(stmts: &[Statement]) -> String {
stmts
.iter()
.map(|stmt| stmt.to_string())
.collect::<Vec<String>>()
.join("")
}
pub fn display_expressions(expressions: &[Expression]) -> String {
expressions
.iter()
.map(|expr| expr.to_string())
.collect::<Vec<String>>()
.join(", ")
}