use rimu_meta::Spanned;
use rust_decimal::Decimal;
use std::fmt;
use crate::{BinaryOperator, UnaryOperator};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Expression {
Null,
Boolean(bool),
String(String),
Number(Decimal),
List(Vec<SpannedExpression>),
Object(Vec<(Spanned<String>, SpannedExpression)>),
Identifier(String),
Unary {
right: Box<SpannedExpression>,
operator: UnaryOperator,
},
Binary {
left: Box<SpannedExpression>,
right: Box<SpannedExpression>,
operator: BinaryOperator,
},
Call {
function: Box<SpannedExpression>,
args: Vec<SpannedExpression>,
},
GetIndex {
container: Box<SpannedExpression>,
index: Box<SpannedExpression>,
},
GetKey {
container: Box<SpannedExpression>,
key: Spanned<String>,
},
GetSlice {
container: Box<SpannedExpression>,
start: Option<Box<SpannedExpression>>,
end: Option<Box<SpannedExpression>>,
},
Error,
}
pub type SpannedExpression = Spanned<Expression>;
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expression::Null => write!(f, "null"),
Expression::Boolean(boolean) => write!(f, "{}", boolean),
Expression::String(string) => write!(f, "\"{}\"", string),
Expression::Number(number) => write!(f, "{}", number),
Expression::List(list) => {
let keys = list
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>()
.join(", ");
write!(f, "[{}]", keys)
}
Expression::Object(object) => {
let entries = object
.iter()
.map(|(key, value)| format!("\"{}\": {}", key, value.to_string()))
.collect::<Vec<String>>()
.join(", ");
write!(f, "{{{}}}", entries)
}
Expression::Identifier(identifier) => write!(f, "{}", identifier),
Expression::Unary { right, operator } => write!(f, "{}{}", operator, right),
Expression::Binary {
left,
operator,
right,
} => write!(f, "{} {} {}", left, operator, right),
Expression::Call { function, args } => {
let args = args
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>()
.join(", ");
write!(f, "{}({})", function, args)
}
Expression::GetIndex { container, index } => write!(f, "{}[{}]", container, index),
Expression::GetKey { container, key } => write!(f, "{}.{}", container, key),
Expression::GetSlice {
container,
start,
end,
} => write!(
f,
"{}[{}:{}]",
container,
start.as_ref().map(|s| s.to_string()).unwrap_or("".into()),
end.as_ref().map(|e| e.to_string()).unwrap_or("".into()),
),
Expression::Error => write!(f, "error"),
}
}
}