1#[cfg(feature = "unsafe-vars")]
28use crate::parser::StdFunc::EUnsafeVar;
29use crate::parser::{
30 BinaryOp::{
31 self, EAdd, EDiv, EExp, EMod, EMul, ESub, EAND, EEQ, EGT, EGTE, ELT, ELTE, ENE, EOR,
32 },
33 ExprPair, Expression, PrintFunc,
34 StdFunc::{
35 self, EFunc, EFuncACos, EFuncACosH, EFuncASin, EFuncASinH, EFuncATan, EFuncATanH, EFuncAbs,
36 EFuncCeil, EFuncCos, EFuncCosH, EFuncE, EFuncFloor, EFuncInt, EFuncLog, EFuncMax, EFuncMin,
37 EFuncPi, EFuncRound, EFuncSign, EFuncSin, EFuncSinH, EFuncTan, EFuncTanH, EVar,
38 },
39 UnaryOp::{self, ENeg, ENot, EParentheses, EPos},
40 Value,
41};
42use crate::slab::{CompileSlab, ParseSlab};
43use crate::Error;
44
45#[macro_export]
47macro_rules! bool_to_f64 {
48 ($b:expr) => {
49 if $b {
50 1.0
51 } else {
52 0.0
53 }
54 };
55}
56
57#[derive(Debug, PartialEq, Copy, Clone)]
62pub struct InstructionI(pub usize);
63
64#[derive(Debug, PartialEq)]
66pub enum IC {
67 I(InstructionI),
68 C(f64),
69}
70
71macro_rules! instr_to_ic {
72 ($cslab:ident, $instr:ident) => {
73 match $instr {
74 IConst(c) => IC::C(c),
75 _ => IC::I($cslab.push_instr($instr)),
76 }
77 };
78}
79macro_rules! ic_to_instr {
80 ($cslab:expr, $dst:ident, $ic:ident) => {
81 match $ic {
82 IC::C(c) => {
83 $dst = IConst(*c);
84 &$dst
85 }
86 IC::I(i) => get_instr!($cslab, i),
87 }
88 };
89}
90
91#[derive(Debug, PartialEq)]
93pub enum Instruction {
94 IConst(f64),
96
97 INeg(InstructionI),
101 INot(InstructionI),
102 IInv(InstructionI),
103
104 IAdd(InstructionI, IC),
106 IMul(InstructionI, IC),
108 IMod {
110 dividend: IC,
111 divisor: IC,
112 },
113 IExp {
114 base: IC,
115 power: IC,
116 },
117
118 ILT(IC, IC),
120 ILTE(IC, IC),
121 IEQ(IC, IC),
122 INE(IC, IC),
123 IGTE(IC, IC),
124 IGT(IC, IC),
125
126 IOR(InstructionI, IC),
128 IAND(InstructionI, IC),
129
130 IVar(String),
132 #[cfg(feature = "unsafe-vars")]
133 IUnsafeVar {
134 name: String,
135 ptr: *const f64,
136 },
137 IFunc {
138 name: String,
139 args: Vec<IC>,
140 },
141
142 IFuncInt(InstructionI),
143 IFuncCeil(InstructionI),
144 IFuncFloor(InstructionI),
145 IFuncAbs(InstructionI),
146 IFuncSign(InstructionI),
147 IFuncLog {
148 base: IC,
149 of: IC,
150 },
151 IFuncRound {
152 modulus: IC,
153 of: IC,
154 },
155 IFuncMin(InstructionI, IC),
156 IFuncMax(InstructionI, IC),
157
158 IFuncSin(InstructionI),
159 IFuncCos(InstructionI),
160 IFuncTan(InstructionI),
161 IFuncASin(InstructionI),
162 IFuncACos(InstructionI),
163 IFuncATan(InstructionI),
164 IFuncSinH(InstructionI),
165 IFuncCosH(InstructionI),
166 IFuncTanH(InstructionI),
167 IFuncASinH(InstructionI),
168 IFuncACosH(InstructionI),
169 IFuncATanH(InstructionI),
170
171 IPrintFunc(PrintFunc), }
173use crate::{eval_var, EvalNamespace};
174#[cfg(feature = "unsafe-vars")]
175use Instruction::IUnsafeVar;
176use Instruction::{
177 IAdd, IConst, IExp, IFunc, IFuncACos, IFuncACosH, IFuncASin, IFuncASinH, IFuncATan, IFuncATanH,
178 IFuncAbs, IFuncCeil, IFuncCos, IFuncCosH, IFuncFloor, IFuncInt, IFuncLog, IFuncMax, IFuncMin,
179 IFuncRound, IFuncSign, IFuncSin, IFuncSinH, IFuncTan, IFuncTanH, IInv, IMod, IMul, INeg, INot,
180 IPrintFunc, IVar, IAND, IEQ, IGT, IGTE, ILT, ILTE, INE, IOR,
181};
182#[cfg(feature = "unsafe-vars")]
183unsafe impl Send for Instruction {}
184
185impl Default for Instruction {
186 fn default() -> Self {
187 IConst(std::f64::NAN)
188 }
189}
190
191pub trait Compiler {
193 fn compile(
197 &self,
198 pslab: &ParseSlab,
199 cslab: &mut CompileSlab,
200 ns: &mut impl EvalNamespace,
201 ) -> Instruction;
202}
203
204#[derive(Debug)]
205struct ExprSlice<'s> {
206 first: &'s Value,
207 pairs: Vec<&'s ExprPair>,
208}
209impl<'s> ExprSlice<'s> {
210 fn new(first: &Value) -> ExprSlice<'_> {
211 ExprSlice {
212 first,
213 pairs: Vec::with_capacity(8),
214 }
215 }
216 fn from_expr(expr: &Expression) -> ExprSlice<'_> {
217 let mut sl = ExprSlice::new(&expr.first);
218 for exprpairref in expr.pairs.iter() {
219 sl.pairs.push(exprpairref)
220 }
221 sl
222 }
223 fn split(&self, bop: BinaryOp, dst: &mut Vec<ExprSlice<'s>>) {
224 dst.push(ExprSlice::new(&self.first));
225 for exprpair in self.pairs.iter() {
226 if exprpair.0 == bop {
227 dst.push(ExprSlice::new(&exprpair.1));
228 } else {
229 match dst.last_mut() {
230 Some(cur) => cur.pairs.push(exprpair),
231 None => (), }
233 }
234 }
235 }
236 fn split_multi(
237 &self,
238 search: &[BinaryOp],
239 xsdst: &mut Vec<ExprSlice<'s>>,
240 opdst: &mut Vec<&'s BinaryOp>,
241 ) {
242 xsdst.push(ExprSlice::new(&self.first));
243 for exprpair in self.pairs.iter() {
244 if search.contains(&exprpair.0) {
245 xsdst.push(ExprSlice::new(&exprpair.1));
246 opdst.push(&exprpair.0);
247 } else {
248 match xsdst.last_mut() {
249 Some(cur) => cur.pairs.push(exprpair),
250 None => (), }
252 }
253 }
254 }
255}
256
257#[macro_export]
259macro_rules! f64_eq {
260 ($l:ident, $r:literal) => {
261 ($l - $r).abs() <= 8.0 * std::f64::EPSILON
262 };
263 ($l:ident, $r:ident) => {
264 ($l - $r).abs() <= 8.0 * std::f64::EPSILON
265 };
266 ($l:expr, $r:literal) => {
267 ($l - $r).abs() <= 8.0 * std::f64::EPSILON
268 };
269 ($l:expr, $r:expr) => {
270 (($l) - ($r)).abs() <= 8.0 * std::f64::EPSILON
271 };
272}
273
274#[macro_export]
278macro_rules! f64_ne {
279 ($l:ident, $r:literal) => {
280 ($l - $r).abs() > 8.0 * std::f64::EPSILON
281 };
282 ($l:ident, $r:ident) => {
283 ($l - $r).abs() > 8.0 * std::f64::EPSILON
284 };
285 ($l:expr, $r:literal) => {
286 ($l - $r).abs() > 8.0 * std::f64::EPSILON
287 };
288 ($l:expr, $r:expr) => {
289 (($l) - ($r)).abs() > 8.0 * std::f64::EPSILON
290 };
291}
292fn neg_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
293 if let IConst(c) = instr {
294 IConst(-c)
295 } else if let INeg(i) = instr {
296 cslab.take_instr(i)
297 } else {
298 INeg(cslab.push_instr(instr))
299 }
300}
301fn not_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
302 if let IConst(c) = instr {
303 IConst(bool_to_f64!(f64_eq!(c, 0.0)))
304 } else if let INot(i) = instr {
305 cslab.take_instr(i)
306 } else {
307 INot(cslab.push_instr(instr))
308 }
309}
310fn inv_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
311 if let IConst(c) = instr {
312 IConst(1.0 / c)
313 } else if let IInv(i) = instr {
314 cslab.take_instr(i)
315 } else {
316 IInv(cslab.push_instr(instr))
317 }
318}
319fn compile_mul(instrs: Vec<Instruction>, cslab: &mut CompileSlab) -> Instruction {
320 let mut out = IConst(1.0);
321 let mut out_set = false;
322 let mut const_prod = 1.0;
323 for instr in instrs {
324 if let IConst(c) = instr {
325 const_prod *= c; } else {
327 if out_set {
328 out = IMul(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
329 } else {
330 out = instr;
331 out_set = true;
332 }
333 }
334 }
335 if f64_ne!(const_prod, 1.0) {
336 if out_set {
337 out = IMul(cslab.push_instr(out), IC::C(const_prod));
338 } else {
339 out = IConst(const_prod);
340 }
341 }
342 out
343}
344fn compile_add(instrs: Vec<Instruction>, cslab: &mut CompileSlab) -> Instruction {
345 let mut out = IConst(0.0);
346 let mut out_set = false;
347 let mut const_sum = 0.0;
348 for instr in instrs {
349 if let IConst(c) = instr {
350 const_sum += c; } else {
352 if out_set {
353 out = IAdd(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
354 } else {
355 out = instr;
356 out_set = true;
357 }
358 }
359 }
360 if f64_ne!(const_sum, 0.0) {
361 if out_set {
362 out = IAdd(cslab.push_instr(out), IC::C(const_sum));
363 } else {
364 out = IConst(const_sum);
365 }
366 }
367 out
368}
369pub(crate) fn log(base: f64, n: f64) -> f64 {
370 if f64_eq!(base, 2.0) {
372 return n.log2();
373 }
374 if f64_eq!(base, 10.0) {
375 return n.log10();
376 }
377 n.log(base)
378}
379
380fn push_mul_leaves(
382 instrs: &mut Vec<Instruction>,
383 cslab: &mut CompileSlab,
384 li: InstructionI,
385 ric: IC,
386) {
387 match ric {
389 IC::I(ri) => {
390 let instr = cslab.take_instr(ri);
391 if let IMul(rli, rric) = instr {
392 push_mul_leaves(instrs, cslab, rli, rric);
393 } else {
394 instrs.push(instr);
395 }
396 }
397 IC::C(c) => instrs.push(IConst(c)),
398 };
399
400 let instr = cslab.take_instr(li);
401 if let IMul(lli, lric) = instr {
402 push_mul_leaves(instrs, cslab, lli, lric);
403 } else {
404 instrs.push(instr);
405 }
406}
407fn push_add_leaves(
408 instrs: &mut Vec<Instruction>,
409 cslab: &mut CompileSlab,
410 li: InstructionI,
411 ric: IC,
412) {
413 match ric {
415 IC::I(ri) => {
416 let instr = cslab.take_instr(ri);
417 if let IAdd(rli, rric) = instr {
418 push_add_leaves(instrs, cslab, rli, rric);
419 } else {
420 instrs.push(instr);
421 }
422 }
423 IC::C(c) => instrs.push(IConst(c)),
424 };
425
426 let instr = cslab.take_instr(li);
427 if let IAdd(lli, lric) = instr {
428 push_add_leaves(instrs, cslab, lli, lric);
429 } else {
430 instrs.push(instr);
431 }
432}
433
434impl Compiler for ExprSlice<'_> {
435 fn compile(
436 &self,
437 pslab: &ParseSlab,
438 cslab: &mut CompileSlab,
439 ns: &mut impl EvalNamespace,
440 ) -> Instruction {
441 let mut lowest_op = match self.pairs.first() {
458 Some(p0) => p0.0,
459 None => return self.first.compile(pslab, cslab, ns),
460 };
461 for exprpair in self.pairs.iter() {
462 if exprpair.0 < lowest_op {
463 lowest_op = exprpair.0
464 }
465 }
466
467 if lowest_op == EEQ
469 || lowest_op == ENE
470 || lowest_op == ELT
471 || lowest_op == EGT
472 || lowest_op == ELTE
473 || lowest_op == EGTE
474 {
475 let mut ops = Vec::<&BinaryOp>::with_capacity(4);
476 let mut xss = Vec::<ExprSlice>::with_capacity(ops.len() + 1);
477 self.split_multi(&[EEQ, ENE, ELT, EGT, ELTE, EGTE], &mut xss, &mut ops);
478 let mut out = match xss.first() {
479 Some(xs) => xs.compile(pslab, cslab, ns),
480 None => IConst(std::f64::NAN), };
482 for (i, op) in ops.into_iter().enumerate() {
483 let instr = match xss.get(i + 1) {
484 Some(xs) => xs.compile(pslab, cslab, ns),
485 None => IConst(std::f64::NAN), };
487 if let IConst(l) = out {
488 if let IConst(r) = instr {
489 out = match op {
490 EEQ => IConst(bool_to_f64!(f64_eq!(l, r))),
491 ENE => IConst(bool_to_f64!(f64_ne!(l, r))),
492 ELT => IConst(bool_to_f64!(l < r)),
493 EGT => IConst(bool_to_f64!(l > r)),
494 ELTE => IConst(bool_to_f64!(l <= r)),
495 EGTE => IConst(bool_to_f64!(l >= r)),
496 _ => IConst(std::f64::NAN), };
498 continue;
499 }
500 }
501 out = match op {
502 EEQ => IEQ(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
503 ENE => INE(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
504 ELT => ILT(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
505 EGT => IGT(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
506 ELTE => ILTE(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
507 EGTE => IGTE(instr_to_ic!(cslab, out), instr_to_ic!(cslab, instr)),
508 _ => IConst(std::f64::NAN), };
510 }
511 return out;
512 }
513
514 match lowest_op {
515 EOR => {
516 let mut xss = Vec::<ExprSlice>::with_capacity(4);
517 self.split(EOR, &mut xss);
518 let mut out = IConst(0.0);
519 let mut out_set = false;
520 for xs in xss.iter() {
521 let instr = xs.compile(pslab, cslab, ns);
522 if out_set {
523 out = IOR(cslab.push_instr(out), instr_to_ic!(cslab, instr));
524 } else {
525 if let IConst(c) = instr {
526 if f64_ne!(c, 0.0) {
527 return instr;
528 }
529 } else {
532 out = instr;
533 out_set = true;
534 }
535 }
536 }
537 out
538 }
539 EAND => {
540 let mut xss = Vec::<ExprSlice>::with_capacity(4);
541 self.split(EAND, &mut xss);
542 let mut out = IConst(1.0);
543 let mut out_set = false;
544 for xs in xss.iter() {
545 let instr = xs.compile(pslab, cslab, ns);
546 if let IConst(c) = instr {
547 if f64_eq!(c, 0.0) {
548 return instr;
549 }
550 }
551 if out_set {
552 if let IConst(_) = out {
553 out = instr;
555 } else {
556 out = IAND(cslab.push_instr(out), instr_to_ic!(cslab, instr));
557 }
558 } else {
559 out = instr;
560 out_set = true;
561 }
562 }
563 out
564 }
565 EAdd => {
566 let mut xss = Vec::<ExprSlice>::with_capacity(4);
567 self.split(EAdd, &mut xss);
568 let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
569 for xs in xss {
570 let instr = xs.compile(pslab, cslab, ns);
571 if let IAdd(li, ric) = instr {
572 push_add_leaves(&mut instrs, cslab, li, ric); } else {
574 instrs.push(instr);
575 }
576 }
577 compile_add(instrs, cslab)
578 }
579 ESub => {
580 let mut xss = Vec::<ExprSlice>::with_capacity(4);
583 self.split(ESub, &mut xss);
584 let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
585 for (i, xs) in xss.into_iter().enumerate() {
586 let instr = xs.compile(pslab, cslab, ns);
587 if i == 0 {
588 instrs.push(instr);
589 } else {
590 instrs.push(neg_wrap(instr, cslab));
591 }
592 }
593 compile_add(instrs, cslab)
594 }
595 EMul => {
596 let mut xss = Vec::<ExprSlice>::with_capacity(4);
597 self.split(EMul, &mut xss);
598 let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
599 for xs in xss {
600 let instr = xs.compile(pslab, cslab, ns);
601 if let IMul(li, ric) = instr {
602 push_mul_leaves(&mut instrs, cslab, li, ric); } else {
604 instrs.push(instr);
605 }
606 }
607 compile_mul(instrs, cslab)
608 }
609 EDiv => {
610 let mut xss = Vec::<ExprSlice>::with_capacity(4);
613 self.split(EDiv, &mut xss);
614 let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
615 for (i, xs) in xss.into_iter().enumerate() {
616 let instr = xs.compile(pslab, cslab, ns);
617 if i == 0 {
618 instrs.push(instr);
619 } else {
620 instrs.push(inv_wrap(instr, cslab));
621 }
622 }
623 compile_mul(instrs, cslab)
624 }
625 EMod => {
669 let mut xss = Vec::<ExprSlice>::with_capacity(2);
670 self.split(EMod, &mut xss);
671 let mut out = IConst(0.0);
672 let mut out_set = false;
673 for xs in xss.iter() {
674 let instr = xs.compile(pslab, cslab, ns);
675 if out_set {
676 if let IConst(dividend) = out {
677 if let IConst(divisor) = instr {
678 out = IConst(dividend % divisor);
679 continue;
680 }
681 }
682 out = IMod {
683 dividend: instr_to_ic!(cslab, out),
684 divisor: instr_to_ic!(cslab, instr),
685 };
686 } else {
687 out = instr;
688 out_set = true;
689 }
690 }
691 out
692 }
693 EExp => {
694 let mut xss = Vec::<ExprSlice>::with_capacity(2);
696 self.split(EExp, &mut xss);
697 let mut out = IConst(0.0);
698 let mut out_set = false;
699 for xs in xss.into_iter().rev() {
700 let instr = xs.compile(pslab, cslab, ns);
701 if out_set {
702 if let IConst(power) = out {
703 if let IConst(base) = instr {
704 out = IConst(base.powf(power));
705 continue;
706 }
707 }
708 out = IExp {
709 base: instr_to_ic!(cslab, instr),
710 power: instr_to_ic!(cslab, out),
711 };
712 } else {
713 out = instr;
714 out_set = true;
715 }
716 }
717 out
718 }
719 ENE | EEQ | EGTE | ELTE | EGT | ELT => IConst(std::f64::NAN), }
742 }
743}
744
745impl Compiler for Expression {
746 fn compile(
747 &self,
748 pslab: &ParseSlab,
749 cslab: &mut CompileSlab,
750 ns: &mut impl EvalNamespace,
751 ) -> Instruction {
752 let top = ExprSlice::from_expr(&self);
753 top.compile(pslab, cslab, ns)
754 }
755}
756
757impl Compiler for Value {
758 fn compile(
759 &self,
760 pslab: &ParseSlab,
761 cslab: &mut CompileSlab,
762 ns: &mut impl EvalNamespace,
763 ) -> Instruction {
764 match self {
765 Value::EConstant(c) => IConst(*c),
766 Value::EUnaryOp(u) => u.compile(pslab, cslab, ns),
767 Value::EStdFunc(f) => f.compile(pslab, cslab, ns),
768 Value::EPrintFunc(pf) => IPrintFunc(pf.clone()),
769 }
770 }
771}
772
773impl Compiler for UnaryOp {
774 fn compile(
775 &self,
776 pslab: &ParseSlab,
777 cslab: &mut CompileSlab,
778 ns: &mut impl EvalNamespace,
779 ) -> Instruction {
780 match self {
781 EPos(i) => get_val!(pslab, i).compile(pslab, cslab, ns),
782 ENeg(i) => {
783 let instr = get_val!(pslab, i).compile(pslab, cslab, ns);
784 if let IConst(c) = instr {
785 IConst(-c)
786 } else {
787 neg_wrap(instr, cslab)
788 }
789 }
790 ENot(i) => {
791 let instr = get_val!(pslab, i).compile(pslab, cslab, ns);
792 if let IConst(c) = instr {
793 IConst(bool_to_f64!(f64_eq!(c, 0.0)))
794 } else {
795 not_wrap(instr, cslab)
796 }
797 }
798 EParentheses(i) => get_expr!(pslab, i).compile(pslab, cslab, ns),
799 }
800 }
801}
802
803impl Compiler for StdFunc {
804 fn compile(
805 &self,
806 pslab: &ParseSlab,
807 cslab: &mut CompileSlab,
808 ns: &mut impl EvalNamespace,
809 ) -> Instruction {
810 match self {
811 EVar(name) => IVar(name.clone()),
812 #[cfg(feature = "unsafe-vars")]
813 EUnsafeVar { name, ptr } => IUnsafeVar {
814 name: name.clone(),
815 ptr: *ptr,
816 },
817 EFunc { name, args: xis } => {
818 let mut args = Vec::<IC>::with_capacity(xis.len());
819 let mut f64_args = Vec::<f64>::with_capacity(xis.len());
820 let mut is_all_const = true;
821 for xi in xis {
822 let instr = get_expr!(pslab, xi).compile(pslab, cslab, ns);
823 if let IConst(c) = instr {
824 f64_args.push(c)
825 } else {
826 is_all_const = false;
827 }
828 args.push(instr_to_ic!(cslab, instr));
829 }
830 if is_all_const {
831 let computed_value = eval_var!(ns, name, f64_args, unsafe {
832 &mut *(&pslab.char_buf as *const _ as *mut _)
833 });
834 if let Ok(value) = computed_value {
835 IConst(value)
836 } else {
837 IFunc {
838 name: name.clone(),
839 args,
840 }
841 }
842 } else {
843 IFunc {
844 name: name.clone(),
845 args,
846 }
847 }
848 }
849
850 EFuncInt(i) => {
851 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
852 if let IConst(c) = instr {
853 IConst(c.trunc())
854 } else {
855 IFuncInt(cslab.push_instr(instr))
856 }
857 }
858 EFuncCeil(i) => {
859 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
860 if let IConst(c) = instr {
861 IConst(c.ceil())
862 } else {
863 IFuncCeil(cslab.push_instr(instr))
864 }
865 }
866 EFuncFloor(i) => {
867 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
868 if let IConst(c) = instr {
869 IConst(c.floor())
870 } else {
871 IFuncFloor(cslab.push_instr(instr))
872 }
873 }
874 EFuncAbs(i) => {
875 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
876 if let IConst(c) = instr {
877 IConst(c.abs())
878 } else {
879 IFuncAbs(cslab.push_instr(instr))
880 }
881 }
882 EFuncSign(i) => {
883 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
884 if let IConst(c) = instr {
885 IConst(c.signum())
886 } else {
887 IFuncSign(cslab.push_instr(instr))
888 }
889 }
890 EFuncLog {
891 base: baseopt,
892 expr: i,
893 } => {
894 let base = match baseopt {
895 Some(bi) => get_expr!(pslab, bi).compile(pslab, cslab, ns),
896 None => IConst(10.0),
897 };
898 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
899 if let IConst(b) = base {
900 if let IConst(n) = instr {
901 return IConst(log(b, n));
902 }
903 }
904 IFuncLog {
905 base: instr_to_ic!(cslab, base),
906 of: instr_to_ic!(cslab, instr),
907 }
908 }
909 EFuncRound {
910 modulus: modopt,
911 expr: i,
912 } => {
913 let modulus = match modopt {
914 Some(mi) => get_expr!(pslab, mi).compile(pslab, cslab, ns),
915 None => IConst(1.0),
916 };
917 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
918 if let IConst(m) = modulus {
919 if let IConst(n) = instr {
920 return IConst((n / m).round() * m); }
922 }
923 IFuncRound {
924 modulus: instr_to_ic!(cslab, modulus),
925 of: instr_to_ic!(cslab, instr),
926 }
927 }
928 EFuncMin {
929 first: fi,
930 rest: is,
931 } => {
932 let first = get_expr!(pslab, fi).compile(pslab, cslab, ns);
933 let mut rest = Vec::<Instruction>::with_capacity(is.len());
934 for i in is {
935 rest.push(get_expr!(pslab, i).compile(pslab, cslab, ns));
936 }
937 let mut out = IConst(0.0);
938 let mut out_set = false;
939 let mut const_min = 0.0;
940 let mut const_min_set = false;
941 if let IConst(f) = first {
942 const_min = f;
943 const_min_set = true;
944 } else {
945 out = first;
946 out_set = true;
947 }
948 for instr in rest {
949 if let IConst(f) = instr {
950 if const_min_set {
951 if f < const_min {
952 const_min = f;
953 }
954 } else {
955 const_min = f;
956 const_min_set = true;
957 }
958 } else {
959 if out_set {
960 out = IFuncMin(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
961 } else {
962 out = instr;
963 out_set = true;
964 }
965 }
966 }
967 if const_min_set {
968 if out_set {
969 out = IFuncMin(cslab.push_instr(out), IC::C(const_min));
970 } else {
971 out = IConst(const_min);
972 }
974 }
975 out
977 }
978 EFuncMax {
979 first: fi,
980 rest: is,
981 } => {
982 let first = get_expr!(pslab, fi).compile(pslab, cslab, ns);
983 let mut rest = Vec::<Instruction>::with_capacity(is.len());
984 for i in is {
985 rest.push(get_expr!(pslab, i).compile(pslab, cslab, ns));
986 }
987 let mut out = IConst(0.0);
988 let mut out_set = false;
989 let mut const_max = 0.0;
990 let mut const_max_set = false;
991 if let IConst(f) = first {
992 const_max = f;
993 const_max_set = true;
994 } else {
995 out = first;
996 out_set = true;
997 }
998 for instr in rest {
999 if let IConst(f) = instr {
1000 if const_max_set {
1001 if f > const_max {
1002 const_max = f;
1003 }
1004 } else {
1005 const_max = f;
1006 const_max_set = true;
1007 }
1008 } else {
1009 if out_set {
1010 out = IFuncMax(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
1011 } else {
1012 out = instr;
1013 out_set = true;
1014 }
1015 }
1016 }
1017 if const_max_set {
1018 if out_set {
1019 out = IFuncMax(cslab.push_instr(out), IC::C(const_max));
1020 } else {
1021 out = IConst(const_max);
1022 }
1024 }
1025 out
1027 }
1028
1029 EFuncE => IConst(std::f64::consts::E),
1030 EFuncPi => IConst(std::f64::consts::PI),
1031
1032 EFuncSin(i) => {
1033 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1034 if let IConst(c) = instr {
1035 IConst(c.sin())
1036 } else {
1037 IFuncSin(cslab.push_instr(instr))
1038 }
1039 }
1040 EFuncCos(i) => {
1041 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1042 if let IConst(c) = instr {
1043 IConst(c.cos())
1044 } else {
1045 IFuncCos(cslab.push_instr(instr))
1046 }
1047 }
1048 EFuncTan(i) => {
1049 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1050 if let IConst(c) = instr {
1051 IConst(c.tan())
1052 } else {
1053 IFuncTan(cslab.push_instr(instr))
1054 }
1055 }
1056 EFuncASin(i) => {
1057 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1058 if let IConst(c) = instr {
1059 IConst(c.asin())
1060 } else {
1061 IFuncASin(cslab.push_instr(instr))
1062 }
1063 }
1064 EFuncACos(i) => {
1065 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1066 if let IConst(c) = instr {
1067 IConst(c.acos())
1068 } else {
1069 IFuncACos(cslab.push_instr(instr))
1070 }
1071 }
1072 EFuncATan(i) => {
1073 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1074 if let IConst(c) = instr {
1075 IConst(c.atan())
1076 } else {
1077 IFuncATan(cslab.push_instr(instr))
1078 }
1079 }
1080 EFuncSinH(i) => {
1081 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1082 if let IConst(c) = instr {
1083 IConst(c.sinh())
1084 } else {
1085 IFuncSinH(cslab.push_instr(instr))
1086 }
1087 }
1088 EFuncCosH(i) => {
1089 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1090 if let IConst(c) = instr {
1091 IConst(c.cosh())
1092 } else {
1093 IFuncCosH(cslab.push_instr(instr))
1094 }
1095 }
1096 EFuncTanH(i) => {
1097 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1098 if let IConst(c) = instr {
1099 IConst(c.tanh())
1100 } else {
1101 IFuncTanH(cslab.push_instr(instr))
1102 }
1103 }
1104 EFuncASinH(i) => {
1105 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1106 if let IConst(c) = instr {
1107 IConst(c.asinh())
1108 } else {
1109 IFuncASinH(cslab.push_instr(instr))
1110 }
1111 }
1112 EFuncACosH(i) => {
1113 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1114 if let IConst(c) = instr {
1115 IConst(c.acosh())
1116 } else {
1117 IFuncACosH(cslab.push_instr(instr))
1118 }
1119 }
1120 EFuncATanH(i) => {
1121 let instr = get_expr!(pslab, i).compile(pslab, cslab, ns);
1122 if let IConst(c) = instr {
1123 IConst(c.atanh())
1124 } else {
1125 IFuncATanH(cslab.push_instr(instr))
1126 }
1127 }
1128 }
1129 }
1130}