fend_core/
value.rs

1use crate::ast::Bop;
2use crate::date::{Date, DayOfWeek, Month};
3use crate::error::{FendError, Interrupt};
4use crate::num::{Base, FormattingStyle, Number};
5use crate::result::FResult;
6use crate::scope::{Scope, compare_option_arc_scope};
7use crate::serialize::{Deserialize, Serialize};
8use crate::{Attrs, Span, SpanKind, date};
9use crate::{ast::Expr, ident::Ident};
10use std::borrow::Cow;
11use std::{cmp, io};
12use std::{
13	fmt::{self, Write},
14	sync::Arc,
15};
16
17pub(crate) mod built_in_function;
18
19use built_in_function::BuiltInFunction;
20
21#[derive(Clone)]
22pub(crate) enum Value {
23	Num(Box<Number>),
24	BuiltInFunction(BuiltInFunction),
25	Format(FormattingStyle),
26	Dp,
27	Sf,
28	Base(Base),
29	// user-defined function with a named parameter
30	Fn(Ident, Box<Expr>, Option<Arc<Scope>>),
31	Object(Vec<(Cow<'static, str>, Box<Value>)>),
32	String(Cow<'static, str>),
33	Bool(bool),
34	Unit, // unit value `()`
35	Month(date::Month),
36	DayOfWeek(date::DayOfWeek),
37	Date(date::Date),
38}
39
40#[derive(Copy, Clone, Eq, PartialEq)]
41pub(crate) enum ApplyMulHandling {
42	OnlyApply,
43	Both,
44}
45
46impl Value {
47	pub(crate) fn compare<I: Interrupt>(
48		&self,
49		other: &Self,
50		ctx: &mut crate::Context,
51		int: &I,
52	) -> FResult<Option<cmp::Ordering>> {
53		let c = |cmp| {
54			if cmp {
55				Some(cmp::Ordering::Equal)
56			} else {
57				None
58			}
59		};
60		Ok(match (self, other) {
61			(Self::Num(a), Self::Num(b)) => a.compare(b, ctx.decimal_separator, int)?,
62			(Self::BuiltInFunction(a), Self::BuiltInFunction(b)) => c(a == b),
63			(Self::Format(a), Self::Format(b)) => c(a == b),
64			(Self::Dp, Self::Dp) | (Self::Sf, Self::Sf) | (Self::Unit, Self::Unit) => c(true),
65			(Self::Base(a), Self::Base(b)) => c(a == b),
66			(Self::Fn(a1, a2, a3), Self::Fn(b1, b2, b3)) => c(a1 == b1
67				&& a2.compare(b2, ctx, int)?
68				&& compare_option_arc_scope(a3.as_ref(), b3.as_ref(), ctx, int)?),
69			(Self::Object(a), Self::Object(b)) => {
70				if a.len() != b.len() {
71					return Ok(None);
72				}
73				for ((a1, a2), (b1, b2)) in a.iter().zip(b.iter()) {
74					if a1 != b1 {
75						return Ok(None);
76					}
77					match a2.compare(b2, ctx, int)? {
78						Some(cmp::Ordering::Equal) => (),
79						other => return Ok(other),
80					}
81				}
82				return Ok(Some(cmp::Ordering::Equal));
83			}
84			(Self::String(a), Self::String(b)) => c(a == b),
85			(Self::Bool(a), Self::Bool(b)) => c(a == b),
86			(Self::Month(a), Self::Month(b)) => c(a == b),
87			(Self::DayOfWeek(a), Self::DayOfWeek(b)) => c(a == b),
88			(Self::Date(a), Self::Date(b)) => c(a == b),
89			_ => None,
90		})
91	}
92
93	pub(crate) fn serialize(&self, write: &mut impl io::Write) -> FResult<()> {
94		match self {
95			Self::Num(n) => {
96				0u8.serialize(write)?;
97				n.serialize(write)?;
98			}
99			Self::BuiltInFunction(f) => {
100				1u8.serialize(write)?;
101				f.serialize(write)?;
102			}
103			Self::Format(f) => {
104				2u8.serialize(write)?;
105				f.serialize(write)?;
106			}
107			Self::Dp => 3u8.serialize(write)?,
108			Self::Sf => 4u8.serialize(write)?,
109			Self::Base(b) => {
110				5u8.serialize(write)?;
111				b.serialize(write)?;
112			}
113			Self::Fn(i, e, s) => {
114				6u8.serialize(write)?;
115				i.serialize(write)?;
116				e.serialize(write)?;
117				match s {
118					None => false.serialize(write)?,
119					Some(s) => {
120						true.serialize(write)?;
121						s.serialize(write)?;
122					}
123				}
124			}
125			Self::Object(o) => {
126				7u8.serialize(write)?;
127				o.len().serialize(write)?;
128				for (k, v) in o {
129					k.as_ref().serialize(write)?;
130					v.serialize(write)?;
131				}
132			}
133			Self::String(s) => {
134				8u8.serialize(write)?;
135				s.as_ref().serialize(write)?;
136			}
137			Self::Unit => 9u8.serialize(write)?,
138			Self::Bool(b) => {
139				10u8.serialize(write)?;
140				b.serialize(write)?;
141			}
142			Self::Month(m) => {
143				11u8.serialize(write)?;
144				m.serialize(write)?;
145			}
146			Self::DayOfWeek(d) => {
147				12u8.serialize(write)?;
148				d.serialize(write)?;
149			}
150			Self::Date(d) => {
151				13u8.serialize(write)?;
152				d.serialize(write)?;
153			}
154		}
155		Ok(())
156	}
157
158	pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> {
159		Ok(match u8::deserialize(read)? {
160			0 => Self::Num(Box::new(Number::deserialize(read)?)),
161			1 => Self::BuiltInFunction(BuiltInFunction::deserialize(read)?),
162			2 => Self::Format(FormattingStyle::deserialize(read)?),
163			3 => Self::Dp,
164			4 => Self::Sf,
165			5 => Self::Base(Base::deserialize(read)?),
166			6 => Self::Fn(
167				Ident::deserialize(read)?,
168				Box::new(Expr::deserialize(read)?),
169				if bool::deserialize(read)? {
170					Some(Arc::new(Scope::deserialize(read)?))
171				} else {
172					None
173				},
174			),
175			7 => Self::Object({
176				let len = usize::deserialize(read)?;
177				let mut v = Vec::with_capacity(len);
178				for _ in 0..len {
179					v.push((
180						Cow::Owned(String::deserialize(read)?),
181						Box::new(Self::deserialize(read)?),
182					));
183				}
184				v
185			}),
186			8 => Self::String(Cow::Owned(String::deserialize(read)?)),
187			9 => Self::Unit,
188			10 => Self::Bool(bool::deserialize(read)?),
189			11 => Self::Month(Month::deserialize(read)?),
190			12 => Self::DayOfWeek(DayOfWeek::deserialize(read)?),
191			13 => Self::Date(Date::deserialize(read)?),
192			_ => return Err(FendError::DeserializationError),
193		})
194	}
195
196	pub(crate) fn type_name(&self) -> &'static str {
197		match self {
198			Self::Num(_) => "number",
199			Self::BuiltInFunction(_) | Self::Fn(_, _, _) => "function",
200			Self::Format(_) => "formatting style",
201			Self::Dp => "decimal places",
202			Self::Sf => "significant figures",
203			Self::Base(_) => "base",
204			Self::Object(_) => "object",
205			Self::String(_) => "string",
206			Self::Bool(_) => "bool",
207			Self::Unit => "()",
208			Self::Month(_) => "month",
209			Self::DayOfWeek(_) => "day of week",
210			Self::Date(_) => "date",
211		}
212	}
213
214	fn as_bool(&self) -> FResult<bool> {
215		if let Self::Bool(b) = self {
216			Ok(*b)
217		} else {
218			Err(FendError::ExpectedABool(self.type_name()))
219		}
220	}
221
222	pub(crate) fn expect_num(self) -> FResult<Number> {
223		match self {
224			Self::Num(bigrat) => Ok(*bigrat),
225			_ => Err(FendError::ExpectedANumber),
226		}
227	}
228
229	pub(crate) fn handle_num(
230		self,
231		eval_fn: impl FnOnce(Number) -> FResult<Number>,
232		lazy_fn: impl FnOnce(Box<Expr>) -> Expr,
233		scope: Option<Arc<Scope>>,
234	) -> FResult<Self> {
235		Ok(match self {
236			Self::Num(n) => Self::Num(Box::new(eval_fn(*n)?)),
237			Self::Fn(param, expr, scope) => Self::Fn(param, Box::new(lazy_fn(expr)), scope),
238			Self::BuiltInFunction(f) => f.wrap_with_expr(lazy_fn, scope),
239			_ => return Err(FendError::ExpectedANumber),
240		})
241	}
242
243	pub(crate) fn handle_two_nums<F1: FnOnce(Box<Expr>) -> Expr, F2: FnOnce(Box<Expr>) -> Expr>(
244		self,
245		rhs: Self,
246		eval_fn: impl FnOnce(Number, Number) -> FResult<Number>,
247		lazy_fn_lhs: impl FnOnce(Number) -> F1,
248		lazy_fn_rhs: impl FnOnce(Number) -> F2,
249		scope: Option<Arc<Scope>>,
250	) -> FResult<Self> {
251		Ok(match (self, rhs) {
252			(Self::Num(a), Self::Num(b)) => Self::Num(Box::new(eval_fn(*a, *b)?)),
253			(Self::BuiltInFunction(f), Self::Num(a)) => f.wrap_with_expr(lazy_fn_lhs(*a), scope),
254			(Self::Num(a), Self::BuiltInFunction(f)) => f.wrap_with_expr(lazy_fn_rhs(*a), scope),
255			(Self::Fn(param, expr, scope), Self::Num(a)) => {
256				Self::Fn(param, Box::new(lazy_fn_lhs(*a)(expr)), scope)
257			}
258			(Self::Num(a), Self::Fn(param, expr, scope)) => {
259				Self::Fn(param, Box::new(lazy_fn_rhs(*a)(expr)), scope)
260			}
261			_ => return Err(FendError::ExpectedANumber),
262		})
263	}
264
265	#[allow(clippy::too_many_arguments)]
266	pub(crate) fn apply<I: Interrupt>(
267		self,
268		other: Expr,
269		apply_mul_handling: ApplyMulHandling,
270		scope: Option<Arc<Scope>>,
271		attrs: Attrs,
272		spans: &mut Vec<Span>,
273		context: &mut crate::Context,
274		int: &I,
275	) -> FResult<Self> {
276		Ok(match self {
277			Self::Num(n) => {
278				let other = crate::ast::evaluate(other, scope.clone(), attrs, spans, context, int)?;
279				if matches!(other, Self::Dp) {
280					let num = Self::Num(n)
281						.expect_num()?
282						.try_as_usize(context.decimal_separator, int)?;
283					return Ok(Self::Format(FormattingStyle::DecimalPlaces(num)));
284				}
285				if matches!(other, Self::Sf) {
286					let num = Self::Num(n)
287						.expect_num()?
288						.try_as_usize(context.decimal_separator, int)?;
289					if num == 0 {
290						return Err(FendError::CannotFormatWithZeroSf);
291					}
292					return Ok(Self::Format(FormattingStyle::SignificantFigures(num)));
293				}
294				if apply_mul_handling == ApplyMulHandling::OnlyApply {
295					let self_ = Self::Num(n);
296					return Err(FendError::IsNotAFunction(
297						self_.format_to_plain_string(0, attrs, true, context, int)?,
298					));
299				}
300				let n2 = n.clone();
301				other.handle_num(
302					|x| n.mul(x, int),
303					|x| Expr::Bop(Bop::Mul, Box::new(Expr::Literal(Self::Num(n2))), x),
304					scope,
305				)?
306			}
307			Self::BuiltInFunction(func) => {
308				Self::apply_built_in_function(func, other, scope, attrs, spans, context, int)?
309			}
310			Self::Fn(param, expr, custom_scope) => {
311				let new_scope = Scope::with_variable(param, other, scope, custom_scope);
312				return crate::ast::evaluate(
313					*expr,
314					Some(Arc::new(new_scope)),
315					attrs,
316					spans,
317					context,
318					int,
319				);
320			}
321			_ => {
322				let stringified_self = self.format_to_plain_string(0, attrs, true, context, int)?;
323				return Err(FendError::IsNotAFunctionOrNumber(stringified_self));
324			}
325		})
326	}
327
328	fn apply_built_in_function<I: Interrupt>(
329		func: BuiltInFunction,
330		arg: Expr,
331		scope: Option<Arc<Scope>>,
332		attrs: Attrs,
333		spans: &mut Vec<Span>,
334		context: &mut crate::Context,
335		int: &I,
336	) -> FResult<Self> {
337		let arg = crate::ast::evaluate(arg, scope.clone(), attrs, spans, context, int)?;
338		Ok(Self::Num(Box::new(match func {
339			BuiltInFunction::Approximately => arg.expect_num()?.make_approximate(),
340			BuiltInFunction::Abs => arg.expect_num()?.abs(int)?,
341			BuiltInFunction::Sin => arg.expect_num()?.sin(scope, attrs, context, int)?,
342			BuiltInFunction::Cos => arg.expect_num()?.cos(scope, attrs, context, int)?,
343			BuiltInFunction::Tan => arg.expect_num()?.tan(scope, attrs, context, int)?,
344			BuiltInFunction::Asin => arg.expect_num()?.asin(context, int)?,
345			BuiltInFunction::Acos => arg.expect_num()?.acos(context, int)?,
346			BuiltInFunction::Atan => arg.expect_num()?.atan(context, int)?,
347			BuiltInFunction::Sinh => arg.expect_num()?.sinh(context, int)?,
348			BuiltInFunction::Cosh => arg.expect_num()?.cosh(context, int)?,
349			BuiltInFunction::Tanh => arg.expect_num()?.tanh(context, int)?,
350			BuiltInFunction::Asinh => arg.expect_num()?.asinh(context, int)?,
351			BuiltInFunction::Acosh => arg.expect_num()?.acosh(context, int)?,
352			BuiltInFunction::Atanh => arg.expect_num()?.atanh(context, int)?,
353			BuiltInFunction::Ln => arg.expect_num()?.ln(context, int)?,
354			BuiltInFunction::Log2 => arg.expect_num()?.log2(context, int)?,
355			BuiltInFunction::Log10 => arg.expect_num()?.log10(context, int)?,
356			BuiltInFunction::Base => {
357				let n: u8 = arg
358					.expect_num()?
359					.try_as_usize(context.decimal_separator, int)?
360					.try_into()
361					.map_err(|_| FendError::UnableToConvertToBase)?;
362				return Ok(Self::Base(Base::from_plain_base(n)?));
363			}
364			BuiltInFunction::Sample => arg.expect_num()?.sample(context, int)?,
365			BuiltInFunction::Mean => arg.expect_num()?.mean(int)?,
366			BuiltInFunction::Not => return Ok(Self::Bool(!arg.as_bool()?)),
367			BuiltInFunction::Conjugate => arg.expect_num()?.conjugate()?,
368			BuiltInFunction::Real => arg.expect_num()?.real()?,
369			BuiltInFunction::Imag => arg.expect_num()?.imag()?,
370			BuiltInFunction::Arg => arg.expect_num()?.arg(context.decimal_separator, int)?,
371			BuiltInFunction::Floor => arg.expect_num()?.floor(int)?,
372			BuiltInFunction::Ceil => arg.expect_num()?.ceil(int)?,
373			BuiltInFunction::Round => arg.expect_num()?.round(int)?,
374			BuiltInFunction::Fibonacci => arg
375				.expect_num()?
376				.fibonacci(context.decimal_separator, int)?,
377			BuiltInFunction::Print => {
378				arg.format(0, spans, attrs, false, context, int)?;
379				return Ok(Self::Unit);
380			}
381			BuiltInFunction::Println => {
382				arg.format(0, spans, attrs, false, context, int)?;
383				spans.push(Span {
384					string: "\n".to_string(),
385					kind: SpanKind::Whitespace,
386				});
387				return Ok(Self::Unit);
388			}
389		})))
390	}
391
392	pub(crate) fn format_to_plain_string<I: Interrupt>(
393		&self,
394		indent: usize,
395		attrs: Attrs,
396		explicit_unit_type: bool,
397		ctx: &mut crate::Context,
398		int: &I,
399	) -> FResult<String> {
400		let mut spans = vec![];
401		self.format(indent, &mut spans, attrs, explicit_unit_type, ctx, int)?;
402		let mut res = String::new();
403		for span in spans {
404			res.push_str(&span.string);
405		}
406		Ok(res)
407	}
408
409	pub(crate) fn format<I: Interrupt>(
410		&self,
411		indent: usize,
412		spans: &mut Vec<Span>,
413		attrs: Attrs,
414		explicit_unit_type: bool,
415		ctx: &mut crate::Context,
416		int: &I,
417	) -> FResult<()> {
418		match self {
419			Self::Num(n) => {
420				n.clone()
421					.simplify(attrs, ctx, int)?
422					.format(ctx, int)?
423					.spans(spans, attrs);
424			}
425			Self::BuiltInFunction(name) => {
426				spans.push(Span {
427					string: name.to_string(),
428					kind: SpanKind::BuiltInFunction,
429				});
430			}
431			Self::Format(fmt) => {
432				spans.push(Span {
433					string: fmt.to_string(),
434					kind: SpanKind::Keyword,
435				});
436			}
437			Self::Dp => {
438				spans.push(Span {
439					string: "dp".to_string(),
440					kind: SpanKind::Keyword,
441				});
442			}
443			Self::Sf => {
444				spans.push(Span {
445					string: "sf".to_string(),
446					kind: SpanKind::Keyword,
447				});
448			}
449			Self::Base(b) => {
450				spans.push(Span {
451					string: "base ".to_string(),
452					kind: SpanKind::Keyword,
453				});
454				spans.push(Span {
455					string: b.base_as_u8().to_string(),
456					kind: SpanKind::Number,
457				});
458			}
459			Self::Fn(name, expr, _scope) => {
460				let expr_str = expr.format(attrs, ctx, int)?;
461				let res = if name.as_str().contains('.') {
462					format!("{name}:{expr_str}")
463				} else {
464					format!("\\{name}.{expr_str}")
465				};
466				spans.push(Span {
467					string: res,
468					kind: SpanKind::Other,
469				});
470			}
471			Self::Object(kv) => {
472				spans.push(Span::from_string("{".to_string()));
473				for (i, (k, v)) in kv.iter().enumerate() {
474					if i != 0 {
475						spans.push(Span::from_string(",".to_string()));
476					}
477					spans.push(Span::from_string("\n".to_string()));
478					for _ in 0..(indent + 4) {
479						spans.push(Span::from_string(" ".to_string()));
480					}
481					spans.push(Span::from_string(format!("{k}: ")));
482					v.format(indent + 4, spans, attrs, true, ctx, int)?;
483				}
484				spans.push(Span::from_string("\n}".to_string()));
485			}
486			Self::String(s) => {
487				spans.push(Span {
488					string: s.to_string(),
489					kind: SpanKind::String,
490				});
491			}
492			Self::Unit => {
493				if explicit_unit_type {
494					spans.push(crate::Span {
495						string: "()".to_string(),
496						kind: crate::SpanKind::Ident,
497					});
498				}
499			}
500			Self::Bool(b) => spans.push(crate::Span {
501				string: b.to_string(),
502				kind: crate::SpanKind::Boolean,
503			}),
504			Self::Month(m) => spans.push(crate::Span {
505				string: m.to_string(),
506				kind: crate::SpanKind::Date,
507			}),
508			Self::DayOfWeek(d) => spans.push(crate::Span {
509				string: d.to_string(),
510				kind: crate::SpanKind::Date,
511			}),
512			Self::Date(d) => spans.push(crate::Span {
513				string: d.to_string(),
514				kind: crate::SpanKind::Date,
515			}),
516		}
517		Ok(())
518	}
519
520	pub(crate) fn get_object_member(self, key: &Ident) -> FResult<Self> {
521		match self {
522			Self::Object(kv) => {
523				for (k, v) in kv {
524					if k == key.as_str() {
525						return Ok(*v);
526					}
527				}
528				Err(FendError::CouldNotFindKeyInObject)
529			}
530			Self::Date(d) => d.get_object_member(key),
531			_ => Err(FendError::ExpectedAnObject),
532		}
533	}
534}
535
536impl fmt::Debug for Value {
537	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538		match self {
539			Self::Num(n) => write!(f, "{n:?}"),
540			Self::BuiltInFunction(name) => write!(f, "built-in function: {}", name.as_str()),
541			Self::Format(fmt) => write!(f, "format: {fmt:?}"),
542			Self::Dp => write!(f, "dp"),
543			Self::Sf => write!(f, "sf"),
544			Self::Base(b) => write!(f, "base: {b:?}"),
545			Self::Fn(name, expr, scope) => {
546				write!(f, "fn: {name} => {expr:?} (scope: {scope:?})")
547			}
548			Self::Object(kv) => {
549				let mut s = "{".to_string();
550				for (k, v) in kv {
551					s.push_str(k);
552					s.push(':');
553					write!(s, "{:?}", *v)?;
554					s.push(',');
555				}
556				s.push('}');
557				write!(f, "{s}")
558			}
559			Self::String(s) => write!(f, r#""{}""#, s.as_ref()),
560			Self::Unit => write!(f, "()"),
561			Self::Bool(b) => write!(f, "{b}"),
562			Self::Month(m) => write!(f, "{m}"),
563			Self::DayOfWeek(d) => write!(f, "{d}"),
564			Self::Date(d) => write!(f, "{d:?}"),
565		}
566	}
567}