1use crate::ast::*;
18use crate::parser::Loc;
19use std::collections::{BTreeMap, BTreeSet, HashSet};
20use std::sync::Arc;
21
22use itertools::Itertools;
23use miette::Diagnostic;
24use serde::{Deserialize, Serialize};
25use smol_str::SmolStr;
26use thiserror::Error;
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(into = "Expr")]
32#[serde(try_from = "Expr")]
33pub struct Value {
34 pub value: ValueKind,
36 pub loc: Option<Loc>,
38}
39
40#[derive(Debug, Clone, PartialOrd, Ord, Serialize, Deserialize)]
43#[serde(into = "Expr")]
44#[serde(try_from = "Expr")]
45pub enum ValueKind {
46 Lit(Literal),
48 Set(Set),
50 Record(Arc<BTreeMap<SmolStr, Value>>),
52 ExtensionValue(Arc<ExtensionValueWithArgs>),
54}
55
56impl Ord for Value {
58 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
59 self.value.cmp(&other.value)
60 }
61}
62
63impl PartialOrd<Value> for Value {
64 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
65 Some(self.cmp(other))
67 }
68}
69
70impl Value {
71 pub fn empty_set(loc: Option<Loc>) -> Self {
73 Self {
74 value: ValueKind::empty_set(),
75 loc,
76 }
77 }
78
79 pub fn empty_record(loc: Option<Loc>) -> Self {
81 Self {
82 value: ValueKind::empty_record(),
83 loc,
84 }
85 }
86
87 pub fn new(value: impl Into<ValueKind>, loc: Option<Loc>) -> Self {
90 Self {
91 value: value.into(),
92 loc,
93 }
94 }
95
96 pub fn set(vals: impl IntoIterator<Item = Value>, loc: Option<Loc>) -> Self {
98 Self {
99 value: ValueKind::set(vals),
100 loc,
101 }
102 }
103
104 pub fn set_of_lits(lits: impl IntoIterator<Item = Literal>, loc: Option<Loc>) -> Self {
109 Self {
110 value: ValueKind::set_of_lits(lits),
111 loc,
112 }
113 }
114
115 pub fn record<K: Into<SmolStr>, V: Into<Value>>(
117 pairs: impl IntoIterator<Item = (K, V)>,
118 loc: Option<Loc>,
119 ) -> Self {
120 Self {
121 value: ValueKind::record(pairs),
122 loc,
123 }
124 }
125
126 pub fn record_arc(pairs: Arc<BTreeMap<SmolStr, Value>>, loc: Option<Loc>) -> Self {
128 Self {
129 value: ValueKind::record_arc(pairs),
130 loc,
131 }
132 }
133
134 pub fn with_maybe_source_loc(self, loc: Option<Loc>) -> Self {
136 Self { loc, ..self }
137 }
138
139 pub fn value_kind(&self) -> &ValueKind {
141 &self.value
142 }
143
144 pub fn source_loc(&self) -> Option<&Loc> {
146 self.loc.as_ref()
147 }
148
149 pub(crate) fn try_as_lit(&self) -> Option<&Literal> {
151 self.value.try_as_lit()
152 }
153
154 pub fn eq_and_same_source_loc(&self, other: &Self) -> bool {
158 self == other && self.source_loc() == other.source_loc()
159 }
160}
161
162impl ValueKind {
163 pub fn empty_set() -> Self {
165 Self::Set(Set::empty())
166 }
167
168 pub fn empty_record() -> Self {
170 Self::Record(Arc::new(BTreeMap::new()))
171 }
172
173 pub fn set(vals: impl IntoIterator<Item = Value>) -> Self {
175 Self::Set(Set::new(vals))
176 }
177
178 pub fn set_of_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
180 Self::Set(Set::from_lits(lits))
181 }
182
183 pub fn record<K: Into<SmolStr>, V: Into<Value>>(
185 pairs: impl IntoIterator<Item = (K, V)>,
186 ) -> Self {
187 Self::Record(Arc::new(
188 pairs
189 .into_iter()
190 .map(|(k, v)| (k.into(), v.into()))
191 .collect(),
192 ))
193 }
194
195 pub fn record_arc(pairs: Arc<BTreeMap<SmolStr, Value>>) -> Self {
197 Self::Record(pairs)
198 }
199
200 pub(crate) fn try_as_lit(&self) -> Option<&Literal> {
202 match &self {
203 Self::Lit(lit) => Some(lit),
204 _ => None,
205 }
206 }
207}
208
209#[derive(Debug, Error)]
210pub enum NotValue {
212 #[error("not a value")]
214 NotValue {
215 loc: Option<Loc>,
217 },
218}
219
220impl Diagnostic for NotValue {
221 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
222 match self {
223 Self::NotValue { loc } => loc.as_ref().map(|loc| {
224 Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span)))
225 as Box<dyn Iterator<Item = _>>
226 }),
227 }
228 }
229
230 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
231 match self {
232 Self::NotValue { loc } => loc.as_ref().map(|loc| &loc.src as &dyn miette::SourceCode),
233 }
234 }
235}
236
237impl TryFrom<Expr> for Value {
238 type Error = NotValue;
239
240 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
241 let loc = expr.source_loc().cloned();
242 Ok(Self {
243 value: ValueKind::try_from(expr)?,
244 loc,
245 })
246 }
247}
248
249impl TryFrom<Expr> for ValueKind {
250 type Error = NotValue;
251
252 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
253 let loc = expr.source_loc().cloned();
254 match expr.into_expr_kind() {
255 ExprKind::Lit(lit) => Ok(Self::Lit(lit)),
256 ExprKind::Unknown(_) => Err(NotValue::NotValue { loc }),
257 ExprKind::Var(_) => Err(NotValue::NotValue { loc }),
258 ExprKind::Slot(_) => Err(NotValue::NotValue { loc }),
259 ExprKind::If { .. } => Err(NotValue::NotValue { loc }),
260 ExprKind::And { .. } => Err(NotValue::NotValue { loc }),
261 ExprKind::Or { .. } => Err(NotValue::NotValue { loc }),
262 ExprKind::UnaryApp { .. } => Err(NotValue::NotValue { loc }),
263 ExprKind::BinaryApp { .. } => Err(NotValue::NotValue { loc }),
264 ExprKind::ExtensionFunctionApp { .. } => Err(NotValue::NotValue { loc }),
265 ExprKind::GetAttr { .. } => Err(NotValue::NotValue { loc }),
266 ExprKind::HasAttr { .. } => Err(NotValue::NotValue { loc }),
267 ExprKind::Like { .. } => Err(NotValue::NotValue { loc }),
268 ExprKind::Is { .. } => Err(NotValue::NotValue { loc }),
269 ExprKind::Set(members) => members
270 .iter()
271 .map(|e| Value::try_from(e.clone()))
272 .collect::<Result<Set, _>>()
273 .map(Self::Set),
274 ExprKind::Record(map) => map
275 .iter()
276 .map(|(k, v)| Value::try_from(v.clone()).map(|v| (k.clone(), v)))
277 .collect::<Result<BTreeMap<SmolStr, Value>, _>>()
278 .map(|m| Self::Record(Arc::new(m))),
279 }
280 }
281}
282
283#[derive(Debug, Clone)]
285pub struct Set {
286 pub authoritative: Arc<BTreeSet<Value>>,
288 pub fast: Option<Arc<HashSet<Literal>>>,
299}
300
301impl Set {
302 pub fn empty() -> Self {
304 Self {
305 authoritative: Arc::new(BTreeSet::new()),
306 fast: Some(Arc::new(HashSet::new())),
307 }
308 }
309
310 pub fn new(vals: impl IntoIterator<Item = Value>) -> Self {
312 let authoritative: BTreeSet<Value> = vals.into_iter().collect();
313 let fast: Option<Arc<HashSet<Literal>>> = authoritative
314 .iter()
315 .map(|v| v.try_as_lit().cloned())
316 .collect::<Option<HashSet<Literal>>>()
317 .map(Arc::new);
318 Self {
319 authoritative: Arc::new(authoritative),
320 fast,
321 }
322 }
323
324 pub fn from_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
326 let fast: HashSet<Literal> = lits.into_iter().collect();
327 let authoritative: BTreeSet<Value> = fast
328 .iter()
329 .map(|lit| Value {
330 value: ValueKind::Lit(lit.clone()),
331 loc: None,
332 })
333 .collect();
334 Self {
335 authoritative: Arc::new(authoritative),
336 fast: Some(Arc::new(fast)),
337 }
338 }
339
340 pub fn len(&self) -> usize {
342 self.authoritative.len()
343 }
344
345 pub fn is_empty(&self) -> bool {
347 self.len() == 0
348 }
349
350 pub fn iter(&self) -> impl Iterator<Item = &Value> {
352 self.authoritative.iter()
353 }
354}
355
356impl FromIterator<Value> for Set {
357 fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
358 let (literals, non_literals): (BTreeSet<_>, BTreeSet<_>) = iter
359 .into_iter()
360 .partition(|v| matches!(&v.value, ValueKind::Lit { .. }));
361
362 if non_literals.is_empty() {
363 Self::from_iter(literals.into_iter().map(|v| match v {
364 Value {
365 value: ValueKind::Lit(lit),
366 ..
367 } => lit,
368 #[allow(clippy::unreachable)]
370 _ => unreachable!(),
371 }))
372 } else {
373 let mut all_items = non_literals;
377 let mut literals = literals;
378 all_items.append(&mut literals);
379 Self {
380 authoritative: Arc::new(all_items),
381 fast: None,
382 }
383 }
384 }
385}
386
387impl FromIterator<Literal> for Set {
388 fn from_iter<T: IntoIterator<Item = Literal>>(iter: T) -> Self {
389 let fast: HashSet<Literal> = iter.into_iter().collect();
392 Self {
393 authoritative: Arc::new(fast.iter().cloned().map(Into::into).collect()),
394 fast: Some(Arc::new(fast)),
395 }
396 }
397}
398
399impl PartialEq for ValueKind {
403 fn eq(&self, other: &Self) -> bool {
404 match (self, other) {
405 (ValueKind::Lit(lit1), ValueKind::Lit(lit2)) => lit1 == lit2,
406 (ValueKind::Set(set1), ValueKind::Set(set2)) => set1 == set2,
407 (ValueKind::Record(r1), ValueKind::Record(r2)) => r1 == r2,
408 (ValueKind::ExtensionValue(ev1), ValueKind::ExtensionValue(ev2)) => ev1 == ev2,
409 (_, _) => false, }
411 }
412}
413
414impl Eq for ValueKind {}
415
416impl PartialEq for Value {
418 fn eq(&self, other: &Value) -> bool {
419 self.value == other.value
420 }
421}
422
423impl Eq for Value {}
424
425impl PartialEq for Set {
427 fn eq(&self, other: &Self) -> bool {
428 match (self.fast.as_ref(), other.fast.as_ref()) {
429 (Some(rc1), Some(rc2)) => rc1 == rc2,
430 (Some(_), None) => false, (None, Some(_)) => false, (None, None) => self.authoritative.as_ref() == other.authoritative.as_ref(),
433 }
434 }
435}
436
437impl Eq for Set {}
438
439impl Ord for Set {
442 fn cmp(&self, other: &Set) -> std::cmp::Ordering {
443 self.authoritative
444 .as_ref()
445 .cmp(other.authoritative.as_ref())
446 }
447}
448
449impl PartialOrd<Set> for Set {
450 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
451 Some(self.cmp(other))
453 }
454}
455
456impl StaticallyTyped for Value {
457 fn type_of(&self) -> Type {
458 self.value.type_of()
459 }
460}
461
462impl StaticallyTyped for ValueKind {
463 fn type_of(&self) -> Type {
464 match self {
465 Self::Lit(lit) => lit.type_of(),
466 Self::Set(_) => Type::Set,
467 Self::Record(_) => Type::Record,
468 Self::ExtensionValue(ev) => ev.type_of(),
469 }
470 }
471}
472
473impl std::fmt::Display for Value {
474 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
475 write!(f, "{}", self.value)
476 }
477}
478
479impl std::fmt::Display for ValueKind {
480 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
481 match self {
482 Self::Lit(lit) => write!(f, "{}", lit),
483 Self::Set(Set {
484 fast,
485 authoritative,
486 }) => {
487 match authoritative.len() {
488 0 => write!(f, "[]"),
489 n @ 1..=5 => {
490 write!(f, "[")?;
491 if let Some(rc) = fast {
492 for (i, item) in rc.as_ref().iter().sorted_unstable().enumerate() {
496 write!(f, "{item}")?;
497 if i < n - 1 {
498 write!(f, ", ")?;
499 }
500 }
501 } else {
502 for (i, item) in authoritative.as_ref().iter().enumerate() {
505 write!(f, "{item}")?;
506 if i < n - 1 {
507 write!(f, ", ")?;
508 }
509 }
510 }
511 write!(f, "]")?;
512 Ok(())
513 }
514 n => write!(f, "<set with {} elements>", n),
515 }
516 }
517 Self::Record(record) => {
518 write!(f, "<first-class record with {} fields>", record.len())
519 }
520 Self::ExtensionValue(ev) => write!(f, "{}", ev),
521 }
522 }
523}
524
525impl<T: Into<Value>> From<Vec<T>> for Value {
531 fn from(v: Vec<T>) -> Self {
532 Self::set(v.into_iter().map(Into::into), None)
533 }
534}
535
536impl<T: Into<Value>> From<Vec<T>> for ValueKind {
539 fn from(v: Vec<T>) -> Self {
540 Self::set(v.into_iter().map(Into::into))
541 }
542}
543
544impl<T: Into<Literal>> From<T> for Value {
550 fn from(lit: T) -> Self {
551 Self {
552 value: lit.into().into(),
553 loc: None,
554 }
555 }
556}
557
558impl<T: Into<Literal>> From<T> for ValueKind {
561 fn from(lit: T) -> Self {
562 Self::Lit(lit.into())
563 }
564}
565
566#[allow(clippy::panic)]
568#[cfg(test)]
569mod test {
570 use super::*;
571
572 #[test]
573 fn values() {
574 assert_eq!(
575 Value::from(true),
576 Value {
577 value: ValueKind::Lit(Literal::Bool(true)),
578 loc: None,
579 },
580 );
581 assert_eq!(
582 Value::from(false),
583 Value {
584 value: ValueKind::Lit(Literal::Bool(false)),
585 loc: None,
586 },
587 );
588 assert_eq!(
589 Value::from(23),
590 Value {
591 value: ValueKind::Lit(Literal::Long(23)),
592 loc: None,
593 },
594 );
595 assert_eq!(
596 Value::from(-47),
597 Value {
598 value: ValueKind::Lit(Literal::Long(-47)),
599 loc: None,
600 },
601 );
602 assert_eq!(
603 Value::from("hello"),
604 Value {
605 value: ValueKind::Lit(Literal::String("hello".into())),
606 loc: None,
607 },
608 );
609 assert_eq!(
610 Value::from("hello".to_owned()),
611 Value {
612 value: ValueKind::Lit(Literal::String("hello".into())),
613 loc: None,
614 },
615 );
616 assert_eq!(
617 Value::from(String::new()),
618 Value {
619 value: ValueKind::Lit(Literal::String(SmolStr::default())),
620 loc: None,
621 },
622 );
623 assert_eq!(
624 Value::from(""),
625 Value {
626 value: ValueKind::Lit(Literal::String(SmolStr::default())),
627 loc: None,
628 },
629 );
630 assert_eq!(
631 Value::from(vec![2, -3, 40]),
632 Value::set(vec![Value::from(2), Value::from(-3), Value::from(40)], None),
633 );
634 assert_eq!(
635 Value::from(vec![Literal::from(false), Literal::from("eggs")]),
636 Value::set(vec![Value::from(false), Value::from("eggs")], None),
637 );
638 assert_eq!(
639 Value::set(vec![Value::from(false), Value::from("eggs")], None),
640 Value::set_of_lits(vec![Literal::from(false), Literal::from("eggs")], None),
641 );
642
643 let mut rec1: BTreeMap<SmolStr, Value> = BTreeMap::new();
644 rec1.insert("ham".into(), 3.into());
645 rec1.insert("eggs".into(), "hickory".into());
646 assert_eq!(
647 Value::record(rec1.clone(), None),
648 Value {
649 value: ValueKind::Record(Arc::new(rec1)),
650 loc: None,
651 },
652 );
653
654 let mut rec2: BTreeMap<SmolStr, Value> = BTreeMap::new();
655 rec2.insert("hi".into(), "ham".into());
656 rec2.insert("eggs".into(), "hickory".into());
657 assert_eq!(
658 Value::record(vec![("hi", "ham"), ("eggs", "hickory"),], None),
659 Value {
660 value: ValueKind::Record(Arc::new(rec2)),
661 loc: None,
662 },
663 );
664
665 assert_eq!(
666 Value::from(EntityUID::with_eid("foo")),
667 Value {
668 value: ValueKind::Lit(Literal::EntityUID(Arc::new(EntityUID::with_eid("foo")))),
669 loc: None,
670 },
671 );
672 }
673
674 #[test]
675 fn value_types() {
676 assert_eq!(Value::from(false).type_of(), Type::Bool);
677 assert_eq!(Value::from(23).type_of(), Type::Long);
678 assert_eq!(Value::from(-47).type_of(), Type::Long);
679 assert_eq!(Value::from("hello").type_of(), Type::String);
680 assert_eq!(Value::from(vec![2, -3, 40]).type_of(), Type::Set);
681 assert_eq!(Value::empty_set(None).type_of(), Type::Set);
682 assert_eq!(Value::empty_record(None).type_of(), Type::Record);
683 assert_eq!(
684 Value::record(vec![("hello", Value::from("ham"))], None).type_of(),
685 Type::Record
686 );
687 assert_eq!(
688 Value::from(EntityUID::with_eid("foo")).type_of(),
689 Type::entity_type(
690 Name::parse_unqualified_name("test_entity_type").expect("valid identifier")
691 )
692 );
693 }
694
695 #[test]
696 fn test_set_is_empty_for_empty_set() {
697 let set = Set {
698 authoritative: Arc::new(BTreeSet::new()),
699 fast: Some(Arc::new(HashSet::new())),
700 };
701 assert!(set.is_empty());
702 }
703
704 #[test]
705 fn test_set_is_not_empty_for_set_with_values() {
706 let set = Set {
707 authoritative: Arc::new(BTreeSet::from([Value::from("abc")])),
708 fast: None,
709 };
710 assert!(!set.is_empty());
711 }
712
713 #[test]
714 fn pretty_printer() {
715 assert_eq!(Value::from("abc").to_string(), r#""abc""#);
716 assert_eq!(Value::from("\t").to_string(), r#""\t""#);
717 assert_eq!(Value::from("🐈").to_string(), r#""🐈""#);
718 }
719
720 #[test]
721 fn set_collect() {
722 let v = vec![Value {
723 value: 1.into(),
724 loc: None,
725 }];
726 let set: Set = v.into_iter().collect();
727 assert_eq!(set.len(), 1);
728 let v2 = vec![Value {
729 value: ValueKind::Set(set),
730 loc: None,
731 }];
732 let set2: Set = v2.into_iter().collect();
733 assert_eq!(set2.len(), 1);
734 }
735}