#[cfg(feature = "unsafe-vars")]
use crate::parser::StdFunc::EUnsafeVar;
use crate::parser::{
BinaryOp::{
self, EAdd, EDiv, EExp, EMod, EMul, ESub, EAND, EEQ, EGT, EGTE, ELT, ELTE, ENE, EOR,
},
ExprPair, Expression, PrintFunc,
StdFunc::{
self, EFunc, EFuncACos, EFuncACosH, EFuncASin, EFuncASinH, EFuncATan, EFuncATanH, EFuncAbs,
EFuncCeil, EFuncCos, EFuncCosH, EFuncE, EFuncFloor, EFuncInt, EFuncLog, EFuncMax, EFuncMin,
EFuncPi, EFuncRound, EFuncSign, EFuncSin, EFuncSinH, EFuncTan, EFuncTanH, EVar,
},
UnaryOp::{self, ENeg, ENot, EParentheses, EPos},
Value,
};
use crate::slab::{CompileSlab, ParseSlab};
use crate::Error;
#[macro_export]
macro_rules! bool_to_f64 {
($b:expr) => {
if $b {
1.0
} else {
0.0
}
};
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct InstructionI(pub usize);
#[derive(Debug, PartialEq)]
pub enum IC {
I(InstructionI),
C(f64),
}
macro_rules! instr_to_ic {
($cslab:ident, $instr:ident) => {
match $instr {
IConst(c) => IC::C(c),
_ => IC::I($cslab.push_instr($instr)),
}
};
}
macro_rules! ic_to_instr {
($cslab:expr, $dst:ident, $ic:ident) => {
match $ic {
IC::C(c) => {
$dst = IConst(*c);
&$dst
}
IC::I(i) => get_instr!($cslab, i),
}
};
}
#[derive(Debug, PartialEq)]
pub enum Instruction {
IConst(f64),
INeg(InstructionI),
INot(InstructionI),
IInv(InstructionI),
IAdd(InstructionI, IC),
IMul(InstructionI, IC),
IMod {
dividend: IC,
divisor: IC,
},
IExp {
base: IC,
power: IC,
},
ILT(IC, IC),
ILTE(IC, IC),
IEQ(IC, IC),
INE(IC, IC),
IGTE(IC, IC),
IGT(IC, IC),
IOR(InstructionI, IC),
IAND(InstructionI, IC),
IVar(String),
#[cfg(feature = "unsafe-vars")]
IUnsafeVar {
name: String,
ptr: *const f64,
},
IFunc {
name: String,
args: Vec<IC>,
},
IFuncInt(InstructionI),
IFuncCeil(InstructionI),
IFuncFloor(InstructionI),
IFuncAbs(InstructionI),
IFuncSign(InstructionI),
IFuncLog {
base: IC,
of: IC,
},
IFuncRound {
modulus: IC,
of: IC,
},
IFuncMin(InstructionI, IC),
IFuncMax(InstructionI, IC),
IFuncSin(InstructionI),
IFuncCos(InstructionI),
IFuncTan(InstructionI),
IFuncASin(InstructionI),
IFuncACos(InstructionI),
IFuncATan(InstructionI),
IFuncSinH(InstructionI),
IFuncCosH(InstructionI),
IFuncTanH(InstructionI),
IFuncASinH(InstructionI),
IFuncACosH(InstructionI),
IFuncATanH(InstructionI),
IPrintFunc(PrintFunc), }
use crate::{eval_var, EvalNamespace};
#[cfg(feature = "unsafe-vars")]
use Instruction::IUnsafeVar;
use Instruction::{
IAdd, IConst, IExp, IFunc, IFuncACos, IFuncACosH, IFuncASin, IFuncASinH, IFuncATan, IFuncATanH,
IFuncAbs, IFuncCeil, IFuncCos, IFuncCosH, IFuncFloor, IFuncInt, IFuncLog, IFuncMax, IFuncMin,
IFuncRound, IFuncSign, IFuncSin, IFuncSinH, IFuncTan, IFuncTanH, IInv, IMod, IMul, INeg, INot,
IPrintFunc, IVar, IAND, IEQ, IGT, IGTE, ILT, ILTE, INE, IOR,
};
#[cfg(feature = "unsafe-vars")]
unsafe impl Send for Instruction {}
impl Default for Instruction {
fn default() -> Self {
IConst(std::f64::NAN)
}
}
pub trait Compiler {
fn compile(
&self,
pslab: &ParseSlab,
cslab: &mut CompileSlab,
ns: &mut impl EvalNamespace,
) -> Instruction;
}
#[derive(Debug)]
struct ExprSlice<'s> {
first: &'s Value,
pairs: Vec<&'s ExprPair>,
}
impl<'s> ExprSlice<'s> {
fn new(first: &Value) -> ExprSlice<'_> {
ExprSlice {
first,
pairs: Vec::with_capacity(8),
}
}
fn from_expr(expr: &Expression) -> ExprSlice<'_> {
let mut sl = ExprSlice::new(&expr.first);
for exprpairref in expr.pairs.iter() {
sl.pairs.push(exprpairref)
}
sl
}
fn split(&self, bop: BinaryOp, dst: &mut Vec<ExprSlice<'s>>) {
dst.push(ExprSlice::new(&self.first));
for exprpair in self.pairs.iter() {
if exprpair.0 == bop {
dst.push(ExprSlice::new(&exprpair.1));
} else {
match dst.last_mut() {
Some(cur) => cur.pairs.push(exprpair),
None => (), }
}
}
}
fn split_multi(
&self,
search: &[BinaryOp],
xsdst: &mut Vec<ExprSlice<'s>>,
opdst: &mut Vec<&'s BinaryOp>,
) {
xsdst.push(ExprSlice::new(&self.first));
for exprpair in self.pairs.iter() {
if search.contains(&exprpair.0) {
xsdst.push(ExprSlice::new(&exprpair.1));
opdst.push(&exprpair.0);
} else {
match xsdst.last_mut() {
Some(cur) => cur.pairs.push(exprpair),
None => (), }
}
}
}
}
#[macro_export]
macro_rules! f64_eq {
($l:ident, $r:literal) => {
($l - $r).abs() <= 8.0 * std::f64::EPSILON
};
($l:ident, $r:ident) => {
($l - $r).abs() <= 8.0 * std::f64::EPSILON
};
($l:expr, $r:literal) => {
($l - $r).abs() <= 8.0 * std::f64::EPSILON
};
($l:expr, $r:expr) => {
(($l) - ($r)).abs() <= 8.0 * std::f64::EPSILON
};
}
#[macro_export]
macro_rules! f64_ne {
($l:ident, $r:literal) => {
($l - $r).abs() > 8.0 * std::f64::EPSILON
};
($l:ident, $r:ident) => {
($l - $r).abs() > 8.0 * std::f64::EPSILON
};
($l:expr, $r:literal) => {
($l - $r).abs() > 8.0 * std::f64::EPSILON
};
($l:expr, $r:expr) => {
(($l) - ($r)).abs() > 8.0 * std::f64::EPSILON
};
}
fn neg_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
if let IConst(c) = instr {
IConst(-c)
} else if let INeg(i) = instr {
cslab.take_instr(i)
} else {
INeg(cslab.push_instr(instr))
}
}
fn not_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
if let IConst(c) = instr {
IConst(bool_to_f64!(f64_eq!(c, 0.0)))
} else if let INot(i) = instr {
cslab.take_instr(i)
} else {
INot(cslab.push_instr(instr))
}
}
fn inv_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
if let IConst(c) = instr {
IConst(1.0 / c)
} else if let IInv(i) = instr {
cslab.take_instr(i)
} else {
IInv(cslab.push_instr(instr))
}
}
fn compile_mul(instrs: Vec<Instruction>, cslab: &mut CompileSlab) -> Instruction {
let mut out = IConst(1.0);
let mut out_set = false;
let mut const_prod = 1.0;
for instr in instrs {
if let IConst(c) = instr {
const_prod *= c; } else {
if out_set {
out = IMul(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
} else {
out = instr;
out_set = true;
}
}
}
if f64_ne!(const_prod, 1.0) {
if out_set {
out = IMul(cslab.push_instr(out), IC::C(const_prod));
} else {
out = IConst(const_prod);
}
}
out
}
fn compile_add(instrs: Vec<Instruction>, cslab: &mut CompileSlab) -> Instruction {
let mut out = IConst(0.0);
let mut out_set = false;
let mut const_sum = 0.0;
for instr in instrs {
if let IConst(c) = instr {
const_sum += c; } else {
if out_set {
out = IAdd(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
} else {
out = instr;
out_set = true;
}
}
}
if f64_ne!(const_sum, 0.0) {
if out_set {
out = IAdd(cslab.push_instr(out), IC::C(const_sum));
} else {
out = IConst(const_sum);
}
}
out
}
pub(crate) fn log(base: f64, n: f64) -> f64 {
if f64_eq!(base, 2.0) {
return n.log2();
}
if f64_eq!(base, 10.0) {
return n.log10();
}
n.log(base)
}
fn push_mul_leaves(
instrs: &mut Vec<Instruction>,
cslab: &mut CompileSlab,
li: InstructionI,
ric: IC,
) {
match ric {
IC::I(ri) => {
let instr = cslab.take_instr(ri);
if let IMul(rli, rric) = instr {
push_mul_leaves(instrs, cslab, rli, rric);
} else {
instrs.push(instr);
}
}
IC::C(c) => instrs.push(IConst(c)),
};
let instr = cslab.take_instr(li);
if let IMul(lli, lric) = instr {
push_mul_leaves(instrs, cslab, lli, lric);
} else {
instrs.push(instr);
}
}
fn push_add_leaves(
instrs: &mut Vec<Instruction>,
cslab: &mut CompileSlab,
li: InstructionI,
ric: IC,
) {
match ric {
IC::I(ri) => {
let instr = cslab.take_instr(ri);
if let IAdd(rli, rric) = instr {
push_add_leaves(instrs, cslab, rli, rric);
} else {
instrs.push(instr);
}
}
IC::C(c) => instrs.push(IConst(c)),
};
let instr = cslab.take_instr(li);
if let IAdd(lli, lric) = instr {
push_add_leaves(instrs, cslab, lli, lric);
} else {
instrs.push(instr);
}
}
impl Compiler for ExprSlice<'_> {
fn compile(
&self,
pslab: &ParseSlab,
cslab: &mut CompileSlab,
ns: &mut impl EvalNamespace,
) -> Instruction {
let mut lowest_op = match self.pairs.first() {
Some(p0) => p0.0,
None => return self.first.compile(pslab, cslab, ns),
};
for exprpair in self.pairs.iter() {
if exprpair.0 < lowest_op {
lowest_op = exprpair.0
}
}
if lowest_op == EEQ
|| lowest_op == ENE
|| lowest_op == ELT
|| lowest_op == EGT
|| lowest_op == ELTE
|| lowest_op == EGTE
{
let mut ops = Vec::<&BinaryOp>::with_capacity(4);
let mut xss = Vec::<ExprSlice>::with_capacity(ops.len() + 1);
self.split_multi(&[EEQ, ENE, ELT, EGT, ELTE, EGTE], &mut xss, &mut ops);
let mut out = match xss.first() {
Some(xs) => xs.compile(pslab, cslab, ns),
None => IConst(std::f64::NAN), };
for (i, op) in ops.into_iter().enumerate() {
let instr = match xss.get(i + 1) {
Some(xs) => xs.compile(pslab, cslab, ns),
None => IConst(std::f64::NAN), };
if let IConst(l) = out {
if let IConst(r) = instr {
out = match op {
EEQ => IConst(bool_to_f64!(f64_eq!(l, r))),
ENE => IConst(bool_to_f64!(f64_ne!(l, r))),
ELT => IConst(bool_to_f64!(l < r)),
EGT => IConst(bool_to_f64!(l > r)),
ELTE => IConst(bool_to_f64!(l <= r)),
EGTE => IConst(bool_to_f64!(l >= r)),
_ => IConst(std::f64::NAN), };
continue;
}
}
out = match op {
EEQ => IEQ(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
ENE => INE(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
ELT => ILT(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
EGT => IGT(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
ELTE => ILTE(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
EGTE => IGTE(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
_ => IConst(std::f64::NAN), };
}
return out;
}
match lowest_op {
EOR => {
let mut xss = Vec::<ExprSlice>::with_capacity(4);
self.split(EOR, &mut xss);
let mut out = IConst(0.0);
let mut out_set = false;
for xs in xss.iter() {
let instr = xs.compile(pslab, cslab, ns);
if out_set {
out = IOR(cslab.push_instr(out), instr_to_ic!(cslab, instr));
} else {
if let IConst(c) = instr {
if f64_ne!(c, 0.0) {
return instr;
}
} else {
out = instr;
out_set = true;
}
}
}
out
}
EAND => {
let mut xss = Vec::<ExprSlice>::with_capacity(4);
self.split(EAND, &mut xss);
let mut out = IConst(1.0);
let mut out_set = false;
for xs in xss.iter() {
let instr = xs.compile(pslab, cslab, ns);
if let IConst(c) = instr {
if f64_eq!(c, 0.0) {
return instr;
}
}
if out_set {
if let IConst(_) = out {
out = instr;
} else {
out = IAND(cslab.push_instr(out), instr_to_ic!(cslab, instr));
}
} else {
out = instr;
out_set = true;
}
}
out
}
EAdd => {
let mut xss = Vec::<ExprSlice>::with_capacity(4);
self.split(EAdd, &mut xss);
let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
for xs in xss {
let instr = xs.compile(pslab, cslab, ns);
if let IAdd(li, ric) = instr {
push_add_leaves(&mut instrs, cslab, li, ric); } else {
instrs.push(instr);
}
}
compile_add(instrs, cslab)
}
ESub => {
let mut xss = Vec::<ExprSlice>::with_capacity(4);
self.split(ESub, &mut xss);
let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
for (i, xs) in xss.into_iter().enumerate() {
let instr = xs.compile(pslab, cslab, ns);
if i == 0 {
instrs.push(instr);
} else {
instrs.push(neg_wrap(instr, cslab));
}
}
compile_add(instrs, cslab)
}
EMul => {
let mut xss = Vec::<ExprSlice>::with_capacity(4);
self.split(EMul, &mut xss);
let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
for xs in xss {
let instr = xs.compile(pslab, cslab, ns);
if let IMul(li, ric) = instr {
push_mul_leaves(&mut instrs, cslab, li, ric); } else {
instrs.push(instr);
}
}
compile_mul(instrs, cslab)
}
EDiv => {
let mut xss = Vec::<ExprSlice>::with_capacity(4);
self.split(EDiv, &mut xss);
let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
for (i, xs) in xss.into_iter().enumerate() {
let instr = xs.compile(pslab, cslab, ns);
if i == 0 {
instrs.push(instr);
} else {
instrs.push(inv_wrap(instr, cslab));
}
}
compile_mul(instrs, cslab)
}
EMod => {
let mut xss = Vec::<ExprSlice>::with_capacity(2);
self.split(EMod, &mut xss);
let mut out = IConst(0.0);
let mut out_set = false;
for xs in xss.iter() {
let instr = xs.compile(pslab, cslab, ns);
if out_set {
if let IConst(dividend) = out {
if let IConst(divisor) = instr {
out = IConst(dividend % divisor);
continue;
}
}
out = IMod {
dividend: instr_to_ic!(cslab, out),
divisor: instr_to_ic!(cslab, instr),
};
} else {
out = instr;
out_set = true;
}
}
out
}
EExp => {
let mut xss = Vec::<ExprSlice>::with_capacity(2);
self.split(EExp, &mut xss);
let mut out = IConst(0.0);
let mut out_set = false;
for xs in xss.into_iter().rev() {
let instr = xs.compile(pslab, cslab, ns);
if out_set {
if let IConst(power) = out {
if let IConst(base) = instr {
out = IConst(base.powf(power));
continue;
}
}
out = IExp {
base: instr_to_ic!(cslab, instr),
power: instr_to_ic!(cslab, out),
};
} else {
out = instr;
out_set = true;
}
}
out
}
ENE | EEQ | EGTE | ELTE | EGT | ELT => IConst(std::f64::NAN), }
}
}
impl Compiler for Expression {
fn compile(
&self,
pslab: &ParseSlab,
cslab: &mut CompileSlab,
ns: &mut impl EvalNamespace,
) -> Instruction {
let top = ExprSlice::from_expr(&self);
top.compile(pslab, cslab, ns)
}
}
impl Compiler for Value {
fn compile(
&self,
pslab: &ParseSlab,
cslab: &mut CompileSlab,
ns: &mut impl EvalNamespace,
) -> Instruction {
match self {
Value::EConstant(c) => IConst(*c),
Value::EUnaryOp(u) => u.compile(pslab, cslab, ns),
Value::EStdFunc(f) => f.compile(pslab, cslab, ns),
Value::EPrintFunc(pf) => IPrintFunc(pf.clone()),
}
}
}
impl Compiler for UnaryOp {
fn compile(
&self,
pslab: &ParseSlab,
cslab: &mut CompileSlab,
ns: &mut impl EvalNamespace,
) -> Instruction {
match self {
EPos(i) => get_val!(pslab, i).compile(pslab, cslab, ns),
ENeg(i) => {
let instr = get_val!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(-c)
} else {
neg_wrap(instr, cslab)
}
}
ENot(i) => {
let instr = get_val!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(bool_to_f64!(f64_eq!(c, 0.0)))
} else {
not_wrap(instr, cslab)
}
}
EParentheses(i) => get_expr!(pslab, i).compile(pslab, cslab, ns),
}
}
}
impl Compiler for StdFunc {
fn compile(
&self,
pslab: &ParseSlab,
cslab: &mut CompileSlab,
ns: &mut impl EvalNamespace,
) -> Instruction {
match self {
EVar(name) => IVar(name.clone()),
#[cfg(feature = "unsafe-vars")]
EUnsafeVar { name, ptr } => IUnsafeVar {
name: name.clone(),
ptr: *ptr,
},
EFunc { name, args: xis } => {
let mut args = Vec::<IC>::with_capacity(xis.len());
let mut f64_args = Vec::<f64>::with_capacity(xis.len());
let mut is_all_const = true;
for xi in xis {
let instr = get_expr!(pslab, xi).compile(pslab, cslab, ns);
if let IConst(c) = instr {
f64_args.push(c)
} else {
is_all_const = false;
}
args.push(instr_to_ic!(cslab, instr));
}
if is_all_const {
let computed_value = eval_var!(ns, name, f64_args, unsafe {
&mut *(&pslab.char_buf as *const _ as *mut _)
});
if let Ok(value) = computed_value {
IConst(value)
} else {
IFunc {
name: name.clone(),
args,
}
}
} else {
IFunc {
name: name.clone(),
args,
}
}
}
EFuncInt(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.trunc())
} else {
IFuncInt(cslab.push_instr(instr))
}
}
EFuncCeil(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.ceil())
} else {
IFuncCeil(cslab.push_instr(instr))
}
}
EFuncFloor(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.floor())
} else {
IFuncFloor(cslab.push_instr(instr))
}
}
EFuncAbs(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.abs())
} else {
IFuncAbs(cslab.push_instr(instr))
}
}
EFuncSign(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.signum())
} else {
IFuncSign(cslab.push_instr(instr))
}
}
EFuncLog {
base: baseopt,
expr: i,
} => {
let base = match baseopt {
Some(bi) => get_expr!(pslab, bi).compile(pslab, cslab, ns),
None => IConst(10.0),
};
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(b) = base {
if let IConst(n) = instr {
return IConst(log(b, n));
}
}
IFuncLog {
base: instr_to_ic!(cslab, base),
of: instr_to_ic!(cslab, instr),
}
}
EFuncRound {
modulus: modopt,
expr: i,
} => {
let modulus = match modopt {
Some(mi) => get_expr!(pslab, mi).compile(pslab, cslab, ns),
None => IConst(1.0),
};
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(m) = modulus {
if let IConst(n) = instr {
return IConst((n / m).round() * m); }
}
IFuncRound {
modulus: instr_to_ic!(cslab, modulus),
of: instr_to_ic!(cslab, instr),
}
}
EFuncMin {
first: fi,
rest: is,
} => {
let first = get_expr!(pslab, fi).compile(pslab, cslab, ns);
let mut rest = Vec::<Instruction>::with_capacity(is.len());
for i in is {
rest.push(get_expr!(pslab, i).compile(pslab, cslab, ns));
}
let mut out = IConst(0.0);
let mut out_set = false;
let mut const_min = 0.0;
let mut const_min_set = false;
if let IConst(f) = first {
const_min = f;
const_min_set = true;
} else {
out = first;
out_set = true;
}
for instr in rest {
if let IConst(f) = instr {
if const_min_set {
if f < const_min {
const_min = f;
}
} else {
const_min = f;
const_min_set = true;
}
} else {
if out_set {
out = IFuncMin(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
} else {
out = instr;
out_set = true;
}
}
}
if const_min_set {
if out_set {
out = IFuncMin(cslab.push_instr(out), IC::C(const_min));
} else {
out = IConst(const_min);
}
}
out
}
EFuncMax {
first: fi,
rest: is,
} => {
let first = get_expr!(pslab, fi).compile(pslab, cslab, ns);
let mut rest = Vec::<Instruction>::with_capacity(is.len());
for i in is {
rest.push(get_expr!(pslab, i).compile(pslab, cslab, ns));
}
let mut out = IConst(0.0);
let mut out_set = false;
let mut const_max = 0.0;
let mut const_max_set = false;
if let IConst(f) = first {
const_max = f;
const_max_set = true;
} else {
out = first;
out_set = true;
}
for instr in rest {
if let IConst(f) = instr {
if const_max_set {
if f > const_max {
const_max = f;
}
} else {
const_max = f;
const_max_set = true;
}
} else {
if out_set {
out = IFuncMax(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
} else {
out = instr;
out_set = true;
}
}
}
if const_max_set {
if out_set {
out = IFuncMax(cslab.push_instr(out), IC::C(const_max));
} else {
out = IConst(const_max);
}
}
out
}
EFuncE => IConst(std::f64::consts::E),
EFuncPi => IConst(std::f64::consts::PI),
EFuncSin(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.sin())
} else {
IFuncSin(cslab.push_instr(instr))
}
}
EFuncCos(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.cos())
} else {
IFuncCos(cslab.push_instr(instr))
}
}
EFuncTan(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.tan())
} else {
IFuncTan(cslab.push_instr(instr))
}
}
EFuncASin(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.asin())
} else {
IFuncASin(cslab.push_instr(instr))
}
}
EFuncACos(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.acos())
} else {
IFuncACos(cslab.push_instr(instr))
}
}
EFuncATan(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.atan())
} else {
IFuncATan(cslab.push_instr(instr))
}
}
EFuncSinH(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.sinh())
} else {
IFuncSinH(cslab.push_instr(instr))
}
}
EFuncCosH(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.cosh())
} else {
IFuncCosH(cslab.push_instr(instr))
}
}
EFuncTanH(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.tanh())
} else {
IFuncTanH(cslab.push_instr(instr))
}
}
EFuncASinH(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.asinh())
} else {
IFuncASinH(cslab.push_instr(instr))
}
}
EFuncACosH(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.acosh())
} else {
IFuncACosH(cslab.push_instr(instr))
}
}
EFuncATanH(i) => {
let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
if let IConst(c) = instr {
IConst(c.atanh())
} else {
IFuncATanH(cslab.push_instr(instr))
}
}
}
}
}