xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/fend-core-1.4.6/src/ast.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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