1use itertools::Itertools;
2use serde::{Deserialize, Serialize};
3use std::fmt::{Display, Formatter};
4use std::hash::Hash;
5use ustr::Ustr;
6
7use super::{
8 Atom, Domain, DomainPtr, Expression, GroundDomain, Metadata, Moo, Range, ReturnType, SetAttr,
9 Typeable, domains::HasDomain, domains::Int, records::RecordValue,
10};
11use crate::ast::domains::MSetAttr;
12use crate::ast::pretty::pretty_vec;
13use crate::bug;
14use polyquine::Quine;
15use uniplate::{Biplate, Tree, Uniplate};
16
17#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate, Hash, Quine)]
18#[uniplate(walk_into=[AbstractLiteral<Literal>])]
19#[biplate(to=Atom)]
20#[biplate(to=AbstractLiteral<Literal>)]
21#[biplate(to=AbstractLiteral<Expression>)]
22#[biplate(to=RecordValue<Literal>)]
23#[biplate(to=RecordValue<Expression>)]
24#[biplate(to=Expression)]
25#[path_prefix(conjure_cp::ast)]
26pub enum Literal {
28 Int(i32),
29 Bool(bool),
30 #[allow(clippy::enum_variant_names)]
32 AbstractLiteral(AbstractLiteral<Literal>),
33}
34
35impl HasDomain for Literal {
36 fn domain_of(&self) -> DomainPtr {
37 match self {
38 Literal::Int(i) => Domain::int(vec![Range::Single(*i)]),
39 Literal::Bool(_) => Domain::bool(),
40 Literal::AbstractLiteral(abstract_literal) => abstract_literal.domain_of(),
41 }
42 }
43}
44
45pub trait AbstractLiteralValue:
47 Clone + Eq + PartialEq + Display + Uniplate + Biplate<RecordValue<Self>> + 'static
48{
49 type Dom: Clone + Eq + PartialEq + Display + Quine + From<GroundDomain> + Into<DomainPtr>;
50}
51impl AbstractLiteralValue for Expression {
52 type Dom = DomainPtr;
53}
54impl AbstractLiteralValue for Literal {
55 type Dom = Moo<GroundDomain>;
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Quine)]
59#[path_prefix(conjure_cp::ast)]
60pub enum AbstractLiteral<T: AbstractLiteralValue> {
61 Set(Vec<T>),
62
63 MSet(Vec<T>),
64
65 Matrix(Vec<T>, T::Dom),
67
68 Tuple(Vec<T>),
70
71 Record(Vec<RecordValue<T>>),
72
73 Function(Vec<(T, T)>),
74}
75
76impl AbstractLiteral<Expression> {
78 pub fn domain_of(&self) -> Option<DomainPtr> {
79 match self {
80 AbstractLiteral::Set(items) => {
81 let item_domains: Vec<DomainPtr> = items
83 .iter()
84 .map(|x| x.domain_of())
85 .collect::<Option<Vec<DomainPtr>>>()?;
86
87 let mut item_domain_iter = item_domains.iter().cloned();
89 let first_item = item_domain_iter.next()?;
90 let item_domain = item_domains
91 .iter()
92 .try_fold(first_item, |x, y| x.union(y))
93 .expect("taking the union of all item domains of a set literal should succeed");
94
95 Some(Domain::set(SetAttr::<Int>::default(), item_domain))
96 }
97
98 AbstractLiteral::MSet(items) => {
99 let item_domains: Vec<DomainPtr> = items
101 .iter()
102 .map(|x| x.domain_of())
103 .collect::<Option<Vec<DomainPtr>>>()?;
104
105 let mut item_domain_iter = item_domains.iter().cloned();
107 let first_item = item_domain_iter.next()?;
108 let item_domain = item_domains
109 .iter()
110 .try_fold(first_item, |x, y| x.union(y))
111 .expect("taking the union of all item domains of a set literal should succeed");
112
113 Some(Domain::mset(MSetAttr::<Int>::default(), item_domain))
114 }
115
116 AbstractLiteral::Matrix(items, _) => {
117 let item_domains = items
119 .iter()
120 .map(|x| x.domain_of())
121 .collect::<Option<Vec<DomainPtr>>>()?;
122
123 let mut item_domain_iter = item_domains.iter().cloned();
125
126 let first_item = item_domain_iter.next()?;
127
128 let item_domain = item_domains
129 .iter()
130 .try_fold(first_item, |x, y| x.union(y))
131 .expect(
132 "taking the union of all item domains of a matrix literal should succeed",
133 );
134
135 let mut new_index_domain = vec![];
136
137 let mut e = Expression::AbstractLiteral(Metadata::new(), self.clone());
139 while let Expression::AbstractLiteral(_, AbstractLiteral::Matrix(elems, idx)) = e {
140 assert!(
141 idx.as_matrix().is_none(),
142 "n-dimensional matrix literals should be represented as a matrix inside a matrix, got {idx}"
143 );
144 new_index_domain.push(idx);
145 e = elems[0].clone();
146 }
147 Some(Domain::matrix(item_domain, new_index_domain))
148 }
149 AbstractLiteral::Tuple(_) => None,
150 AbstractLiteral::Record(_) => None,
151 AbstractLiteral::Function(_) => None,
152 }
153 }
154}
155
156impl HasDomain for AbstractLiteral<Literal> {
157 fn domain_of(&self) -> DomainPtr {
158 Domain::from_literal_vec(&[Literal::AbstractLiteral(self.clone())])
159 .expect("abstract literals should be correctly typed")
160 }
161}
162
163impl Typeable for AbstractLiteral<Expression> {
164 fn return_type(&self) -> ReturnType {
165 match self {
166 AbstractLiteral::Set(items) if items.is_empty() => {
167 ReturnType::Set(Box::new(ReturnType::Unknown))
168 }
169 AbstractLiteral::Set(items) => {
170 let item_type = items[0].return_type();
171
172 let item_types: Vec<ReturnType> = items.iter().map(|x| x.return_type()).collect();
174
175 assert!(
176 item_types.iter().all(|x| x == &item_type),
177 "all items in a set should have the same type"
178 );
179
180 ReturnType::Set(Box::new(item_type))
181 }
182 AbstractLiteral::MSet(items) if items.is_empty() => {
183 ReturnType::MSet(Box::new(ReturnType::Unknown))
184 }
185 AbstractLiteral::MSet(items) => {
186 let item_type = items[0].return_type();
187
188 let item_types: Vec<ReturnType> = items.iter().map(|x| x.return_type()).collect();
190
191 assert!(
192 item_types.iter().all(|x| x == &item_type),
193 "all items in a set should have the same type"
194 );
195
196 ReturnType::MSet(Box::new(item_type))
197 }
198 AbstractLiteral::Matrix(items, _) if items.is_empty() => {
199 ReturnType::Matrix(Box::new(ReturnType::Unknown))
200 }
201 AbstractLiteral::Matrix(items, _) => {
202 let item_type = items[0].return_type();
203
204 let item_types: Vec<ReturnType> = items.iter().map(|x| x.return_type()).collect();
206
207 assert!(
208 item_types.iter().all(|x| x == &item_type),
209 "all items in a matrix should have the same type. items: {items} types: {types:#?}",
210 items = pretty_vec(items),
211 types = items
212 .iter()
213 .map(|x| x.return_type())
214 .collect::<Vec<ReturnType>>()
215 );
216
217 ReturnType::Matrix(Box::new(item_type))
218 }
219 AbstractLiteral::Tuple(items) => {
220 let mut item_types = vec![];
221 for item in items {
222 item_types.push(item.return_type());
223 }
224 ReturnType::Tuple(item_types)
225 }
226 AbstractLiteral::Record(items) => {
227 let mut item_types = vec![];
228 for item in items {
229 item_types.push(item.value.return_type());
230 }
231 ReturnType::Record(item_types)
232 }
233 AbstractLiteral::Function(items) => {
234 if items.is_empty() {
235 return ReturnType::Function(
236 Box::new(ReturnType::Unknown),
237 Box::new(ReturnType::Unknown),
238 );
239 }
240
241 let (x1, y1) = &items[0];
243 let (t1, t2) = (x1.return_type(), y1.return_type());
244 for (x, y) in items {
245 let (tx, ty) = (x.return_type(), y.return_type());
246 if tx != t1 {
247 bug!("Expected {t1}, got {x}: {tx}");
248 }
249 if ty != t2 {
250 bug!("Expected {t2}, got {y}: {ty}");
251 }
252 }
253
254 ReturnType::Function(Box::new(t1), Box::new(t2))
255 }
256 }
257 }
258}
259
260impl<T> AbstractLiteral<T>
261where
262 T: AbstractLiteralValue,
263{
264 pub fn matrix_implied_indices(elems: Vec<T>) -> Self {
268 AbstractLiteral::Matrix(elems, GroundDomain::Int(vec![Range::UnboundedR(1)]).into())
269 }
270
271 pub fn unwrap_list(&self) -> Option<&Vec<T>> {
276 let AbstractLiteral::Matrix(elems, domain) = self else {
277 return None;
278 };
279
280 let domain: DomainPtr = domain.clone().into();
281 let Some(GroundDomain::Int(ranges)) = domain.as_ground() else {
282 return None;
283 };
284
285 let [Range::UnboundedR(1)] = ranges[..] else {
286 return None;
287 };
288
289 Some(elems)
290 }
291}
292
293impl<T> Display for AbstractLiteral<T>
294where
295 T: AbstractLiteralValue,
296{
297 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
298 match self {
299 AbstractLiteral::Set(elems) => {
300 let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
301 write!(f, "{{{elems_str}}}")
302 }
303 AbstractLiteral::MSet(elems) => {
304 let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
305 write!(f, "mset({elems_str})")
306 }
307 AbstractLiteral::Matrix(elems, index_domain) => {
308 let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
309 write!(f, "[{elems_str};{index_domain}]")
310 }
311 AbstractLiteral::Tuple(elems) => {
312 let elems_str: String = elems.iter().map(|x| format!("{x}")).join(",");
313 write!(f, "({elems_str})")
314 }
315 AbstractLiteral::Record(entries) => {
316 let entries_str: String = entries
317 .iter()
318 .map(|entry| format!("{}: {}", entry.name, entry.value))
319 .join(",");
320 write!(f, "{{{entries_str}}}")
321 }
322 AbstractLiteral::Function(entries) => {
323 let entries_str: String = entries
324 .iter()
325 .map(|entry| format!("{} --> {}", entry.0, entry.1))
326 .join(",");
327 write!(f, "function({entries_str})")
328 }
329 }
330 }
331}
332
333impl<T> Uniplate for AbstractLiteral<T>
334where
335 T: AbstractLiteralValue + Biplate<AbstractLiteral<T>>,
336{
337 fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
338 match self {
340 AbstractLiteral::Set(vec) => {
341 let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(vec);
342 (f1_tree, Box::new(move |x| AbstractLiteral::Set(f1_ctx(x))))
343 }
344 AbstractLiteral::MSet(vec) => {
345 let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(vec);
346 (f1_tree, Box::new(move |x| AbstractLiteral::MSet(f1_ctx(x))))
347 }
348 AbstractLiteral::Matrix(elems, index_domain) => {
349 let index_domain = index_domain.clone();
350 let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(elems);
351 (
352 f1_tree,
353 Box::new(move |x| AbstractLiteral::Matrix(f1_ctx(x), index_domain.clone())),
354 )
355 }
356 AbstractLiteral::Tuple(elems) => {
357 let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(elems);
358 (
359 f1_tree,
360 Box::new(move |x| AbstractLiteral::Tuple(f1_ctx(x))),
361 )
362 }
363 AbstractLiteral::Record(entries) => {
364 let (f1_tree, f1_ctx) = <_ as Biplate<AbstractLiteral<T>>>::biplate(entries);
365 (
366 f1_tree,
367 Box::new(move |x| AbstractLiteral::Record(f1_ctx(x))),
368 )
369 }
370 AbstractLiteral::Function(entries) => {
371 let entry_count = entries.len();
372 let flattened: Vec<T> = entries
373 .iter()
374 .flat_map(|(lhs, rhs)| [lhs.clone(), rhs.clone()])
375 .collect();
376
377 let (f1_tree, f1_ctx) =
378 <Vec<T> as Biplate<AbstractLiteral<T>>>::biplate(&flattened);
379 (
380 f1_tree,
381 Box::new(move |x| {
382 let rebuilt = f1_ctx(x);
383 assert_eq!(
384 rebuilt.len(),
385 entry_count * 2,
386 "number of function literal children should remain unchanged"
387 );
388
389 let mut iter = rebuilt.into_iter();
390 let mut pairs = Vec::with_capacity(entry_count);
391 while let (Some(lhs), Some(rhs)) = (iter.next(), iter.next()) {
392 pairs.push((lhs, rhs));
393 }
394
395 AbstractLiteral::Function(pairs)
396 }),
397 )
398 }
399 }
400 }
401}
402
403impl<U, To> Biplate<To> for AbstractLiteral<U>
404where
405 To: Uniplate,
406 U: AbstractLiteralValue + Biplate<AbstractLiteral<U>> + Biplate<To>,
407 RecordValue<U>: Biplate<AbstractLiteral<U>> + Biplate<To>,
408{
409 fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
410 if std::any::TypeId::of::<To>() == std::any::TypeId::of::<AbstractLiteral<U>>() {
411 unsafe {
414 let self_to = std::mem::transmute::<&AbstractLiteral<U>, &To>(self).clone();
416 let tree = Tree::One(self_to);
417 let ctx = Box::new(move |x| {
418 let Tree::One(x) = x else {
419 panic!();
420 };
421
422 std::mem::transmute::<&To, &AbstractLiteral<U>>(&x).clone()
423 });
424
425 (tree, ctx)
426 }
427 } else {
428 match self {
430 AbstractLiteral::Set(vec) => {
431 let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(vec);
432 (f1_tree, Box::new(move |x| AbstractLiteral::Set(f1_ctx(x))))
433 }
434 AbstractLiteral::MSet(vec) => {
435 let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(vec);
436 (f1_tree, Box::new(move |x| AbstractLiteral::MSet(f1_ctx(x))))
437 }
438 AbstractLiteral::Matrix(elems, index_domain) => {
439 let index_domain = index_domain.clone();
440 let (f1_tree, f1_ctx) = <Vec<U> as Biplate<To>>::biplate(elems);
441 (
442 f1_tree,
443 Box::new(move |x| AbstractLiteral::Matrix(f1_ctx(x), index_domain.clone())),
444 )
445 }
446 AbstractLiteral::Tuple(elems) => {
447 let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(elems);
448 (
449 f1_tree,
450 Box::new(move |x| AbstractLiteral::Tuple(f1_ctx(x))),
451 )
452 }
453 AbstractLiteral::Record(entries) => {
454 let (f1_tree, f1_ctx) = <_ as Biplate<To>>::biplate(entries);
455 (
456 f1_tree,
457 Box::new(move |x| AbstractLiteral::Record(f1_ctx(x))),
458 )
459 }
460 AbstractLiteral::Function(entries) => {
461 let entry_count = entries.len();
462 let flattened: Vec<U> = entries
463 .iter()
464 .flat_map(|(lhs, rhs)| [lhs.clone(), rhs.clone()])
465 .collect();
466
467 let (f1_tree, f1_ctx) = <Vec<U> as Biplate<To>>::biplate(&flattened);
468 (
469 f1_tree,
470 Box::new(move |x| {
471 let rebuilt = f1_ctx(x);
472 assert_eq!(
473 rebuilt.len(),
474 entry_count * 2,
475 "number of function literal children should remain unchanged"
476 );
477
478 let mut iter = rebuilt.into_iter();
479 let mut pairs = Vec::with_capacity(entry_count);
480 while let (Some(lhs), Some(rhs)) = (iter.next(), iter.next()) {
481 pairs.push((lhs, rhs));
482 }
483
484 AbstractLiteral::Function(pairs)
485 }),
486 )
487 }
488 }
489 }
490 }
491}
492
493impl TryFrom<Literal> for i32 {
494 type Error = &'static str;
495
496 fn try_from(value: Literal) -> Result<Self, Self::Error> {
497 match value {
498 Literal::Int(i) => Ok(i),
499 _ => Err("Cannot convert non-i32 literal to i32"),
500 }
501 }
502}
503
504impl TryFrom<Box<Literal>> for i32 {
505 type Error = &'static str;
506
507 fn try_from(value: Box<Literal>) -> Result<Self, Self::Error> {
508 (*value).try_into()
509 }
510}
511
512impl TryFrom<&Box<Literal>> for i32 {
513 type Error = &'static str;
514
515 fn try_from(value: &Box<Literal>) -> Result<Self, Self::Error> {
516 TryFrom::<&Literal>::try_from(value.as_ref())
517 }
518}
519
520impl TryFrom<&Moo<Literal>> for i32 {
521 type Error = &'static str;
522
523 fn try_from(value: &Moo<Literal>) -> Result<Self, Self::Error> {
524 TryFrom::<&Literal>::try_from(value.as_ref())
525 }
526}
527
528impl TryFrom<&Literal> for i32 {
529 type Error = &'static str;
530
531 fn try_from(value: &Literal) -> Result<Self, Self::Error> {
532 match value {
533 Literal::Int(i) => Ok(*i),
534 _ => Err("Cannot convert non-i32 literal to i32"),
535 }
536 }
537}
538
539impl TryFrom<Literal> for bool {
540 type Error = &'static str;
541
542 fn try_from(value: Literal) -> Result<Self, Self::Error> {
543 match value {
544 Literal::Bool(b) => Ok(b),
545 _ => Err("Cannot convert non-bool literal to bool"),
546 }
547 }
548}
549
550impl TryFrom<&Literal> for bool {
551 type Error = &'static str;
552
553 fn try_from(value: &Literal) -> Result<Self, Self::Error> {
554 match value {
555 Literal::Bool(b) => Ok(*b),
556 _ => Err("Cannot convert non-bool literal to bool"),
557 }
558 }
559}
560
561impl From<i32> for Literal {
562 fn from(i: i32) -> Self {
563 Literal::Int(i)
564 }
565}
566
567impl From<bool> for Literal {
568 fn from(b: bool) -> Self {
569 Literal::Bool(b)
570 }
571}
572
573impl From<Literal> for Ustr {
574 fn from(value: Literal) -> Self {
575 Ustr::from(&format!("{value}"))
577 }
578}
579
580impl AbstractLiteral<Expression> {
581 pub fn into_literals(self) -> Option<AbstractLiteral<Literal>> {
584 match self {
585 AbstractLiteral::Set(elements) => {
586 let literals = elements
587 .into_iter()
588 .map(|expr| match expr {
589 Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
590 Expression::AbstractLiteral(_, abslit) => {
591 Some(Literal::AbstractLiteral(abslit.into_literals()?))
592 }
593 _ => None,
594 })
595 .collect::<Option<Vec<_>>>()?;
596 Some(AbstractLiteral::Set(literals))
597 }
598 AbstractLiteral::MSet(elements) => {
599 let literals = elements
600 .into_iter()
601 .map(|expr| match expr {
602 Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
603 Expression::AbstractLiteral(_, abslit) => {
604 Some(Literal::AbstractLiteral(abslit.into_literals()?))
605 }
606 _ => None,
607 })
608 .collect::<Option<Vec<_>>>()?;
609 Some(AbstractLiteral::MSet(literals))
610 }
611 AbstractLiteral::Matrix(items, domain) => {
612 let mut literals = vec![];
613 for item in items {
614 let literal = match item {
615 Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
616 Expression::AbstractLiteral(_, abslit) => {
617 Some(Literal::AbstractLiteral(abslit.into_literals()?))
618 }
619 _ => None,
620 }?;
621 literals.push(literal);
622 }
623
624 Some(AbstractLiteral::Matrix(literals, domain.resolve()?))
625 }
626 AbstractLiteral::Tuple(items) => {
627 let mut literals = vec![];
628 for item in items {
629 let literal = match item {
630 Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
631 Expression::AbstractLiteral(_, abslit) => {
632 Some(Literal::AbstractLiteral(abslit.into_literals()?))
633 }
634 _ => None,
635 }?;
636 literals.push(literal);
637 }
638
639 Some(AbstractLiteral::Tuple(literals))
640 }
641 AbstractLiteral::Record(entries) => {
642 let mut literals = vec![];
643 for entry in entries {
644 let literal = match entry.value {
645 Expression::Atomic(_, Atom::Literal(lit)) => Some(lit),
646 Expression::AbstractLiteral(_, abslit) => {
647 Some(Literal::AbstractLiteral(abslit.into_literals()?))
648 }
649 _ => None,
650 }?;
651
652 literals.push((entry.name, literal));
653 }
654 Some(AbstractLiteral::Record(
655 literals
656 .into_iter()
657 .map(|(name, literal)| RecordValue {
658 name,
659 value: literal,
660 })
661 .collect(),
662 ))
663 }
664 AbstractLiteral::Function(_) => todo!("Implement into_literals for functions"),
665 }
666 }
667}
668
669impl Display for Literal {
671 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
672 match &self {
673 Literal::Int(i) => write!(f, "{i}"),
674 Literal::Bool(b) => write!(f, "{b}"),
675 Literal::AbstractLiteral(l) => write!(f, "{l:?}"),
676 }
677 }
678}
679
680#[cfg(test)]
681mod tests {
682
683 use super::*;
684 use crate::{into_matrix, matrix};
685 use uniplate::Uniplate;
686
687 #[test]
688 fn matrix_uniplate_universe() {
689 let my_matrix: AbstractLiteral<Literal> = into_matrix![
691 vec![Literal::AbstractLiteral(matrix![Literal::Bool(true);Moo::new(GroundDomain::Bool)]); 5];
692 Moo::new(GroundDomain::Bool)
693 ];
694
695 let expected_index_domains = vec![Moo::new(GroundDomain::Bool); 6];
696 let actual_index_domains: Vec<Moo<GroundDomain>> =
697 my_matrix.cata(&move |elem, children| {
698 let mut res = vec![];
699 res.extend(children.into_iter().flatten());
700 if let AbstractLiteral::Matrix(_, index_domain) = elem {
701 res.push(index_domain);
702 }
703
704 res
705 });
706
707 assert_eq!(actual_index_domains, expected_index_domains);
708 }
709}