1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::grammar::*;
use crate::math::*;
use crate::utils::*;
macro_rules! get_binary_args {
    ($expr:expr, $op:pat) => {
        match $expr.as_ref() {
            Expr::BinaryExpr(BinaryExpr { op: $op, lhs, rhs }) => {
                match (lhs.as_ref(), rhs.as_ref()) {
                    (Expr::Const(l), Expr::Const(r)) => Some((l, r)),
                    _ => None,
                }
            }
            _ => None,
        }
    };
}
macro_rules! get_flattened_binary_args {
    ($expr:expr, $op:expr) => {
        match $expr.as_ref() {
            Expr::BinaryExpr(child) if child.op == $op => {
                Some(get_flattened_binary_args($expr, $op))
            }
            _ => None,
        }
    };
}
macro_rules! get_unary_arg {
    ($expr:expr, $op:pat) => {
        match $expr.as_ref() {
            Expr::UnaryExpr(UnaryExpr { op: $op, rhs }) => Some(rhs.clone()),
            _ => None,
        }
    };
}
pub(super) fn add(expr: RcExpr) -> Option<RcExpr> {
    let span = expr.span;
    let mut args = get_flattened_binary_args!(expr, BinaryOperator::Plus)?;
    let mut konst = 0.;
    let mut i = 0;
    for _ in 0..args.len() {
        match args[i].as_ref() {
            Expr::Const(f) => {
                konst += f;
                args.swap_remove(i);
            }
            _ => i += 1,
        }
    }
    args.push(rc_expr!(konst.into(), span));
    Some(unflatten_binary_expr(
        &args,
        BinaryOperator::Plus,
        UnflattenStrategy::Left,
    ))
}
pub(super) fn subtract(expr: RcExpr) -> Option<RcExpr> {
    let (l, r) = get_binary_args!(expr, BinaryOperator::Minus)?;
    Some(rc_expr!(Expr::Const(l - r), expr.span))
}
pub(super) fn multiply(expr: RcExpr) -> Option<RcExpr> {
    let span = expr.span;
    let mut args = get_flattened_binary_args!(expr, BinaryOperator::Mult)?;
    let mut konst = 1.;
    let mut i = 0;
    for _ in 0..args.len() {
        match args[i].as_ref() {
            Expr::Const(f) => {
                konst *= f;
                args.swap_remove(i);
            }
            _ => i += 1,
        }
    }
    args.push(rc_expr!(konst.into(), span));
    Some(unflatten_binary_expr(
        &args,
        BinaryOperator::Mult,
        UnflattenStrategy::Left,
    ))
}
pub(super) fn divide(expr: RcExpr) -> Option<RcExpr> {
    let og_span = expr.span;
    match expr.as_ref() {
        Expr::BinaryExpr(BinaryExpr {
            op: BinaryOperator::Div,
            lhs,
            rhs,
        }) => match (lhs.as_ref(), rhs.as_ref()) {
            (Expr::Const(l), Expr::Const(r)) => Some(rc_expr!(Expr::Const(l / r), og_span)),
            _ => {
                
                let (numerator, relative_to) = Poly::from_expr(lhs.clone(), None).ok()?;
                let relative_to = match relative_to {
                    Some(e) => e,
                    
                    
                    None => return None,
                };
                let (denominator, _) =
                    Poly::from_expr(rhs.clone(), Some(relative_to.clone())).ok()?;
                let (_, numerator, denominator) = gcd_poly_zz_heu(numerator, denominator).ok()?;
                
                let numer_expr = numerator.to_expr(relative_to.clone(), lhs.span);
                if denominator.is_one() {
                    Some(numer_expr)
                } else {
                    let denom_expr = denominator.to_expr(relative_to, rhs.span);
                    let division = BinaryExpr::div(numer_expr, denom_expr);
                    Some(rc_expr!(Expr::BinaryExpr(division), og_span))
                }
            }
        },
        _ => None,
    }
}
pub(super) fn modulo(expr: RcExpr) -> Option<RcExpr> {
    let (l, r) = get_binary_args!(expr, BinaryOperator::Mod)?;
    Some(rc_expr!(Expr::Const(l % r), expr.span))
}
pub(super) fn exponentiate(expr: RcExpr) -> Option<RcExpr> {
    let (l, r) = get_binary_args!(expr, BinaryOperator::Exp)?;
    Some(rc_expr!(Expr::Const(l.powf(*r)), expr.span))
}
pub(super) fn posate(expr: RcExpr) -> Option<RcExpr> {
    get_unary_arg!(expr, UnaryOperator::SignPositive)
}
pub(super) fn negate(expr: RcExpr) -> Option<RcExpr> {
    match get_unary_arg!(expr, UnaryOperator::SignNegative)?.as_ref() {
        Expr::Const(n) => Some(rc_expr!(Expr::Const(-n), expr.span)),
        _ => None,
    }
}