use crate::slab::{ParseSlab, CompileSlab};
use crate::parser::{Expression, ExprPair, Value, UnaryOp::{self, EPos, ENeg, ENot, EParentheses}, BinaryOp::{self, EOR, EAND, ENE, EEQ, EGTE, ELTE, EGT, ELT, EAdd, ESub, EMul, EDiv, EMod, EExp}, StdFunc::{self, EVar, EFunc, EFuncInt, EFuncCeil, EFuncFloor, EFuncAbs, EFuncSign, EFuncLog, EFuncRound, EFuncMin, EFuncMax, EFuncE, EFuncPi, EFuncSin, EFuncCos, EFuncTan, EFuncASin, EFuncACos, EFuncATan, EFuncSinH, EFuncCosH, EFuncTanH, EFuncASinH, EFuncACosH, EFuncATanH}, PrintFunc};
#[cfg(feature="unsafe-vars")]
use crate::parser::StdFunc::EUnsafeVar;
#[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 Instruction::{IConst, INeg, INot, IInv, IAdd, IMul, IMod, IExp, ILT, ILTE, IEQ, INE, IGTE, IGT, IOR, IAND, IVar, IFunc, IFuncInt, IFuncCeil, IFuncFloor, IFuncAbs, IFuncSign, IFuncLog, IFuncRound, IFuncMin, IFuncMax, IFuncSin, IFuncCos, IFuncTan, IFuncASin, IFuncACos, IFuncATan, IFuncSinH, IFuncCosH, IFuncTanH, IFuncASinH, IFuncACosH, IFuncATanH, IPrintFunc};
#[cfg(feature="unsafe-vars")]
use Instruction::IUnsafeVar;
impl Default for Instruction {
fn default() -> Self { IConst(std::f64::NAN) }
}
pub trait Compiler {
fn compile(&self, pslab:&ParseSlab, cslab:&mut CompileSlab) -> 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) -> Instruction {
let mut lowest_op = match self.pairs.first() {
Some(p0) => p0.0,
None => return self.first.compile(pslab,cslab),
};
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),
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),
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);
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);
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);
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);
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);
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);
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);
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);
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) -> Instruction {
let top = ExprSlice::from_expr(&self);
top.compile(pslab,cslab)
}
}
impl Compiler for Value {
fn compile(&self, pslab:&ParseSlab, cslab:&mut CompileSlab) -> Instruction {
match self {
Value::EConstant(c) => IConst(*c),
Value::EUnaryOp(u) => u.compile(pslab,cslab),
Value::EStdFunc(f) => f.compile(pslab,cslab),
Value::EPrintFunc(pf) => IPrintFunc(pf.clone()),
}
}
}
impl Compiler for UnaryOp {
fn compile(&self, pslab:&ParseSlab, cslab:&mut CompileSlab) -> Instruction {
match self {
EPos(i) => get_val!(pslab,i).compile(pslab,cslab),
ENeg(i) => {
let instr = get_val!(pslab,i).compile(pslab,cslab);
if let IConst(c) = instr {
IConst(-c)
} else {
neg_wrap(instr,cslab)
}
}
ENot(i) => {
let instr = get_val!(pslab,i).compile(pslab,cslab);
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),
}
}
}
impl Compiler for StdFunc {
fn compile(&self, pslab:&ParseSlab, cslab:&mut CompileSlab) -> 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());
for xi in xis {
let instr = get_expr!(pslab,xi).compile(pslab,cslab);
args.push(instr_to_ic!(cslab,instr));
}
IFunc{name:name.clone(), args}
}
EFuncInt(i) => {
let instr = get_expr!(pslab,i).compile(pslab,cslab);
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);
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);
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);
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);
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),
None => IConst(10.0),
};
let instr = get_expr!(pslab,i).compile(pslab,cslab);
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),
None => IConst(1.0),
};
let instr = get_expr!(pslab,i).compile(pslab,cslab);
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);
let mut rest = Vec::<Instruction>::with_capacity(is.len());
for i in is { rest.push(get_expr!(pslab,i).compile(pslab,cslab)); }
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);
let mut rest = Vec::<Instruction>::with_capacity(is.len());
for i in is { rest.push(get_expr!(pslab,i).compile(pslab,cslab)); }
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
if let IConst(c) = instr {
IConst(c.atanh())
} else {
IFuncATanH(cslab.push_instr(instr))
}
}
}
}
}