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 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, 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}