1use std::cell::RefCell;
28
29#[cfg(feature = "unsafe-vars")]
30use crate::parser::StdFunc::EUnsafeVar;
31use crate::{parser::{
32 BinaryOp::{
33 self, EAdd, EDiv, EExp, EMod, EMul, ESub, EAND, EEQ, EGT, EGTE, ELT, ELTE, ENE, EOR,
34 },
35 ExprPair, Expression, PrintFunc,
36 StdFunc::{
37 self, EFunc, EFuncACos, EFuncACosH, EFuncASin, EFuncASinH, EFuncATan, EFuncATanH, EFuncAbs,
38 EFuncCeil, EFuncCos, EFuncCosH, EFuncE, EFuncFloor, EFuncInt, EFuncLog, EFuncMax, EFuncMin,
39 EFuncPi, EFuncRound, EFuncSign, EFuncSin, EFuncSinH, EFuncTan, EFuncTanH, EVar,
40 },
41 UnaryOp::{self, ENeg, ENot, EParentheses, EPos},
42 Value,
43}, ExpressionI};
44use crate::slab::{CompileSlab, ParseSlab};
45use crate::Error;
46
47#[macro_export]
49macro_rules! bool_to_f64 {
50 ($b:expr) => {
51 if $b {
52 1.0_f64
53 } else {
54 0.0_f64
55 }
56 };
57}
58
59#[derive(Debug, PartialEq, Eq, Copy, Clone)]
64pub struct InstructionI(pub usize);
65
66#[derive(Debug, PartialEq)]
68pub enum IC {
69 I(InstructionI),
70 C(f64),
71}
72
73macro_rules! instr_to_ic {
74 ($cslab:ident, $instr:ident) => {
75 match $instr {
76 IConst(c) => IC::C(c),
77 _ => IC::I($cslab.push_instr($instr)),
78 }
79 };
80}
81macro_rules! ic_to_instr {
82 ($cslab:expr, $dst:ident, $ic:ident) => {
83 match $ic {
84 IC::C(c) => {
85 $dst = IConst(*c);
86 &$dst
87 }
88 IC::I(i) => get_instr!($cslab, i),
89 }
90 };
91}
92
93#[derive(Debug, PartialEq)]
95pub enum Instruction {
96 IConst(f64),
98
99 INeg(InstructionI),
103 INot(InstructionI),
104 IInv(InstructionI),
105
106 IAdd(InstructionI, IC),
108 IMul(InstructionI, IC),
110 IMod {
112 dividend: IC,
113 divisor: IC,
114 },
115 IExp {
116 base: IC,
117 power: IC,
118 },
119
120 ILT(IC, IC),
122 ILTE(IC, IC),
123 IEQ(IC, IC),
124 INE(IC, IC),
125 IGTE(IC, IC),
126 IGT(IC, IC),
127
128 IOR(InstructionI, IC),
130 IAND(InstructionI, IC),
131
132 IVar(String),
134 #[cfg(feature = "unsafe-vars")]
135 IUnsafeVar {
136 name: String,
137 ptr: *const f64,
138 },
139 IFunc {
140 name: String,
141 args: Vec<IC>,
142 },
143
144 IFuncInt(InstructionI),
145 IFuncCeil(InstructionI),
146 IFuncFloor(InstructionI),
147 IFuncAbs(InstructionI),
148 IFuncSign(InstructionI),
149 IFuncLog {
150 base: IC,
151 of: IC,
152 },
153 IFuncRound {
154 modulus: IC,
155 of: IC,
156 },
157 IFuncMin(InstructionI, IC),
158 IFuncMax(InstructionI, IC),
159
160 IFuncSin(InstructionI),
161 IFuncCos(InstructionI),
162 IFuncTan(InstructionI),
163 IFuncASin(InstructionI),
164 IFuncACos(InstructionI),
165 IFuncATan(InstructionI),
166 IFuncSinH(InstructionI),
167 IFuncCosH(InstructionI),
168 IFuncTanH(InstructionI),
169 IFuncASinH(InstructionI),
170 IFuncACosH(InstructionI),
171 IFuncATanH(InstructionI),
172
173 IPrintFunc(PrintFunc), }
175use crate::{eval_var, EvalNamespace};
176#[cfg(feature = "unsafe-vars")]
177use Instruction::IUnsafeVar;
178use Instruction::{
179 IAdd, IConst, IExp, IFunc, IFuncACos, IFuncACosH, IFuncASin, IFuncASinH, IFuncATan, IFuncATanH,
180 IFuncAbs, IFuncCeil, IFuncCos, IFuncCosH, IFuncFloor, IFuncInt, IFuncLog, IFuncMax, IFuncMin,
181 IFuncRound, IFuncSign, IFuncSin, IFuncSinH, IFuncTan, IFuncTanH, IInv, IMod, IMul, INeg, INot,
182 IPrintFunc, IVar, IAND, IEQ, IGT, IGTE, ILT, ILTE, INE, IOR,
183};
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}
209
210impl<'s> ExprSlice<'s> {
211 fn new(first: &Value) -> ExprSlice<'_> {
212 ExprSlice {
213 first,
214 pairs: Vec::with_capacity(8),
215 }
216 }
217
218 fn from_expr(expr: &Expression) -> ExprSlice<'_> {
219 let mut sl = ExprSlice::new(&expr.first);
220 for exprpairref in &expr.pairs {
221 sl.pairs.push(exprpairref);
222 }
223 sl
224 }
225
226 fn split(&self, bop: BinaryOp, dst: &mut Vec<ExprSlice<'s>>) {
227 dst.push(ExprSlice::new(self.first));
228 for exprpair in &self.pairs {
229 if exprpair.0 == bop {
230 dst.push(ExprSlice::new(&exprpair.1));
231 } else if let Some(cur) = dst.last_mut() {
232 cur.pairs.push(exprpair);
233 }
234 }
235 }
236
237 fn split_multi(
238 &self,
239 search: &[BinaryOp],
240 xsdst: &mut Vec<ExprSlice<'s>>,
241 opdst: &mut Vec<&'s BinaryOp>,
242 ) {
243 xsdst.push(ExprSlice::new(self.first));
244 for exprpair in &self.pairs {
245 if search.contains(&exprpair.0) {
246 xsdst.push(ExprSlice::new(&exprpair.1));
247 opdst.push(&exprpair.0);
248 } else if let Some(cur) = xsdst.last_mut() {
249 cur.pairs.push(exprpair);
250 }
251 }
252 }
253
254 #[inline]
256 fn process_comparisons(
257 &self,
258 parsed_slab: &ParseSlab,
259 compiled_slab: &mut CompileSlab,
260 namespace: &mut impl EvalNamespace
261 ) -> Instruction {
262 let mut ops = Vec::<&BinaryOp>::with_capacity(4);
263 let mut xss = Vec::<ExprSlice>::with_capacity(ops.len() + 1);
264 self.split_multi(&[EEQ, ENE, ELT, EGT, ELTE, EGTE], &mut xss, &mut ops);
265 let mut out: Instruction = xss.first().map_or(IConst(std::f64::NAN), |xs| {
266 xs.compile(parsed_slab, compiled_slab, namespace)
267 });
268
269 for (i, op) in ops.into_iter().enumerate() {
270 let instruction: Instruction = xss.get(i + 1).map_or(IConst(f64::NAN), |xs| {
271 xs.compile(parsed_slab, compiled_slab, namespace)
272 });
273
274 if let IConst(l) = out {
275 if let IConst(r) = instruction {
276 out = match op {
277 EEQ => IConst(bool_to_f64!(crate::f64_eq!(l, r))),
278 ENE => IConst(bool_to_f64!(crate::f64_ne!(l, r))),
279 ELT => IConst(bool_to_f64!(l < r)),
280 EGT => IConst(bool_to_f64!(l > r)),
281 ELTE => IConst(bool_to_f64!(l <= r)),
282 EGTE => IConst(bool_to_f64!(l >= r)),
283 _ => IConst(std::f64::NAN), };
285 continue;
286 }
287 }
288 out = match op {
289 EEQ => IEQ(instr_to_ic!(compiled_slab, out), instr_to_ic!(compiled_slab, instruction)),
290 ENE => INE(instr_to_ic!(compiled_slab, out), instr_to_ic!(compiled_slab, instruction)),
291 ELT => ILT(instr_to_ic!(compiled_slab, out), instr_to_ic!(compiled_slab, instruction)),
292 EGT => IGT(instr_to_ic!(compiled_slab, out), instr_to_ic!(compiled_slab, instruction)),
293 ELTE => ILTE(instr_to_ic!(compiled_slab, out), instr_to_ic!(compiled_slab, instruction)),
294 EGTE => IGTE(instr_to_ic!(compiled_slab, out), instr_to_ic!(compiled_slab, instruction)),
295 _ => IConst(std::f64::NAN), };
297 }
298 out
299 }
300
301 #[inline]
303 fn process_or(
304 &self,
305 parsed_slab: &ParseSlab,
306 compiled_slab: &mut CompileSlab,
307 namespace: &mut impl EvalNamespace
308 ) -> Instruction {
309 let mut xss = Vec::<ExprSlice>::with_capacity(4);
310 self.split(EOR, &mut xss);
311 let mut out = IConst(0.0);
312 let mut out_set = false;
313 for xs in &xss {
314 let instr = xs.compile(parsed_slab, compiled_slab, namespace);
315 if out_set {
316 out = IOR(compiled_slab.push_instr(out), instr_to_ic!(compiled_slab, instr));
317 } else if let IConst(c) = instr {
318 if crate::f64_ne!(c, 0.0) {
319 return instr;
320 }
321 } else {
322 out = instr;
323 out_set = true;
324 }
325 }
326 out
327 }
328
329 #[inline]
331 fn process_and(
332 &self,
333 parsed_slab: &ParseSlab,
334 compiled_slab: &mut CompileSlab,
335 namespace: &mut impl EvalNamespace
336 ) -> Instruction {
337 let mut xss = Vec::<ExprSlice>::with_capacity(4);
338 self.split(EAND, &mut xss);
339 let mut out = IConst(1.0);
340 let mut out_set = false;
341 for xs in &xss {
342 let instr = xs.compile(parsed_slab, compiled_slab, namespace);
343 if let IConst(c) = instr {
344 if crate::f64_eq!(c, 0.0) {
345 return instr;
346 }
347 }
348 if out_set {
349 if let IConst(_) = out {
350 out = instr;
352 } else {
353 out = IAND(compiled_slab.push_instr(out), instr_to_ic!(compiled_slab, instr));
354 }
355 } else {
356 out = instr;
357 out_set = true;
358 }
359 }
360 out
361 }
362
363 #[inline]
365 fn process_addition(
366 &self,
367 parsed_slab: &ParseSlab,
368 compiled_slab: &mut CompileSlab,
369 namespace: &mut impl EvalNamespace
370 ) -> Instruction {
371 let mut xss = Vec::<ExprSlice>::with_capacity(4);
372 self.split(EAdd, &mut xss);
373 let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
374 for xs in xss {
375 let instr = xs.compile(parsed_slab, compiled_slab, namespace);
376 if let IAdd(li, ric) = instr {
377 push_add_leaves(&mut instrs, compiled_slab, li, &ric); } else {
379 instrs.push(instr);
380 }
381 }
382 compile_add(instrs, compiled_slab)
383 }
384
385 #[inline]
387 fn process_subtraction(&self, parsed_slab: &ParseSlab, compiled_slab: &mut CompileSlab, namespace: &mut impl EvalNamespace) -> Instruction {
388 let mut xss = Vec::<ExprSlice>::with_capacity(4);
391 self.split(ESub, &mut xss);
392 let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
393 for (i, xs) in xss.into_iter().enumerate() {
394 let instr = xs.compile(parsed_slab, compiled_slab, namespace);
395 if i == 0 {
396 instrs.push(instr);
397 } else {
398 instrs.push(neg_wrap(instr, compiled_slab));
399 }
400 }
401 compile_add(instrs, compiled_slab)
402 }
403
404 #[inline]
406 fn process_multiplication(
407 &self,
408 parsed_slab: &ParseSlab,
409 compiled_slab: &mut CompileSlab,
410 namespace: &mut impl EvalNamespace
411 ) -> Instruction {
412 let mut xss = Vec::<ExprSlice>::with_capacity(4);
413 self.split(EMul, &mut xss);
414 let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
415 for xs in xss {
416 let instr = xs.compile(parsed_slab, compiled_slab, namespace);
417 if let IMul(li, ric) = instr {
418 push_mul_leaves(&mut instrs, compiled_slab, li, &ric); } else {
420 instrs.push(instr);
421 }
422 }
423 compile_mul(instrs, compiled_slab)
424 }
425}
426
427macro_rules! process_fn {
431 ($name:ident, $operation:ident, $fallback:ident) => {
432 #[inline]
433 fn $name(
434 parsed_slab: &ParseSlab,
435 compiled_slab: &mut CompileSlab,
436 namespace: &mut impl EvalNamespace,
437 expr: ExpressionI
438 ) -> Instruction {
439 let instruction = get_expr!(parsed_slab, expr).compile(parsed_slab, compiled_slab, namespace);
440 if let IConst(target) = instruction {
441 IConst(target.$operation())
442 } else {
443 $fallback(compiled_slab.push_instr(instruction))
444 }
445 }
446 };
447}
448
449#[macro_export]
451macro_rules! f64_eq {
452 ($l:ident, $r:literal) => {
453 ($l - $r).abs() <= 8.0 * std::f64::EPSILON
454 };
455 ($l:ident, $r:ident) => {
456 ($l - $r).abs() <= 8.0 * std::f64::EPSILON
457 };
458 ($l:expr, $r:literal) => {
459 ($l - $r).abs() <= 8.0 * std::f64::EPSILON
460 };
461 ($l:expr, $r:expr) => {
462 (($l) - ($r)).abs() <= 8.0 * std::f64::EPSILON
463 };
464}
465
466#[macro_export]
470macro_rules! f64_ne {
471 ($l:ident, $r:literal) => {
472 ($l - $r).abs() > 8.0 * std::f64::EPSILON
473 };
474 ($l:ident, $r:ident) => {
475 ($l - $r).abs() > 8.0 * std::f64::EPSILON
476 };
477 ($l:expr, $r:literal) => {
478 ($l - $r).abs() > 8.0 * std::f64::EPSILON
479 };
480 ($l:expr, $r:expr) => {
481 (($l) - ($r)).abs() > 8.0 * std::f64::EPSILON
482 };
483}
484fn neg_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
485 if let IConst(c) = instr {
486 IConst(-c)
487 } else if let INeg(i) = instr {
488 cslab.take_instr(i)
489 } else {
490 INeg(cslab.push_instr(instr))
491 }
492}
493fn not_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
494 if let IConst(c) = instr {
495 IConst(bool_to_f64!(f64_eq!(c, 0.0)))
496 } else if let INot(i) = instr {
497 cslab.take_instr(i)
498 } else {
499 INot(cslab.push_instr(instr))
500 }
501}
502fn inv_wrap(instr: Instruction, cslab: &mut CompileSlab) -> Instruction {
503 if let IConst(c) = instr {
504 IConst(1.0 / c)
505 } else if let IInv(i) = instr {
506 cslab.take_instr(i)
507 } else {
508 IInv(cslab.push_instr(instr))
509 }
510}
511fn compile_mul(instrs: Vec<Instruction>, cslab: &mut CompileSlab) -> Instruction {
512 let mut out = IConst(1.0);
513 let mut out_set = false;
514 let mut const_prod = 1.0;
515 for instr in instrs {
516 if let IConst(c) = instr {
517 const_prod *= c; } else if out_set {
519 out = IMul(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
520 } else {
521 out = instr;
522 out_set = true;
523 }
524 }
525 if f64_ne!(const_prod, 1.0) {
526 if out_set {
527 out = IMul(cslab.push_instr(out), IC::C(const_prod));
528 } else {
529 out = IConst(const_prod);
530 }
531 }
532 out
533}
534fn compile_add(instrs: Vec<Instruction>, cslab: &mut CompileSlab) -> Instruction {
535 let mut out = IConst(0.0);
536 let mut out_set = false;
537 let mut const_sum = 0.0;
538 for instr in instrs {
539 if let IConst(c) = instr {
540 const_sum += c; } else if out_set {
542 out = IAdd(cslab.push_instr(out), IC::I(cslab.push_instr(instr)));
543 } else {
544 out = instr;
545 out_set = true;
546 }
547 }
548 if f64_ne!(const_sum, 0.0) {
549 if out_set {
550 out = IAdd(cslab.push_instr(out), IC::C(const_sum));
551 } else {
552 out = IConst(const_sum);
553 }
554 }
555 out
556}
557pub(crate) fn log(base: f64, n: f64) -> f64 {
558 if f64_eq!(base, 2.0) {
560 return n.log2();
561 }
562 if f64_eq!(base, 10.0) {
563 return n.log10();
564 }
565 n.log(base)
566}
567
568fn push_mul_leaves(
570 instrs: &mut Vec<Instruction>,
571 cslab: &mut CompileSlab,
572 li: InstructionI,
573 ric: &IC,
574) {
575 match *ric {
577 IC::I(ri) => {
578 let instr = cslab.take_instr(ri);
579 if let IMul(rli, rric) = instr {
580 push_mul_leaves(instrs, cslab, rli, &rric);
581 } else {
582 instrs.push(instr);
583 }
584 }
585 IC::C(c) => instrs.push(IConst(c)),
586 };
587
588 let instr = cslab.take_instr(li);
589 if let IMul(lli, lric) = instr {
590 push_mul_leaves(instrs, cslab, lli, &lric);
591 } else {
592 instrs.push(instr);
593 }
594}
595fn push_add_leaves(
596 instrs: &mut Vec<Instruction>,
597 cslab: &mut CompileSlab,
598 li: InstructionI,
599 ric: &IC,
600) {
601 match *ric {
603 IC::I(ri) => {
604 let instr = cslab.take_instr(ri);
605 if let IAdd(rli, rric) = instr {
606 push_add_leaves(instrs, cslab, rli, &rric);
607 } else {
608 instrs.push(instr);
609 }
610 }
611 IC::C(c) => instrs.push(IConst(c)),
612 };
613
614 let instr = cslab.take_instr(li);
615 if let IAdd(lli, lric) = instr {
616 push_add_leaves(instrs, cslab, lli, &lric);
617 } else {
618 instrs.push(instr);
619 }
620}
621
622impl Compiler for ExprSlice<'_> {
623 fn compile(
624 &self,
625 parsed_slab: &ParseSlab,
626 compiled_slab: &mut CompileSlab,
627 namespace: &mut impl EvalNamespace,
628 ) -> Instruction {
629 let mut lowest_op = match self.pairs.first() {
646 Some(p0) => p0.0,
647 None => return self.first.compile(parsed_slab, compiled_slab, namespace),
648 };
649 for exprpair in &self.pairs {
650 if exprpair.0 < lowest_op {
651 lowest_op = exprpair.0;
652 }
653 }
654
655 if lowest_op == EEQ
657 || lowest_op == ENE
658 || lowest_op == ELT
659 || lowest_op == EGT
660 || lowest_op == ELTE
661 || lowest_op == EGTE
662 {
663 return self.process_comparisons(parsed_slab, compiled_slab, namespace)
664 }
665
666 match lowest_op {
667 EOR => self.process_or(parsed_slab, compiled_slab, namespace),
668 EAND => self.process_and(parsed_slab, compiled_slab, namespace),
669 EAdd => self.process_addition(parsed_slab, compiled_slab, namespace),
670 ESub => self.process_subtraction(parsed_slab, compiled_slab, namespace),
671 EMul => self.process_multiplication(parsed_slab, compiled_slab, namespace),
672 EDiv => {
673 let mut xss = Vec::<ExprSlice>::with_capacity(4);
676 self.split(EDiv, &mut xss);
677 let mut instrs = Vec::<Instruction>::with_capacity(xss.len());
678 for (i, xs) in xss.into_iter().enumerate() {
679 let instr = xs.compile(parsed_slab, compiled_slab, namespace);
680 if i == 0 {
681 instrs.push(instr);
682 } else {
683 instrs.push(inv_wrap(instr, compiled_slab));
684 }
685 }
686 compile_mul(instrs, compiled_slab)
687 }
688 EMod => {
732 let mut xss = Vec::<ExprSlice>::with_capacity(2);
733 self.split(EMod, &mut xss);
734 let mut out = IConst(0.0);
735 let mut out_set = false;
736 for xs in &xss {
737 let instr = xs.compile(parsed_slab, compiled_slab, namespace);
738 if out_set {
739 if let IConst(dividend) = out {
740 if let IConst(divisor) = instr {
741 out = IConst(dividend % divisor);
742 continue;
743 }
744 }
745 out = IMod {
746 dividend: instr_to_ic!(compiled_slab, out),
747 divisor: instr_to_ic!(compiled_slab, instr),
748 };
749 } else {
750 out = instr;
751 out_set = true;
752 }
753 }
754 out
755 }
756 EExp => {
757 let mut xss = Vec::<ExprSlice>::with_capacity(2);
759 self.split(EExp, &mut xss);
760 let mut out = IConst(0.0);
761 let mut out_set = false;
762 for xs in xss.into_iter().rev() {
763 let instr = xs.compile(parsed_slab, compiled_slab, namespace);
764 if out_set {
765 if let IConst(power) = out {
766 if let IConst(base) = instr {
767 out = IConst(base.powf(power));
768 continue;
769 }
770 }
771 out = IExp {
772 base: instr_to_ic!(compiled_slab, instr),
773 power: instr_to_ic!(compiled_slab, out),
774 };
775 } else {
776 out = instr;
777 out_set = true;
778 }
779 }
780 out
781 }
782 ENE | EEQ | EGTE | ELTE | EGT | ELT => IConst(std::f64::NAN), }
805 }
806}
807
808impl Compiler for Expression {
809 fn compile(
810 &self,
811 parsed_slab: &ParseSlab,
812 compiled_slab: &mut CompileSlab,
813 ns: &mut impl EvalNamespace,
814 ) -> Instruction {
815 let top = ExprSlice::from_expr(self);
816 top.compile(parsed_slab, compiled_slab, ns)
817 }
818}
819
820impl Compiler for Value {
821 fn compile(
822 &self,
823 parsed_slab: &ParseSlab,
824 compiled_slab: &mut CompileSlab,
825 ns: &mut impl EvalNamespace,
826 ) -> Instruction {
827 match self {
828 Self::EConstant(c) => IConst(*c),
829 Self::EUnaryOp(u) => u.compile(parsed_slab, compiled_slab, ns),
830 Self::EStdFunc(f) => f.compile(parsed_slab, compiled_slab, ns),
831 Self::EPrintFunc(pf) => IPrintFunc(pf.clone()),
832 }
833 }
834}
835
836impl Compiler for UnaryOp {
837 fn compile(
838 &self,
839 parsed_slab: &ParseSlab,
840 compiled_slab: &mut CompileSlab,
841 ns: &mut impl EvalNamespace,
842 ) -> Instruction {
843 match self {
844 EPos(i) => get_val!(parsed_slab, i).compile(parsed_slab, compiled_slab, ns),
845 ENeg(i) => {
846 let instr = get_val!(parsed_slab, i).compile(parsed_slab, compiled_slab, ns);
847 if let IConst(c) = instr {
848 IConst(-c)
849 } else {
850 neg_wrap(instr, compiled_slab)
851 }
852 }
853 ENot(i) => {
854 let instr = get_val!(parsed_slab, i).compile(parsed_slab, compiled_slab, ns);
855 if let IConst(c) = instr {
856 IConst(bool_to_f64!(f64_eq!(c, 0.0)))
857 } else {
858 not_wrap(instr, compiled_slab)
859 }
860 }
861 EParentheses(i) => get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, ns),
862 }
863 }
864}
865
866impl StdFunc {
867 #[inline]
869 fn process_custom_fn(
870 parsed_slab: &ParseSlab,
871 compiled_slab: &mut CompileSlab,
872 namespace: &mut impl EvalNamespace,
873 name: &String,
874 expressions: &Vec<ExpressionI>,
875 celled_parsed_slab: &RefCell<String>
876 ) -> Instruction {
877 let mut args = Vec::<IC>::with_capacity(expressions.len());
878 let mut f64_args = Vec::<f64>::with_capacity(expressions.len());
879 let mut is_all_const = true;
880 for expr in expressions {
881 let instr = get_expr!(parsed_slab, expr).compile(parsed_slab, compiled_slab, namespace);
882 if let IConst(c) = instr {
883 f64_args.push(c);
884 } else {
885 is_all_const = false;
886 }
887 args.push(instr_to_ic!(compiled_slab, instr));
888 }
889 if is_all_const {
890 let computed_value = eval_var!(namespace, name, f64_args, &mut celled_parsed_slab.borrow_mut());
891 computed_value.map_or_else(|_| IFunc { name: name.clone(), args }, IConst)
892 } else {
893 IFunc {
894 name: name.clone(),
895 args,
896 }
897 }
898 }
899
900 #[inline]
902 fn process_int_fn(
903 parsed_slab: &ParseSlab,
904 compiled_slab: &mut CompileSlab,
905 namespace: &mut impl EvalNamespace,
906 expression: ExpressionI
907 ) -> Instruction {
908 let instr = get_expr!(parsed_slab, expression).compile(parsed_slab, compiled_slab, namespace);
909 if let IConst(c) = instr {
910 IConst(c.trunc())
911 } else {
912 IFuncInt(compiled_slab.push_instr(instr))
913 }
914 }
915
916 #[inline]
918 fn process_ceil_fn(
919 parsed_slab: &ParseSlab,
920 compiled_slab: &mut CompileSlab,
921 namespace: &mut impl EvalNamespace,
922 expr: ExpressionI
923 ) -> Instruction {
924 let instr = get_expr!(parsed_slab, expr).compile(parsed_slab, compiled_slab, namespace);
925 if let IConst(c) = instr {
926 IConst(c.ceil())
927 } else {
928 IFuncCeil(compiled_slab.push_instr(instr))
929 }
930 }
931
932 #[inline]
934 fn process_floor_fn(
935 parsed_slab: &ParseSlab,
936 compiled_slab: &mut CompileSlab,
937 namespace: &mut impl EvalNamespace,
938 expr: ExpressionI
939 ) -> Instruction {
940 let instr = get_expr!(parsed_slab, expr).compile(parsed_slab, compiled_slab, namespace);
941 if let IConst(c) = instr {
942 IConst(c.floor())
943 } else {
944 IFuncFloor(compiled_slab.push_instr(instr))
945 }
946 }
947
948 #[inline]
950 fn process_abs_fn(
951 parsed_slab: &ParseSlab,
952 compiled_slab: &mut CompileSlab,
953 namespace: &mut impl EvalNamespace,
954 expr: ExpressionI
955 ) -> Instruction {
956 let instr = get_expr!(parsed_slab, expr).compile(parsed_slab, compiled_slab, namespace);
957 if let IConst(c) = instr {
958 IConst(c.abs())
959 } else {
960 IFuncAbs(compiled_slab.push_instr(instr))
961 }
962 }
963
964 #[inline]
966 fn process_signum(
967 parsed_slab: &ParseSlab,
968 compiled_slab: &mut CompileSlab,
969 namespace: &mut impl EvalNamespace,
970 expr: ExpressionI
971 ) -> Instruction {
972 let instr = get_expr!(parsed_slab, expr).compile(parsed_slab, compiled_slab, namespace);
973 if let IConst(c) = instr {
974 IConst(c.signum())
975 } else {
976 IFuncSign(compiled_slab.push_instr(instr))
977 }
978 }
979
980 #[inline]
982 fn process_log(
983 parsed_slab: &ParseSlab,
984 compiled_slab: &mut CompileSlab,
985 namespace: &mut impl EvalNamespace,
986 base_options: &Option<ExpressionI>,
987 expr: ExpressionI
988 ) -> Instruction {
989 let base: Instruction = base_options.as_ref().map_or(IConst(10.0), |bi| get_expr!(parsed_slab, bi).compile(parsed_slab, compiled_slab, namespace));
990 let instr = get_expr!(parsed_slab, expr).compile(parsed_slab, compiled_slab, namespace);
991 if let IConst(b) = base {
992 if let IConst(n) = instr {
993 return IConst(log(b, n));
994 }
995 }
996 IFuncLog {
997 base: instr_to_ic!(compiled_slab, base),
998 of: instr_to_ic!(compiled_slab, instr),
999 }
1000 }
1001
1002 #[inline]
1004 fn process_round(
1005 parsed_slab: &ParseSlab,
1006 compiled_slab: &mut CompileSlab,
1007 namespace: &mut impl EvalNamespace,
1008 mod_option: &Option<ExpressionI>,
1009 expr: ExpressionI
1010 ) -> Instruction {
1011 let modulus: Instruction = mod_option.as_ref().map_or(IConst(1.0), |mi| get_expr!(parsed_slab, mi).compile(parsed_slab, compiled_slab, namespace));
1012 let instr = get_expr!(parsed_slab, expr).compile(parsed_slab, compiled_slab, namespace);
1013 if let IConst(m) = modulus {
1014 if let IConst(n) = instr {
1015 return IConst((n / m).round() * m); }
1017 }
1018 IFuncRound {
1019 modulus: instr_to_ic!(compiled_slab, modulus),
1020 of: instr_to_ic!(compiled_slab, instr),
1021 }
1022 }
1023
1024 #[inline]
1026 fn process_min(
1027 parsed_slab: &ParseSlab,
1028 compiled_slab: &mut CompileSlab,
1029 namespace: &mut impl EvalNamespace,
1030 fi: ExpressionI,
1031 is: &Vec<ExpressionI>
1032 ) -> Instruction {
1033 let first = get_expr!(parsed_slab, fi).compile(parsed_slab, compiled_slab, namespace);
1034 let mut rest = Vec::<Instruction>::with_capacity(is.len());
1035 for i in is {
1036 rest.push(get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, namespace));
1037 }
1038 let mut out = IConst(0.0);
1039 let mut out_set = false;
1040 let mut const_min = 0.0;
1041 let mut const_min_set = false;
1042 if let IConst(f) = first {
1043 const_min = f;
1044 const_min_set = true;
1045 } else {
1046 out = first;
1047 out_set = true;
1048 }
1049 for instr in rest {
1050 if let IConst(f) = instr {
1051 if const_min_set {
1052 if f < const_min {
1053 const_min = f;
1054 }
1055 } else {
1056 const_min = f;
1057 const_min_set = true;
1058 }
1059 } else if out_set {
1060 out = IFuncMin(compiled_slab.push_instr(out), IC::I(compiled_slab.push_instr(instr)));
1061 } else {
1062 out = instr;
1063 out_set = true;
1064 }
1065 }
1066 if const_min_set {
1067 if out_set {
1068 out = IFuncMin(compiled_slab.push_instr(out), IC::C(const_min));
1069 } else {
1070 out = IConst(const_min);
1071 }
1073 }
1074 out
1076 }
1077
1078 #[inline]
1080 fn process_max(
1081 parsed_slab: &ParseSlab,
1082 compiled_slab: &mut CompileSlab,
1083 namespace: &mut impl EvalNamespace,
1084 fi: ExpressionI,
1085 is: &Vec<ExpressionI>
1086 ) -> Instruction {
1087 let first = get_expr!(parsed_slab, fi).compile(parsed_slab, compiled_slab, namespace);
1088 let mut rest = Vec::<Instruction>::with_capacity(is.len());
1089 for i in is {
1090 rest.push(get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, namespace));
1091 }
1092 let mut out = IConst(0.0);
1093 let mut out_set = false;
1094 let mut const_max = 0.0;
1095 let mut const_max_set = false;
1096 if let IConst(f) = first {
1097 const_max = f;
1098 const_max_set = true;
1099 } else {
1100 out = first;
1101 out_set = true;
1102 }
1103 for instr in rest {
1104 if let IConst(f) = instr {
1105 if const_max_set {
1106 if f > const_max {
1107 const_max = f;
1108 }
1109 } else {
1110 const_max = f;
1111 const_max_set = true;
1112 }
1113 } else if out_set {
1114 out = IFuncMax(compiled_slab.push_instr(out), IC::I(compiled_slab.push_instr(instr)));
1115 } else {
1116 out = instr;
1117 out_set = true;
1118 }
1119 }
1120 if const_max_set {
1121 if out_set {
1122 out = IFuncMax(compiled_slab.push_instr(out), IC::C(const_max));
1123 } else {
1124 out = IConst(const_max);
1125 }
1127 }
1128 out
1130 }
1131
1132 process_fn!(process_sin, sin, IFuncSin);
1133 process_fn!(process_cos, cos, IFuncCos);
1134 process_fn!(process_tan, tan, IFuncTan);
1135 process_fn!(process_asin, asin, IFuncASin);
1136 process_fn!(process_acos, acos, IFuncACos);
1137 process_fn!(process_atan, atan, IFuncATan);
1138}
1139
1140impl Compiler for StdFunc {
1141 fn compile(
1142 &self,
1143 parsed_slab: &ParseSlab,
1144 compiled_slab: &mut CompileSlab,
1145 namespace: &mut impl EvalNamespace,
1146 ) -> Instruction {
1147 let celled_parsed_slab = RefCell::from(parsed_slab.char_buf.clone());
1148 match self {
1149 EVar(name) => IVar(name.clone()),
1150 #[cfg(feature = "unsafe-vars")]
1151 EUnsafeVar { name, ptr } => IUnsafeVar {
1152 name: name.clone(),
1153 ptr: *ptr,
1154 },
1155 EFunc { name, args } => Self::process_custom_fn(parsed_slab, compiled_slab, namespace, name, args, &celled_parsed_slab),
1156
1157 EFuncInt(expr) => Self::process_int_fn(parsed_slab, compiled_slab, namespace, *expr),
1158 EFuncCeil(expr) => Self::process_ceil_fn(parsed_slab, compiled_slab, namespace, *expr),
1159 EFuncFloor(expr) => Self::process_floor_fn(parsed_slab, compiled_slab, namespace, *expr),
1160 EFuncAbs(expr) => Self::process_abs_fn(parsed_slab, compiled_slab, namespace, *expr),
1161 EFuncSign(expr) => Self::process_signum(parsed_slab, compiled_slab, namespace, *expr),
1162 EFuncLog {
1163 base: base_option,
1164 expr,
1165 } => {
1166 Self::process_log(parsed_slab, compiled_slab, namespace, base_option, *expr)
1167 }
1168 EFuncRound {
1169 modulus: mod_option,
1170 expr,
1171 } => {
1172 Self::process_round(parsed_slab, compiled_slab, namespace, mod_option, *expr)
1173 }
1174 EFuncMin {
1175 first: fi,
1176 rest: is,
1177 } => {
1178 Self::process_min(parsed_slab, compiled_slab, namespace, *fi, is)
1179 }
1180 EFuncMax {
1181 first: fi,
1182 rest: is,
1183 } => {
1184 Self::process_max(parsed_slab, compiled_slab, namespace, *fi, is)
1185 }
1186
1187 EFuncE => IConst(std::f64::consts::E),
1188 EFuncPi => IConst(std::f64::consts::PI),
1189
1190 EFuncSin(expr) => Self::process_sin(parsed_slab, compiled_slab, namespace, *expr),
1191 EFuncCos(expr) => Self::process_cos(parsed_slab, compiled_slab, namespace, *expr),
1192 EFuncTan(expr) => Self::process_tan(parsed_slab, compiled_slab, namespace, *expr),
1193 EFuncASin(expr) => Self::process_asin(parsed_slab, compiled_slab, namespace, *expr),
1194 EFuncACos(expr) => Self::process_acos(parsed_slab, compiled_slab, namespace, *expr),
1195 EFuncATan(expr) => Self::process_atan(parsed_slab, compiled_slab, namespace, *expr),
1196 EFuncSinH(i) => {
1197 let instr = get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, namespace);
1198 if let IConst(c) = instr {
1199 IConst(c.sinh())
1200 } else {
1201 IFuncSinH(compiled_slab.push_instr(instr))
1202 }
1203 }
1204 EFuncCosH(i) => {
1205 let instr = get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, namespace);
1206 if let IConst(c) = instr {
1207 IConst(c.cosh())
1208 } else {
1209 IFuncCosH(compiled_slab.push_instr(instr))
1210 }
1211 }
1212 EFuncTanH(i) => {
1213 let instr = get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, namespace);
1214 if let IConst(c) = instr {
1215 IConst(c.tanh())
1216 } else {
1217 IFuncTanH(compiled_slab.push_instr(instr))
1218 }
1219 }
1220 EFuncASinH(i) => {
1221 let instr = get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, namespace);
1222 if let IConst(c) = instr {
1223 IConst(c.asinh())
1224 } else {
1225 IFuncASinH(compiled_slab.push_instr(instr))
1226 }
1227 }
1228 EFuncACosH(i) => {
1229 let instr = get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, namespace);
1230 if let IConst(c) = instr {
1231 IConst(c.acosh())
1232 } else {
1233 IFuncACosH(compiled_slab.push_instr(instr))
1234 }
1235 }
1236 EFuncATanH(i) => {
1237 let instr = get_expr!(parsed_slab, i).compile(parsed_slab, compiled_slab, namespace);
1238 if let IConst(c) = instr {
1239 IConst(c.atanh())
1240 } else {
1241 IFuncATanH(compiled_slab.push_instr(instr))
1242 }
1243 }
1244 }
1245 }
1246}