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\", \"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 "elliptic_pi" => two_arg_fun(
759 quote!(zenith_float::ExactNum::elliptic_pi_complete),
760 expr,
761 2,
762 err,
763 cc,
764 true,
765 ),
766 "elliptic_pi_inc" => three_arg_fun(
767 quote!(zenith_float::ExactNum::elliptic_pi),
768 expr,
769 2,
770 err,
771 cc,
772 true,
773 ),
774 "legendre_p" => legendre_p_fun(expr, 2, err, cc),
775 "legendre_p_assoc" => legendre_p_assoc_fun(expr, 2, err, cc),
776 "hypergeom_2f1" => four_arg_fun(
777 quote!(zenith_float::ExactNum::hypergeom_2f1),
778 expr,
779 EXPONENT_BIT_SIZE + 1,
780 err,
781 cc,
782 ),
783 "betainc" => three_arg_fun(
784 quote!(zenith_float::ExactNum::betainc),
785 expr,
786 EXPONENT_BIT_SIZE + 1,
787 err,
788 cc,
789 true,
790 ),
791 "normal_pdf" => three_arg_fun(
792 quote!(zenith_float::ExactNum::normal_pdf),
793 expr,
794 EXPONENT_BIT_SIZE + 1,
795 err,
796 cc,
797 true,
798 ),
799 "normal_cdf" => three_arg_fun(
800 quote!(zenith_float::ExactNum::normal_cdf),
801 expr,
802 EXPONENT_BIT_SIZE + 1,
803 err,
804 cc,
805 true,
806 ),
807 "gamma_pdf" => three_arg_fun(
808 quote!(zenith_float::ExactNum::gamma_pdf),
809 expr,
810 EXPONENT_BIT_SIZE + 1,
811 err,
812 cc,
813 true,
814 ),
815 "beta_pdf" => three_arg_fun(
816 quote!(zenith_float::ExactNum::beta_pdf),
817 expr,
818 EXPONENT_BIT_SIZE + 1,
819 err,
820 cc,
821 true,
822 ),
823 "poisson_pmf" => two_arg_fun(
824 quote!(zenith_float::ExactNum::poisson_pmf),
825 expr,
826 EXPONENT_BIT_SIZE + 1,
827 err,
828 cc,
829 true,
830 ),
831 "binomial_pmf" => three_arg_fun(
832 quote!(zenith_float::ExactNum::binomial_pmf),
833 expr,
834 EXPONENT_BIT_SIZE + 1,
835 err,
836 cc,
837 true,
838 ),
839 "chi_squared_cdf" => two_arg_fun(
840 quote!(zenith_float::ExactNum::chi_squared_cdf),
841 expr,
842 EXPONENT_BIT_SIZE + 1,
843 err,
844 cc,
845 true,
846 ),
847 "student_t_pdf" => two_arg_fun(
848 quote!(zenith_float::ExactNum::student_t_pdf),
849 expr,
850 EXPONENT_BIT_SIZE + 1,
851 err,
852 cc,
853 true,
854 ),
855 "ldexp" => ldexp_fun(expr, 2, err, cc, false),
856 "scalb" => ldexp_fun(expr, 2, err, cc, true),
857 "logb" => one_arg_fun(
858 quote!(zenith_float::ExactNum::logb),
859 expr,
860 1,
861 err,
862 cc,
863 false,
864 ),
865 _ => return Err(Error::new(expr.span(), errmes)),
866 }?;
867
868 return Ok(ts);
869 }
870 }
871 Err(Error::new(expr.span(), errmes))
872}
873
874fn traverse_group(
875 expr: &ExprGroup,
876 err: &mut Vec<usize>,
877 cc: &mut Consts,
878) -> Result<TokenStream, Error> {
879 traverse_expr(&expr.expr, err, cc)
880}
881
882fn traverse_lit(expr: &ExprLit, cc: &mut Consts) -> Result<TokenStream, Error> {
883 let span = expr.span();
884
885 match &expr.lit {
886 Lit::Str(v) => str_to_exact_num_expr(&v.value(), span, cc),
887 Lit::Int(v) => str_to_exact_num_expr(v.base10_digits(), span, cc),
888 Lit::Float(v) => str_to_exact_num_expr(v.base10_digits(), span, cc),
889 _ => Err(Error::new(
890 expr.span(),
891 "unexpected literal. Only string, integer, or floating point literals are supported.",
892 )),
893 }
894}
895
896fn traverse_paren(
897 expr: &ExprParen,
898 err: &mut Vec<usize>,
899 cc: &mut Consts,
900) -> Result<TokenStream, Error> {
901 traverse_expr(&expr.expr, err, cc)
902}
903
904fn traverse_path(expr: &ExprPath) -> Result<TokenStream, Error> {
905 Ok(if expr.path.is_ident("pi") {
906 quote!({ cc.pi(p_wrk, zenith_float::RoundingMode::None) })
907 } else if expr.path.is_ident("e") {
908 quote!({ cc.e(p_wrk, zenith_float::RoundingMode::None) })
909 } else if expr.path.is_ident("ln_2") {
910 quote!({ cc.ln_2(p_wrk, zenith_float::RoundingMode::None) })
911 } else if expr.path.is_ident("ln_10") {
912 quote!({ cc.ln_10(p_wrk, zenith_float::RoundingMode::None) })
913 } else if expr.path.is_ident("sqrt2") {
914 quote!({ cc.sqrt2(p_wrk, zenith_float::RoundingMode::None) })
915 } else if expr.path.is_ident("phi") {
916 quote!({ cc.phi(p_wrk, zenith_float::RoundingMode::None) })
917 } else if expr.path.is_ident("euler_gamma") {
918 quote!({ cc.euler_gamma(p_wrk, zenith_float::RoundingMode::None) })
919 } else {
920 quote!({
921 let mut arg = zenith_float::ExactNum::from_ext((#expr).clone(), p_wrk, zenith_float::RoundingMode::ToEven, cc);
922 arg.set_inexact(false);
923 arg = zenith_float::macro_util::check_exponent_range(arg, emin, emax);
924 arg
925 })
926 })
927}
928
929fn traverse_unary(
930 expr: &ExprUnary,
931 err: &mut Vec<usize>,
932 cc: &mut Consts,
933) -> Result<TokenStream, Error> {
934 let op_expr = traverse_expr(&expr.expr, err, cc)?;
935
936 match expr.op {
937 UnOp::Neg(_) => Ok(quote!(zenith_float::ExactNum::neg(&(#op_expr)))),
938 _ => Err(Error::new(
939 expr.span(),
940 "unexpected unary operator. Only \"-\" is allowed.",
941 )),
942 }
943}
944
945fn traverse_expr(expr: &Expr, err: &mut Vec<usize>, cc: &mut Consts) -> Result<TokenStream, Error> {
946 match expr {
947 Expr::Binary(e) => traverse_binary(e, err,cc),
948 Expr::Call(e) => traverse_call(e, err,cc),
949 Expr::Group(e) => traverse_group(e, err,cc),
950 Expr::Lit(e) => traverse_lit(e, cc),
951 Expr::Paren(e) => traverse_paren(e, err, cc),
952 Expr::Path(e) => traverse_path(e),
953 Expr::Unary(e) => traverse_unary(e, err, cc),
954 _ => 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.")),
955 }
956}
957
958#[proc_macro]
961#[allow(missing_docs)]
962pub fn expr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
963 let pmi = syn::parse_macro_input!(input as MacroInput);
964
965 let MacroInput { expr, ctx } = pmi;
966
967 let mut err = Vec::new();
968
969 let mut cc = Consts::new().expect("Failed to initialize constant cache.");
970
971 let expr = traverse_expr(&expr, &mut err, &mut cc).unwrap_or_else(|e| e.to_compile_error());
972
973 let err_sz = err.len();
974
975 let ret = quote!({
976 use zenith_float::FromExt;
977 use zenith_float::ctx::Contextable;
978
979 let mut ctx = &mut (#ctx);
980 let p: usize = ctx.precision();
981 let rm = ctx.rounding_mode();
982 let emin = ctx.emin();
983 let emax = ctx.emax();
984 let cc = ctx.consts();
985
986 let mut p_rnd = p + zenith_float::WORD_BIT_SIZE;
987 let mut errs: [usize; #err_sz] = [#(#err, )*];
988
989 loop {
990 let p_wrk = p_rnd.saturating_add(errs.iter().sum());
991
992 let mut ret: zenith_float::ExactNum = (#expr).into();
993
994 if let Err(err) = ret.set_precision(p, rm) {
995 ret = zenith_float::ExactNum::nan(Some(err));
996 }
997
998 break zenith_float::macro_util::check_exponent_range(ret, emin, emax);
999 }
1000 });
1001
1002 ret.into()
1003}
1004
1005#[proc_macro]
1007#[allow(missing_docs)]
1008pub fn cexpr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1009 cplx::cexpr(input)
1010}
1011
1012#[proc_macro]
1017pub fn exact(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1018 let lit = syn::parse_macro_input!(input as syn::LitStr);
1019 str_to_exact_num_literal(&lit.value(), lit.span())
1020 .unwrap_or_else(|e| e.to_compile_error())
1021 .into()
1022}
1023
1024#[proc_macro]
1026pub fn fbig(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1027 exact(input)
1028}