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 serde::{Deserialize, Serialize};
27use smol_str::SmolStr;
28use thiserror::Error;
29
30#[derive(Educe, Debug, Clone, Serialize, Deserialize)]
33#[educe(PartialEq, Eq, PartialOrd, Ord)]
34#[serde(into = "Expr")]
35#[serde(try_from = "Expr")]
36pub struct Value {
37 pub value: ValueKind,
39 #[educe(PartialEq(ignore))]
41 #[educe(PartialOrd(ignore))]
42 pub loc: Option<Loc>,
43}
44
45#[derive(Debug, Clone, PartialOrd, Ord, Serialize, Deserialize)]
48#[serde(into = "Expr")]
49#[serde(try_from = "Expr")]
50pub enum ValueKind {
51 Lit(Literal),
53 Set(Set),
55 Record(Arc<BTreeMap<SmolStr, Value>>),
57 ExtensionValue(Arc<RepresentableExtensionValue>),
59}
60
61impl Value {
62 pub fn empty_set(loc: Option<Loc>) -> Self {
64 Self {
65 value: ValueKind::empty_set(),
66 loc,
67 }
68 }
69
70 pub fn empty_record(loc: Option<Loc>) -> Self {
72 Self {
73 value: ValueKind::empty_record(),
74 loc,
75 }
76 }
77
78 pub fn new(value: impl Into<ValueKind>, loc: Option<Loc>) -> Self {
81 Self {
82 value: value.into(),
83 loc,
84 }
85 }
86
87 pub fn set(vals: impl IntoIterator<Item = Value>, loc: Option<Loc>) -> Self {
89 Self {
90 value: ValueKind::set(vals),
91 loc,
92 }
93 }
94
95 pub fn set_of_lits(lits: impl IntoIterator<Item = Literal>, loc: Option<Loc>) -> Self {
100 Self {
101 value: ValueKind::set_of_lits(lits),
102 loc,
103 }
104 }
105
106 pub fn record<K: Into<SmolStr>, V: Into<Value>>(
108 pairs: impl IntoIterator<Item = (K, V)>,
109 loc: Option<Loc>,
110 ) -> Self {
111 Self {
112 value: ValueKind::record(pairs),
113 loc,
114 }
115 }
116
117 pub fn record_arc(pairs: Arc<BTreeMap<SmolStr, Value>>, loc: Option<Loc>) -> Self {
119 Self {
120 value: ValueKind::record_arc(pairs),
121 loc,
122 }
123 }
124
125 pub fn with_maybe_source_loc(self, loc: Option<Loc>) -> Self {
127 Self { loc, ..self }
128 }
129
130 pub fn value_kind(&self) -> &ValueKind {
132 &self.value
133 }
134
135 pub fn source_loc(&self) -> Option<&Loc> {
137 self.loc.as_ref()
138 }
139
140 pub(crate) fn try_as_lit(&self) -> Option<&Literal> {
142 self.value.try_as_lit()
143 }
144
145 pub fn eq_and_same_source_loc(&self, other: &Self) -> bool {
149 self == other && self.source_loc() == other.source_loc()
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
206impl BoundedDisplay for ValueKind {
207 fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result {
208 match self {
209 Self::Lit(lit) => write!(f, "{lit}"),
210 Self::Set(Set {
211 fast,
212 authoritative,
213 }) => {
214 write!(f, "[")?;
215 let truncated = n.map(|n| authoritative.len() > n).unwrap_or(false);
216 if let Some(rc) = fast {
217 let elements = match n {
221 Some(n) => Box::new(rc.as_ref().iter().sorted_unstable().take(n))
222 as Box<dyn Iterator<Item = &Literal>>,
223 None => Box::new(rc.as_ref().iter().sorted_unstable())
224 as Box<dyn Iterator<Item = &Literal>>,
225 };
226 for (i, item) in elements.enumerate() {
227 write!(f, "{item}")?;
228 if i < authoritative.len() - 1 {
229 write!(f, ", ")?;
230 }
231 }
232 } else {
233 let elements = match n {
236 Some(n) => Box::new(authoritative.as_ref().iter().take(n))
237 as Box<dyn Iterator<Item = &Value>>,
238 None => Box::new(authoritative.as_ref().iter())
239 as Box<dyn Iterator<Item = &Value>>,
240 };
241 for (i, item) in elements.enumerate() {
242 BoundedDisplay::fmt(item, f, n)?;
243 if i < authoritative.len() - 1 {
244 write!(f, ", ")?;
245 }
246 }
247 }
248 if truncated {
249 write!(f, ".. ")?;
250 }
251 write!(f, "]")?;
252 Ok(())
253 }
254 Self::Record(record) => {
255 write!(f, "{{")?;
256 let truncated = n.map(|n| record.len() > n).unwrap_or(false);
257 let elements = match n {
260 Some(n) => Box::new(record.as_ref().iter().take(n))
261 as Box<dyn Iterator<Item = (&SmolStr, &Value)>>,
262 None => Box::new(record.as_ref().iter())
263 as Box<dyn Iterator<Item = (&SmolStr, &Value)>>,
264 };
265 for (i, (k, v)) in elements.enumerate() {
266 match UnreservedId::from_str(k) {
267 Ok(k) => {
268 write!(f, "{k}: ")?;
270 }
271 Err(_) => {
272 write!(f, "\"{k}\": ")?;
274 }
275 }
276 BoundedDisplay::fmt(v, f, n)?;
277 if i < record.len() - 1 {
278 write!(f, ", ")?;
279 }
280 }
281 if truncated {
282 write!(f, ".. ")?;
283 }
284 write!(f, "}}")?;
285 Ok(())
286 }
287 Self::ExtensionValue(ev) => write!(f, "{}", RestrictedExpr::from(ev.as_ref().clone())),
288 }
289 }
290}
291
292#[derive(Debug, Error)]
293pub enum NotValue {
295 #[error("not a value")]
297 NotValue {
298 loc: Option<Loc>,
300 },
301}
302
303impl Diagnostic for NotValue {
304 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
305 match self {
306 Self::NotValue { loc } => loc.as_ref().map(|loc| {
307 Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span)))
308 as Box<dyn Iterator<Item = _>>
309 }),
310 }
311 }
312
313 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
314 match self {
315 Self::NotValue { loc } => loc.as_ref().map(|loc| &loc.src as &dyn miette::SourceCode),
316 }
317 }
318}
319
320impl TryFrom<Expr> for Value {
321 type Error = NotValue;
322
323 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
324 let loc = expr.source_loc().cloned();
325 Ok(Self {
326 value: ValueKind::try_from(expr)?,
327 loc,
328 })
329 }
330}
331
332impl TryFrom<Expr> for ValueKind {
333 type Error = NotValue;
334
335 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
336 let loc = expr.source_loc().cloned();
337 match expr.into_expr_kind() {
338 ExprKind::Lit(lit) => Ok(Self::Lit(lit)),
339 ExprKind::Unknown(_) => Err(NotValue::NotValue { loc }),
340 ExprKind::Var(_) => Err(NotValue::NotValue { loc }),
341 ExprKind::Slot(_) => Err(NotValue::NotValue { loc }),
342 ExprKind::If { .. } => Err(NotValue::NotValue { loc }),
343 ExprKind::And { .. } => Err(NotValue::NotValue { loc }),
344 ExprKind::Or { .. } => Err(NotValue::NotValue { loc }),
345 ExprKind::UnaryApp { .. } => Err(NotValue::NotValue { loc }),
346 ExprKind::BinaryApp { .. } => Err(NotValue::NotValue { loc }),
347 ExprKind::ExtensionFunctionApp { .. } => Err(NotValue::NotValue { loc }),
348 ExprKind::GetAttr { .. } => Err(NotValue::NotValue { loc }),
349 ExprKind::HasAttr { .. } => Err(NotValue::NotValue { loc }),
350 ExprKind::Like { .. } => Err(NotValue::NotValue { loc }),
351 ExprKind::Is { .. } => Err(NotValue::NotValue { loc }),
352 ExprKind::Set(members) => members
353 .iter()
354 .map(|e| Value::try_from(e.clone()))
355 .collect::<Result<Set, _>>()
356 .map(Self::Set),
357 ExprKind::Record(map) => map
358 .iter()
359 .map(|(k, v)| Value::try_from(v.clone()).map(|v| (k.clone(), v)))
360 .collect::<Result<BTreeMap<SmolStr, Value>, _>>()
361 .map(|m| Self::Record(Arc::new(m))),
362 }
363 }
364}
365
366#[derive(Debug, Clone)]
368pub struct Set {
369 pub authoritative: Arc<BTreeSet<Value>>,
371 pub fast: Option<Arc<HashSet<Literal>>>,
382}
383
384impl Set {
385 pub fn empty() -> Self {
387 Self {
388 authoritative: Arc::new(BTreeSet::new()),
389 fast: Some(Arc::new(HashSet::new())),
390 }
391 }
392
393 pub fn new(vals: impl IntoIterator<Item = Value>) -> Self {
395 let authoritative: BTreeSet<Value> = vals.into_iter().collect();
396 let fast: Option<Arc<HashSet<Literal>>> = authoritative
397 .iter()
398 .map(|v| v.try_as_lit().cloned())
399 .collect::<Option<HashSet<Literal>>>()
400 .map(Arc::new);
401 Self {
402 authoritative: Arc::new(authoritative),
403 fast,
404 }
405 }
406
407 pub fn from_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
409 let fast: HashSet<Literal> = lits.into_iter().collect();
410 let authoritative: BTreeSet<Value> = fast
411 .iter()
412 .map(|lit| Value {
413 value: ValueKind::Lit(lit.clone()),
414 loc: None,
415 })
416 .collect();
417 Self {
418 authoritative: Arc::new(authoritative),
419 fast: Some(Arc::new(fast)),
420 }
421 }
422
423 pub fn len(&self) -> usize {
425 self.authoritative.len()
426 }
427
428 pub fn is_empty(&self) -> bool {
430 self.len() == 0
431 }
432
433 pub fn iter(&self) -> impl Iterator<Item = &Value> {
435 self.authoritative.iter()
436 }
437}
438
439impl FromIterator<Value> for Set {
440 fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
441 let (literals, non_literals): (BTreeSet<_>, BTreeSet<_>) = iter
442 .into_iter()
443 .partition(|v| matches!(&v.value, ValueKind::Lit { .. }));
444
445 if non_literals.is_empty() {
446 Self::from_iter(literals.into_iter().map(|v| match v {
447 Value {
448 value: ValueKind::Lit(lit),
449 ..
450 } => lit,
451 #[allow(clippy::unreachable)]
453 _ => unreachable!(),
454 }))
455 } else {
456 let mut all_items = non_literals;
460 let mut literals = literals;
461 all_items.append(&mut literals);
462 Self {
463 authoritative: Arc::new(all_items),
464 fast: None,
465 }
466 }
467 }
468}
469
470impl FromIterator<Literal> for Set {
471 fn from_iter<T: IntoIterator<Item = Literal>>(iter: T) -> Self {
472 let fast: HashSet<Literal> = iter.into_iter().collect();
475 Self {
476 authoritative: Arc::new(fast.iter().cloned().map(Into::into).collect()),
477 fast: Some(Arc::new(fast)),
478 }
479 }
480}
481
482impl PartialEq for ValueKind {
485 fn eq(&self, other: &Self) -> bool {
486 match (self, other) {
487 (ValueKind::Lit(lit1), ValueKind::Lit(lit2)) => lit1 == lit2,
488 (ValueKind::Set(set1), ValueKind::Set(set2)) => set1 == set2,
489 (ValueKind::Record(r1), ValueKind::Record(r2)) => r1 == r2,
490 (ValueKind::ExtensionValue(ev1), ValueKind::ExtensionValue(ev2)) => ev1 == ev2,
491 (_, _) => false, }
493 }
494}
495
496impl Eq for ValueKind {}
497
498impl PartialEq for Set {
500 fn eq(&self, other: &Self) -> bool {
501 match (self.fast.as_ref(), other.fast.as_ref()) {
502 (Some(rc1), Some(rc2)) => rc1 == rc2,
503 (Some(_), None) => false, (None, Some(_)) => false, (None, None) => self.authoritative.as_ref() == other.authoritative.as_ref(),
506 }
507 }
508}
509impl Eq for Set {}
510
511impl Ord for Set {
514 fn cmp(&self, other: &Set) -> std::cmp::Ordering {
515 self.authoritative
516 .as_ref()
517 .cmp(other.authoritative.as_ref())
518 }
519}
520
521impl PartialOrd<Set> for Set {
522 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
523 Some(self.cmp(other))
525 }
526}
527
528impl StaticallyTyped for Value {
529 fn type_of(&self) -> Type {
530 self.value.type_of()
531 }
532}
533
534impl StaticallyTyped for ValueKind {
535 fn type_of(&self) -> Type {
536 match self {
537 Self::Lit(lit) => lit.type_of(),
538 Self::Set(_) => Type::Set,
539 Self::Record(_) => Type::Record,
540 Self::ExtensionValue(ev) => ev.type_of(),
541 }
542 }
543}
544
545pub trait BoundedDisplay {
554 fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result;
557
558 fn fmt_bounded(&self, f: &mut impl std::fmt::Write, n: usize) -> std::fmt::Result {
562 self.fmt(f, Some(n))
563 }
564
565 fn fmt_unbounded(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
569 self.fmt(f, None)
570 }
571}
572
573pub trait BoundedToString {
582 fn to_string(&self, n: Option<usize>) -> String;
585
586 fn to_string_bounded(&self, n: usize) -> String {
590 self.to_string(Some(n))
591 }
592
593 fn to_string_unbounded(&self) -> String {
597 self.to_string(None)
598 }
599}
600
601impl<T: BoundedDisplay> BoundedToString for T {
606 fn to_string(&self, n: Option<usize>) -> String {
607 let mut s = String::new();
608 #[allow(clippy::expect_used)]
610 BoundedDisplay::fmt(self, &mut s, n).expect("a `BoundedDisplay` implementation returned an error when writing to a `String`, which shouldn't happen");
611 s
612 }
613}
614
615impl std::fmt::Display for Value {
616 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
617 write!(f, "{}", self.value)
618 }
619}
620
621impl std::fmt::Display for ValueKind {
622 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
623 BoundedDisplay::fmt_unbounded(self, f)
624 }
625}
626
627impl<T: Into<Value>> From<Vec<T>> for Value {
633 fn from(v: Vec<T>) -> Self {
634 Self::set(v.into_iter().map(Into::into), None)
635 }
636}
637
638impl<T: Into<Value>> From<Vec<T>> for ValueKind {
641 fn from(v: Vec<T>) -> Self {
642 Self::set(v.into_iter().map(Into::into))
643 }
644}
645
646impl<T: Into<Literal>> From<T> for Value {
652 fn from(lit: T) -> Self {
653 Self {
654 value: lit.into().into(),
655 loc: None,
656 }
657 }
658}
659
660impl<T: Into<Literal>> From<T> for ValueKind {
663 fn from(lit: T) -> Self {
664 Self::Lit(lit.into())
665 }
666}
667
668#[allow(clippy::panic)]
670#[cfg(test)]
671mod test {
672 use super::*;
673
674 #[test]
675 fn values() {
676 assert_eq!(
677 Value::from(true),
678 Value {
679 value: ValueKind::Lit(Literal::Bool(true)),
680 loc: None,
681 },
682 );
683 assert_eq!(
684 Value::from(false),
685 Value {
686 value: ValueKind::Lit(Literal::Bool(false)),
687 loc: None,
688 },
689 );
690 assert_eq!(
691 Value::from(23),
692 Value {
693 value: ValueKind::Lit(Literal::Long(23)),
694 loc: None,
695 },
696 );
697 assert_eq!(
698 Value::from(-47),
699 Value {
700 value: ValueKind::Lit(Literal::Long(-47)),
701 loc: None,
702 },
703 );
704 assert_eq!(
705 Value::from("hello"),
706 Value {
707 value: ValueKind::Lit(Literal::String("hello".into())),
708 loc: None,
709 },
710 );
711 assert_eq!(
712 Value::from("hello".to_owned()),
713 Value {
714 value: ValueKind::Lit(Literal::String("hello".into())),
715 loc: None,
716 },
717 );
718 assert_eq!(
719 Value::from(String::new()),
720 Value {
721 value: ValueKind::Lit(Literal::String(SmolStr::default())),
722 loc: None,
723 },
724 );
725 assert_eq!(
726 Value::from(""),
727 Value {
728 value: ValueKind::Lit(Literal::String(SmolStr::default())),
729 loc: None,
730 },
731 );
732 assert_eq!(
733 Value::from(vec![2, -3, 40]),
734 Value::set(vec![Value::from(2), Value::from(-3), Value::from(40)], None),
735 );
736 assert_eq!(
737 Value::from(vec![Literal::from(false), Literal::from("eggs")]),
738 Value::set(vec![Value::from(false), Value::from("eggs")], None),
739 );
740 assert_eq!(
741 Value::set(vec![Value::from(false), Value::from("eggs")], None),
742 Value::set_of_lits(vec![Literal::from(false), Literal::from("eggs")], None),
743 );
744
745 let mut rec1: BTreeMap<SmolStr, Value> = BTreeMap::new();
746 rec1.insert("ham".into(), 3.into());
747 rec1.insert("eggs".into(), "hickory".into());
748 assert_eq!(
749 Value::record(rec1.clone(), None),
750 Value {
751 value: ValueKind::Record(Arc::new(rec1)),
752 loc: None,
753 },
754 );
755
756 let mut rec2: BTreeMap<SmolStr, Value> = BTreeMap::new();
757 rec2.insert("hi".into(), "ham".into());
758 rec2.insert("eggs".into(), "hickory".into());
759 assert_eq!(
760 Value::record(vec![("hi", "ham"), ("eggs", "hickory"),], None),
761 Value {
762 value: ValueKind::Record(Arc::new(rec2)),
763 loc: None,
764 },
765 );
766
767 assert_eq!(
768 Value::from(EntityUID::with_eid("foo")),
769 Value {
770 value: ValueKind::Lit(Literal::EntityUID(Arc::new(EntityUID::with_eid("foo")))),
771 loc: None,
772 },
773 );
774 }
775
776 #[test]
777 fn value_types() {
778 assert_eq!(Value::from(false).type_of(), Type::Bool);
779 assert_eq!(Value::from(23).type_of(), Type::Long);
780 assert_eq!(Value::from(-47).type_of(), Type::Long);
781 assert_eq!(Value::from("hello").type_of(), Type::String);
782 assert_eq!(Value::from(vec![2, -3, 40]).type_of(), Type::Set);
783 assert_eq!(Value::empty_set(None).type_of(), Type::Set);
784 assert_eq!(Value::empty_record(None).type_of(), Type::Record);
785 assert_eq!(
786 Value::record(vec![("hello", Value::from("ham"))], None).type_of(),
787 Type::Record
788 );
789 assert_eq!(
790 Value::from(EntityUID::with_eid("foo")).type_of(),
791 Type::entity_type(
792 Name::parse_unqualified_name("test_entity_type").expect("valid identifier")
793 )
794 );
795 }
796
797 #[test]
798 fn test_set_is_empty_for_empty_set() {
799 let set = Set {
800 authoritative: Arc::new(BTreeSet::new()),
801 fast: Some(Arc::new(HashSet::new())),
802 };
803 assert!(set.is_empty());
804 }
805
806 #[test]
807 fn test_set_is_not_empty_for_set_with_values() {
808 let set = Set {
809 authoritative: Arc::new(BTreeSet::from([Value::from("abc")])),
810 fast: None,
811 };
812 assert!(!set.is_empty());
813 }
814
815 #[test]
816 fn pretty_printer() {
817 assert_eq!(ToString::to_string(&Value::from("abc")), r#""abc""#);
818 assert_eq!(ToString::to_string(&Value::from("\t")), r#""\t""#);
819 assert_eq!(ToString::to_string(&Value::from("🐈")), r#""🐈""#);
820 }
821
822 #[test]
823 fn set_collect() {
824 let v = vec![Value {
825 value: 1.into(),
826 loc: None,
827 }];
828 let set: Set = v.into_iter().collect();
829 assert_eq!(set.len(), 1);
830 let v2 = vec![Value {
831 value: ValueKind::Set(set),
832 loc: None,
833 }];
834 let set2: Set = v2.into_iter().collect();
835 assert_eq!(set2.len(), 1);
836 }
837}