1#![allow(missing_docs)]
6#![deny(unused)]
7#![deny(clippy::suspicious)]
8
9mod cplx;
10mod util;
11
12use proc_macro2::TokenStream;
13use quote::quote;
14use syn::{
15 parse::Parse, spanned::Spanned, BinOp, Error, Expr, ExprBinary, ExprCall, ExprGroup, ExprLit,
16 ExprParen, ExprPath, ExprUnary, Lit, Token, UnOp,
17};
18use util::{check_arg_num, str_to_exact_num_expr, str_to_exact_num_literal};
19use zenith_float_num::{Consts, EXPONENT_BIT_SIZE};
20
21pub(crate) const SPEC_ADD_ERR: usize = 32;
25
26pub(crate) struct MacroInput {
27 pub(crate) expr: Expr,
28 pub(crate) ctx: Expr,
29}
30
31impl Parse for MacroInput {
32 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
33 let expr = input.parse()?;
34 input.parse::<Token![,]>()?;
35
36 let ctx = input.parse()?;
37
38 Ok(MacroInput { expr, ctx })
39 }
40}
41
42fn traverse_binary(
43 expr: &ExprBinary,
44 err: &mut Vec<usize>,
45 cc: &mut Consts,
46) -> Result<TokenStream, Error> {
47 let left_expr = traverse_expr(&expr.left, err, cc)?;
48 let right_expr = traverse_expr(&expr.right, err, cc)?;
49
50 let errs_id = err.len();
51
52 let ts = match expr.op {
53 BinOp::Add(_) => {
54 err.push(2);
55 quote!({
56 let arg1 = #left_expr;
57 let arg2 = #right_expr;
58 let ret = zenith_float::ExactNum::add(&arg1, &arg2, p_wrk, zenith_float::RoundingMode::None);
59 if arg1.inexact() || arg2.inexact() {
60 if let (Some(e1), Some(e2), Some(e3)) = (arg1.exponent(), arg2.exponent(), ret.exponent()) {
61 if (e1 as isize - e2 as isize).abs() <= 1 && arg1.sign() != arg2.sign() {
62 let newerr = (e1.max(e2) as isize - e3 as isize).unsigned_abs() + 1;
63 if errs[#errs_id] < newerr {
64 errs[#errs_id] = newerr;
65 continue;
66 }
67 }
68 }
69 }
70 ret
71 })
72 }
73 BinOp::Sub(_) => {
74 err.push(2);
75 quote!({
76 let arg1 = #left_expr;
77 let arg2 = #right_expr;
78 let ret = zenith_float::ExactNum::sub(&arg1, &arg2, p_wrk, zenith_float::RoundingMode::None);
79 if arg1.inexact() || arg2.inexact() {
80 if let (Some(e1), Some(e2), Some(e3)) = (arg1.exponent(), arg2.exponent(), ret.exponent()) {
81 if (e1 as isize - e2 as isize).abs() <= 1 && arg1.sign() == arg2.sign() {
82 let newerr = (e1.max(e2) as isize - e3 as isize).unsigned_abs() + 1;
83 if errs[#errs_id] < newerr {
84 errs[#errs_id] = newerr;
85 continue;
86 }
87 }
88 }
89 }
90 ret
91 })
92 }
93 BinOp::Mul(_) => {
94 err.push(3);
95 quote!(
96 zenith_float::ExactNum::mul(&(#left_expr), &(#right_expr), p_wrk, zenith_float::RoundingMode::None))
97 }
98 BinOp::Div(_) => {
99 err.push(3);
100 quote!(zenith_float::ExactNum::div(&(#left_expr), &(#right_expr), p_wrk, zenith_float::RoundingMode::None))
101 }
102 BinOp::Rem(_) => {
103 quote!(zenith_float::ExactNum::rem(&(#left_expr), &(#right_expr)))
104 }
105 _ => return Err(Error::new(
106 expr.span(),
107 "unexpected binary operator. Only \"+\", \"-\", \"*\", \"/\", and \"%\" are allowed.",
108 )),
109 };
110
111 Ok(ts)
112}
113
114fn one_arg_fun(
115 fun: TokenStream,
116 expr: &ExprCall,
117 initial_err: usize,
118 err: &mut Vec<usize>,
119 cc: &mut Consts,
120 use_cc: bool,
121) -> Result<TokenStream, Error> {
122 check_arg_num(1, expr)?;
123
124 let arg = traverse_expr(&expr.args[0], err, cc)?;
125 err.push(initial_err);
126
127 let ret = if use_cc {
128 quote!(#fun(&(#arg), p_wrk, zenith_float::RoundingMode::None, cc))
129 } else {
130 quote!(#fun(&(#arg), p_wrk, zenith_float::RoundingMode::None))
131 };
132
133 Ok(ret)
134}
135
136fn two_arg_fun(
137 fun: TokenStream,
138 expr: &ExprCall,
139 initial_err: usize,
140 err: &mut Vec<usize>,
141 cc: &mut Consts,
142 use_cc: bool,
143) -> Result<TokenStream, Error> {
144 check_arg_num(2, expr)?;
145
146 let arg1 = traverse_expr(&expr.args[0], err, cc)?;
147 let arg2 = traverse_expr(&expr.args[1], err, cc)?;
148 err.push(initial_err);
149
150 let ret = if use_cc {
151 quote!(#fun(&(#arg1), &(#arg2), p_wrk, zenith_float::RoundingMode::None, cc))
152 } else {
153 quote!(#fun(&(#arg1), &(#arg2), p_wrk, zenith_float::RoundingMode::None))
154 };
155
156 Ok(ret)
157}
158
159fn three_arg_fun(
160 fun: TokenStream,
161 expr: &ExprCall,
162 initial_err: usize,
163 err: &mut Vec<usize>,
164 cc: &mut Consts,
165 use_cc: bool,
166) -> Result<TokenStream, Error> {
167 check_arg_num(3, expr)?;
168
169 let arg1 = traverse_expr(&expr.args[0], err, cc)?;
170 let arg2 = traverse_expr(&expr.args[1], err, cc)?;
171 let arg3 = traverse_expr(&expr.args[2], err, cc)?;
172 err.push(initial_err);
173
174 let ret = if use_cc {
175 quote!(#fun(&(#arg1), &(#arg2), &(#arg3), p_wrk, zenith_float::RoundingMode::None, cc))
176 } else {
177 quote!(#fun(&(#arg1), &(#arg2), &(#arg3), p_wrk, zenith_float::RoundingMode::None))
178 };
179 Ok(ret)
180}
181
182fn root_fun(
183 expr: &ExprCall,
184 initial_err: usize,
185 err: &mut Vec<usize>,
186 cc: &mut Consts,
187) -> Result<TokenStream, Error> {
188 check_arg_num(2, expr)?;
189
190 let arg = traverse_expr(&expr.args[0], err, cc)?;
191 let n = &expr.args[1];
192 err.push(initial_err);
193
194 Ok(quote!(zenith_float::ExactNum::nth_root(
195 &(#arg),
196 #n as usize,
197 p_wrk,
198 zenith_float::RoundingMode::None
199 )))
200}
201
202fn ldexp_fun(
203 expr: &ExprCall,
204 initial_err: usize,
205 err: &mut Vec<usize>,
206 cc: &mut Consts,
207 scalb: bool,
208) -> Result<TokenStream, Error> {
209 check_arg_num(2, expr)?;
210
211 let arg = traverse_expr(&expr.args[0], err, cc)?;
212 let n = &expr.args[1];
213 err.push(initial_err);
214
215 let fun = if scalb {
216 quote!(zenith_float::ExactNum::scalb)
217 } else {
218 quote!(zenith_float::ExactNum::ldexp)
219 };
220
221 Ok(quote!(#fun(
222 &(#arg),
223 #n as zenith_float::Exponent,
224 p_wrk,
225 zenith_float::RoundingMode::None
226 )))
227}
228
229fn bessel_j_fun(
230 expr: &ExprCall,
231 initial_err: usize,
232 err: &mut Vec<usize>,
233 cc: &mut Consts,
234) -> Result<TokenStream, Error> {
235 check_arg_num(2, expr)?;
236
237 let arg = traverse_expr(&expr.args[0], err, cc)?;
238 let n = &expr.args[1];
239 err.push(initial_err);
240
241 Ok(quote!(zenith_float::ExactNum::bessel_j(
242 &(#arg),
243 #n as usize,
244 p_wrk,
245 zenith_float::RoundingMode::None,
246 cc
247 )))
248}
249
250fn four_arg_fun(
251 fun: TokenStream,
252 expr: &ExprCall,
253 initial_err: usize,
254 err: &mut Vec<usize>,
255 cc: &mut Consts,
256) -> Result<TokenStream, Error> {
257 check_arg_num(4, expr)?;
258 let arg1 = traverse_expr(&expr.args[0], err, cc)?;
259 let arg2 = traverse_expr(&expr.args[1], err, cc)?;
260 let arg3 = traverse_expr(&expr.args[2], err, cc)?;
261 let arg4 = traverse_expr(&expr.args[3], err, cc)?;
262 err.push(initial_err);
263 Ok(quote!(#fun(
264 &(#arg1),
265 &(#arg2),
266 &(#arg3),
267 &(#arg4),
268 p_wrk,
269 zenith_float::RoundingMode::None,
270 cc
271 )))
272}
273
274fn legendre_p_fun(
275 expr: &ExprCall,
276 initial_err: usize,
277 err: &mut Vec<usize>,
278 cc: &mut Consts,
279) -> Result<TokenStream, Error> {
280 check_arg_num(2, expr)?;
281 let arg = traverse_expr(&expr.args[0], err, cc)?;
282 let n = &expr.args[1];
283 err.push(initial_err);
284 Ok(quote!(zenith_float::ExactNum::legendre_p(
285 &(#arg),
286 #n as u32,
287 p_wrk,
288 zenith_float::RoundingMode::None
289 )))
290}
291
292fn legendre_p_assoc_fun(
293 expr: &ExprCall,
294 initial_err: usize,
295 err: &mut Vec<usize>,
296 cc: &mut Consts,
297) -> Result<TokenStream, Error> {
298 check_arg_num(3, expr)?;
299 let arg = traverse_expr(&expr.args[0], err, cc)?;
300 let n = &expr.args[1];
301 let m = &expr.args[2];
302 err.push(initial_err);
303 Ok(quote!(zenith_float::ExactNum::assoc_legendre_p(
304 &(#arg),
305 #n as u32,
306 #m as i32,
307 p_wrk,
308 zenith_float::RoundingMode::None
309 )))
310}
311
312fn one_arg_fun_errcheck(
313 fun: TokenStream,
314 expr: &ExprCall,
315 initial_err: usize,
316 err: &mut Vec<usize>,
317 errcheck: TokenStream,
318 cc: &mut Consts,
319) -> Result<TokenStream, Error> {
320 check_arg_num(1, expr)?;
321
322 let arg = traverse_expr(&expr.args[0], err, cc)?;
323 let errs_id = err.len();
324 err.push(initial_err);
325
326 Ok(quote!({
327 let arg = #arg;
328
329 let newerr = zenith_float::macro_util::compute_added_err(#errcheck);
330 if errs[#errs_id] < newerr {
331 errs[#errs_id] = newerr;
332 continue;
333 }
334
335 #fun(&arg, p_wrk, zenith_float::RoundingMode::None, cc)
336 }))
337}
338
339fn trig_fun(
340 fun: TokenStream,
341 expr: &ExprCall,
342 initial_err: usize,
343 err: &mut Vec<usize>,
344 errfun: TokenStream,
345 cc: &mut Consts,
346) -> Result<TokenStream, Error> {
347 check_arg_num(1, expr)?;
348
349 let arg = traverse_expr(&expr.args[0], err, cc)?;
350 let errs_id = err.len();
351 err.push(initial_err);
352
353 Ok(quote!({
354 let arg = zenith_float::macro_util::check_exponent_range(#arg, emin, emax);
355
356 let newerr = zenith_float::macro_util::compute_added_err(zenith_float::macro_util::ErrAlgo::Trig(&arg, p_wrk, #errfun, cc, emin));
357 if errs[#errs_id] < newerr {
358 errs[#errs_id] = newerr;
359 continue;
360 }
361
362 #fun(&arg, p_wrk, zenith_float::RoundingMode::None, cc)
363 }))
364}
365
366fn two_arg_fun_errcheck(
367 fun: TokenStream,
368 expr: &ExprCall,
369 initial_err: usize,
370 err: &mut Vec<usize>,
371 errcheck: TokenStream,
372 cc: &mut Consts,
373) -> Result<TokenStream, Error> {
374 check_arg_num(2, expr)?;
375
376 let arg1 = traverse_expr(&expr.args[0], err, cc)?;
377 let arg2 = traverse_expr(&expr.args[1], err, cc)?;
378
379 let errs_id = err.len();
380
381 err.push(initial_err);
382
383 Ok(quote!({
384 let arg1 = #arg1;
385 let arg2 = #arg2;
386
387 let newerr = zenith_float::macro_util::compute_added_err(#errcheck);
388 if errs[#errs_id] < newerr {
389 errs[#errs_id] = newerr;
390 continue;
391 }
392
393 #fun(&arg1, &arg2, p_wrk, zenith_float::RoundingMode::None, cc)
394 }))
395}
396
397fn traverse_call(
398 expr: &ExprCall,
399 err: &mut Vec<usize>,
400 cc: &mut Consts,
401) -> Result<TokenStream, Error> {
402 let errmes = "unexpected function name. Only \"recip\", \"sqrt\", \"cbrt\", \"root\", \"ln\", \"log2\", \"log10\", \"log\", \"log1p\", \"exp\", \"exp2\", \"exp10\", \"expm1\", \"pow\", \"rem_pi\", \"sin\", \"cos\", \"tan\", \"asin\", \"acos\", \"atan\", \"atan2\", \"hypot\", \"fma\", \"mul_add\", \"sinh\", \"cosh\", \"tanh\", \"asinh\", \"acosh\", \"atanh\", \"erf\", \"erfc\", \"gamma\", \"ln_gamma\", \"digamma\", \"gammainc\", \"gammainc_upper\", \"ei\", \"si\", \"ci\", \"li\", \"fresnel_s\", \"fresnel_c\", \"ai\", \"bi\", \"bessel_j\", \"bessel_j_nu\", \"bessel_y\", \"bessel_i\", \"bessel_k\", \"elliptic_k\", \"elliptic_e\", \"elliptic_e_inc\", \"elliptic_f\", \"elliptic_pi\", \"elliptic_pi_inc\", \"jacobi_am\", \"jacobi_sn\", \"jacobi_cn\", \"jacobi_dn\", \"jacobi_cd\", \"jacobi_ns\", \"jacobi_nc\", \"jacobi_nd\", \"jacobi_sc\", \"jacobi_sd\", \"jacobi_cs\", \"jacobi_ds\", \"jacobi_dc\", \"legendre_p\", \"legendre_p_assoc\", \"hypergeom_2f1\", \"betainc\", \"normal_pdf\", \"normal_cdf\", \"gamma_pdf\", \"beta_pdf\", \"poisson_pmf\", \"binomial_pmf\", \"chi_squared_cdf\", \"student_t_pdf\", \"ldexp\", \"scalb\", \"logb\" are allowed.";
403
404 if let Expr::Path(fun) = expr.func.as_ref() {
405 if let Some(fname) = fun.path.get_ident() {
406 let ts = match fname.to_string().as_str() {
407 "recip" => one_arg_fun(
408 quote!(zenith_float::ExactNum::reciprocal),
409 expr,
410 2,
411 err,
412 cc,
413 false,
414 ),
415 "sqrt" => one_arg_fun(
416 quote!(zenith_float::ExactNum::sqrt),
417 expr,
418 1,
419 err,
420 cc,
421 false,
422 ),
423 "cbrt" => one_arg_fun(
424 quote!(zenith_float::ExactNum::cbrt),
425 expr,
426 1,
427 err,
428 cc,
429 false,
430 ),
431 "root" => root_fun(expr, 1, err, cc),
432 "ln" => one_arg_fun_errcheck(
433 quote!(zenith_float::ExactNum::ln),
434 expr,
435 SPEC_ADD_ERR,
436 err,
437 quote!(zenith_float::macro_util::ErrAlgo::Log(&arg, 2, emin)),
438 cc,
439 ),
440 "log2" => one_arg_fun_errcheck(
441 quote!(zenith_float::ExactNum::log2),
442 expr,
443 SPEC_ADD_ERR,
444 err,
445 quote!(zenith_float::macro_util::ErrAlgo::Log(&arg, 3, emin)),
446 cc,
447 ),
448 "log10" => one_arg_fun_errcheck(
449 quote!(zenith_float::ExactNum::log10),
450 expr,
451 SPEC_ADD_ERR,
452 err,
453 quote!(zenith_float::macro_util::ErrAlgo::Log(&arg, 6, emin)),
454 cc,
455 ),
456 "log" => two_arg_fun_errcheck(
457 quote!(zenith_float::ExactNum::log),
458 expr,
459 SPEC_ADD_ERR,
460 err,
461 quote!(zenith_float::macro_util::ErrAlgo::Log2(&arg2, &arg1, emin)),
462 cc,
463 ),
464 "log1p" => one_arg_fun(
465 quote!(zenith_float::ExactNum::log1p),
466 expr,
467 SPEC_ADD_ERR,
468 err,
469 cc,
470 true,
471 ),
472 "exp" => one_arg_fun(
473 quote!(zenith_float::ExactNum::exp),
474 expr,
475 EXPONENT_BIT_SIZE + 1,
476 err,
477 cc,
478 true,
479 ),
480 "exp2" => one_arg_fun(
481 quote!(zenith_float::ExactNum::exp2),
482 expr,
483 EXPONENT_BIT_SIZE + 1,
484 err,
485 cc,
486 true,
487 ),
488 "exp10" => one_arg_fun(
489 quote!(zenith_float::ExactNum::exp10),
490 expr,
491 EXPONENT_BIT_SIZE + 1,
492 err,
493 cc,
494 true,
495 ),
496 "expm1" => one_arg_fun(
497 quote!(zenith_float::ExactNum::expm1),
498 expr,
499 EXPONENT_BIT_SIZE + 1,
500 err,
501 cc,
502 true,
503 ),
504 "pow" => two_arg_fun_errcheck(
505 quote!(zenith_float::ExactNum::pow),
506 expr,
507 EXPONENT_BIT_SIZE + SPEC_ADD_ERR,
508 err,
509 quote!(zenith_float::macro_util::ErrAlgo::Pow(&arg1, &arg2, emin)),
510 cc,
511 ),
512 "rem_pi" => one_arg_fun(
513 quote!(zenith_float::ExactNum::rem_pi),
514 expr,
515 SPEC_ADD_ERR,
516 err,
517 cc,
518 true,
519 ),
520 "sin" => trig_fun(
521 quote!(zenith_float::ExactNum::sin),
522 expr,
523 SPEC_ADD_ERR,
524 err,
525 quote!(zenith_float::macro_util::TrigFun::Sin),
526 cc,
527 ),
528 "cos" => trig_fun(
529 quote!(zenith_float::ExactNum::cos),
530 expr,
531 SPEC_ADD_ERR,
532 err,
533 quote!(zenith_float::macro_util::TrigFun::Cos),
534 cc,
535 ),
536 "tan" => trig_fun(
537 quote!(zenith_float::ExactNum::tan),
538 expr,
539 SPEC_ADD_ERR,
540 err,
541 quote!(zenith_float::macro_util::TrigFun::Tan),
542 cc,
543 ),
544 "asin" => one_arg_fun_errcheck(
545 quote!(zenith_float::ExactNum::asin),
546 expr,
547 SPEC_ADD_ERR / 2,
548 err,
549 quote!(zenith_float::macro_util::ErrAlgo::Asin(&arg, emin)),
550 cc,
551 ),
552 "acos" => one_arg_fun_errcheck(
553 quote!(zenith_float::ExactNum::acos),
554 expr,
555 SPEC_ADD_ERR / 2,
556 err,
557 quote!(zenith_float::macro_util::ErrAlgo::Acos(&arg, emin)),
558 cc,
559 ),
560 "atan" => one_arg_fun(quote!(zenith_float::ExactNum::atan), expr, 2, err, cc, true),
561 "atan2" => two_arg_fun(
562 quote!(zenith_float::ExactNum::atan2),
563 expr,
564 2,
565 err,
566 cc,
567 true,
568 ),
569 "hypot" => two_arg_fun(
570 quote!(zenith_float::ExactNum::hypot),
571 expr,
572 2,
573 err,
574 cc,
575 false,
576 ),
577 "fma" => {
578 three_arg_fun(quote!(zenith_float::ExactNum::fma), expr, 2, err, cc, false)
579 }
580 "mul_add" => three_arg_fun(
581 quote!(zenith_float::ExactNum::mul_add),
582 expr,
583 2,
584 err,
585 cc,
586 false,
587 ),
588 "sinh" => one_arg_fun(
589 quote!(zenith_float::ExactNum::sinh),
590 expr,
591 EXPONENT_BIT_SIZE + 1,
592 err,
593 cc,
594 true,
595 ),
596 "cosh" => one_arg_fun(
597 quote!(zenith_float::ExactNum::cosh),
598 expr,
599 EXPONENT_BIT_SIZE + 1,
600 err,
601 cc,
602 true,
603 ),
604 "tanh" => one_arg_fun(quote!(zenith_float::ExactNum::tanh), expr, 2, err, cc, true),
605 "asinh" => one_arg_fun(
606 quote!(zenith_float::ExactNum::asinh),
607 expr,
608 2,
609 err,
610 cc,
611 true,
612 ),
613 "acosh" => one_arg_fun_errcheck(
614 quote!(zenith_float::ExactNum::acosh),
615 expr,
616 SPEC_ADD_ERR,
617 err,
618 quote!(zenith_float::macro_util::ErrAlgo::Acosh(&arg, emin)),
619 cc,
620 ),
621 "atanh" => one_arg_fun_errcheck(
622 quote!(zenith_float::ExactNum::atanh),
623 expr,
624 SPEC_ADD_ERR,
625 err,
626 quote!(zenith_float::macro_util::ErrAlgo::Atanh(&arg, emin)),
627 cc,
628 ),
629 "erf" => one_arg_fun(quote!(zenith_float::ExactNum::erf), expr, 2, err, cc, true),
630 "erfc" => one_arg_fun(quote!(zenith_float::ExactNum::erfc), expr, 2, err, cc, true),
631 "gamma" => one_arg_fun(
632 quote!(zenith_float::ExactNum::gamma),
633 expr,
634 EXPONENT_BIT_SIZE + 1,
635 err,
636 cc,
637 true,
638 ),
639 "ln_gamma" => one_arg_fun(
640 quote!(zenith_float::ExactNum::ln_gamma),
641 expr,
642 EXPONENT_BIT_SIZE + 1,
643 err,
644 cc,
645 true,
646 ),
647 "digamma" => one_arg_fun(
648 quote!(zenith_float::ExactNum::digamma),
649 expr,
650 EXPONENT_BIT_SIZE + 1,
651 err,
652 cc,
653 true,
654 ),
655 "gammainc" => two_arg_fun(
656 quote!(zenith_float::ExactNum::gammainc),
657 expr,
658 EXPONENT_BIT_SIZE + 1,
659 err,
660 cc,
661 true,
662 ),
663 "gammainc_upper" => two_arg_fun(
664 quote!(zenith_float::ExactNum::gammainc_upper),
665 expr,
666 EXPONENT_BIT_SIZE + 1,
667 err,
668 cc,
669 true,
670 ),
671 "ei" => one_arg_fun(quote!(zenith_float::ExactNum::ei), expr, 2, err, cc, true),
672 "si" => one_arg_fun(quote!(zenith_float::ExactNum::si), expr, 2, err, cc, true),
673 "ci" => one_arg_fun(quote!(zenith_float::ExactNum::ci), expr, 2, err, cc, true),
674 "li" => one_arg_fun(quote!(zenith_float::ExactNum::li), expr, 2, err, cc, true),
675 "fresnel_s" => one_arg_fun(
676 quote!(zenith_float::ExactNum::fresnel_s),
677 expr,
678 2,
679 err,
680 cc,
681 true,
682 ),
683 "fresnel_c" => one_arg_fun(
684 quote!(zenith_float::ExactNum::fresnel_c),
685 expr,
686 2,
687 err,
688 cc,
689 true,
690 ),
691 "ai" => one_arg_fun(quote!(zenith_float::ExactNum::ai), expr, 2, err, cc, true),
692 "bi" => one_arg_fun(quote!(zenith_float::ExactNum::bi), expr, 2, err, cc, true),
693 "bessel_j" => bessel_j_fun(expr, 2, err, cc),
694 "bessel_j_nu" => two_arg_fun(
695 quote!(zenith_float::ExactNum::bessel_j_nu),
696 expr,
697 2,
698 err,
699 cc,
700 true,
701 ),
702 "bessel_y" => two_arg_fun(
703 quote!(zenith_float::ExactNum::bessel_y),
704 expr,
705 2,
706 err,
707 cc,
708 true,
709 ),
710 "bessel_i" => two_arg_fun(
711 quote!(zenith_float::ExactNum::bessel_i),
712 expr,
713 2,
714 err,
715 cc,
716 true,
717 ),
718 "bessel_k" => two_arg_fun(
719 quote!(zenith_float::ExactNum::bessel_k),
720 expr,
721 2,
722 err,
723 cc,
724 true,
725 ),
726 "elliptic_k" => one_arg_fun(
727 quote!(zenith_float::ExactNum::elliptic_k),
728 expr,
729 2,
730 err,
731 cc,
732 true,
733 ),
734 "elliptic_e" => one_arg_fun(
735 quote!(zenith_float::ExactNum::elliptic_e_complete),
736 expr,
737 2,
738 err,
739 cc,
740 true,
741 ),
742 "elliptic_e_inc" => two_arg_fun(
743 quote!(zenith_float::ExactNum::elliptic_e),
744 expr,
745 2,
746 err,
747 cc,
748 true,
749 ),
750 "elliptic_f" => two_arg_fun(
751 quote!(zenith_float::ExactNum::elliptic_f),
752 expr,
753 2,
754 err,
755 cc,
756 true,
757 ),
758 "jacobi_am" => two_arg_fun(
759 quote!(zenith_float::ExactNum::jacobi_am),
760 expr,
761 2,
762 err,
763 cc,
764 true,
765 ),
766 "jacobi_sn" => two_arg_fun(
767 quote!(zenith_float::ExactNum::jacobi_sn),
768 expr,
769 2,
770 err,
771 cc,
772 true,
773 ),
774 "jacobi_cn" => two_arg_fun(
775 quote!(zenith_float::ExactNum::jacobi_cn),
776 expr,
777 2,
778 err,
779 cc,
780 true,
781 ),
782 "jacobi_dn" => two_arg_fun(
783 quote!(zenith_float::ExactNum::jacobi_dn),
784 expr,
785 2,
786 err,
787 cc,
788 true,
789 ),
790 "jacobi_cd" => two_arg_fun(
791 quote!(zenith_float::ExactNum::jacobi_cd),
792 expr,
793 2,
794 err,
795 cc,
796 true,
797 ),
798 "jacobi_ns" => two_arg_fun(
799 quote!(zenith_float::ExactNum::jacobi_ns),
800 expr,
801 2,
802 err,
803 cc,
804 true,
805 ),
806 "jacobi_nc" => two_arg_fun(
807 quote!(zenith_float::ExactNum::jacobi_nc),
808 expr,
809 2,
810 err,
811 cc,
812 true,
813 ),
814 "jacobi_nd" => two_arg_fun(
815 quote!(zenith_float::ExactNum::jacobi_nd),
816 expr,
817 2,
818 err,
819 cc,
820 true,
821 ),
822 "jacobi_sc" => two_arg_fun(
823 quote!(zenith_float::ExactNum::jacobi_sc),
824 expr,
825 2,
826 err,
827 cc,
828 true,
829 ),
830 "jacobi_sd" => two_arg_fun(
831 quote!(zenith_float::ExactNum::jacobi_sd),
832 expr,
833 2,
834 err,
835 cc,
836 true,
837 ),
838 "jacobi_cs" => two_arg_fun(
839 quote!(zenith_float::ExactNum::jacobi_cs),
840 expr,
841 2,
842 err,
843 cc,
844 true,
845 ),
846 "jacobi_ds" => two_arg_fun(
847 quote!(zenith_float::ExactNum::jacobi_ds),
848 expr,
849 2,
850 err,
851 cc,
852 true,
853 ),
854 "jacobi_dc" => two_arg_fun(
855 quote!(zenith_float::ExactNum::jacobi_dc),
856 expr,
857 2,
858 err,
859 cc,
860 true,
861 ),
862 "elliptic_pi" => two_arg_fun(
863 quote!(zenith_float::ExactNum::elliptic_pi_complete),
864 expr,
865 2,
866 err,
867 cc,
868 true,
869 ),
870 "elliptic_pi_inc" => three_arg_fun(
871 quote!(zenith_float::ExactNum::elliptic_pi),
872 expr,
873 2,
874 err,
875 cc,
876 true,
877 ),
878 "legendre_p" => legendre_p_fun(expr, 2, err, cc),
879 "legendre_p_assoc" => legendre_p_assoc_fun(expr, 2, err, cc),
880 "hypergeom_2f1" => four_arg_fun(
881 quote!(zenith_float::ExactNum::hypergeom_2f1),
882 expr,
883 EXPONENT_BIT_SIZE + 1,
884 err,
885 cc,
886 ),
887 "betainc" => three_arg_fun(
888 quote!(zenith_float::ExactNum::betainc),
889 expr,
890 EXPONENT_BIT_SIZE + 1,
891 err,
892 cc,
893 true,
894 ),
895 "normal_pdf" => three_arg_fun(
896 quote!(zenith_float::ExactNum::normal_pdf),
897 expr,
898 EXPONENT_BIT_SIZE + 1,
899 err,
900 cc,
901 true,
902 ),
903 "normal_cdf" => three_arg_fun(
904 quote!(zenith_float::ExactNum::normal_cdf),
905 expr,
906 EXPONENT_BIT_SIZE + 1,
907 err,
908 cc,
909 true,
910 ),
911 "gamma_pdf" => three_arg_fun(
912 quote!(zenith_float::ExactNum::gamma_pdf),
913 expr,
914 EXPONENT_BIT_SIZE + 1,
915 err,
916 cc,
917 true,
918 ),
919 "beta_pdf" => three_arg_fun(
920 quote!(zenith_float::ExactNum::beta_pdf),
921 expr,
922 EXPONENT_BIT_SIZE + 1,
923 err,
924 cc,
925 true,
926 ),
927 "poisson_pmf" => two_arg_fun(
928 quote!(zenith_float::ExactNum::poisson_pmf),
929 expr,
930 EXPONENT_BIT_SIZE + 1,
931 err,
932 cc,
933 true,
934 ),
935 "binomial_pmf" => three_arg_fun(
936 quote!(zenith_float::ExactNum::binomial_pmf),
937 expr,
938 EXPONENT_BIT_SIZE + 1,
939 err,
940 cc,
941 true,
942 ),
943 "chi_squared_cdf" => two_arg_fun(
944 quote!(zenith_float::ExactNum::chi_squared_cdf),
945 expr,
946 EXPONENT_BIT_SIZE + 1,
947 err,
948 cc,
949 true,
950 ),
951 "student_t_pdf" => two_arg_fun(
952 quote!(zenith_float::ExactNum::student_t_pdf),
953 expr,
954 EXPONENT_BIT_SIZE + 1,
955 err,
956 cc,
957 true,
958 ),
959 "ldexp" => ldexp_fun(expr, 2, err, cc, false),
960 "scalb" => ldexp_fun(expr, 2, err, cc, true),
961 "logb" => one_arg_fun(
962 quote!(zenith_float::ExactNum::logb),
963 expr,
964 1,
965 err,
966 cc,
967 false,
968 ),
969 _ => return Err(Error::new(expr.span(), errmes)),
970 }?;
971
972 return Ok(ts);
973 }
974 }
975 Err(Error::new(expr.span(), errmes))
976}
977
978fn traverse_group(
979 expr: &ExprGroup,
980 err: &mut Vec<usize>,
981 cc: &mut Consts,
982) -> Result<TokenStream, Error> {
983 traverse_expr(&expr.expr, err, cc)
984}
985
986fn traverse_lit(expr: &ExprLit, cc: &mut Consts) -> Result<TokenStream, Error> {
987 let span = expr.span();
988
989 match &expr.lit {
990 Lit::Str(v) => str_to_exact_num_expr(&v.value(), span, cc),
991 Lit::Int(v) => str_to_exact_num_expr(v.base10_digits(), span, cc),
992 Lit::Float(v) => str_to_exact_num_expr(v.base10_digits(), span, cc),
993 _ => Err(Error::new(
994 expr.span(),
995 "unexpected literal. Only string, integer, or floating point literals are supported.",
996 )),
997 }
998}
999
1000fn traverse_paren(
1001 expr: &ExprParen,
1002 err: &mut Vec<usize>,
1003 cc: &mut Consts,
1004) -> Result<TokenStream, Error> {
1005 traverse_expr(&expr.expr, err, cc)
1006}
1007
1008fn traverse_path(expr: &ExprPath) -> Result<TokenStream, Error> {
1009 Ok(if expr.path.is_ident("pi") {
1010 quote!({ cc.pi(p_wrk, zenith_float::RoundingMode::None) })
1011 } else if expr.path.is_ident("e") {
1012 quote!({ cc.e(p_wrk, zenith_float::RoundingMode::None) })
1013 } else if expr.path.is_ident("ln_2") {
1014 quote!({ cc.ln_2(p_wrk, zenith_float::RoundingMode::None) })
1015 } else if expr.path.is_ident("ln_10") {
1016 quote!({ cc.ln_10(p_wrk, zenith_float::RoundingMode::None) })
1017 } else if expr.path.is_ident("sqrt2") {
1018 quote!({ cc.sqrt2(p_wrk, zenith_float::RoundingMode::None) })
1019 } else if expr.path.is_ident("phi") {
1020 quote!({ cc.phi(p_wrk, zenith_float::RoundingMode::None) })
1021 } else if expr.path.is_ident("euler_gamma") {
1022 quote!({ cc.euler_gamma(p_wrk, zenith_float::RoundingMode::None) })
1023 } else {
1024 quote!({
1025 let mut arg = zenith_float::ExactNum::from_ext((#expr).clone(), p_wrk, zenith_float::RoundingMode::ToEven, cc);
1026 arg.set_inexact(false);
1027 arg = zenith_float::macro_util::check_exponent_range(arg, emin, emax);
1028 arg
1029 })
1030 })
1031}
1032
1033fn traverse_unary(
1034 expr: &ExprUnary,
1035 err: &mut Vec<usize>,
1036 cc: &mut Consts,
1037) -> Result<TokenStream, Error> {
1038 let op_expr = traverse_expr(&expr.expr, err, cc)?;
1039
1040 match expr.op {
1041 UnOp::Neg(_) => Ok(quote!(zenith_float::ExactNum::neg(&(#op_expr)))),
1042 _ => Err(Error::new(
1043 expr.span(),
1044 "unexpected unary operator. Only \"-\" is allowed.",
1045 )),
1046 }
1047}
1048
1049fn traverse_expr(expr: &Expr, err: &mut Vec<usize>, cc: &mut Consts) -> Result<TokenStream, Error> {
1050 match expr {
1051 Expr::Binary(e) => traverse_binary(e, err,cc),
1052 Expr::Call(e) => traverse_call(e, err,cc),
1053 Expr::Group(e) => traverse_group(e, err,cc),
1054 Expr::Lit(e) => traverse_lit(e, cc),
1055 Expr::Paren(e) => traverse_paren(e, err, cc),
1056 Expr::Path(e) => traverse_path(e),
1057 Expr::Unary(e) => traverse_unary(e, err, cc),
1058 _ => Err(Error::new(expr.span(), "unexpected expression. Only operators \"+\", \"-\", \"*\", \"/\", \"%\", functions \"recip\", \"sqrt\", \"cbrt\", \"ln\", \"log2\", \"log10\", \"log\", \"exp\", \"pow\", \"sin\", \"cos\", \"tan\", \"asin\", \"acos\", \"atan\", \"sinh\", \"cosh\", \"tanh\", \"asinh\", \"acosh\", \"atanh\", literals and variables, and grouping with parentheses are supported.")),
1059 }
1060}
1061
1062#[proc_macro]
1065#[allow(missing_docs)]
1066pub fn expr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1067 let pmi = syn::parse_macro_input!(input as MacroInput);
1068
1069 let MacroInput { expr, ctx } = pmi;
1070
1071 let mut err = Vec::new();
1072
1073 let mut cc = Consts::new().expect("Failed to initialize constant cache.");
1074
1075 let expr = traverse_expr(&expr, &mut err, &mut cc).unwrap_or_else(|e| e.to_compile_error());
1076
1077 let err_sz = err.len();
1078
1079 let ret = quote!({
1080 use zenith_float::FromExt;
1081 use zenith_float::ctx::Contextable;
1082
1083 let mut ctx = &mut (#ctx);
1084 let p: usize = ctx.precision();
1085 let rm = ctx.rounding_mode();
1086 let emin = ctx.emin();
1087 let emax = ctx.emax();
1088 let cc = ctx.consts();
1089
1090 let mut p_rnd = p + zenith_float::WORD_BIT_SIZE;
1091 let mut errs: [usize; #err_sz] = [#(#err, )*];
1092
1093 loop {
1094 let p_wrk = p_rnd.saturating_add(errs.iter().sum());
1095
1096 let mut ret: zenith_float::ExactNum = (#expr).into();
1097
1098 if let Err(err) = ret.set_precision(p, rm) {
1099 ret = zenith_float::ExactNum::nan(Some(err));
1100 }
1101
1102 break zenith_float::macro_util::check_exponent_range(ret, emin, emax);
1103 }
1104 });
1105
1106 ret.into()
1107}
1108
1109#[proc_macro]
1111#[allow(missing_docs)]
1112pub fn cexpr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1113 cplx::cexpr(input)
1114}
1115
1116#[proc_macro]
1121pub fn exact(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1122 let lit = syn::parse_macro_input!(input as syn::LitStr);
1123 str_to_exact_num_literal(&lit.value(), lit.span())
1124 .unwrap_or_else(|e| e.to_compile_error())
1125 .into()
1126}
1127
1128#[proc_macro]
1130pub fn fbig(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1131 exact(input)
1132}