use serde::{Deserialize, Serialize};
use crate::excel_error::ExcelError;
use crate::range_ref::RangeRef;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
pub enum Expr {
Ref(String),
Range(RangeRef),
Number(f64),
Str(String),
Bool(bool),
BinaryOp {
left: Box<Expr>,
op: BinOp,
right: Box<Expr>,
},
UnaryOp {
op: UnOp,
operand: Box<Expr>,
},
Call {
name: String,
args: Vec<Expr>,
},
Name(String),
ErrorLit(ExcelError),
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Pow,
Concat,
Eq,
Ne,
Lt,
Gt,
Le,
Ge,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
pub enum UnOp {
Neg,
Pos,
Percent,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn number_serializes_to_its_value() {
let v = serde_json::to_value(Expr::Number(1.0)).expect("serialize");
assert_eq!(v["Number"], 1.0);
}
#[test]
fn call_carries_name_and_args() {
let expr = Expr::Call {
name: "CEILING".to_string(),
args: vec![Expr::Number(700.0), Expr::Number(50.0)],
};
let v = serde_json::to_value(&expr).expect("serialize Call");
assert_eq!(v["Call"]["name"], "CEILING");
assert_eq!(v["Call"]["args"][0]["Number"], 700.0);
assert_eq!(v["Call"]["args"][1]["Number"], 50.0);
}
#[test]
fn range_stores_sheet_once_via_rangeref() {
let expr = Expr::Range(RangeRef {
sheet: "5_Quantities".to_string(),
start: "B2".to_string(),
end: "B10".to_string(),
});
let v = serde_json::to_value(&expr).expect("serialize Range");
assert_eq!(v["Range"]["sheet"], "5_Quantities");
assert_eq!(v["Range"]["start"], "B2");
assert_eq!(v["Range"]["end"], "B10");
}
#[test]
fn binary_op_round_trips_shape() {
let expr = Expr::BinaryOp {
left: Box::new(Expr::Ref("A1".to_string())),
op: BinOp::Mul,
right: Box::new(Expr::Number(1.05)),
};
let v = serde_json::to_value(&expr).expect("serialize BinaryOp");
assert_eq!(v["BinaryOp"]["left"]["Ref"], "A1");
assert_eq!(v["BinaryOp"]["op"], "Mul");
assert_eq!(v["BinaryOp"]["right"]["Number"], 1.05);
}
#[test]
fn error_lit_wraps_shared_excel_error() {
let expr = Expr::ErrorLit(ExcelError::Ref);
let v = serde_json::to_value(&expr).expect("serialize ErrorLit");
assert_eq!(v["ErrorLit"], "Ref");
}
#[test]
fn unary_op_serializes() {
let expr = Expr::UnaryOp {
op: UnOp::Neg,
operand: Box::new(Expr::Number(3.0)),
};
let v = serde_json::to_value(&expr).expect("serialize UnaryOp");
assert_eq!(v["UnaryOp"]["op"], "Neg");
assert_eq!(v["UnaryOp"]["operand"]["Number"], 3.0);
}
}