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 pub fn all_literal_uids(&self) -> HashSet<EntityUID> {
149 self.value.all_literal_uids()
150 }
151}
152
153impl BoundedDisplay for Value {
154 fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result {
155 BoundedDisplay::fmt(&self.value, f, n)
156 }
157}
158
159impl ValueKind {
160 pub fn empty_set() -> Self {
162 Self::Set(Set::empty())
163 }
164
165 pub fn empty_record() -> Self {
167 Self::Record(Arc::new(BTreeMap::new()))
168 }
169
170 pub fn set(vals: impl IntoIterator<Item = Value>) -> Self {
172 Self::Set(Set::new(vals))
173 }
174
175 pub fn set_of_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
177 Self::Set(Set::from_lits(lits))
178 }
179
180 pub fn record<K: Into<SmolStr>, V: Into<Value>>(
182 pairs: impl IntoIterator<Item = (K, V)>,
183 ) -> Self {
184 Self::Record(Arc::new(
185 pairs
186 .into_iter()
187 .map(|(k, v)| (k.into(), v.into()))
188 .collect(),
189 ))
190 }
191
192 pub fn record_arc(pairs: Arc<BTreeMap<SmolStr, Value>>) -> Self {
194 Self::Record(pairs)
195 }
196
197 pub(crate) fn try_as_lit(&self) -> Option<&Literal> {
199 match &self {
200 Self::Lit(lit) => Some(lit),
201 _ => None,
202 }
203 }
204
205 pub fn all_literal_uids(&self) -> HashSet<EntityUID> {
207 match self {
208 ValueKind::Lit(Literal::EntityUID(uid)) => HashSet::from([uid.as_ref().clone()]),
209 ValueKind::Lit(_) => HashSet::new(),
210 ValueKind::Set(set) => set.iter().flat_map(Value::all_literal_uids).collect(),
211 ValueKind::Record(record) => {
212 record.values().flat_map(Value::all_literal_uids).collect()
213 }
214 ValueKind::ExtensionValue(_) => HashSet::new(),
215 }
216 }
217}
218
219impl BoundedDisplay for ValueKind {
220 fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result {
221 match self {
222 Self::Lit(lit) => write!(f, "{lit}"),
223 Self::Set(Set {
224 fast,
225 authoritative,
226 }) => {
227 write!(f, "[")?;
228 let truncated = n.map(|n| authoritative.len() > n).unwrap_or(false);
229 if let Some(rc) = fast {
230 let elements = match n {
234 Some(n) => Box::new(rc.as_ref().iter().sorted_unstable().take(n))
235 as Box<dyn Iterator<Item = &Literal>>,
236 None => Box::new(rc.as_ref().iter().sorted_unstable())
237 as Box<dyn Iterator<Item = &Literal>>,
238 };
239 for (i, item) in elements.enumerate() {
240 write!(f, "{item}")?;
241 if i < authoritative.len() - 1 {
242 write!(f, ", ")?;
243 }
244 }
245 } else {
246 let elements = match n {
249 Some(n) => Box::new(authoritative.as_ref().iter().take(n))
250 as Box<dyn Iterator<Item = &Value>>,
251 None => Box::new(authoritative.as_ref().iter())
252 as Box<dyn Iterator<Item = &Value>>,
253 };
254 for (i, item) in elements.enumerate() {
255 BoundedDisplay::fmt(item, f, n)?;
256 if i < authoritative.len() - 1 {
257 write!(f, ", ")?;
258 }
259 }
260 }
261 if truncated {
262 write!(f, ".. ")?;
263 }
264 write!(f, "]")?;
265 Ok(())
266 }
267 Self::Record(record) => {
268 write!(f, "{{")?;
269 let truncated = n.map(|n| record.len() > n).unwrap_or(false);
270 let elements = match n {
273 Some(n) => Box::new(record.as_ref().iter().take(n))
274 as Box<dyn Iterator<Item = (&SmolStr, &Value)>>,
275 None => Box::new(record.as_ref().iter())
276 as Box<dyn Iterator<Item = (&SmolStr, &Value)>>,
277 };
278 for (i, (k, v)) in elements.enumerate() {
279 match UnreservedId::from_str(k) {
280 Ok(k) => {
281 write!(f, "{k}: ")?;
283 }
284 Err(_) => {
285 write!(f, "\"{k}\": ")?;
287 }
288 }
289 BoundedDisplay::fmt(v, f, n)?;
290 if i < record.len() - 1 {
291 write!(f, ", ")?;
292 }
293 }
294 if truncated {
295 write!(f, ".. ")?;
296 }
297 write!(f, "}}")?;
298 Ok(())
299 }
300 Self::ExtensionValue(ev) => write!(f, "{}", RestrictedExpr::from(ev.as_ref().clone())),
301 }
302 }
303}
304
305#[derive(Debug, Error)]
306pub enum NotValue {
308 #[error("not a value")]
310 NotValue {
311 loc: Option<Loc>,
313 },
314}
315
316impl Diagnostic for NotValue {
317 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
318 match self {
319 Self::NotValue { loc } => loc.as_ref().map(|loc| {
320 Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span))) as _
321 }),
322 }
323 }
324
325 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
326 match self {
327 Self::NotValue { loc } => loc.as_ref().map(|loc| &loc.src as &dyn miette::SourceCode),
328 }
329 }
330}
331
332impl TryFrom<Expr> for Value {
333 type Error = NotValue;
334
335 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
336 let loc = expr.source_loc().cloned();
337 Ok(Self {
338 value: ValueKind::try_from(expr)?,
339 loc,
340 })
341 }
342}
343
344impl TryFrom<Expr> for ValueKind {
345 type Error = NotValue;
346
347 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
348 let loc = expr.source_loc().cloned();
349 match expr.into_expr_kind() {
350 ExprKind::Lit(lit) => Ok(Self::Lit(lit)),
351 ExprKind::Unknown(_) => Err(NotValue::NotValue { loc }),
352 ExprKind::Var(_) => Err(NotValue::NotValue { loc }),
353 ExprKind::Slot(_) => Err(NotValue::NotValue { loc }),
354 ExprKind::If { .. } => Err(NotValue::NotValue { loc }),
355 ExprKind::And { .. } => Err(NotValue::NotValue { loc }),
356 ExprKind::Or { .. } => Err(NotValue::NotValue { loc }),
357 ExprKind::UnaryApp { .. } => Err(NotValue::NotValue { loc }),
358 ExprKind::BinaryApp { .. } => Err(NotValue::NotValue { loc }),
359 ExprKind::ExtensionFunctionApp { .. } => Err(NotValue::NotValue { loc }),
360 ExprKind::GetAttr { .. } => Err(NotValue::NotValue { loc }),
361 ExprKind::HasAttr { .. } => Err(NotValue::NotValue { loc }),
362 ExprKind::Like { .. } => Err(NotValue::NotValue { loc }),
363 ExprKind::Is { .. } => Err(NotValue::NotValue { loc }),
364 ExprKind::Set(members) => members
365 .iter()
366 .map(|e| Value::try_from(e.clone()))
367 .collect::<Result<Set, _>>()
368 .map(Self::Set),
369 ExprKind::Record(map) => map
370 .iter()
371 .map(|(k, v)| Value::try_from(v.clone()).map(|v| (k.clone(), v)))
372 .collect::<Result<BTreeMap<SmolStr, Value>, _>>()
373 .map(|m| Self::Record(Arc::new(m))),
374 #[cfg(feature = "tolerant-ast")]
375 ExprKind::Error { .. } => Err(NotValue::NotValue { loc }),
376 }
377 }
378}
379
380#[derive(Debug, Clone)]
382pub struct Set {
383 pub authoritative: Arc<BTreeSet<Value>>,
385 pub fast: Option<Arc<HashSet<Literal>>>,
396}
397
398impl Set {
399 pub fn empty() -> Self {
401 Self {
402 authoritative: Arc::new(BTreeSet::new()),
403 fast: Some(Arc::new(HashSet::new())),
404 }
405 }
406
407 pub fn new(vals: impl IntoIterator<Item = Value>) -> Self {
409 let authoritative: BTreeSet<Value> = vals.into_iter().collect();
410 let fast: Option<Arc<HashSet<Literal>>> = authoritative
411 .iter()
412 .map(|v| v.try_as_lit().cloned())
413 .collect::<Option<HashSet<Literal>>>()
414 .map(Arc::new);
415 Self {
416 authoritative: Arc::new(authoritative),
417 fast,
418 }
419 }
420
421 pub fn from_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
423 let fast: HashSet<Literal> = lits.into_iter().collect();
424 let authoritative: BTreeSet<Value> = fast
425 .iter()
426 .map(|lit| Value {
427 value: ValueKind::Lit(lit.clone()),
428 loc: None,
429 })
430 .collect();
431 Self {
432 authoritative: Arc::new(authoritative),
433 fast: Some(Arc::new(fast)),
434 }
435 }
436
437 pub fn len(&self) -> usize {
439 self.authoritative.len()
440 }
441
442 pub fn is_empty(&self) -> bool {
444 self.len() == 0
445 }
446
447 pub fn iter(&self) -> impl Iterator<Item = &Value> {
449 self.authoritative.iter()
450 }
451
452 pub fn is_subset(&self, other: &Set) -> bool {
454 match (&self.fast, &other.fast) {
455 (Some(ls1), Some(ls2)) => ls1.is_subset(ls2.as_ref()),
458 (None, Some(_)) => false,
462 _ => self.authoritative.is_subset(&other.authoritative),
465 }
466 }
467
468 pub fn is_disjoint(&self, other: &Set) -> bool {
470 match (&self.fast, &other.fast) {
471 (Some(ls1), Some(ls2)) => ls1.is_disjoint(ls2.as_ref()),
474 _ => self.authoritative.is_disjoint(&other.authoritative),
477 }
478 }
479
480 pub fn contains(&self, value: &Value) -> bool {
482 match (&self.fast, &value.value) {
483 (Some(ls), ValueKind::Lit(lit)) => ls.contains(lit),
486 (Some(_), _) => false,
490 _ => self.authoritative.contains(value),
493 }
494 }
495}
496
497impl FromIterator<Value> for Set {
498 fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
499 let (literals, non_literals): (BTreeSet<_>, BTreeSet<_>) = iter
500 .into_iter()
501 .partition(|v| matches!(&v.value, ValueKind::Lit { .. }));
502
503 if non_literals.is_empty() {
504 Self::from_iter(literals.into_iter().map(|v| match v {
505 Value {
506 value: ValueKind::Lit(lit),
507 ..
508 } => lit,
509 #[allow(clippy::unreachable)]
511 _ => unreachable!(),
512 }))
513 } else {
514 let mut all_items = non_literals;
518 let mut literals = literals;
519 all_items.append(&mut literals);
520 Self {
521 authoritative: Arc::new(all_items),
522 fast: None,
523 }
524 }
525 }
526}
527
528impl FromIterator<Literal> for Set {
529 fn from_iter<T: IntoIterator<Item = Literal>>(iter: T) -> Self {
530 let fast: HashSet<Literal> = iter.into_iter().collect();
533 Self {
534 authoritative: Arc::new(fast.iter().cloned().map(Into::into).collect()),
535 fast: Some(Arc::new(fast)),
536 }
537 }
538}
539
540impl PartialEq for ValueKind {
543 fn eq(&self, other: &Self) -> bool {
544 match (self, other) {
545 (ValueKind::Lit(lit1), ValueKind::Lit(lit2)) => lit1 == lit2,
546 (ValueKind::Set(set1), ValueKind::Set(set2)) => set1 == set2,
547 (ValueKind::Record(r1), ValueKind::Record(r2)) => r1 == r2,
548 (ValueKind::ExtensionValue(ev1), ValueKind::ExtensionValue(ev2)) => ev1 == ev2,
549 (_, _) => false, }
551 }
552}
553
554impl Eq for ValueKind {}
555
556impl PartialEq for Set {
558 fn eq(&self, other: &Self) -> bool {
559 match (self.fast.as_ref(), other.fast.as_ref()) {
560 (Some(rc1), Some(rc2)) => rc1 == rc2,
561 (Some(_), None) => false, (None, Some(_)) => false, (None, None) => self.authoritative.as_ref() == other.authoritative.as_ref(),
564 }
565 }
566}
567impl Eq for Set {}
568
569impl Ord for Set {
572 fn cmp(&self, other: &Set) -> std::cmp::Ordering {
573 self.authoritative
574 .as_ref()
575 .cmp(other.authoritative.as_ref())
576 }
577}
578
579impl PartialOrd<Set> for Set {
580 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
581 Some(self.cmp(other))
583 }
584}
585
586impl StaticallyTyped for Value {
587 fn type_of(&self) -> Type {
588 self.value.type_of()
589 }
590}
591
592impl StaticallyTyped for ValueKind {
593 fn type_of(&self) -> Type {
594 match self {
595 Self::Lit(lit) => lit.type_of(),
596 Self::Set(_) => Type::Set,
597 Self::Record(_) => Type::Record,
598 Self::ExtensionValue(ev) => ev.type_of(),
599 }
600 }
601}
602
603pub trait BoundedDisplay {
612 fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result;
615
616 fn fmt_bounded(&self, f: &mut impl std::fmt::Write, n: usize) -> std::fmt::Result {
620 self.fmt(f, Some(n))
621 }
622
623 fn fmt_unbounded(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
627 self.fmt(f, None)
628 }
629}
630
631pub trait BoundedToString {
640 fn to_string(&self, n: Option<usize>) -> String;
643
644 fn to_string_bounded(&self, n: usize) -> String {
648 self.to_string(Some(n))
649 }
650
651 fn to_string_unbounded(&self) -> String {
655 self.to_string(None)
656 }
657}
658
659impl<T: BoundedDisplay> BoundedToString for T {
664 fn to_string(&self, n: Option<usize>) -> String {
665 let mut s = String::new();
666 #[allow(clippy::expect_used)]
668 BoundedDisplay::fmt(self, &mut s, n).expect("a `BoundedDisplay` implementation returned an error when writing to a `String`, which shouldn't happen");
669 s
670 }
671}
672
673impl std::fmt::Display for Value {
674 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
675 write!(f, "{}", self.value)
676 }
677}
678
679impl std::fmt::Display for ValueKind {
680 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
681 BoundedDisplay::fmt_unbounded(self, f)
682 }
683}
684
685impl<T: Into<Value>> From<Vec<T>> for Value {
691 fn from(v: Vec<T>) -> Self {
692 Self::set(v.into_iter().map(Into::into), None)
693 }
694}
695
696impl<T: Into<Value>> From<Vec<T>> for ValueKind {
699 fn from(v: Vec<T>) -> Self {
700 Self::set(v.into_iter().map(Into::into))
701 }
702}
703
704impl<T: Into<Literal>> From<T> for Value {
710 fn from(lit: T) -> Self {
711 Self {
712 value: lit.into().into(),
713 loc: None,
714 }
715 }
716}
717
718impl<T: Into<Literal>> From<T> for ValueKind {
721 fn from(lit: T) -> Self {
722 Self::Lit(lit.into())
723 }
724}
725
726#[allow(clippy::panic)]
728#[cfg(test)]
729mod test {
730 use super::*;
731
732 #[test]
733 fn values() {
734 assert_eq!(
735 Value::from(true),
736 Value {
737 value: ValueKind::Lit(Literal::Bool(true)),
738 loc: None,
739 },
740 );
741 assert_eq!(
742 Value::from(false),
743 Value {
744 value: ValueKind::Lit(Literal::Bool(false)),
745 loc: None,
746 },
747 );
748 assert_eq!(
749 Value::from(23),
750 Value {
751 value: ValueKind::Lit(Literal::Long(23)),
752 loc: None,
753 },
754 );
755 assert_eq!(
756 Value::from(-47),
757 Value {
758 value: ValueKind::Lit(Literal::Long(-47)),
759 loc: None,
760 },
761 );
762 assert_eq!(
763 Value::from("hello"),
764 Value {
765 value: ValueKind::Lit(Literal::String("hello".into())),
766 loc: None,
767 },
768 );
769 assert_eq!(
770 Value::from("hello".to_owned()),
771 Value {
772 value: ValueKind::Lit(Literal::String("hello".into())),
773 loc: None,
774 },
775 );
776 assert_eq!(
777 Value::from(String::new()),
778 Value {
779 value: ValueKind::Lit(Literal::String(SmolStr::default())),
780 loc: None,
781 },
782 );
783 assert_eq!(
784 Value::from(""),
785 Value {
786 value: ValueKind::Lit(Literal::String(SmolStr::default())),
787 loc: None,
788 },
789 );
790 assert_eq!(
791 Value::from(vec![2, -3, 40]),
792 Value::set(vec![Value::from(2), Value::from(-3), Value::from(40)], None),
793 );
794 assert_eq!(
795 Value::from(vec![Literal::from(false), Literal::from("eggs")]),
796 Value::set(vec![Value::from(false), Value::from("eggs")], None),
797 );
798 assert_eq!(
799 Value::set(vec![Value::from(false), Value::from("eggs")], None),
800 Value::set_of_lits(vec![Literal::from(false), Literal::from("eggs")], None),
801 );
802
803 let mut rec1: BTreeMap<SmolStr, Value> = BTreeMap::new();
804 rec1.insert("ham".into(), 3.into());
805 rec1.insert("eggs".into(), "hickory".into());
806 assert_eq!(
807 Value::record(rec1.clone(), None),
808 Value {
809 value: ValueKind::Record(Arc::new(rec1)),
810 loc: None,
811 },
812 );
813
814 let mut rec2: BTreeMap<SmolStr, Value> = BTreeMap::new();
815 rec2.insert("hi".into(), "ham".into());
816 rec2.insert("eggs".into(), "hickory".into());
817 assert_eq!(
818 Value::record(vec![("hi", "ham"), ("eggs", "hickory"),], None),
819 Value {
820 value: ValueKind::Record(Arc::new(rec2)),
821 loc: None,
822 },
823 );
824
825 assert_eq!(
826 Value::from(EntityUID::with_eid("foo")),
827 Value {
828 value: ValueKind::Lit(Literal::EntityUID(Arc::new(EntityUID::with_eid("foo")))),
829 loc: None,
830 },
831 );
832 }
833
834 #[test]
835 fn value_types() {
836 assert_eq!(Value::from(false).type_of(), Type::Bool);
837 assert_eq!(Value::from(23).type_of(), Type::Long);
838 assert_eq!(Value::from(-47).type_of(), Type::Long);
839 assert_eq!(Value::from("hello").type_of(), Type::String);
840 assert_eq!(Value::from(vec![2, -3, 40]).type_of(), Type::Set);
841 assert_eq!(Value::empty_set(None).type_of(), Type::Set);
842 assert_eq!(Value::empty_record(None).type_of(), Type::Record);
843 assert_eq!(
844 Value::record(vec![("hello", Value::from("ham"))], None).type_of(),
845 Type::Record
846 );
847 assert_eq!(
848 Value::from(EntityUID::with_eid("foo")).type_of(),
849 Type::entity_type(
850 Name::parse_unqualified_name("test_entity_type").expect("valid identifier")
851 )
852 );
853 }
854
855 #[test]
856 fn test_set_is_empty_for_empty_set() {
857 let set = Set {
858 authoritative: Arc::new(BTreeSet::new()),
859 fast: Some(Arc::new(HashSet::new())),
860 };
861 assert!(set.is_empty());
862 }
863
864 #[test]
865 fn test_set_is_not_empty_for_set_with_values() {
866 let set = Set {
867 authoritative: Arc::new(BTreeSet::from([Value::from("abc")])),
868 fast: None,
869 };
870 assert!(!set.is_empty());
871 }
872
873 #[test]
874 fn pretty_printer() {
875 assert_eq!(ToString::to_string(&Value::from("abc")), r#""abc""#);
876 assert_eq!(ToString::to_string(&Value::from("\t")), r#""\t""#);
877 assert_eq!(ToString::to_string(&Value::from("🐈")), r#""🐈""#);
878 }
879
880 #[test]
881 fn set_collect() {
882 let v = vec![Value {
883 value: 1.into(),
884 loc: None,
885 }];
886 let set: Set = v.into_iter().collect();
887 assert_eq!(set.len(), 1);
888 let v2 = vec![Value {
889 value: ValueKind::Set(set),
890 loc: None,
891 }];
892 let set2: Set = v2.into_iter().collect();
893 assert_eq!(set2.len(), 1);
894 }
895}