1use crate::ast::*;
18use crate::parser::Loc;
19use std::collections::{BTreeMap, BTreeSet, HashSet};
20use std::str::FromStr;
21use std::sync::Arc;
22
23use educe::Educe;
24use itertools::Itertools;
25use miette::Diagnostic;
26use smol_str::SmolStr;
27use thiserror::Error;
28
29#[derive(Educe, Debug, Clone)]
32#[educe(PartialEq, Eq, PartialOrd, Ord)]
33pub struct Value {
34 pub value: ValueKind,
36 #[educe(PartialEq(ignore))]
38 #[educe(PartialOrd(ignore))]
39 pub loc: Option<Loc>,
40}
41
42#[derive(Debug, Clone, PartialOrd, Ord)]
45pub enum ValueKind {
46 Lit(Literal),
48 Set(Set),
50 Record(Arc<BTreeMap<SmolStr, Value>>),
52 ExtensionValue(Arc<RepresentableExtensionValue>),
54}
55
56impl Value {
57 pub fn empty_set(loc: Option<Loc>) -> Self {
59 Self {
60 value: ValueKind::empty_set(),
61 loc,
62 }
63 }
64
65 pub fn empty_record(loc: Option<Loc>) -> Self {
67 Self {
68 value: ValueKind::empty_record(),
69 loc,
70 }
71 }
72
73 pub fn new(value: impl Into<ValueKind>, loc: Option<Loc>) -> Self {
76 Self {
77 value: value.into(),
78 loc,
79 }
80 }
81
82 pub fn set(vals: impl IntoIterator<Item = Value>, loc: Option<Loc>) -> Self {
84 Self {
85 value: ValueKind::set(vals),
86 loc,
87 }
88 }
89
90 pub fn set_of_lits(lits: impl IntoIterator<Item = Literal>, loc: Option<Loc>) -> Self {
95 Self {
96 value: ValueKind::set_of_lits(lits),
97 loc,
98 }
99 }
100
101 pub fn record<K: Into<SmolStr>, V: Into<Value>>(
103 pairs: impl IntoIterator<Item = (K, V)>,
104 loc: Option<Loc>,
105 ) -> Self {
106 Self {
107 value: ValueKind::record(pairs),
108 loc,
109 }
110 }
111
112 pub fn record_arc(pairs: Arc<BTreeMap<SmolStr, Value>>, loc: Option<Loc>) -> Self {
114 Self {
115 value: ValueKind::record_arc(pairs),
116 loc,
117 }
118 }
119
120 pub fn with_maybe_source_loc(self, loc: Option<Loc>) -> Self {
122 Self { loc, ..self }
123 }
124
125 pub fn value_kind(&self) -> &ValueKind {
127 &self.value
128 }
129
130 pub fn source_loc(&self) -> Option<&Loc> {
132 self.loc.as_ref()
133 }
134
135 pub(crate) fn try_as_lit(&self) -> Option<&Literal> {
137 self.value.try_as_lit()
138 }
139
140 pub fn eq_and_same_source_loc(&self, other: &Self) -> bool {
144 self == other && self.source_loc() == other.source_loc()
145 }
146}
147
148impl BoundedDisplay for Value {
149 fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result {
150 BoundedDisplay::fmt(&self.value, f, n)
151 }
152}
153
154impl ValueKind {
155 pub fn empty_set() -> Self {
157 Self::Set(Set::empty())
158 }
159
160 pub fn empty_record() -> Self {
162 Self::Record(Arc::new(BTreeMap::new()))
163 }
164
165 pub fn set(vals: impl IntoIterator<Item = Value>) -> Self {
167 Self::Set(Set::new(vals))
168 }
169
170 pub fn set_of_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
172 Self::Set(Set::from_lits(lits))
173 }
174
175 pub fn record<K: Into<SmolStr>, V: Into<Value>>(
177 pairs: impl IntoIterator<Item = (K, V)>,
178 ) -> Self {
179 Self::Record(Arc::new(
180 pairs
181 .into_iter()
182 .map(|(k, v)| (k.into(), v.into()))
183 .collect(),
184 ))
185 }
186
187 pub fn record_arc(pairs: Arc<BTreeMap<SmolStr, Value>>) -> Self {
189 Self::Record(pairs)
190 }
191
192 pub(crate) fn try_as_lit(&self) -> Option<&Literal> {
194 match &self {
195 Self::Lit(lit) => Some(lit),
196 _ => None,
197 }
198 }
199}
200
201impl BoundedDisplay for ValueKind {
202 fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result {
203 match self {
204 Self::Lit(lit) => write!(f, "{lit}"),
205 Self::Set(Set {
206 fast,
207 authoritative,
208 }) => {
209 write!(f, "[")?;
210 let truncated = n.map(|n| authoritative.len() > n).unwrap_or(false);
211 if let Some(rc) = fast {
212 let elements = match n {
216 Some(n) => Box::new(rc.as_ref().iter().sorted_unstable().take(n))
217 as Box<dyn Iterator<Item = &Literal>>,
218 None => Box::new(rc.as_ref().iter().sorted_unstable())
219 as Box<dyn Iterator<Item = &Literal>>,
220 };
221 for (i, item) in elements.enumerate() {
222 write!(f, "{item}")?;
223 if i < authoritative.len() - 1 {
224 write!(f, ", ")?;
225 }
226 }
227 } else {
228 let elements = match n {
231 Some(n) => Box::new(authoritative.as_ref().iter().take(n))
232 as Box<dyn Iterator<Item = &Value>>,
233 None => Box::new(authoritative.as_ref().iter())
234 as Box<dyn Iterator<Item = &Value>>,
235 };
236 for (i, item) in elements.enumerate() {
237 BoundedDisplay::fmt(item, f, n)?;
238 if i < authoritative.len() - 1 {
239 write!(f, ", ")?;
240 }
241 }
242 }
243 if truncated {
244 write!(f, ".. ")?;
245 }
246 write!(f, "]")?;
247 Ok(())
248 }
249 Self::Record(record) => {
250 write!(f, "{{")?;
251 let truncated = n.map(|n| record.len() > n).unwrap_or(false);
252 let elements = match n {
255 Some(n) => Box::new(record.as_ref().iter().take(n))
256 as Box<dyn Iterator<Item = (&SmolStr, &Value)>>,
257 None => Box::new(record.as_ref().iter())
258 as Box<dyn Iterator<Item = (&SmolStr, &Value)>>,
259 };
260 for (i, (k, v)) in elements.enumerate() {
261 match UnreservedId::from_str(k) {
262 Ok(k) => {
263 write!(f, "{k}: ")?;
265 }
266 Err(_) => {
267 write!(f, "\"{k}\": ")?;
269 }
270 }
271 BoundedDisplay::fmt(v, f, n)?;
272 if i < record.len() - 1 {
273 write!(f, ", ")?;
274 }
275 }
276 if truncated {
277 write!(f, ".. ")?;
278 }
279 write!(f, "}}")?;
280 Ok(())
281 }
282 Self::ExtensionValue(ev) => write!(f, "{}", RestrictedExpr::from(ev.as_ref().clone())),
283 }
284 }
285}
286
287#[derive(Debug, Error)]
288pub enum NotValue {
290 #[error("not a value")]
292 NotValue {
293 loc: Option<Loc>,
295 },
296}
297
298impl Diagnostic for NotValue {
299 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
300 match self {
301 Self::NotValue { loc } => loc.as_ref().map(|loc| {
302 Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span))) as _
303 }),
304 }
305 }
306
307 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
308 match self {
309 Self::NotValue { loc } => loc.as_ref().map(|loc| &loc.src as &dyn miette::SourceCode),
310 }
311 }
312}
313
314impl TryFrom<Expr> for Value {
315 type Error = NotValue;
316
317 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
318 let loc = expr.source_loc().cloned();
319 Ok(Self {
320 value: ValueKind::try_from(expr)?,
321 loc,
322 })
323 }
324}
325
326impl TryFrom<Expr> for ValueKind {
327 type Error = NotValue;
328
329 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
330 let loc = expr.source_loc().cloned();
331 match expr.into_expr_kind() {
332 ExprKind::Lit(lit) => Ok(Self::Lit(lit)),
333 ExprKind::Unknown(_) => Err(NotValue::NotValue { loc }),
334 ExprKind::Var(_) => Err(NotValue::NotValue { loc }),
335 ExprKind::Slot(_) => Err(NotValue::NotValue { loc }),
336 ExprKind::If { .. } => Err(NotValue::NotValue { loc }),
337 ExprKind::And { .. } => Err(NotValue::NotValue { loc }),
338 ExprKind::Or { .. } => Err(NotValue::NotValue { loc }),
339 ExprKind::UnaryApp { .. } => Err(NotValue::NotValue { loc }),
340 ExprKind::BinaryApp { .. } => Err(NotValue::NotValue { loc }),
341 ExprKind::ExtensionFunctionApp { .. } => Err(NotValue::NotValue { loc }),
342 ExprKind::GetAttr { .. } => Err(NotValue::NotValue { loc }),
343 ExprKind::HasAttr { .. } => Err(NotValue::NotValue { loc }),
344 ExprKind::Like { .. } => Err(NotValue::NotValue { loc }),
345 ExprKind::Is { .. } => Err(NotValue::NotValue { loc }),
346 ExprKind::Set(members) => members
347 .iter()
348 .map(|e| Value::try_from(e.clone()))
349 .collect::<Result<Set, _>>()
350 .map(Self::Set),
351 ExprKind::Record(map) => map
352 .iter()
353 .map(|(k, v)| Value::try_from(v.clone()).map(|v| (k.clone(), v)))
354 .collect::<Result<BTreeMap<SmolStr, Value>, _>>()
355 .map(|m| Self::Record(Arc::new(m))),
356 #[cfg(feature = "tolerant-ast")]
357 ExprKind::Error { .. } => Err(NotValue::NotValue { loc }),
358 }
359 }
360}
361
362#[derive(Debug, Clone)]
364pub struct Set {
365 pub authoritative: Arc<BTreeSet<Value>>,
367 pub fast: Option<Arc<HashSet<Literal>>>,
378}
379
380impl Set {
381 pub fn empty() -> Self {
383 Self {
384 authoritative: Arc::new(BTreeSet::new()),
385 fast: Some(Arc::new(HashSet::new())),
386 }
387 }
388
389 pub fn new(vals: impl IntoIterator<Item = Value>) -> Self {
391 let authoritative: BTreeSet<Value> = vals.into_iter().collect();
392 let fast: Option<Arc<HashSet<Literal>>> = authoritative
393 .iter()
394 .map(|v| v.try_as_lit().cloned())
395 .collect::<Option<HashSet<Literal>>>()
396 .map(Arc::new);
397 Self {
398 authoritative: Arc::new(authoritative),
399 fast,
400 }
401 }
402
403 pub fn from_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
405 let fast: HashSet<Literal> = lits.into_iter().collect();
406 let authoritative: BTreeSet<Value> = fast
407 .iter()
408 .map(|lit| Value {
409 value: ValueKind::Lit(lit.clone()),
410 loc: None,
411 })
412 .collect();
413 Self {
414 authoritative: Arc::new(authoritative),
415 fast: Some(Arc::new(fast)),
416 }
417 }
418
419 pub fn len(&self) -> usize {
421 self.authoritative.len()
422 }
423
424 pub fn is_empty(&self) -> bool {
426 self.len() == 0
427 }
428
429 pub fn iter(&self) -> impl Iterator<Item = &Value> {
431 self.authoritative.iter()
432 }
433}
434
435impl FromIterator<Value> for Set {
436 fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
437 let (literals, non_literals): (BTreeSet<_>, BTreeSet<_>) = iter
438 .into_iter()
439 .partition(|v| matches!(&v.value, ValueKind::Lit { .. }));
440
441 if non_literals.is_empty() {
442 Self::from_iter(literals.into_iter().map(|v| match v {
443 Value {
444 value: ValueKind::Lit(lit),
445 ..
446 } => lit,
447 #[allow(clippy::unreachable)]
449 _ => unreachable!(),
450 }))
451 } else {
452 let mut all_items = non_literals;
456 let mut literals = literals;
457 all_items.append(&mut literals);
458 Self {
459 authoritative: Arc::new(all_items),
460 fast: None,
461 }
462 }
463 }
464}
465
466impl FromIterator<Literal> for Set {
467 fn from_iter<T: IntoIterator<Item = Literal>>(iter: T) -> Self {
468 let fast: HashSet<Literal> = iter.into_iter().collect();
471 Self {
472 authoritative: Arc::new(fast.iter().cloned().map(Into::into).collect()),
473 fast: Some(Arc::new(fast)),
474 }
475 }
476}
477
478impl PartialEq for ValueKind {
481 fn eq(&self, other: &Self) -> bool {
482 match (self, other) {
483 (ValueKind::Lit(lit1), ValueKind::Lit(lit2)) => lit1 == lit2,
484 (ValueKind::Set(set1), ValueKind::Set(set2)) => set1 == set2,
485 (ValueKind::Record(r1), ValueKind::Record(r2)) => r1 == r2,
486 (ValueKind::ExtensionValue(ev1), ValueKind::ExtensionValue(ev2)) => ev1 == ev2,
487 (_, _) => false, }
489 }
490}
491
492impl Eq for ValueKind {}
493
494impl PartialEq for Set {
496 fn eq(&self, other: &Self) -> bool {
497 match (self.fast.as_ref(), other.fast.as_ref()) {
498 (Some(rc1), Some(rc2)) => rc1 == rc2,
499 (Some(_), None) => false, (None, Some(_)) => false, (None, None) => self.authoritative.as_ref() == other.authoritative.as_ref(),
502 }
503 }
504}
505impl Eq for Set {}
506
507impl Ord for Set {
510 fn cmp(&self, other: &Set) -> std::cmp::Ordering {
511 self.authoritative
512 .as_ref()
513 .cmp(other.authoritative.as_ref())
514 }
515}
516
517impl PartialOrd<Set> for Set {
518 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
519 Some(self.cmp(other))
521 }
522}
523
524impl StaticallyTyped for Value {
525 fn type_of(&self) -> Type {
526 self.value.type_of()
527 }
528}
529
530impl StaticallyTyped for ValueKind {
531 fn type_of(&self) -> Type {
532 match self {
533 Self::Lit(lit) => lit.type_of(),
534 Self::Set(_) => Type::Set,
535 Self::Record(_) => Type::Record,
536 Self::ExtensionValue(ev) => ev.type_of(),
537 }
538 }
539}
540
541pub trait BoundedDisplay {
550 fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result;
553
554 fn fmt_bounded(&self, f: &mut impl std::fmt::Write, n: usize) -> std::fmt::Result {
558 self.fmt(f, Some(n))
559 }
560
561 fn fmt_unbounded(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
565 self.fmt(f, None)
566 }
567}
568
569pub trait BoundedToString {
578 fn to_string(&self, n: Option<usize>) -> String;
581
582 fn to_string_bounded(&self, n: usize) -> String {
586 self.to_string(Some(n))
587 }
588
589 fn to_string_unbounded(&self) -> String {
593 self.to_string(None)
594 }
595}
596
597impl<T: BoundedDisplay> BoundedToString for T {
602 fn to_string(&self, n: Option<usize>) -> String {
603 let mut s = String::new();
604 #[allow(clippy::expect_used)]
606 BoundedDisplay::fmt(self, &mut s, n).expect("a `BoundedDisplay` implementation returned an error when writing to a `String`, which shouldn't happen");
607 s
608 }
609}
610
611impl std::fmt::Display for Value {
612 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
613 write!(f, "{}", self.value)
614 }
615}
616
617impl std::fmt::Display for ValueKind {
618 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
619 BoundedDisplay::fmt_unbounded(self, f)
620 }
621}
622
623impl<T: Into<Value>> From<Vec<T>> for Value {
629 fn from(v: Vec<T>) -> Self {
630 Self::set(v.into_iter().map(Into::into), None)
631 }
632}
633
634impl<T: Into<Value>> From<Vec<T>> for ValueKind {
637 fn from(v: Vec<T>) -> Self {
638 Self::set(v.into_iter().map(Into::into))
639 }
640}
641
642impl<T: Into<Literal>> From<T> for Value {
648 fn from(lit: T) -> Self {
649 Self {
650 value: lit.into().into(),
651 loc: None,
652 }
653 }
654}
655
656impl<T: Into<Literal>> From<T> for ValueKind {
659 fn from(lit: T) -> Self {
660 Self::Lit(lit.into())
661 }
662}
663
664#[allow(clippy::panic)]
666#[cfg(test)]
667mod test {
668 use super::*;
669
670 #[test]
671 fn values() {
672 assert_eq!(
673 Value::from(true),
674 Value {
675 value: ValueKind::Lit(Literal::Bool(true)),
676 loc: None,
677 },
678 );
679 assert_eq!(
680 Value::from(false),
681 Value {
682 value: ValueKind::Lit(Literal::Bool(false)),
683 loc: None,
684 },
685 );
686 assert_eq!(
687 Value::from(23),
688 Value {
689 value: ValueKind::Lit(Literal::Long(23)),
690 loc: None,
691 },
692 );
693 assert_eq!(
694 Value::from(-47),
695 Value {
696 value: ValueKind::Lit(Literal::Long(-47)),
697 loc: None,
698 },
699 );
700 assert_eq!(
701 Value::from("hello"),
702 Value {
703 value: ValueKind::Lit(Literal::String("hello".into())),
704 loc: None,
705 },
706 );
707 assert_eq!(
708 Value::from("hello".to_owned()),
709 Value {
710 value: ValueKind::Lit(Literal::String("hello".into())),
711 loc: None,
712 },
713 );
714 assert_eq!(
715 Value::from(String::new()),
716 Value {
717 value: ValueKind::Lit(Literal::String(SmolStr::default())),
718 loc: None,
719 },
720 );
721 assert_eq!(
722 Value::from(""),
723 Value {
724 value: ValueKind::Lit(Literal::String(SmolStr::default())),
725 loc: None,
726 },
727 );
728 assert_eq!(
729 Value::from(vec![2, -3, 40]),
730 Value::set(vec![Value::from(2), Value::from(-3), Value::from(40)], None),
731 );
732 assert_eq!(
733 Value::from(vec![Literal::from(false), Literal::from("eggs")]),
734 Value::set(vec![Value::from(false), Value::from("eggs")], None),
735 );
736 assert_eq!(
737 Value::set(vec![Value::from(false), Value::from("eggs")], None),
738 Value::set_of_lits(vec![Literal::from(false), Literal::from("eggs")], None),
739 );
740
741 let mut rec1: BTreeMap<SmolStr, Value> = BTreeMap::new();
742 rec1.insert("ham".into(), 3.into());
743 rec1.insert("eggs".into(), "hickory".into());
744 assert_eq!(
745 Value::record(rec1.clone(), None),
746 Value {
747 value: ValueKind::Record(Arc::new(rec1)),
748 loc: None,
749 },
750 );
751
752 let mut rec2: BTreeMap<SmolStr, Value> = BTreeMap::new();
753 rec2.insert("hi".into(), "ham".into());
754 rec2.insert("eggs".into(), "hickory".into());
755 assert_eq!(
756 Value::record(vec![("hi", "ham"), ("eggs", "hickory"),], None),
757 Value {
758 value: ValueKind::Record(Arc::new(rec2)),
759 loc: None,
760 },
761 );
762
763 assert_eq!(
764 Value::from(EntityUID::with_eid("foo")),
765 Value {
766 value: ValueKind::Lit(Literal::EntityUID(Arc::new(EntityUID::with_eid("foo")))),
767 loc: None,
768 },
769 );
770 }
771
772 #[test]
773 fn value_types() {
774 assert_eq!(Value::from(false).type_of(), Type::Bool);
775 assert_eq!(Value::from(23).type_of(), Type::Long);
776 assert_eq!(Value::from(-47).type_of(), Type::Long);
777 assert_eq!(Value::from("hello").type_of(), Type::String);
778 assert_eq!(Value::from(vec![2, -3, 40]).type_of(), Type::Set);
779 assert_eq!(Value::empty_set(None).type_of(), Type::Set);
780 assert_eq!(Value::empty_record(None).type_of(), Type::Record);
781 assert_eq!(
782 Value::record(vec![("hello", Value::from("ham"))], None).type_of(),
783 Type::Record
784 );
785 assert_eq!(
786 Value::from(EntityUID::with_eid("foo")).type_of(),
787 Type::entity_type(
788 Name::parse_unqualified_name("test_entity_type").expect("valid identifier")
789 )
790 );
791 }
792
793 #[test]
794 fn test_set_is_empty_for_empty_set() {
795 let set = Set {
796 authoritative: Arc::new(BTreeSet::new()),
797 fast: Some(Arc::new(HashSet::new())),
798 };
799 assert!(set.is_empty());
800 }
801
802 #[test]
803 fn test_set_is_not_empty_for_set_with_values() {
804 let set = Set {
805 authoritative: Arc::new(BTreeSet::from([Value::from("abc")])),
806 fast: None,
807 };
808 assert!(!set.is_empty());
809 }
810
811 #[test]
812 fn pretty_printer() {
813 assert_eq!(ToString::to_string(&Value::from("abc")), r#""abc""#);
814 assert_eq!(ToString::to_string(&Value::from("\t")), r#""\t""#);
815 assert_eq!(ToString::to_string(&Value::from("🐈")), r#""🐈""#);
816 }
817
818 #[test]
819 fn set_collect() {
820 let v = vec![Value {
821 value: 1.into(),
822 loc: None,
823 }];
824 let set: Set = v.into_iter().collect();
825 assert_eq!(set.len(), 1);
826 let v2 = vec![Value {
827 value: ValueKind::Set(set),
828 loc: None,
829 }];
830 let set2: Set = v2.into_iter().collect();
831 assert_eq!(set2.len(), 1);
832 }
833}