1 use crate::error::{FendError, Interrupt};
2 use crate::eval::evaluate_to_value;
3 use crate::ident::Ident;
4 use crate::interrupt::test_int;
5 use crate::num::{Base, FormattingStyle, Number, Range, RangeBound};
6 use crate::result::FResult;
7 use crate::scope::Scope;
8 use crate::serialize::{Deserialize, Serialize};
9 use crate::value::{built_in_function::BuiltInFunction, ApplyMulHandling, Value};
10 use crate::Attrs;
11 use std::sync::Arc;
12 use std::{borrow, cmp, fmt, io};
13
14 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
15 pub(crate) enum BitwiseBop {
16 And,
17 Or,
18 Xor,
19 LeftShift,
20 RightShift,
21 }
22
23 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
24 pub(crate) enum Bop {
25 Plus,
26 ImplicitPlus,
27 Minus,
28 Mul,
29 Div,
30 Mod,
31 Pow,
32 Bitwise(BitwiseBop),
33 Combination,
34 Permutation,
35 }
36
37 impl Bop {
serialize(self, write: &mut impl io::Write) -> FResult<()>38 pub(crate) fn serialize(self, write: &mut impl io::Write) -> FResult<()> {
39 let n: u8 = match self {
40 Self::Plus => 0,
41 Self::ImplicitPlus => 1,
42 Self::Minus => 2,
43 Self::Mul => 3,
44 Self::Div => 4,
45 Self::Mod => 5,
46 Self::Pow => 6,
47 Self::Bitwise(BitwiseBop::And) => 7,
48 Self::Bitwise(BitwiseBop::Or) => 8,
49 Self::Bitwise(BitwiseBop::Xor) => 9,
50 Self::Bitwise(BitwiseBop::LeftShift) => 10,
51 Self::Bitwise(BitwiseBop::RightShift) => 11,
52 Self::Combination => 12,
53 Self::Permutation => 13,
54 };
55 n.serialize(write)?;
56 Ok(())
57 }
58
deserialize(read: &mut impl io::Read) -> FResult<Self>59 pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> {
60 Ok(match u8::deserialize(read)? {
61 0 => Self::Plus,
62 1 => Self::ImplicitPlus,
63 2 => Self::Minus,
64 3 => Self::Mul,
65 4 => Self::Div,
66 5 => Self::Mod,
67 6 => Self::Pow,
68 7 => Self::Bitwise(BitwiseBop::And),
69 8 => Self::Bitwise(BitwiseBop::Or),
70 9 => Self::Bitwise(BitwiseBop::Xor),
71 10 => Self::Bitwise(BitwiseBop::LeftShift),
72 11 => Self::Bitwise(BitwiseBop::RightShift),
73 12 => Self::Combination,
74 13 => Self::Permutation,
75 _ => return Err(FendError::DeserializationError),
76 })
77 }
78 }
79
80 impl fmt::Display for Bop {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 let s = match self {
83 Self::Plus => "+",
84 Self::ImplicitPlus => " ",
85 Self::Minus => "-",
86 Self::Mul => "*",
87 Self::Div => "/",
88 Self::Mod => " mod ",
89 Self::Pow => "^",
90 Self::Bitwise(BitwiseBop::And) => "&",
91 Self::Bitwise(BitwiseBop::Or) => "|",
92 Self::Bitwise(BitwiseBop::Xor) => " xor ",
93 Self::Bitwise(BitwiseBop::LeftShift) => "<<",
94 Self::Bitwise(BitwiseBop::RightShift) => ">>",
95 Self::Combination => "nCr",
96 Self::Permutation => "nPr",
97 };
98 write!(f, "{s}")
99 }
100 }
101
102 #[derive(Clone, Debug)]
103 pub(crate) enum Expr {
104 Literal(Value),
105 Ident(Ident),
106 Parens(Box<Expr>),
107 UnaryMinus(Box<Expr>),
108 UnaryPlus(Box<Expr>),
109 UnaryDiv(Box<Expr>),
110 Factorial(Box<Expr>),
111 Bop(Bop, Box<Expr>, Box<Expr>),
112 // Call a function or multiply the expressions
113 Apply(Box<Expr>, Box<Expr>),
114 // Call a function, or throw an error if lhs is not a function
115 ApplyFunctionCall(Box<Expr>, Box<Expr>),
116 // Multiply the expressions
117 ApplyMul(Box<Expr>, Box<Expr>),
118
119 As(Box<Expr>, Box<Expr>),
120 Fn(Ident, Box<Expr>),
121
122 Of(Ident, Box<Expr>),
123
124 Assign(Ident, Box<Expr>),
125 Equality(bool, Box<Expr>, Box<Expr>),
126 Statements(Box<Expr>, Box<Expr>),
127 }
128
129 impl Expr {
compare<I: Interrupt>(&self, other: &Self, int: &I) -> FResult<bool>130 pub(crate) fn compare<I: Interrupt>(&self, other: &Self, int: &I) -> FResult<bool> {
131 Ok(match (self, other) {
132 (Self::Literal(a), Self::Literal(b)) => {
133 a.compare(b, int)? == Some(cmp::Ordering::Equal)
134 }
135 (Self::Ident(a), Self::Ident(b)) => a == b,
136 (Self::Parens(a), Self::Parens(b)) => a.compare(b, int)?,
137 (Self::UnaryMinus(a), Self::UnaryMinus(b)) => a.compare(b, int)?,
138 (Self::UnaryPlus(a), Self::UnaryPlus(b)) => a.compare(b, int)?,
139 (Self::UnaryDiv(a), Self::UnaryDiv(b)) => a.compare(b, int)?,
140 (Self::Factorial(a), Self::Factorial(b)) => a.compare(b, int)?,
141 (Self::Bop(a1, a2, a3), Self::Bop(b1, b2, b3)) => {
142 a1 == b1 && a2.compare(b2, int)? && a3.compare(b3, int)?
143 }
144 (Self::Apply(a1, a2), Self::Apply(b1, b2)) => {
145 a1.compare(b1, int)? && a2.compare(b2, int)?
146 }
147 (Self::ApplyFunctionCall(a1, a2), Self::ApplyFunctionCall(b1, b2)) => {
148 a1.compare(b1, int)? && a2.compare(b2, int)?
149 }
150 (Self::ApplyMul(a1, a2), Self::ApplyMul(b1, b2)) => {
151 a1.compare(b1, int)? && a2.compare(b2, int)?
152 }
153 (Self::As(a1, a2), Self::As(b1, b2)) => a1.compare(b1, int)? && a2.compare(b2, int)?,
154 (Self::Fn(a1, a2), Self::Fn(b1, b2)) => a1 == b1 && a2.compare(b2, int)?,
155 (Self::Of(a1, a2), Self::Of(b1, b2)) => a1 == b1 && a2.compare(b2, int)?,
156 (Self::Assign(a1, a2), Self::Assign(b1, b2)) => a1 == b1 && a2.compare(b2, int)?,
157 (Self::Equality(a1, a2, a3), Self::Equality(b1, b2, b3)) => {
158 a1 == b1 && a2.compare(b2, int)? && a3.compare(b3, int)?
159 }
160 (Self::Statements(a1, a2), Self::Statements(b1, b2)) => {
161 a1.compare(b1, int)? && a2.compare(b2, int)?
162 }
163 _ => false,
164 })
165 }
166
serialize(&self, write: &mut impl io::Write) -> FResult<()>167 pub(crate) fn serialize(&self, write: &mut impl io::Write) -> FResult<()> {
168 match self {
169 Self::Literal(x) => {
170 0u8.serialize(write)?;
171 x.serialize(write)?;
172 }
173 Self::Ident(i) => {
174 1u8.serialize(write)?;
175 i.serialize(write)?;
176 }
177 Self::Parens(e) => {
178 2u8.serialize(write)?;
179 e.serialize(write)?;
180 }
181 Self::UnaryMinus(e) => {
182 3u8.serialize(write)?;
183 e.serialize(write)?;
184 }
185 Self::UnaryPlus(e) => {
186 4u8.serialize(write)?;
187 e.serialize(write)?;
188 }
189 Self::UnaryDiv(e) => {
190 5u8.serialize(write)?;
191 e.serialize(write)?;
192 }
193 Self::Factorial(e) => {
194 6u8.serialize(write)?;
195 e.serialize(write)?;
196 }
197 Self::Bop(op, a, b) => {
198 7u8.serialize(write)?;
199 op.serialize(write)?;
200 a.serialize(write)?;
201 b.serialize(write)?;
202 }
203 Self::Apply(a, b) => {
204 8u8.serialize(write)?;
205 a.serialize(write)?;
206 b.serialize(write)?;
207 }
208 Self::ApplyFunctionCall(a, b) => {
209 9u8.serialize(write)?;
210 a.serialize(write)?;
211 b.serialize(write)?;
212 }
213 Self::ApplyMul(a, b) => {
214 10u8.serialize(write)?;
215 a.serialize(write)?;
216 b.serialize(write)?;
217 }
218 Self::As(a, b) => {
219 11u8.serialize(write)?;
220 a.serialize(write)?;
221 b.serialize(write)?;
222 }
223 Self::Fn(a, b) => {
224 12u8.serialize(write)?;
225 a.serialize(write)?;
226 b.serialize(write)?;
227 }
228 Self::Of(a, b) => {
229 13u8.serialize(write)?;
230 a.serialize(write)?;
231 b.serialize(write)?;
232 }
233 Self::Assign(a, b) => {
234 14u8.serialize(write)?;
235 a.serialize(write)?;
236 b.serialize(write)?;
237 }
238 Self::Statements(a, b) => {
239 15u8.serialize(write)?;
240 a.serialize(write)?;
241 b.serialize(write)?;
242 }
243 Self::Equality(is_equals, a, b) => {
244 16u8.serialize(write)?;
245 is_equals.serialize(write)?;
246 a.serialize(write)?;
247 b.serialize(write)?;
248 }
249 }
250 Ok(())
251 }
252
deserialize(read: &mut impl io::Read) -> FResult<Self>253 pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> {
254 Ok(match u8::deserialize(read)? {
255 0 => Self::Literal(Value::deserialize(read)?),
256 1 => Self::Ident(Ident::deserialize(read)?),
257 2 => Self::Parens(Box::new(Self::deserialize(read)?)),
258 3 => Self::UnaryMinus(Box::new(Self::deserialize(read)?)),
259 4 => Self::UnaryPlus(Box::new(Self::deserialize(read)?)),
260 5 => Self::UnaryDiv(Box::new(Self::deserialize(read)?)),
261 6 => Self::Factorial(Box::new(Self::deserialize(read)?)),
262 7 => Self::Bop(
263 Bop::deserialize(read)?,
264 Box::new(Self::deserialize(read)?),
265 Box::new(Self::deserialize(read)?),
266 ),
267 8 => Self::Apply(
268 Box::new(Self::deserialize(read)?),
269 Box::new(Self::deserialize(read)?),
270 ),
271 9 => Self::ApplyFunctionCall(
272 Box::new(Self::deserialize(read)?),
273 Box::new(Self::deserialize(read)?),
274 ),
275 10 => Self::ApplyMul(
276 Box::new(Self::deserialize(read)?),
277 Box::new(Self::deserialize(read)?),
278 ),
279 11 => Self::As(
280 Box::new(Self::deserialize(read)?),
281 Box::new(Self::deserialize(read)?),
282 ),
283 12 => Self::Fn(
284 Ident::deserialize(read)?,
285 Box::new(Self::deserialize(read)?),
286 ),
287 13 => Self::Of(
288 Ident::deserialize(read)?,
289 Box::new(Self::deserialize(read)?),
290 ),
291 14 => Self::Assign(
292 Ident::deserialize(read)?,
293 Box::new(Self::deserialize(read)?),
294 ),
295 15 => Self::Statements(
296 Box::new(Self::deserialize(read)?),
297 Box::new(Self::deserialize(read)?),
298 ),
299 16 => Self::Equality(
300 bool::deserialize(read)?,
301 Box::new(Self::deserialize(read)?),
302 Box::new(Self::deserialize(read)?),
303 ),
304 _ => return Err(FendError::DeserializationError),
305 })
306 }
307
format<I: Interrupt>( &self, attrs: Attrs, ctx: &mut crate::Context, int: &I, ) -> FResult<String>308 pub(crate) fn format<I: Interrupt>(
309 &self,
310 attrs: Attrs,
311 ctx: &mut crate::Context,
312 int: &I,
313 ) -> FResult<String> {
314 Ok(match self {
315 Self::Literal(Value::String(s)) => format!(r#""{}""#, s.as_ref()),
316 Self::Literal(v) => v.format_to_plain_string(0, attrs, ctx, int)?,
317 Self::Ident(ident) => ident.to_string(),
318 Self::Parens(x) => format!("({})", x.format(attrs, ctx, int)?),
319 Self::UnaryMinus(x) => format!("(-{})", x.format(attrs, ctx, int)?),
320 Self::UnaryPlus(x) => format!("(+{})", x.format(attrs, ctx, int)?),
321 Self::UnaryDiv(x) => format!("(/{})", x.format(attrs, ctx, int)?),
322 Self::Factorial(x) => format!("{}!", x.format(attrs, ctx, int)?),
323 Self::Bop(op, a, b) => {
324 format!(
325 "({}{op}{})",
326 a.format(attrs, ctx, int)?,
327 b.format(attrs, ctx, int)?
328 )
329 }
330 Self::Apply(a, b) => format!(
331 "({} ({}))",
332 a.format(attrs, ctx, int)?,
333 b.format(attrs, ctx, int)?
334 ),
335 Self::ApplyFunctionCall(a, b) | Self::ApplyMul(a, b) => {
336 format!(
337 "({} {})",
338 a.format(attrs, ctx, int)?,
339 b.format(attrs, ctx, int)?
340 )
341 }
342 Self::As(a, b) => format!(
343 "({} as {})",
344 a.format(attrs, ctx, int)?,
345 b.format(attrs, ctx, int)?
346 ),
347 Self::Fn(a, b) => {
348 if a.as_str().contains('.') {
349 format!("({a}:{})", b.format(attrs, ctx, int)?)
350 } else {
351 format!("\\{a}.{}", b.format(attrs, ctx, int)?)
352 }
353 }
354 Self::Of(a, b) => format!("{a} of {}", b.format(attrs, ctx, int)?),
355 Self::Assign(a, b) => format!("{a} = {}", b.format(attrs, ctx, int)?),
356 Self::Statements(a, b) => format!(
357 "{}; {}",
358 a.format(attrs, ctx, int)?,
359 b.format(attrs, ctx, int)?
360 ),
361 Self::Equality(is_equals, a, b) => format!(
362 "{} {} {}",
363 a.format(attrs, ctx, int)?,
364 if *is_equals { "==" } else { "!=" },
365 b.format(attrs, ctx, int)?
366 ),
367 })
368 }
369 }
370
371 /// returns true if rhs is '-1' or '(-1)'
should_compute_inverse<I: Interrupt>(rhs: &Expr, int: &I) -> FResult<bool>372 fn should_compute_inverse<I: Interrupt>(rhs: &Expr, int: &I) -> FResult<bool> {
373 if let Expr::UnaryMinus(inner) = rhs {
374 if let Expr::Literal(Value::Num(n)) = &**inner {
375 if n.is_unitless_one(int)? {
376 return Ok(true);
377 }
378 }
379 } else if let Expr::Parens(inner) = rhs {
380 if let Expr::UnaryMinus(inner2) = &**inner {
381 if let Expr::Literal(Value::Num(n)) = &**inner2 {
382 if n.is_unitless_one(int)? {
383 return Ok(true);
384 }
385 }
386 }
387 }
388 Ok(false)
389 }
390
391 #[allow(clippy::too_many_lines)]
evaluate<I: Interrupt>( expr: Expr, scope: Option<Arc<Scope>>, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Value>392 pub(crate) fn evaluate<I: Interrupt>(
393 expr: Expr,
394 scope: Option<Arc<Scope>>,
395 attrs: Attrs,
396 context: &mut crate::Context,
397 int: &I,
398 ) -> FResult<Value> {
399 macro_rules! eval {
400 ($e:expr) => {
401 evaluate($e, scope.clone(), attrs, context, int)
402 };
403 }
404 test_int(int)?;
405 Ok(match expr {
406 Expr::Literal(v) => v,
407 Expr::Ident(ident) => resolve_identifier(&ident, scope, attrs, context, int)?,
408 Expr::Parens(x) => eval!(*x)?,
409 Expr::UnaryMinus(x) => eval!(*x)?.handle_num(|x| Ok(-x), Expr::UnaryMinus, scope)?,
410 Expr::UnaryPlus(x) => eval!(*x)?.handle_num(Ok, Expr::UnaryPlus, scope)?,
411 Expr::UnaryDiv(x) => {
412 eval!(*x)?.handle_num(|x| Number::from(1).div(x, int), Expr::UnaryDiv, scope)?
413 }
414 Expr::Factorial(x) => {
415 eval!(*x)?.handle_num(|x| x.factorial(int), Expr::Factorial, scope)?
416 }
417 Expr::Bop(Bop::Plus, a, b) => evaluate_add(eval!(*a)?, eval!(*b)?, scope, int)?,
418 Expr::Bop(Bop::Minus, a, b) => {
419 let a = eval!(*a)?;
420 match a {
421 Value::Num(a) => Value::Num(Box::new(a.sub(eval!(*b)?.expect_num()?, int)?)),
422 Value::Date(a) => a.sub(eval!(*b)?, int)?,
423 f @ (Value::BuiltInFunction(_) | Value::Fn(_, _, _)) => f.apply(
424 Expr::UnaryMinus(b),
425 ApplyMulHandling::OnlyApply,
426 scope,
427 attrs,
428 context,
429 int,
430 )?,
431 _ => return Err(FendError::InvalidOperandsForSubtraction),
432 }
433 }
434 Expr::Bop(Bop::Pow, a, b) => {
435 let lhs = eval!(*a)?;
436 if should_compute_inverse(&b, int)? {
437 let result = match &lhs {
438 Value::BuiltInFunction(f) => Some(f.invert()?),
439 Value::Fn(_, _, _) => return Err(FendError::InversesOfLambdasUnsupported),
440 _ => None,
441 };
442 if let Some(res) = result {
443 return Ok(res);
444 }
445 }
446 lhs.handle_two_nums(
447 eval!(*b)?,
448 |a, b| a.pow(b, int),
449 |a| {
450 |f| {
451 Expr::Bop(
452 Bop::Pow,
453 f,
454 Box::new(Expr::Literal(Value::Num(Box::new(a)))),
455 )
456 }
457 },
458 |a| {
459 |f| {
460 Expr::Bop(
461 Bop::Pow,
462 Box::new(Expr::Literal(Value::Num(Box::new(a)))),
463 f,
464 )
465 }
466 },
467 scope,
468 )?
469 }
470 Expr::Bop(bop, a, b) => eval!(*a)?.handle_two_nums(
471 eval!(*b)?,
472 |a, b| a.bop(bop, b, attrs, context, int),
473 |a| |f| Expr::Bop(bop, f, Box::new(Expr::Literal(Value::Num(Box::new(a))))),
474 |a| |f| Expr::Bop(bop, Box::new(Expr::Literal(Value::Num(Box::new(a)))), f),
475 scope,
476 )?,
477 Expr::Apply(a, b) | Expr::ApplyMul(a, b) => {
478 if let (Expr::Ident(a), Expr::Ident(b)) = (&*a, &*b) {
479 let ident = format!("{a}_{b}");
480 if let Ok(val) = crate::units::query_unit_static(&ident, attrs, context, int) {
481 return Ok(val);
482 }
483 }
484 match (*a, *b) {
485 (a, Expr::Of(x, expr)) if x.as_str() == "%" => eval!(a)?
486 .handle_num(
487 |x| x.div(Number::from(100), int),
488 Expr::UnaryDiv,
489 scope.clone(),
490 )?
491 .apply(*expr, ApplyMulHandling::Both, scope, attrs, context, int)?,
492 (a, b) => eval!(a)?.apply(b, ApplyMulHandling::Both, scope, attrs, context, int)?,
493 }
494 }
495 Expr::ApplyFunctionCall(a, b) => {
496 eval!(*a)?.apply(*b, ApplyMulHandling::OnlyApply, scope, attrs, context, int)?
497 }
498 Expr::As(a, b) => evaluate_as(*a, *b, scope, attrs, context, int)?,
499 Expr::Fn(a, b) => Value::Fn(a, b, scope),
500 Expr::Of(a, b) => eval!(*b)?.get_object_member(&a)?,
501 Expr::Assign(a, b) => {
502 let rhs = evaluate(*b, scope, attrs, context, int)?;
503 context.variables.insert(a.to_string(), rhs.clone());
504 rhs
505 }
506 Expr::Statements(a, b) => {
507 let _lhs = evaluate(*a, scope.clone(), attrs, context, int)?;
508 evaluate(*b, scope, attrs, context, int)?
509 }
510 Expr::Equality(is_equals, a, b) => {
511 let lhs = evaluate(*a, scope.clone(), attrs, context, int)?;
512 let rhs = evaluate(*b, scope, attrs, context, int)?;
513 Value::Bool(match lhs.compare(&rhs, int)? {
514 Some(cmp::Ordering::Equal) => is_equals,
515 Some(cmp::Ordering::Greater | cmp::Ordering::Less) | None => !is_equals,
516 })
517 }
518 })
519 }
520
evaluate_add<I: Interrupt>( a: Value, b: Value, scope: Option<Arc<Scope>>, int: &I, ) -> FResult<Value>521 fn evaluate_add<I: Interrupt>(
522 a: Value,
523 b: Value,
524 scope: Option<Arc<Scope>>,
525 int: &I,
526 ) -> FResult<Value> {
527 Ok(match (a, b) {
528 (Value::Num(a), Value::Num(b)) => Value::Num(Box::new(a.add(*b, int)?)),
529 (Value::String(a), Value::String(b)) => {
530 Value::String(format!("{}{}", a.as_ref(), b.as_ref()).into())
531 }
532 (Value::BuiltInFunction(f), Value::Num(a)) => f.wrap_with_expr(
533 |f| Expr::Bop(Bop::Plus, f, Box::new(Expr::Literal(Value::Num(a)))),
534 scope,
535 ),
536 (Value::Num(a), Value::BuiltInFunction(f)) => f.wrap_with_expr(
537 |f| Expr::Bop(Bop::Plus, Box::new(Expr::Literal(Value::Num(a))), f),
538 scope,
539 ),
540 (Value::Fn(param, expr, scope), Value::Num(a)) => Value::Fn(
541 param,
542 Box::new(Expr::Bop(
543 Bop::Plus,
544 expr,
545 Box::new(Expr::Literal(Value::Num(a))),
546 )),
547 scope,
548 ),
549 (Value::Num(a), Value::Fn(param, expr, scope)) => Value::Fn(
550 param,
551 Box::new(Expr::Bop(
552 Bop::Plus,
553 Box::new(Expr::Literal(Value::Num(a))),
554 expr,
555 )),
556 scope,
557 ),
558 (Value::Date(d), b) => d.add(b, int)?,
559 _ => return Err(FendError::ExpectedANumber),
560 })
561 }
562
evaluate_as<I: Interrupt>( a: Expr, b: Expr, scope: Option<Arc<Scope>>, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Value>563 fn evaluate_as<I: Interrupt>(
564 a: Expr,
565 b: Expr,
566 scope: Option<Arc<Scope>>,
567 attrs: Attrs,
568 context: &mut crate::Context,
569 int: &I,
570 ) -> FResult<Value> {
571 if let Expr::Ident(ident) = &b {
572 match ident.as_str() {
573 "bool" | "boolean" => {
574 let num = evaluate(a, scope, attrs, context, int)?.expect_num()?;
575 return Ok(Value::Bool(!num.is_zero(int)?));
576 }
577 "date" => {
578 let a = evaluate(a, scope, attrs, context, int)?;
579 return if let Value::String(s) = a {
580 Ok(Value::Date(crate::date::Date::parse(s.as_ref())?))
581 } else {
582 Err(FendError::ExpectedAString)
583 };
584 }
585 "string" => {
586 return Ok(Value::String(
587 evaluate(a, scope, attrs, context, int)?
588 .format_to_plain_string(0, attrs, context, int)?
589 .into(),
590 ));
591 }
592 "codepoint" => {
593 let a = evaluate(a, scope, attrs, context, int)?;
594 if let Value::String(s) = a {
595 let ch = s
596 .as_ref()
597 .chars()
598 .next()
599 .ok_or(FendError::StringCannotBeEmpty)?;
600 if s.len() > ch.len_utf8() {
601 return Err(FendError::StringCannotBeLonger);
602 }
603 let value = Value::Num(Box::new(
604 Number::from(u64::from(ch as u32)).with_base(Base::HEX),
605 ));
606 return Ok(value);
607 }
608 return Err(FendError::ExpectedAString);
609 }
610 "char" | "character" => {
611 let a = evaluate(a, scope, attrs, context, int)?;
612 if let Value::Num(v) = a {
613 let n = v.try_as_usize(int)?;
614 let ch = n
615 .try_into()
616 .ok()
617 .and_then(std::char::from_u32)
618 .ok_or(FendError::InvalidCodepoint(n))?;
619
620 return Ok(Value::String(ch.to_string().into()));
621 }
622 return Err(FendError::ExpectedANumber);
623 }
624 "roman" | "roman_numeral" => {
625 let a = evaluate(a, scope, attrs, context, int)?
626 .expect_num()?
627 .try_as_usize(int)?;
628 if a == 0 {
629 return Err(FendError::RomanNumeralZero);
630 }
631 let upper_limit = 100_000;
632 if a > upper_limit {
633 return Err(FendError::OutOfRange {
634 value: Box::new(a),
635 range: Range {
636 start: RangeBound::Closed(Box::new(1)),
637 end: RangeBound::Closed(Box::new(upper_limit)),
638 },
639 });
640 }
641 return Ok(Value::String(borrow::Cow::Owned(to_roman(a))));
642 }
643 _ => (),
644 }
645 }
646 Ok(match evaluate(b, scope.clone(), attrs, context, int)? {
647 Value::Num(b) => Value::Num(Box::new(
648 evaluate(a, scope, attrs, context, int)?
649 .expect_num()?
650 .convert_to(*b, int)?,
651 )),
652 Value::Format(fmt) => Value::Num(Box::new(
653 evaluate(a, scope, attrs, context, int)?
654 .expect_num()?
655 .with_format(fmt),
656 )),
657 Value::Dp => {
658 return Err(FendError::SpecifyNumDp);
659 }
660 Value::Sf => {
661 return Err(FendError::SpecifyNumSf);
662 }
663 Value::Base(base) => Value::Num(Box::new(
664 evaluate(a, scope, attrs, context, int)?
665 .expect_num()?
666 .with_base(base),
667 )),
668 other => {
669 return Err(FendError::CannotConvertValueTo(other.type_name()));
670 }
671 })
672 }
673
resolve_identifier<I: Interrupt>( ident: &Ident, scope: Option<Arc<Scope>>, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Value>674 pub(crate) fn resolve_identifier<I: Interrupt>(
675 ident: &Ident,
676 scope: Option<Arc<Scope>>,
677 attrs: Attrs,
678 context: &mut crate::Context,
679 int: &I,
680 ) -> FResult<Value> {
681 macro_rules! eval_box {
682 ($input:expr) => {
683 Box::new(evaluate_to_value(
684 $input,
685 scope.clone(),
686 attrs,
687 context,
688 int,
689 )?)
690 };
691 }
692 if let Some(scope) = scope.clone() {
693 if let Some(val) = scope.get(ident, attrs, context, int)? {
694 return Ok(val);
695 }
696 }
697 if let Some(val) = context.variables.get(ident.as_str()) {
698 return Ok(val.clone());
699 }
700 Ok(match ident.as_str() {
701 "pi" | "\u{3c0}" => Value::Num(Box::new(Number::pi())),
702 "tau" | "\u{3c4}" => Value::Num(Box::new(Number::pi().mul(2.into(), int)?)),
703 "e" => evaluate_to_value("approx. 2.718281828459045235", scope, attrs, context, int)?,
704 "phi" => evaluate_to_value("(1 + sqrt(5))/2", scope, attrs, context, int)?,
705 "i" => Value::Num(Box::new(Number::i())),
706 "true" => Value::Bool(true),
707 "false" => Value::Bool(false),
708 "sample" | "roll" => Value::BuiltInFunction(BuiltInFunction::Sample),
709 "mean" | "average" => Value::BuiltInFunction(BuiltInFunction::Mean),
710 "sqrt" => evaluate_to_value("x: x^(1/2)", scope, attrs, context, int)?,
711 "cbrt" => evaluate_to_value("x: x^(1/3)", scope, attrs, context, int)?,
712 "real" | "re" | "Re" => Value::BuiltInFunction(BuiltInFunction::Real),
713 "imag" | "im" | "Im" => Value::BuiltInFunction(BuiltInFunction::Imag),
714 "conjugate" => Value::BuiltInFunction(BuiltInFunction::Conjugate),
715 "unitless" => Value::Num(Box::new(Number::from(1))),
716 "arg" => Value::BuiltInFunction(BuiltInFunction::Arg),
717 "abs" => Value::BuiltInFunction(BuiltInFunction::Abs),
718 "floor" => Value::BuiltInFunction(BuiltInFunction::Floor),
719 "ceil" => Value::BuiltInFunction(BuiltInFunction::Ceil),
720 "round" => Value::BuiltInFunction(BuiltInFunction::Round),
721 "sin" => Value::BuiltInFunction(BuiltInFunction::Sin),
722 "cos" => Value::BuiltInFunction(BuiltInFunction::Cos),
723 "tan" => Value::BuiltInFunction(BuiltInFunction::Tan),
724 "asin" => Value::BuiltInFunction(BuiltInFunction::Asin),
725 "acos" => Value::BuiltInFunction(BuiltInFunction::Acos),
726 "atan" => Value::BuiltInFunction(BuiltInFunction::Atan),
727 "sinh" => Value::BuiltInFunction(BuiltInFunction::Sinh),
728 "cosh" => Value::BuiltInFunction(BuiltInFunction::Cosh),
729 "tanh" => Value::BuiltInFunction(BuiltInFunction::Tanh),
730 "asinh" => Value::BuiltInFunction(BuiltInFunction::Asinh),
731 "acosh" => Value::BuiltInFunction(BuiltInFunction::Acosh),
732 "atanh" => Value::BuiltInFunction(BuiltInFunction::Atanh),
733 "cis" => evaluate_to_value(
734 "theta => cos theta + i * sin theta",
735 scope,
736 attrs,
737 context,
738 int,
739 )?,
740 "ln" => Value::BuiltInFunction(BuiltInFunction::Ln),
741 "log2" => Value::BuiltInFunction(BuiltInFunction::Log2),
742 "log" | "log10" => Value::BuiltInFunction(BuiltInFunction::Log10),
743 "not" => Value::BuiltInFunction(BuiltInFunction::Not),
744 "exp" => evaluate_to_value("x: e^x", scope, attrs, context, int)?,
745 "approx." | "approximately" => Value::BuiltInFunction(BuiltInFunction::Approximately),
746 "auto" => Value::Format(FormattingStyle::Auto),
747 "exact" => Value::Format(FormattingStyle::Exact),
748 "frac" | "fraction" => Value::Format(FormattingStyle::ImproperFraction),
749 "mixed_frac" | "mixed_fraction" => Value::Format(FormattingStyle::MixedFraction),
750 "float" => Value::Format(FormattingStyle::ExactFloat),
751 "dp" => Value::Dp,
752 "sf" => Value::Sf,
753 "base" => Value::BuiltInFunction(BuiltInFunction::Base),
754 "dec" | "decimal" => Value::Base(Base::from_plain_base(10)?),
755 "hex" | "hexadecimal" => Value::Base(Base::from_plain_base(16)?),
756 "bin" | "binary" => Value::Base(Base::from_plain_base(2)?),
757 "ternary" => Value::Base(Base::from_plain_base(3)?),
758 "senary" | "seximal" => Value::Base(Base::from_plain_base(6)?),
759 "oct" | "octal" => Value::Base(Base::from_plain_base(8)?),
760 "version" => Value::String(crate::get_version_as_str().into()),
761 "square" => evaluate_to_value("x: x^2", scope, attrs, context, int)?,
762 "cubic" => evaluate_to_value("x: x^3", scope, attrs, context, int)?,
763 "earth" => Value::Object(vec![
764 ("axial_tilt".into(), eval_box!("23.4392811 degrees")),
765 ("eccentricity".into(), eval_box!("0.0167086")),
766 ("escape_velocity".into(), eval_box!("11.186 km/s")),
767 ("gravity".into(), eval_box!("9.80665 m/s^2")),
768 ("mass".into(), eval_box!("5.97237e24 kg")),
769 ("volume".into(), eval_box!("1.08321e12 km^3")),
770 ]),
771 "today" => Value::Date(crate::date::Date::today(context)?),
772 "tomorrow" => Value::Date(crate::date::Date::today(context)?.next()),
773 "yesterday" => Value::Date(crate::date::Date::today(context)?.prev()),
774 _ => return crate::units::query_unit(ident.as_str(), attrs, context, int),
775 })
776 }
777
to_roman(mut num: usize) -> String778 fn to_roman(mut num: usize) -> String {
779 // based on https://stackoverflow.com/a/41358305
780 let mut result = String::new();
781 for (r, n) in [
782 ("M", 1000),
783 ("CM", 900),
784 ("D", 500),
785 ("CD", 400),
786 ("C", 100),
787 ("XC", 90),
788 ("L", 50),
789 ("XL", 40),
790 ("X", 10),
791 ("IX", 9),
792 ("V", 5),
793 ("IV", 4),
794 ("I", 1),
795 ] {
796 let q = num / n;
797 num -= q * n;
798 for _ in 0..q {
799 result.push_str(r);
800 }
801 }
802 result
803 }
804