mod parse;
#[cfg(test)]
mod tests;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::common::ColumnName;
pub use parse::{ExpressionError, ExpressionErrorKind, MAX_DEPTH};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expression {
Column(ColumnName),
Number(NumberLiteral),
Negate(Box<Expression>),
Binary {
op: BinaryOp,
left: Box<Expression>,
right: Box<Expression>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BinaryOp {
Add,
Subtract,
Multiply,
Divide,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NumberLiteral(String);
impl Expression {
pub fn parse(input: &str) -> Result<Self, ExpressionError> {
parse::parse(input)
}
pub fn as_column(&self) -> Option<&ColumnName> {
match self {
Self::Column(column) => Some(column),
_ => None,
}
}
pub fn columns(&self) -> Vec<&ColumnName> {
let mut out = Vec::new();
self.collect_columns(&mut out);
out
}
fn collect_columns<'a>(&'a self, out: &mut Vec<&'a ColumnName>) {
match self {
Self::Column(column) => {
if !out.contains(&column) {
out.push(column);
}
}
Self::Number(_) => {}
Self::Negate(inner) => inner.collect_columns(out),
Self::Binary { left, right, .. } => {
left.collect_columns(out);
right.collect_columns(out);
}
}
}
fn precedence(&self) -> u8 {
match self {
Self::Binary { op, .. } => op.precedence(),
Self::Negate(_) => 3,
Self::Column(_) | Self::Number(_) => 4,
}
}
}
impl BinaryOp {
pub fn symbol(self) -> &'static str {
match self {
Self::Add => "+",
Self::Subtract => "-",
Self::Multiply => "*",
Self::Divide => "/",
}
}
fn precedence(self) -> u8 {
match self {
Self::Add | Self::Subtract => 1,
Self::Multiply | Self::Divide => 2,
}
}
}
impl NumberLiteral {
pub fn as_str(&self) -> &str {
&self.0
}
}
impl From<ColumnName> for Expression {
fn from(column: ColumnName) -> Self {
Self::Column(column)
}
}
impl FromStr for Expression {
type Err = ExpressionError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
Self::parse(input)
}
}
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Column(column) => f.write_str(column.as_ref()),
Self::Number(number) => f.write_str(number.as_str()),
Self::Negate(inner) => match **inner {
Self::Negate(_) => write!(f, "- {inner}"),
Self::Binary { .. } => write!(f, "-({inner})"),
Self::Column(_) | Self::Number(_) => write!(f, "-{inner}"),
},
Self::Binary { op, left, right } => {
write_operand(f, left, left.precedence() < op.precedence())?;
write!(f, " {} ", op.symbol())?;
write_operand(f, right, right.precedence() <= op.precedence())
}
}
}
}
fn write_operand(f: &mut fmt::Formatter<'_>, operand: &Expression, group: bool) -> fmt::Result {
if group {
write!(f, "({operand})")
} else {
write!(f, "{operand}")
}
}
impl Hash for Expression {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Self::Column(column) => column.hash(state),
other => other.to_string().hash(state),
}
}
}
impl Serialize for Expression {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.collect_str(self)
}
}
impl<'de> Deserialize<'de> for Expression {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let text = String::deserialize(deserializer)?;
Self::parse(&text)
.map_err(|e| serde::de::Error::custom(format!("invalid expression `{text}`: {e}")))
}
}