use core::fmt;
use std::{
collections::HashMap,
fmt::Display,
sync::{Arc, Mutex},
};
use once_cell::sync::Lazy;
pub mod absolute_value;
pub mod constant;
pub mod derivative;
pub mod exponent;
pub mod fraction;
pub mod integer;
pub mod integral;
pub mod logarithm;
pub mod negation;
pub mod product;
pub mod read_from_json;
pub mod substitution;
pub mod sum;
pub mod trig_expression;
pub mod undefined;
pub mod variable;
pub use absolute_value::AbsoluteValue;
pub use constant::ConstantExp;
pub use derivative::Derivative;
pub use exponent::Exponent;
pub use fraction::Fraction;
pub use integer::Integer;
pub use integral::Integral;
pub use logarithm::Logarithm;
pub use negation::Negation;
pub use product::Product;
use serde_json::Value;
pub use sum::Sum;
pub use trig_expression::TrigExp;
pub use variable::Variable;
use self::{substitution::Substitution, undefined::UNDEFINED};
pub trait IExpression {
fn to_unambigious_string(&self) -> String;
fn id(&self) -> String;
fn to_json(&self) -> Value;
}
pub type ExpressionId = String;
#[derive(Eq, Clone)]
pub enum Expression {
Negation(Arc<Negation>),
Integer(Arc<Integer>),
Product(Arc<Product>),
Exponent(Arc<Exponent>),
Sum(Arc<Sum>),
Variable(Arc<Variable>),
Fraction(Arc<Fraction>),
Logarithm(Arc<Logarithm>),
Derivative(Arc<Derivative>),
Integral(Arc<Integral>),
Trig(Arc<TrigExp>),
AbsoluteValue(Arc<AbsoluteValue>),
ConstantExp(Arc<ConstantExp>),
Substitution(Arc<Substitution>),
Undefined,
}
impl fmt::Debug for Expression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:?}",
match self {
Expression::Negation(ref p) => p as &dyn fmt::Debug,
Expression::Integer(p) => p as &dyn fmt::Debug,
Expression::Product(p) => p as &dyn fmt::Debug,
Expression::Exponent(p) => p as &dyn fmt::Debug,
Expression::Sum(p) => p as &dyn fmt::Debug,
Expression::Variable(p) => p as &dyn fmt::Debug,
Expression::Fraction(p) => p as &dyn fmt::Debug,
Expression::Logarithm(p) => p as &dyn fmt::Debug,
Expression::Derivative(p) => p as &dyn fmt::Debug,
Expression::Integral(p) => p as &dyn fmt::Debug,
Expression::Trig(p) => p as &dyn fmt::Debug,
Expression::AbsoluteValue(p) => p as &dyn fmt::Debug,
Expression::ConstantExp(p) => p as &dyn fmt::Debug,
Expression::Substitution(p) => p as &dyn fmt::Debug,
Expression::Undefined => {
return write!(f, "Undefined");
}
}
)
}
}
impl PartialEq for Expression {
fn eq(&self, other: &Self) -> bool {
if matches!(self, Expression::Undefined) && matches!(other, Expression::Undefined) {
return true;
}
let first: Arc<dyn IExpression> = match self {
Expression::Negation(p) => p.clone(),
Expression::Integer(p) => p.clone(),
Expression::Product(p) => p.clone(),
Expression::Exponent(p) => p.clone(),
Expression::Sum(p) => p.clone(),
Expression::Variable(p) => p.clone(),
Expression::Fraction(p) => p.clone(),
Expression::Logarithm(p) => p.clone(),
Expression::Derivative(p) => p.clone(),
Expression::Integral(p) => p.clone(),
Expression::Trig(p) => p.clone(),
Expression::AbsoluteValue(p) => p.clone(),
Expression::ConstantExp(p) => p.clone(),
Expression::Substitution(p) => p.clone(),
Expression::Undefined => return false,
};
let second: Arc<dyn IExpression> = match other {
Expression::Negation(p) => p.clone(),
Expression::Integer(p) => p.clone(),
Expression::Product(p) => p.clone(),
Expression::Exponent(p) => p.clone(),
Expression::Sum(p) => p.clone(),
Expression::Variable(p) => p.clone(),
Expression::Fraction(p) => p.clone(),
Expression::Logarithm(p) => p.clone(),
Expression::Derivative(p) => p.clone(),
Expression::Integral(p) => p.clone(),
Expression::Trig(p) => p.clone(),
Expression::AbsoluteValue(p) => p.clone(),
Expression::ConstantExp(p) => p.clone(),
Expression::Substitution(p) => p.clone(),
Expression::Undefined => return false,
};
Arc::ptr_eq(&first, &second)
}
}
static EXPRESSION_INSTANCES: Lazy<Mutex<HashMap<ExpressionId, Expression>>> =
Lazy::new(|| Mutex::new(HashMap::new()));
impl Expression {
pub fn as_stringable(&self) -> Arc<dyn IExpression> {
match self {
Expression::Integer(i) => i.clone(),
Expression::Negation(n) => n.clone(),
Expression::Product(p) => p.clone(),
Expression::Exponent(e) => e.clone(),
Expression::Sum(s) => s.clone(),
Expression::Variable(v) => v.clone(),
Expression::Fraction(f) => f.clone(),
Expression::Logarithm(l) => l.clone(),
Expression::Derivative(d) => d.clone(),
Expression::Integral(i) => i.clone(),
Expression::Trig(t) => t.clone(),
Expression::AbsoluteValue(a) => a.clone(),
Expression::ConstantExp(c) => c.clone(),
Expression::Substitution(s) => s.clone(),
Expression::Undefined => Arc::new(UNDEFINED),
}
}
pub fn to_json(&self) -> Value {
match self {
Expression::Integer(i) => i.to_json(),
Expression::Negation(n) => n.to_json(),
Expression::Product(p) => p.to_json(),
Expression::Exponent(e) => e.to_json(),
Expression::Sum(s) => s.to_json(),
Expression::Variable(v) => v.to_json(),
Expression::Fraction(f) => f.to_json(),
Expression::Logarithm(l) => l.to_json(),
Expression::Derivative(d) => d.to_json(),
Expression::Integral(i) => i.to_json(),
Expression::Trig(t) => t.to_json(),
Expression::AbsoluteValue(a) => a.to_json(),
Expression::ConstantExp(c) => c.to_json(),
Expression::Substitution(s) => s.to_json(),
Expression::Undefined => UNDEFINED.to_json(),
}
}
}
impl Display for Expression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_stringable().to_unambigious_string())
}
}
impl std::hash::Hash for Expression {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_stringable().id().hash(state)
}
}