Skip to main content

conjure_cp_core/parse/
parse_model.rs

1#![allow(clippy::unwrap_used)]
2#![allow(clippy::expect_used)]
3use std::sync::{Arc, RwLock};
4use ustr::Ustr;
5
6use serde_json::Map as JsonMap;
7use serde_json::Value;
8use serde_json::Value as JsonValue;
9
10use crate::ast::Moo;
11use crate::ast::PartitionAttr;
12use crate::ast::PermutationAttr;
13use crate::ast::Typeable;
14use crate::ast::ac_operators::ACOperatorKind;
15use crate::ast::comprehension::ComprehensionBuilder;
16use crate::ast::records::Field;
17use crate::ast::{
18    AbstractLiteral, Atom, BinaryAttr, DeclarationPtr, Domain, Expression, FuncAttr, IntVal,
19    JectivityAttr, Literal, MSetAttr, Name, PartialityAttr, Range, RelAttr, ReturnType,
20    SequenceAttr, SetAttr, SymbolTable, SymbolTablePtr,
21};
22use crate::ast::{DomainPtr, Metadata};
23use crate::context::Context;
24use crate::error::{Error, Result};
25use crate::{Model, bug, error, into_matrix_expr, throw_error};
26
27#[allow(unused_macros)]
28macro_rules! parser_trace {
29    ($($arg:tt)+) => {
30        log::trace!(target:"jsonparser",$($arg)+)
31    };
32}
33
34#[allow(unused_macros)]
35macro_rules! parser_debug {
36    ($($arg:tt)+) => {
37        log::debug!(target:"jsonparser",$($arg)+)
38    };
39}
40
41pub fn model_from_json(str: &str, context: Arc<RwLock<Context<'static>>>) -> Result<Model> {
42    let mut m = Model::new(context);
43    let v: JsonValue = serde_json::from_str(str)?;
44    let statements = v["mStatements"]
45        .as_array()
46        .ok_or(error!("mStatements is not an array"))?;
47
48    for statement in statements {
49        let entry = statement
50            .as_object()
51            .ok_or(error!("mStatements contains a non-object"))?
52            .iter()
53            .next()
54            .ok_or(error!("mStatements contains an empty object"))?;
55
56        match entry.0.as_str() {
57            "Declaration" => {
58                let decl = entry
59                    .1
60                    .as_object()
61                    .ok_or(error!("Declaration is not an object".to_owned()))?;
62
63                // One field in the declaration should tell us what kind it is.
64                //
65                // Find it, ignoring the other fields.
66                //
67                // e.g. FindOrGiven,
68
69                let mut valid_decl: bool = false;
70                let scope = m.symbols_ptr_unchecked().clone();
71                let model = &mut m;
72                for (kind, value) in decl {
73                    match kind.as_str() {
74                        "FindOrGiven" => {
75                            parse_variable(value, &mut model.symbols_mut())?;
76                            valid_decl = true;
77                            break;
78                        }
79                        "Letting" => {
80                            parse_letting(value, &scope)?;
81                            valid_decl = true;
82                            break;
83                        }
84                        _ => continue,
85                    }
86                }
87
88                if !valid_decl {
89                    throw_error!("Declaration is not a valid kind")?;
90                }
91            }
92            "SuchThat" => {
93                let constraints_arr = match entry.1.as_array() {
94                    Some(x) => x,
95                    None => bug!("SuchThat is not a vector"),
96                };
97
98                let constraints: Vec<Expression> = constraints_arr
99                    .iter()
100                    .map(|x| parse_expression(x, m.symbols_ptr_unchecked()))
101                    .collect::<Result<Vec<_>>>()?;
102                m.add_constraints(constraints);
103            }
104            otherwise => bug!("Unhandled Statement {:#?}", otherwise),
105        }
106    }
107    Ok(m)
108}
109
110fn parse_variable(v: &JsonValue, symtab: &mut SymbolTable) -> Result<()> {
111    let arr = v.as_array().ok_or(error!("FindOrGiven is not an array"))?;
112
113    let variable_type = arr[0]
114        .as_str()
115        .ok_or(error!("FindOrGiven[0] is not a string"))?;
116
117    let name = arr[1]
118        .as_object()
119        .ok_or(error!("FindOrGiven[1] is not an object"))?["Name"]
120        .as_str()
121        .ok_or(error!("FindOrGiven[1].Name is not a string"))?;
122
123    let name = Name::User(Ustr::from(name));
124
125    let domain = arr[2]
126        .as_object()
127        .ok_or(error!("FindOrGiven[2] is not an object"))?
128        .iter()
129        .next()
130        .ok_or(error!("FindOrGiven[2] is an empty object"))?;
131
132    let domain = parse_domain(domain.0, domain.1, symtab)?;
133
134    let decl = match variable_type {
135        "Find" => DeclarationPtr::new_find(name.clone(), domain),
136        "Given" => DeclarationPtr::new_given(name.clone(), domain),
137        _ => {
138            return Err(error!("FindOrGiven[0] is not 'Find' or 'Given'"));
139        }
140    };
141
142    symtab.insert(decl).ok_or(Error::Parse(format!(
143        "Could not add {name} to symbol table as it already exists"
144    )))
145}
146
147fn parse_letting(v: &JsonValue, scope: &SymbolTablePtr) -> Result<()> {
148    let arr = v.as_array().ok_or(error!("Letting is not an array"))?;
149    let name = arr[0]
150        .as_object()
151        .ok_or(error!("Letting[0] is not an object"))?["Name"]
152        .as_str()
153        .ok_or(error!("Letting[0].Name is not a string"))?;
154    let name = Name::User(Ustr::from(name));
155    // value letting
156    match parse_expression(&arr[1], scope) {
157        Ok(value) => {
158            let mut symtab = scope.write();
159            symtab
160                .insert(DeclarationPtr::new_value_letting(name.clone(), value))
161                .ok_or(Error::Parse(format!(
162                    "Could not add {name} to symbol table as it already exists"
163                )))
164        }
165        Err(expression_error) => {
166            // A letting whose value is not an expression may be a domain letting. Use
167            // `get` here rather than indexing so an unsupported value expression is
168            // reported as a parse error instead of panicking on a missing `Domain` key.
169            let domain = arr[1]
170                .as_object()
171                .and_then(|value| value.get("Domain"))
172                .ok_or(expression_error)?
173                .as_object()
174                .ok_or(error!("Letting[1].Domain is not an object"))?
175                .iter()
176                .next()
177                .ok_or(error!("Letting[1].Domain is an empty object"))?;
178
179            let mut symtab = scope.write();
180            let domain = parse_domain(domain.0, domain.1, &mut symtab)?;
181
182            symtab
183                .insert(DeclarationPtr::new_domain_letting(name.clone(), domain))
184                .ok_or(Error::Parse(format!(
185                    "Could not add {name} to symbol table as it already exists"
186                )))
187        }
188    }
189}
190
191fn parse_domain(
192    domain_name: &str,
193    domain_value: &JsonValue,
194    symbols: &mut SymbolTable,
195) -> Result<DomainPtr> {
196    match domain_name {
197        "DomainInt" => Ok(parse_int_domain(domain_value, symbols)?),
198        "DomainBool" => Ok(Domain::bool()),
199        "DomainReference" => {
200            let name = Name::user(
201                domain_value
202                    .as_array()
203                    .ok_or(error!("DomainReference is not an array"))?[0]
204                    .as_object()
205                    .ok_or(error!("DomainReference[0] is not an object"))?["Name"]
206                    .as_str()
207                    .ok_or(error!("DomainReference[0].Name is not a string"))?,
208            );
209            let ptr = symbols
210                .lookup(&name)
211                .ok_or(error!(format!("Name {name} not found")))?;
212            let dom =
213                Domain::reference(ptr).ok_or(error!("Could not construct reference domain"))?;
214            Ok(dom)
215        }
216        "DomainSet" => {
217            let dom = domain_value.get(2).and_then(|v| v.as_object());
218            let domain_obj = dom.ok_or(error!("DomainSet is missing domain object"))?;
219            let domain = domain_obj
220                .iter()
221                .next()
222                .ok_or(Error::Parse("DomainSet is an empty object".to_owned()))?;
223            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
224            let size = domain_value
225                .get(1)
226                .and_then(|v| v.as_object())
227                .ok_or(error!("Set size attributes is not an object"))?;
228            let size = parse_size_attr(size, symbols)?;
229            let attr: SetAttr<IntVal> = SetAttr::new(size);
230            Ok(Domain::set(attr, domain))
231        }
232        "DomainMSet" => {
233            let dom = domain_value
234                .get(2)
235                .and_then(|v| v.as_object())
236                .expect("domain object exists");
237            let domain = dom
238                .iter()
239                .next()
240                .ok_or(Error::Parse("DomainMSet is an empty object".to_owned()))?;
241            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
242
243            // Parse Attributes
244            let attributes = domain_value
245                .get(1)
246                .and_then(|v| v.as_array())
247                .ok_or(error!("MSet attributes is not a json array"))?;
248
249            let size = attributes
250                .first()
251                .and_then(|v| v.as_object())
252                .ok_or(error!("MSet size attributes is not an object"))?;
253            let size = parse_size_attr(size, symbols)?;
254
255            let occurrence = attributes
256                .get(1)
257                .and_then(|v| v.as_object())
258                .ok_or(error!("MSet occurrence attributes is not an object"))?;
259            let occurrence = parse_occur_attr(occurrence, symbols)?;
260
261            let attr: MSetAttr<IntVal> = MSetAttr {
262                size,
263                occurrence,
264                representation: None,
265            };
266            Ok(Domain::mset(attr, domain))
267        }
268        "DomainPartition" => {
269            let dom = domain_value
270                .get(2)
271                .and_then(|v| v.as_object())
272                .expect("domain object exists");
273            let domain = dom.iter().next().ok_or(Error::Parse(
274                "DomainPartition is an empty object".to_owned(),
275            ))?;
276            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
277
278            let attributes = domain_value
279                .get(1)
280                .and_then(|v| v.as_object())
281                .ok_or(error!("Partition attributes is not an object"))?;
282
283            let mut num_parts = Range::Unbounded;
284            let mut part_len = Range::Unbounded;
285            let mut is_regular = false;
286
287            if let Some(val) = attributes.get("partsNum") {
288                let attr_map = val.as_object().expect("numParts should be an object");
289                num_parts = parse_size_attr(attr_map, symbols)?;
290            }
291            if let Some(val) = attributes.get("partsSize") {
292                let attr_map = val.as_object().expect("partsSize should be an object");
293                part_len = parse_size_attr(attr_map, symbols)?;
294            }
295            if let Some(val) = attributes.get("isRegular").and_then(|v| v.as_bool()) {
296                is_regular = val;
297            }
298
299            let attr: PartitionAttr<IntVal> = PartitionAttr {
300                num_parts,
301                part_len,
302                is_regular,
303            };
304            Ok(Domain::partition(attr, domain))
305        }
306        "DomainPermutation" => {
307            let dom = domain_value
308                .get(2)
309                .and_then(|v| v.as_object())
310                .expect("domain object exists");
311            let domain = dom.iter().next().ok_or(Error::Parse(
312                "DomainPermutation is an empty object".to_owned(),
313            ))?;
314            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
315
316            let attributes = domain_value
317                .get(1)
318                .and_then(|v| v.as_object())
319                .ok_or(error!("Permutation attributes is not an object"))?;
320
321            let mut num_moved = Range::Unbounded;
322            if let Some(val) = attributes.get("numMoved") {
323                let attr_map = val.as_object().expect("numMoved should be an object");
324                num_moved = parse_size_attr(attr_map, symbols)?;
325            }
326
327            let attr: PermutationAttr<IntVal> = PermutationAttr { num_moved };
328            Ok(Domain::permutation(attr, domain))
329        }
330        "DomainMatrix" => {
331            let domain_value = domain_value
332                .as_array()
333                .ok_or(error!("Domain matrix is not an array"))?;
334
335            let indexed_by_domain = domain_value[0].clone();
336            let (index_domain_name, index_domain_value) = indexed_by_domain
337                .as_object()
338                .ok_or(error!("DomainMatrix[0] is not an object"))?
339                .iter()
340                .next()
341                .ok_or(error!(""))?;
342
343            let (value_domain_name, value_domain_value) = domain_value[1]
344                .as_object()
345                .ok_or(error!(""))?
346                .iter()
347                .next()
348                .ok_or(error!(""))?;
349
350            // Conjure stores a 2-d matrix as a matrix of a matrix.
351            //
352            // Therefore, the index is always a Domain.
353
354            let mut index_domains: Vec<DomainPtr> = vec![];
355
356            index_domains.push(parse_domain(
357                index_domain_name,
358                index_domain_value,
359                symbols,
360            )?);
361
362            // We want to store 2-d matrices as a matrix with two index domains, not a matrix in a
363            // matrix.
364            //
365            // Walk through the value domain until it is not a DomainMatrix, adding the index to
366            // our list of indices.
367            let mut value_domain = parse_domain(value_domain_name, value_domain_value, symbols)?;
368            while let Some((new_value_domain, mut indices)) = value_domain.as_matrix() {
369                index_domains.append(&mut indices);
370                value_domain = new_value_domain.clone()
371            }
372
373            Ok(Domain::matrix(value_domain, index_domains))
374        }
375
376        "DomainSequence" => {
377            let dom = domain_value
378                .get(2)
379                .and_then(|v| v.as_object())
380                .expect("domain object exists");
381            let domain = dom
382                .iter()
383                .next()
384                .ok_or(Error::Parse("DomainSequence is an empty object".to_owned()))?;
385            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
386
387            // Parse Attributes
388            let attributes = domain_value
389                .get(1)
390                .and_then(|v| v.as_array())
391                .ok_or(error!("Sequence attributes is not a json array"))?;
392
393            let size = attributes
394                .first()
395                .and_then(|v| v.as_object())
396                .ok_or(error!("Sequence size attributes is not an object"))?;
397            let size = parse_size_attr(size, symbols)?;
398
399            let jectivity = attributes
400                .get(1)
401                .and_then(|v| v.as_str())
402                .ok_or(error!("jectivity is not a string"))?;
403            let jectivity = match jectivity {
404                "JectivityAttr_Injective" => Some(JectivityAttr::Injective),
405                "JectivityAttr_Surjective" => Some(JectivityAttr::Surjective),
406                "JectivityAttr_Bijective" => Some(JectivityAttr::Bijective),
407                "JectivityAttr_None" => Some(JectivityAttr::None),
408                _ => None,
409            };
410            let jectivity =
411                jectivity.ok_or(Error::Parse("Jectivity is an unknown type".to_owned()))?;
412
413            let attr: SequenceAttr<IntVal> = SequenceAttr {
414                size,
415                jectivity,
416                representation: None,
417            };
418            match attr.size {
419                Range::Unbounded | Range::UnboundedR(_) => Err(Error::Parse(
420                    "Sequence must have size or maxSize attribute".to_string(),
421                )),
422                _ => Ok(Domain::sequence(attr, domain)),
423            }
424        }
425
426        "DomainTuple" => {
427            let domain_value = domain_value
428                .as_array()
429                .ok_or(error!("Domain tuple is not an array"))?;
430
431            //iterate through the array and parse each domain
432            let domain = domain_value
433                .iter()
434                .map(|x| {
435                    let domain = x
436                        .as_object()
437                        .ok_or(error!("DomainTuple[0] is not an object"))?
438                        .iter()
439                        .next()
440                        .ok_or(error!("DomainTuple[0] is an empty object"))?;
441                    parse_domain(domain.0, domain.1, symbols)
442                })
443                .collect::<Result<Vec<DomainPtr>>>()?;
444
445            Ok(Domain::tuple(domain))
446        }
447        "DomainRecord" | "DomainVariant" => {
448            // Records and Variants can be parsed the same way for the most part
449            let is_record = domain_name == "DomainRecord";
450            // Get the actual string for error message purposes
451            let domain_string = match is_record {
452                true => "Record",
453                false => "Variant",
454            };
455            let domain_value = domain_value.as_array().ok_or(error!(&format!(
456                "Domain {domain_string} is not a json array"
457            )))?;
458
459            let mut entries = vec![];
460
461            for item in domain_value {
462                //collect the name of the field
463                let name = item[0]
464                    .as_object()
465                    .ok_or(error!("FindOrGiven[1] is not an object"))?["Name"]
466                    .as_str()
467                    .ok_or(error!("FindOrGiven[1].Name is not a string"))?;
468
469                let name = Name::User(Ustr::from(name));
470                // then collect the domain of the field
471                let domain = item[1]
472                    .as_object()
473                    .ok_or(error!("FindOrGiven[2] is not an object"))?
474                    .iter()
475                    .next()
476                    .ok_or(error!("FindOrGiven[2] is an empty object"))?;
477
478                let rec = Field {
479                    name,
480                    value: parse_domain(domain.0, domain.1, symbols)?,
481                };
482
483                entries.push(rec);
484            }
485
486            if is_record {
487                Ok(Domain::record(entries))
488            } else {
489                Ok(Domain::variant(entries))
490            }
491        }
492        "DomainFunction" => {
493            let domain = domain_value
494                .get(2)
495                .and_then(|v| v.as_object())
496                .ok_or(error!("Function domain is not an object"))?;
497            let domain = domain
498                .iter()
499                .next()
500                .ok_or(Error::Parse("DomainSet is an empty object".to_owned()))?;
501            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
502
503            let codomain = domain_value
504                .get(3)
505                .and_then(|v| v.as_object())
506                .ok_or(error!("Function codomain is not an object"))?;
507            let codomain = codomain
508                .iter()
509                .next()
510                .ok_or(Error::Parse("DomainSet is an empty object".to_owned()))?;
511            let codomain = parse_domain(codomain.0.as_str(), codomain.1, symbols)?;
512
513            // Attribute parsing
514            let attributes = domain_value
515                .get(1)
516                .and_then(|v| v.as_array())
517                .ok_or(error!("Function attributes is not a json array"))?;
518            let size = attributes
519                .first()
520                .and_then(|v| v.as_object())
521                .ok_or(error!("Function size attributes is not an object"))?;
522            let size = parse_size_attr(size, symbols)?;
523            let partiality = attributes
524                .get(1)
525                .and_then(|v| v.as_str())
526                .ok_or(error!("Function partiality is not a string"))?;
527            let partiality = match partiality {
528                "PartialityAttr_Partial" => Some(PartialityAttr::Partial),
529                "PartialityAttr_Total" => Some(PartialityAttr::Total),
530                _ => None,
531            };
532            let partiality =
533                partiality.ok_or(Error::Parse("Partiality is an unknown type".to_owned()))?;
534            let jectivity = attributes
535                .get(2)
536                .and_then(|v| v.as_str())
537                .ok_or(error!("Function jectivity is not a string"))?;
538            let jectivity = match jectivity {
539                "JectivityAttr_Injective" => Some(JectivityAttr::Injective),
540                "JectivityAttr_Surjective" => Some(JectivityAttr::Surjective),
541                "JectivityAttr_Bijective" => Some(JectivityAttr::Bijective),
542                "JectivityAttr_None" => Some(JectivityAttr::None),
543                _ => None,
544            };
545            let jectivity =
546                jectivity.ok_or(Error::Parse("Jectivity is an unknown type".to_owned()))?;
547
548            let attr: FuncAttr<IntVal> = FuncAttr {
549                size,
550                partiality,
551                jectivity,
552            };
553
554            Ok(Domain::function(attr, domain, codomain))
555        }
556
557        "DomainRelation" => {
558            let domains = domain_value
559                .get(2)
560                .and_then(|v| v.as_array())
561                .ok_or(Error::Parse(
562                    "Relation domains are not a json array".to_owned(),
563                ))?;
564            let domains = domains
565                .iter()
566                .map(|x| {
567                    let domain = x
568                        .as_object()
569                        .ok_or(Error::Parse("Relation domain is not an object".to_owned()))?
570                        .iter()
571                        .next()
572                        .ok_or(Error::Parse(
573                            "Relation domain is an empty object".to_owned(),
574                        ))?;
575                    parse_domain(domain.0, domain.1, symbols)
576                })
577                .collect::<Result<Vec<DomainPtr>>>()?;
578
579            // Attribute parsing
580            let attributes = domain_value
581                .get(1)
582                .and_then(|v| v.as_array())
583                .ok_or(Error::Parse(
584                    "Relation attributes are not a json array".to_owned(),
585                ))?;
586            let size = attributes
587                .first()
588                .and_then(|v| v.as_object())
589                .ok_or(Error::Parse(
590                    "Relation size attributes are not an object".to_owned(),
591                ))?;
592            let size = parse_size_attr(size, symbols)?;
593            let binary = attributes
594                .get(1)
595                .and_then(|v| v.as_array())
596                .ok_or(Error::Parse(
597                    "Relation binary attributes are not a json array".to_owned(),
598                ))?;
599            let binary = binary
600                .iter()
601                .map(|x| {
602                    let attr = x.as_str().ok_or(Error::Parse(
603                        "Relation binary attribute is not a string".to_owned(),
604                    ))?;
605                    match attr {
606                        "BinRelAttr_Reflexive" => Ok(BinaryAttr::Reflexive),
607                        "BinRelAttr_Irreflexive" => Ok(BinaryAttr::Irreflexive),
608                        "BinRelAttr_Coreflexive" => Ok(BinaryAttr::Coreflexive),
609                        "BinRelAttr_Symmetric" => Ok(BinaryAttr::Symmetric),
610                        "BinRelAttr_AntiSymmetric" => Ok(BinaryAttr::AntiSymmetric),
611                        "BinRelAttr_ASymmetric" => Ok(BinaryAttr::ASymmetric),
612                        "BinRelAttr_Transitive" => Ok(BinaryAttr::Transitive),
613                        "BinRelAttr_Total" => Ok(BinaryAttr::Total),
614                        "BinRelAttr_Connex" => Ok(BinaryAttr::Connex),
615                        "BinRelAttr_Euclidean" => Ok(BinaryAttr::Euclidean),
616                        "BinRelAttr_Serial" => Ok(BinaryAttr::Serial),
617                        "BinRelAttr_Equivalence" => Ok(BinaryAttr::Equivalence),
618                        "BinRelAttr_PartialOrder" => Ok(BinaryAttr::PartialOrder),
619                        "BinRelAttr_LeftTotal" => Ok(BinaryAttr::LeftTotal),
620                        "BinRelAttr_RightTotal" => Ok(BinaryAttr::RightTotal),
621                        "BinRelAttr_LinearOrder" => Ok(BinaryAttr::LinearOrder),
622                        "BinRelAttr_WeakOrder" => Ok(BinaryAttr::WeakOrder),
623                        "BinRelAttr_PreOrder" => Ok(BinaryAttr::PreOrder),
624                        "BinRelAttr_StrictPartialOrder" => Ok(BinaryAttr::StrictPartialOrder),
625                        _ => Err(Error::Parse(
626                            "Relation binary attribute is invalid".to_owned(),
627                        )),
628                    }
629                })
630                .collect::<Result<Vec<BinaryAttr>>>()?;
631
632            let attr: RelAttr<IntVal> = RelAttr { size, binary };
633
634            Ok(Domain::relation(attr, domains))
635        }
636        _ => Err(Error::Parse(
637            "FindOrGiven[2] is an unknown object".to_owned(), // consider covered
638        )),
639    }
640}
641
642fn parse_size_attr(
643    attr_map: &JsonMap<String, JsonValue>,
644    symbols: &mut SymbolTable,
645) -> Result<Range<IntVal>> {
646    let scope = SymbolTablePtr::new();
647    *scope.write() = symbols.clone();
648
649    let attr_obj = attr_map
650        .iter()
651        .next()
652        .ok_or(Error::Parse("SizeAttr is an empty object".to_owned()))?;
653    match attr_obj.0.as_str() {
654        "SizeAttr_None" => Ok(Range::Unbounded),
655        "SizeAttr_MinSize" => {
656            let size = parse_expression_to_int_val(attr_obj.1, &scope)?;
657            Ok(Range::UnboundedR(size))
658        }
659        "SizeAttr_MaxSize" => {
660            let size = parse_expression_to_int_val(attr_obj.1, &scope)?;
661            Ok(Range::UnboundedL(size))
662        }
663        "SizeAttr_MinMaxSize" => {
664            let min_max = attr_obj
665                .1
666                .as_array()
667                .ok_or(error!("SizeAttr MinMaxSize is not a json array"))?;
668            let min = min_max
669                .first()
670                .ok_or(error!("SizeAttr Min is not present"))?;
671            let min_int = parse_expression_to_int_val(min, &scope)?;
672            let max = min_max
673                .get(1)
674                .ok_or(error!("SizeAttr Max is not present"))?;
675            let max_int = parse_expression_to_int_val(max, &scope)?;
676            Ok(Range::Bounded(min_int, max_int))
677        }
678        "SizeAttr_Size" => {
679            let size = parse_expression_to_int_val(attr_obj.1, &scope)?;
680            Ok(Range::Single(size))
681        }
682        _ => Err(Error::Parse("SizeAttr is an unknown type".to_owned())),
683    }
684}
685
686fn parse_occur_attr(
687    attr_map: &JsonMap<String, JsonValue>,
688    symbols: &mut SymbolTable,
689) -> Result<Range<IntVal>> {
690    let scope = SymbolTablePtr::new();
691    *scope.write() = symbols.clone();
692    let attr_obj = attr_map
693        .iter()
694        .next()
695        .ok_or(Error::Parse("OccurAttr is an empty object".to_owned()))?;
696    match attr_obj.0.as_str() {
697        "OccurAttr_None" => Ok(Range::Unbounded),
698        "OccurAttr_MinOccur" => {
699            let size_int = parse_expression_to_int_val(attr_obj.1, &scope)?;
700            Ok(Range::UnboundedR(size_int))
701        }
702        "OccurAttr_MaxOccur" => {
703            let size_int = parse_expression_to_int_val(attr_obj.1, &scope)?;
704            Ok(Range::UnboundedL(size_int))
705        }
706        "OccurAttr_MinMaxOccur" => {
707            let min_max = attr_obj
708                .1
709                .as_array()
710                .ok_or(error!("OccurAttr MinMaxOccur is not a json array"))?;
711            let min = min_max
712                .first()
713                .ok_or(error!("OccurAttr Min is not present"))?;
714            let min_int = parse_expression_to_int_val(min, &scope)?;
715            let max = min_max
716                .get(1)
717                .ok_or(error!("OccurAttr Max is not present"))?;
718            let max_int = parse_expression_to_int_val(max, &scope)?;
719            Ok(Range::Bounded(min_int, max_int))
720        }
721        "OccurAttr_Size" => {
722            let size_int = parse_expression_to_int_val(attr_obj.1, &scope)?;
723            Ok(Range::Single(size_int))
724        }
725        _ => Err(Error::Parse("OccurAttr is an unknown type".to_owned())),
726    }
727}
728
729fn parse_int_domain(v: &JsonValue, symbols: &SymbolTable) -> Result<DomainPtr> {
730    let scope = SymbolTablePtr::new();
731    *scope.write() = symbols.clone();
732
733    let mut ranges = Vec::new();
734    let arr = v
735        .as_array()
736        .ok_or(error!("DomainInt is not an array".to_owned()))?[1]
737        .as_array()
738        .ok_or(error!("DomainInt[1] is not an array".to_owned()))?;
739    if arr.is_empty() {
740        return Ok(Domain::int(vec![Range::Bounded(
741            crate::ast::OXIDE_INT_MIN,
742            crate::ast::OXIDE_INT_MAX,
743        )]));
744    }
745    for range in arr {
746        let range = range
747            .as_object()
748            .ok_or(error!("DomainInt[1] contains a non-object"))?
749            .iter()
750            .next()
751            .ok_or(error!("DomainInt[1] contains an empty object"))?;
752        match range.0.as_str() {
753            "RangeBounded" => {
754                let arr = range
755                    .1
756                    .as_array()
757                    .ok_or(error!("RangeBounded is not an array".to_owned()))?;
758                let mut nums = Vec::new();
759                for item in arr.iter() {
760                    let num = parse_expression_to_int_val(item, &scope)?;
761                    nums.push(num);
762                }
763                let lower = nums
764                    .first()
765                    .cloned()
766                    .ok_or(error!("RangeBounded lower bound missing"))?;
767                let upper = nums
768                    .get(1)
769                    .cloned()
770                    .ok_or(error!("RangeBounded upper bound missing"))?;
771                ranges.push(Range::Bounded(lower, upper));
772            }
773            "RangeSingle" => {
774                let num = parse_expression_to_int_val(range.1, &scope)?;
775                ranges.push(Range::Single(num));
776            }
777            _ => return throw_error!("DomainInt[1] contains an unknown object"),
778        }
779    }
780    Ok(Domain::int(ranges))
781}
782
783fn parse_expression_to_int_val(obj: &JsonValue, scope: &SymbolTablePtr) -> Result<IntVal> {
784    parser_trace!("trying to parse domain value as expression: {}", obj);
785    let expr = parse_expression(obj, scope)?;
786
787    if let Some(Literal::Int(i)) = expr.clone().into_literal() {
788        return Ok(IntVal::Const(i as i64));
789    }
790
791    if let Expression::Atomic(_, Atom::Reference(reference)) = &expr
792        && let Ok(reference_val) = IntVal::new_ref(reference)
793    {
794        return Ok(reference_val);
795    }
796
797    IntVal::new_expr(Moo::new(expr))
798        .map_err(|e| error!(format!("Could not parse integer expression: {e}")))
799}
800
801type BinOp = fn(Metadata, Moo<Expression>, Moo<Expression>) -> Expression;
802type UnaryOp = fn(Metadata, Moo<Expression>) -> Expression;
803
804fn binary_operator(op_name: &str) -> Option<BinOp> {
805    match op_name {
806        "MkOpIn" => Some(Expression::In),
807        "MkOpUnion" => Some(Expression::Union),
808        "MkOpIntersect" => Some(Expression::Intersect),
809        "MkOpSupset" => Some(Expression::Supset),
810        "MkOpSupsetEq" => Some(Expression::SupsetEq),
811        "MkOpSubset" => Some(Expression::Subset),
812        "MkOpSubsetEq" => Some(Expression::SubsetEq),
813        "MkOpEq" => Some(Expression::Eq),
814        "MkOpNeq" => Some(Expression::Neq),
815        "MkOpGeq" => Some(Expression::Geq),
816        "MkOpLeq" => Some(Expression::Leq),
817        "MkOpGt" => Some(Expression::Gt),
818        "MkOpLt" => Some(Expression::Lt),
819        "MkOpLexLt" => Some(Expression::LexLt),
820        "MkOpLexGt" => Some(Expression::LexGt),
821        "MkOpLexLeq" => Some(Expression::LexLeq),
822        "MkOpLexGeq" => Some(Expression::LexGeq),
823        "MkOpDiv" => Some(Expression::UnsafeDiv),
824        "MkOpMod" => Some(Expression::UnsafeMod),
825        "MkOpMinus" => Some(Expression::Minus),
826        "MkOpImply" => Some(Expression::Imply),
827        "MkOpIff" => Some(Expression::Iff),
828        "MkOpPow" => Some(Expression::UnsafePow),
829        "MkOpImage" => Some(Expression::Image),
830        "MkOpImageSet" => Some(Expression::ImageSet),
831        "MkOpPreImage" => Some(Expression::PreImage),
832        "MkOpInverse" => Some(Expression::Inverse),
833        "MkOpCompose" => Some(Expression::Compose),
834        "MkOpRestrict" => Some(Expression::Restrict),
835        "MkOpApart" => Some(Expression::Apart),
836        "MkOpTogether" => Some(Expression::Together),
837        "MkOpParty" => Some(Expression::Party),
838        "MkOpSubstring" => Some(Expression::Substring),
839        "MkOpSubsequence" => Some(Expression::Subsequence),
840        _ => None,
841    }
842}
843
844fn unary_operator(op_name: &str, inner: Option<&Expression>) -> Option<UnaryOp> {
845    match op_name {
846        "MkOpNot" => Some(Expression::Not),
847        "MkOpNegate" => Some(Expression::Neg),
848        "MkOpTwoBars" => {
849            if let Some(inner) = inner {
850                match inner.return_type() {
851                    ReturnType::Int => Some(Expression::Abs),
852                    ReturnType::Matrix(_)
853                    | ReturnType::Set(_)
854                    | ReturnType::MSet(_)
855                    | ReturnType::Function(_, _)
856                    | ReturnType::Relation(_) => Some(Expression::Card),
857                    _ => None,
858                }
859            } else {
860                // Internal expression cannot be known yet, so we just have to assume
861                Some(Expression::Abs)
862            }
863        }
864        "MkOpAnd" => Some(Expression::And),
865        "MkOpSum" => Some(Expression::Sum),
866        "MkOpProduct" => Some(Expression::Product),
867        "MkOpOr" => Some(Expression::Or),
868        "MkOpMin" => Some(Expression::Min),
869        "MkOpMax" => Some(Expression::Max),
870        "MkOpAllDiff" => Some(Expression::AllDiff),
871        "MkOpToInt" => Some(Expression::ToInt),
872        "MkOpDefined" => Some(Expression::Defined),
873        "MkOpPermInverse" => Some(Expression::PermInverse),
874        "MkOpRange" => Some(Expression::Range),
875        "MkOpFactorial" => Some(Expression::Factorial),
876        "MkOpToMSet" => Some(Expression::ToMSet),
877        "MkOpToRelation" => Some(Expression::ToRelation),
878        "MkOpParticipants" => Some(Expression::Participants),
879        "MkOpParts" => Some(Expression::Parts),
880        _ => None,
881    }
882}
883
884fn parse_reference_name(obj: &JsonValue) -> Result<Name> {
885    // { Name: "x" } directly
886    if let Some(name) = obj.get("Name").and_then(|x| x.as_str()) {
887        return Ok(Name::User(Ustr::from(name)));
888    }
889
890    // {
891    //   Reference: [
892    //     { Name: "x" }
893    //   ]
894    // }
895    let ref_arr = obj["Reference"]
896        .as_array()
897        .ok_or_else(|| error!("Reference.as_array"))?;
898    let ref_obj = ref_arr
899        .first()
900        .and_then(|x| x.as_object())
901        .ok_or_else(|| error!("Reference[0].as_object"))?;
902    let name = ref_obj
903        .get("Name")
904        .and_then(|x| x.as_str())
905        .ok_or_else(|| error!("Reference[0].Name.as_str"))?;
906    Ok(Name::User(Ustr::from(name)))
907}
908
909pub fn parse_expression(obj: &JsonValue, scope: &SymbolTablePtr) -> Result<Expression> {
910    let fail = |stage: &str| -> Error {
911        Error::Parse(format!(
912            "Could not parse expression at stage `{stage}` for json `{obj}`"
913        ))
914    };
915
916    match obj {
917        Value::Object(op) if op.contains_key("Op") => {
918            let op_obj = op
919                .get("Op")
920                .and_then(Value::as_object)
921                .ok_or_else(|| fail("Op.as_object"))?;
922            let (op_name, _) = op_obj.iter().next().ok_or_else(|| fail("Op.iter().next"))?;
923
924            if op_obj.contains_key("MkOpFlatten") {
925                parse_flatten_op(op_obj, scope)
926            } else if op_obj.contains_key("MkOpTable") {
927                parse_table_op(op_obj, scope)
928            } else if op_obj.contains_key("MkOpIndexing") || op_obj.contains_key("MkOpSlicing") {
929                parse_indexing_slicing_op(op_obj, scope)
930            } else if op_obj.contains_key("MkOpActive") {
931                parse_active_op(op_obj, scope)
932            } else if op_obj.contains_key("MkOpRelationProj") {
933                parse_relation_projection(op_obj, scope)
934            } else if op_obj.contains_key("MkOpToSet") {
935                parse_to_set(op_obj, scope)
936            } else if binary_operator(op_name).is_some() {
937                parse_bin_op(op_obj, scope)
938            } else if unary_operator(op_name, None).is_some() {
939                parse_unary_op(op_obj, scope)
940            } else {
941                Err(fail("Op.unknown"))
942            }
943        }
944        Value::Object(comprehension) if comprehension.contains_key("Comprehension") => {
945            parse_comprehension(comprehension, scope.clone())
946        }
947        Value::Object(refe) if refe.contains_key("Reference") => {
948            let user_name = parse_reference_name(obj)?;
949
950            let declaration: DeclarationPtr = scope
951                .read()
952                .lookup(&user_name)
953                .ok_or_else(|| fail("Reference.lookup"))?;
954
955            Ok(Expression::Atomic(
956                Metadata::new(),
957                Atom::Reference(crate::ast::Reference::new(declaration)),
958            ))
959        }
960        // In the case where refering to fields. This not behind a reference
961        Value::Object(refe) if refe.contains_key("Name") => {
962            let name = refe
963                .get("Name")
964                .and_then(|x| x.as_str())
965                .ok_or_else(|| fail("Reference[0].Name.as_str"))?;
966            let user_name = Name::User(Ustr::from(name));
967
968            let declaration: DeclarationPtr = scope
969                .read()
970                .lookup(&user_name)
971                .ok_or_else(|| fail("Reference.lookup"))?;
972
973            Ok(Expression::Atomic(
974                Metadata::new(),
975                Atom::Reference(crate::ast::Reference::new(declaration)),
976            ))
977        }
978        Value::Object(abslit) if abslit.contains_key("AbstractLiteral") => {
979            let abstract_literal = abslit["AbstractLiteral"]
980                .as_object()
981                .ok_or_else(|| fail("AbstractLiteral.as_object"))?;
982
983            if abstract_literal.contains_key("AbsLitSet") {
984                parse_abs_lit(&abslit["AbstractLiteral"]["AbsLitSet"], scope)
985            } else if abstract_literal.contains_key("AbsLitFunction") {
986                parse_abs_function(&abslit["AbstractLiteral"]["AbsLitFunction"], scope)
987            } else if abstract_literal.contains_key("AbsLitMSet") {
988                parse_abs_mset(&abslit["AbstractLiteral"]["AbsLitMSet"], scope)
989            } else if abstract_literal.contains_key("AbsLitVariant") {
990                parse_abs_variant(&abslit["AbstractLiteral"]["AbsLitVariant"], scope)
991            } else if abstract_literal.contains_key("AbsLitRelation") {
992                parse_abs_relation(&abslit["AbstractLiteral"]["AbsLitRelation"], scope)
993            } else if abstract_literal.contains_key("AbsLitPartition") {
994                parse_abs_partition(&abslit["AbstractLiteral"]["AbsLitPartition"], scope)
995            } else if abstract_literal.contains_key("AbsLitPermutation") {
996                parse_abs_permutation(&abslit["AbstractLiteral"]["AbsLitPermutation"], scope)
997            } else if abstract_literal.contains_key("AbsLitSequence") {
998                parse_abs_sequence(&abslit["AbstractLiteral"]["AbsLitSequence"], scope)
999            } else {
1000                parse_abstract_matrix_as_expr(obj, scope)
1001            }
1002        }
1003
1004        Value::Object(constant) if constant.contains_key("Constant") => {
1005            parse_constant(constant, scope).or_else(|_| parse_abstract_matrix_as_expr(obj, scope))
1006        }
1007
1008        Value::Object(constant) if constant.contains_key("ConstantAbstract") => {
1009            let literal = constant
1010                .get("ConstantAbstract")
1011                .and_then(Value::as_object)
1012                .ok_or_else(|| fail("ConstantAbstract.as_object"))?;
1013            if literal.contains_key("AbsLitMatrix") {
1014                parse_abstract_matrix_as_expr(obj, scope)
1015            } else {
1016                parse_constant_abstract(literal, scope)
1017            }
1018        }
1019
1020        Value::Object(constant) if constant.contains_key("ConstantInt") => {
1021            parse_constant(constant, scope)
1022        }
1023        Value::Object(constant) if constant.contains_key("ConstantBool") => {
1024            parse_constant(constant, scope)
1025        }
1026
1027        _ => Err(fail("no_match")),
1028    }
1029}
1030
1031fn parse_abs_lit(abs_set: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1032    let values = abs_set
1033        .as_array()
1034        .ok_or(error!("AbsLitSet is not an array"))?;
1035    let expressions = values
1036        .iter()
1037        .map(|values| parse_expression(values, scope))
1038        .collect::<Result<Vec<_>>>()?;
1039
1040    Ok(Expression::AbstractLiteral(
1041        Metadata::new(),
1042        AbstractLiteral::Set(expressions),
1043    ))
1044}
1045
1046fn parse_constant_abstract(
1047    literal: &serde_json::Map<String, Value>,
1048    scope: &SymbolTablePtr,
1049) -> Result<Expression> {
1050    if let Some(value) = literal.get("AbsLitSet") {
1051        parse_abs_lit(value, scope)
1052    } else if let Some(value) = literal.get("AbsLitMSet") {
1053        parse_abs_mset(value, scope)
1054    } else if let Some(value) = literal.get("AbsLitTuple") {
1055        parse_abs_tuple(value, scope)
1056    } else if let Some(value) = literal.get("AbsLitRecord") {
1057        parse_abs_record(value, scope)
1058    } else if let Some(value) = literal.get("AbsLitPartition") {
1059        parse_abs_partition(value, scope)
1060    } else if let Some(value) = literal.get("AbsLitPermutation") {
1061        parse_abs_permutation(value, scope)
1062    } else if let Some(value) = literal.get("AbsLitFunction") {
1063        parse_abs_function(value, scope)
1064    } else if let Some(value) = literal.get("AbsLitVariant") {
1065        parse_abs_variant(value, scope)
1066    } else if let Some(value) = literal.get("AbsLitRelation") {
1067        parse_abs_relation(value, scope)
1068    } else if let Some(value) = literal.get("AbsLitSequence") {
1069        parse_abs_sequence(value, scope)
1070    } else {
1071        Err(error!("Unhandled ConstantAbstract literal type"))
1072    }
1073}
1074
1075fn parse_abs_mset(abs_mset: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1076    let values = abs_mset
1077        .as_array()
1078        .ok_or(error!("AbsLitMSet is not an array"))?;
1079    let expressions = values
1080        .iter()
1081        .map(|values| parse_expression(values, scope))
1082        .collect::<Result<Vec<_>>>()?;
1083
1084    Ok(Expression::AbstractLiteral(
1085        Metadata::new(),
1086        AbstractLiteral::MSet(expressions),
1087    ))
1088}
1089
1090fn parse_abs_partition(abs_partition: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1091    let parts = abs_partition
1092        .as_array()
1093        .ok_or(error!("AbsLitPartition is not an array"))?;
1094
1095    let mut partition: Vec<Vec<_>> = Vec::new();
1096
1097    for part in parts {
1098        let vals = part
1099            .as_array()
1100            .ok_or(error!("Part in AbsLitPartition is not an array"))?;
1101
1102        let exprs = vals
1103            .iter()
1104            .map(|values| parse_expression(values, scope))
1105            .collect::<Result<Vec<_>>>()?;
1106
1107        partition.push(exprs);
1108    }
1109
1110    Ok(Expression::AbstractLiteral(
1111        Metadata::new(),
1112        AbstractLiteral::Partition(partition),
1113    ))
1114}
1115
1116fn parse_abs_permutation(abs_permutation: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1117    let cycles = abs_permutation
1118        .as_array()
1119        .ok_or(error!("AbsLitPermutation is not an array"))?;
1120
1121    let mut permutation: Vec<Vec<_>> = Vec::new();
1122
1123    for cycle in cycles {
1124        let vals = cycle
1125            .as_array()
1126            .ok_or(error!("Cycle in AbsLitPermutation is not an array"))?;
1127
1128        let exprs = vals
1129            .iter()
1130            .map(|values| parse_expression(values, scope))
1131            .collect::<Result<Vec<_>>>()?;
1132
1133        permutation.push(exprs);
1134    }
1135
1136    Ok(Expression::AbstractLiteral(
1137        Metadata::new(),
1138        AbstractLiteral::Permutation(permutation),
1139    ))
1140}
1141
1142fn parse_abs_sequence(abs_seq: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1143    let values = abs_seq
1144        .as_array()
1145        .ok_or(error!("AbsLitSequence is not an array"))?;
1146    let expressions = values
1147        .iter()
1148        .map(|values| parse_expression(values, scope))
1149        .collect::<Result<Vec<_>>>()?;
1150
1151    Ok(Expression::AbstractLiteral(
1152        Metadata::new(),
1153        AbstractLiteral::Sequence(expressions),
1154    ))
1155}
1156
1157fn parse_abs_tuple(abs_tuple: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1158    let values = abs_tuple
1159        .as_array()
1160        .ok_or(error!("AbsLitTuple is not an array"))?;
1161    let expressions = values
1162        .iter()
1163        .map(|values| parse_expression(values, scope))
1164        .collect::<Result<Vec<_>>>()?;
1165
1166    Ok(Expression::AbstractLiteral(
1167        Metadata::new(),
1168        AbstractLiteral::Tuple(expressions),
1169    ))
1170}
1171
1172//parses an abstract record as an expression
1173fn parse_abs_record(abs_record: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1174    let entries = abs_record
1175        .as_array()
1176        .ok_or(error!("AbsLitRecord is not an array"))?;
1177    let mut rec = vec![];
1178
1179    for entry in entries {
1180        let entry = entry
1181            .as_array()
1182            .ok_or(error!("AbsLitRecord entry is not an array"))?;
1183        let name = entry[0]
1184            .as_object()
1185            .ok_or(error!("AbsLitRecord field name is not an object"))?["Name"]
1186            .as_str()
1187            .ok_or(error!("AbsLitRecord field name is not a string"))?;
1188
1189        let value = parse_expression(&entry[1], scope)?;
1190
1191        let name = Name::User(Ustr::from(name));
1192        let rec_entry = Field {
1193            name: name.clone(),
1194            value,
1195        };
1196        rec.push(rec_entry);
1197    }
1198
1199    Ok(Expression::AbstractLiteral(
1200        Metadata::new(),
1201        AbstractLiteral::Record(rec),
1202    ))
1203}
1204
1205//parses an abstract variant as an expression
1206fn parse_abs_variant(abs_variant: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1207    let entry = abs_variant
1208        .as_array()
1209        .ok_or(error!("AbsLitVariant is not an array"))?;
1210    let name = entry[1]
1211        .as_object()
1212        .ok_or(error!("AbsLitVariant field name is not an object"))?["Name"]
1213        .as_str()
1214        .ok_or(error!("AbsLitVariant field name is not a string"))?;
1215
1216    let value = parse_expression(&entry[2], scope)?;
1217
1218    let name = Name::User(Ustr::from(name));
1219    let rec_entry = Field { name, value };
1220
1221    Ok(Expression::AbstractLiteral(
1222        Metadata::new(),
1223        AbstractLiteral::Variant(Moo::new(rec_entry)),
1224    ))
1225}
1226
1227//parses an abstract function as an expression
1228fn parse_abs_function(abs_function: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1229    let entries = abs_function
1230        .as_array()
1231        .ok_or(error!("AbsLitFunction is not an array"))?;
1232    let mut assignments = vec![];
1233
1234    for entry in entries {
1235        let entry = entry
1236            .as_array()
1237            .ok_or(error!("Explicit function assignment is not an array"))?;
1238        let expression = entry
1239            .iter()
1240            .map(|values| parse_expression(values, scope))
1241            .collect::<Result<Vec<_>>>()?;
1242        let domain_value = expression
1243            .first()
1244            .ok_or(error!("Invalid function domain"))?;
1245        let codomain_value = expression
1246            .get(1)
1247            .ok_or(error!("Invalid function codomain"))?;
1248        let tuple = (domain_value.clone(), codomain_value.clone());
1249        assignments.push(tuple);
1250    }
1251    Ok(Expression::AbstractLiteral(
1252        Metadata::new(),
1253        AbstractLiteral::Function(assignments),
1254    ))
1255}
1256
1257//parses an abstract relation as an expression
1258fn parse_abs_relation(abs_relation: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
1259    let entries = abs_relation
1260        .as_array()
1261        .ok_or(error!("AbsLitRelation is not an array"))?;
1262    let mut assignments = vec![];
1263
1264    for entry in entries {
1265        let entry = entry
1266            .as_array()
1267            .ok_or(error!("Explicit relation assignment is not an array"))?;
1268        let expression = entry
1269            .iter()
1270            .map(|values| parse_expression(values, scope))
1271            .collect::<Result<Vec<_>>>()?;
1272        assignments.push(expression);
1273    }
1274    Ok(Expression::AbstractLiteral(
1275        Metadata::new(),
1276        AbstractLiteral::Relation(assignments),
1277    ))
1278}
1279
1280fn parse_comprehension(
1281    comprehension: &serde_json::Map<String, Value>,
1282    scope: SymbolTablePtr,
1283) -> Result<Expression> {
1284    let fail = |stage: &str| -> Error {
1285        Error::Parse(format!("Could not parse comprehension at stage `{stage}`"))
1286    };
1287
1288    let value = &comprehension["Comprehension"];
1289    let mut comprehension = ComprehensionBuilder::new(scope.clone());
1290    let generator_symboltable = comprehension.generator_symboltable();
1291    let return_expr_symboltable = comprehension.return_expr_symboltable();
1292
1293    let generators_and_guards_array = value
1294        .pointer("/1")
1295        .and_then(Value::as_array)
1296        .ok_or_else(|| fail("Comprehension.pointer(/1).as_array"))?;
1297    let generators_and_guards = generators_and_guards_array.iter();
1298
1299    for gen_or_guard in generators_and_guards {
1300        let gen_or_guard_obj = gen_or_guard
1301            .as_object()
1302            .ok_or_else(|| fail("generator_or_guard.as_object"))?;
1303        let (name, inner) = gen_or_guard_obj
1304            .iter()
1305            .next()
1306            .ok_or_else(|| fail("generator_or_guard.iter().next"))?;
1307        comprehension = match name.as_str() {
1308            "Generator" => {
1309                // TODO: more things than GenDomainNoRepr and Single names here?
1310                let generator_obj = inner
1311                    .as_object()
1312                    .ok_or_else(|| fail("Generator.inner.as_object"))?;
1313                let (name, gen_inner) = generator_obj
1314                    .iter()
1315                    .next()
1316                    .ok_or_else(|| fail("Generator.inner.iter().next"))?;
1317                match name.as_str() {
1318                    "GenDomainNoRepr" => {
1319                        let name = gen_inner
1320                            .pointer("/0/Single/Name")
1321                            .and_then(Value::as_str)
1322                            .ok_or_else(|| {
1323                                fail("GenDomainNoRepr.pointer(/0/Single/Name).as_str")
1324                            })?;
1325                        let domain_obj = gen_inner
1326                            .pointer("/1")
1327                            .and_then(Value::as_object)
1328                            .ok_or_else(|| fail("GenDomainNoRepr.pointer(/1).as_object"))?;
1329                        let (domain_name, domain_value) = domain_obj
1330                            .iter()
1331                            .next()
1332                            .ok_or_else(|| fail("GenDomainNoRepr.domain.iter().next"))?;
1333                        let domain = parse_domain(
1334                            domain_name,
1335                            domain_value,
1336                            &mut generator_symboltable.write(),
1337                        )?;
1338                        comprehension.generator(DeclarationPtr::new_find(name.into(), domain))
1339                    }
1340                    "GenInExpr" => {
1341                        let name = gen_inner
1342                            .pointer("/0/Single/Name")
1343                            .and_then(Value::as_str)
1344                            .ok_or_else(|| {
1345                                fail("GenDomainNoRepr.pointer(/0/Single/Name).as_str")
1346                            })?;
1347                        let generator_expr = gen_inner
1348                            .pointer("/1")
1349                            .ok_or_else(|| fail("GenInExpr.pointer(/1)"))?;
1350                        let expr = parse_expression(generator_expr, &scope)
1351                            .map_err(|_| fail("GenInExpr.parse_expression"))?;
1352                        comprehension.expression_generator(name.into(), expr)
1353                    }
1354                    _ => {
1355                        bug!("unknown generator type inside comprehension {name}");
1356                    }
1357                }
1358            }
1359
1360            "Condition" => {
1361                let expr = parse_expression(inner, &generator_symboltable)
1362                    .map_err(|_| fail("Condition.parse_expression"))?;
1363                comprehension.guard(expr)
1364            }
1365
1366            x => {
1367                bug!("unknown field inside comprehension {x}");
1368            }
1369        }
1370    }
1371
1372    let return_expr_value = value
1373        .pointer("/0")
1374        .ok_or_else(|| fail("Comprehension.pointer(/0)"))?;
1375    let expr = parse_expression(return_expr_value, &return_expr_symboltable)
1376        .map_err(|_| fail("Comprehension.return_expr.parse_expression"))?;
1377
1378    Ok(Expression::Comprehension(
1379        Metadata::new(),
1380        Moo::new(comprehension.with_return_value(expr)),
1381    ))
1382}
1383
1384fn unary_skip_operator(op_name: &str) -> Option<ACOperatorKind> {
1385    match op_name {
1386        "MkOpAnd" => Some(ACOperatorKind::And),
1387        "MkOpOr" => Some(ACOperatorKind::Or),
1388        "MkOpSum" => Some(ACOperatorKind::Sum),
1389        "MkOpProduct" => Some(ACOperatorKind::Product),
1390        // Not true AC operators (no universal identity element), but still need their own
1391        // skip-operator tag so a symbolic guard lowers correctly instead of silently substituting
1392        // Sum's identity (0).
1393        "MkOpMin" => Some(ACOperatorKind::Min),
1394        "MkOpMax" => Some(ACOperatorKind::Max),
1395        _ => None,
1396    }
1397}
1398
1399fn set_comprehension_skip_operator(
1400    expr: Expression,
1401    skip_operator: Option<ACOperatorKind>,
1402) -> Expression {
1403    let Expression::Comprehension(meta, comprehension) = expr else {
1404        return expr;
1405    };
1406    if let Some(skip_operator) = skip_operator {
1407        let mut comprehension = Moo::unwrap_or_clone(comprehension);
1408        comprehension.skip_operator = Some(skip_operator);
1409        Expression::Comprehension(meta, Moo::new(comprehension))
1410    } else {
1411        Expression::Comprehension(meta, comprehension)
1412    }
1413}
1414
1415fn parse_bin_op(
1416    bin_op: &serde_json::Map<String, Value>,
1417    scope: &SymbolTablePtr,
1418) -> Result<Expression> {
1419    // we know there is a single key value pair in this object
1420    // extract the value, ignore the key
1421    let (key, value) = bin_op
1422        .into_iter()
1423        .next()
1424        .ok_or(error!("Binary op object is empty"))?;
1425
1426    let constructor = binary_operator(key.as_str())
1427        .ok_or(error!(format!("Unknown binary operator `{}`", key)))?;
1428
1429    match &value {
1430        Value::Array(bin_op_args) if bin_op_args.len() == 2 => {
1431            let arg1 = parse_expression(&bin_op_args[0], scope)?;
1432            let arg2 = parse_expression(&bin_op_args[1], scope)?;
1433
1434            // Conjure spells set difference with minus, so the operand types decide which of the
1435            // two it is -- the same choice the Essence parser makes.
1436            if key == "MkOpMinus"
1437                && (matches!(arg1.try_return_type(), Some(ReturnType::Set(_)))
1438                    || matches!(arg2.try_return_type(), Some(ReturnType::Set(_))))
1439            {
1440                return Ok(Expression::Difference(
1441                    Metadata::new(),
1442                    Moo::new(arg1),
1443                    Moo::new(arg2),
1444                ));
1445            }
1446
1447            Ok(constructor(Metadata::new(), Moo::new(arg1), Moo::new(arg2)))
1448        }
1449        _ => Err(error!("Binary operator arguments are not a 2-array")),
1450    }
1451}
1452
1453fn parse_table_op(
1454    op: &serde_json::Map<String, Value>,
1455    scope: &SymbolTablePtr,
1456) -> Result<Expression> {
1457    let args = op
1458        .get("MkOpTable")
1459        .ok_or(error!("MkOpTable missing"))?
1460        .as_array()
1461        .ok_or(error!("MkOpTable is not an array"))?;
1462
1463    if args.len() != 2 {
1464        return Err(error!("MkOpTable arguments are not a 2-array"));
1465    }
1466
1467    let tuple_expr = parse_expression(&args[0], scope)?;
1468    let allowed_rows_expr = parse_expression(&args[1], scope)?;
1469
1470    let (tuple_elems, _) = tuple_expr
1471        .clone()
1472        .unwrap_matrix_unchecked()
1473        .ok_or(error!("MkOpTable first argument is not a matrix"))?;
1474    let (allowed_rows, _) = allowed_rows_expr
1475        .clone()
1476        .unwrap_matrix_unchecked()
1477        .ok_or(error!("MkOpTable second argument is not a matrix"))?;
1478
1479    for row_expr in allowed_rows {
1480        let (row_elems, _) = row_expr
1481            .unwrap_matrix_unchecked()
1482            .ok_or(error!("MkOpTable row is not a matrix"))?;
1483
1484        if row_elems.len() != tuple_elems.len() {
1485            return Err(error!("MkOpTable row width does not match tuple width"));
1486        }
1487    }
1488
1489    Ok(Expression::Table(
1490        Metadata::new(),
1491        Moo::new(tuple_expr),
1492        Moo::new(allowed_rows_expr),
1493    ))
1494}
1495
1496/// If LHS is a record/variant and RHS is a field name,
1497/// returns Ok(Some(record_expr, field_name)).
1498/// If LHS is any other type, return Ok(None).
1499fn parse_record_field(
1500    op_args: &[Value],
1501    scope: &SymbolTablePtr,
1502) -> Result<Option<(Expression, Name)>> {
1503    if op_args.len() != 2 {
1504        return Err(error!("Expected 2 arguments to record indexing operation"));
1505    }
1506
1507    let lhs = parse_expression(&op_args[0], scope)?;
1508    match lhs.return_type() {
1509        // If indexing into a record, parse string field name
1510        // and check that such a field exists
1511        ReturnType::Record(ents) | ReturnType::Variant(ents) => {
1512            let field_name = parse_reference_name(&op_args[1])?;
1513            let has_name = ents.iter().any(|x| x.name.eq(&field_name));
1514            if !has_name {
1515                return Err(error!(format!(
1516                    "Unknown field `{field_name}` in record `{lhs}`"
1517                )));
1518            }
1519            Ok(Some((lhs, field_name)))
1520        }
1521        _ => Ok(None),
1522    }
1523}
1524
1525fn parse_active_op(
1526    op: &serde_json::Map<String, Value>,
1527    scope: &SymbolTablePtr,
1528) -> Result<Expression> {
1529    // we know there is a single key value pair in this object
1530    // extract the value, ignore the key
1531    let (_, value) = op
1532        .into_iter()
1533        .next()
1534        .ok_or(error!("MkOpActive op object is empty"))?;
1535
1536    let Value::Array(op_args) = &value else {
1537        return Err(error!("MkOpActive op array is not an array"));
1538    };
1539    let Some((lhs, rhs)) = parse_record_field(op_args, scope)? else {
1540        return Err(error!("MkOpActive op expected record or variant"));
1541    };
1542    Ok(Expression::Active(Metadata::new(), Moo::new(lhs), rhs))
1543}
1544
1545fn parse_indexing_slicing_op(
1546    op: &serde_json::Map<String, Value>,
1547    scope: &SymbolTablePtr,
1548) -> Result<Expression> {
1549    // we know there is a single key value pair in this object
1550    // extract the value, ignore the key
1551    let (key, value) = op
1552        .into_iter()
1553        .next()
1554        .ok_or(error!("Indexing/Slicing op object is empty"))?;
1555
1556    // we know that this is meant to be a mkopindexing, so anything that goes wrong from here is a
1557    // bug!
1558
1559    // Conjure does a[1,2,3] as MkOpIndexing(MkOpIndexing(MkOpIndexing(a,3),2),1).
1560    //
1561    // And  a[1,..,3] as MkOpIndexing(MkOpSlicing(MkOpIndexing(a,3)),1).
1562    //
1563    // However, we want this in a flattened form: Index(a, [1,2,3])
1564    let mut target: Expression;
1565    let mut indices: Vec<Option<Expression>> = vec![];
1566
1567    // true if this has no slicing, false otherwise.
1568    let mut all_known = true;
1569
1570    match key.as_str() {
1571        "MkOpIndexing" => {
1572            match &value {
1573                Value::Array(op_args) if op_args.len() == 2 => {
1574                    target = parse_expression(&op_args[0], scope)?;
1575
1576                    match parse_record_field(op_args, scope)? {
1577                        // For record indexing, generate nested RecordField exprs
1578                        Some((lhs, rhs)) => {
1579                            target = Expression::RecordField(Metadata::new(), Moo::new(lhs), rhs)
1580                        }
1581                        // Append any other indices to the flat list as normal
1582                        _ => indices.push(Some(parse_expression(&op_args[1], scope)?)),
1583                    }
1584                }
1585                _ => return Err(error!("Unknown object inside MkOpIndexing")),
1586            };
1587        }
1588
1589        "MkOpSlicing" => {
1590            all_known = false;
1591            match &value {
1592                Value::Array(op_args) if op_args.len() == 3 => {
1593                    // NB: records can't be sliced into so no need to check!
1594                    target = parse_expression(&op_args[0], scope)?;
1595                    indices.push(None);
1596                }
1597                _ => return Err(error!("Unknown object inside MkOpSlicing")),
1598            };
1599        }
1600
1601        _ => return Err(error!("Unknown indexing/slicing operator")),
1602    }
1603
1604    loop {
1605        match &mut target {
1606            Expression::UnsafeIndex(_, new_target, new_indices) => {
1607                indices.extend(new_indices.iter().cloned().rev().map(Some));
1608                target = Moo::unwrap_or_clone(new_target.clone());
1609            }
1610
1611            Expression::UnsafeSlice(_, new_target, new_indices) => {
1612                all_known = false;
1613                indices.extend(new_indices.iter().cloned().rev());
1614                target = Moo::unwrap_or_clone(new_target.clone());
1615            }
1616
1617            _ => {
1618                // not a slice or an index, we have reached the target.
1619                break;
1620            }
1621        }
1622    }
1623
1624    // If we had a record field and no other indices, the list will be empty
1625    if indices.is_empty() {
1626        return Ok(target);
1627    }
1628
1629    indices.reverse();
1630
1631    if all_known {
1632        Ok(Expression::UnsafeIndex(
1633            Metadata::new(),
1634            Moo::new(target),
1635            indices
1636                .into_iter()
1637                .collect::<Option<Vec<_>>>()
1638                .ok_or(error!("Missing index in fully-known indexing operation"))?,
1639        ))
1640    } else {
1641        Ok(Expression::UnsafeSlice(
1642            Metadata::new(),
1643            Moo::new(target),
1644            indices,
1645        ))
1646    }
1647}
1648
1649// Parses relation projection, to get a Vec<Option<Expression>> for the projections
1650fn parse_relation_projection(
1651    op: &serde_json::Map<String, Value>,
1652    scope: &SymbolTablePtr,
1653) -> Result<Expression> {
1654    let args = op
1655        .get("MkOpRelationProj")
1656        .ok_or(error!("MkOpRelationProj missing"))?
1657        .as_array()
1658        .ok_or(error!("MkOpRelationProj is not an array"))?;
1659    let first = args
1660        .first()
1661        .ok_or(error!("MkOpRelationProj missing first argument"))?;
1662    let second = args
1663        .get(1)
1664        .ok_or(error!("MkOpRelationProj missing second argument"))?
1665        .as_array()
1666        .ok_or(error!("MkOpRelationProj second argument is not an array"))?;
1667    let relation = parse_expression(first, scope).ok();
1668    // We build a vec of option expressions.
1669    // In the case where a relation domain is not being projected it is None, otherwise it is Some with the expression
1670    // We parse the 'null' as an error, which is mapped to None after parse_expression()
1671    let projections = second
1672        .iter()
1673        .map(|expr| parse_expression(expr, scope).ok())
1674        .collect();
1675    if let Some(relation) = relation {
1676        Ok(Expression::RelationProj(
1677            Metadata::new(),
1678            Moo::new(relation),
1679            projections,
1680        ))
1681    } else {
1682        Err(error!("MkOpRelationProj does not contain relation"))
1683    }
1684}
1685
1686// The ToSet operator is not truely a unary operator.
1687// The internal expression is 2nd in the array, with 'false' as the first element
1688// Therefore it needs separate parsing
1689fn parse_to_set(op: &serde_json::Map<String, Value>, scope: &SymbolTablePtr) -> Result<Expression> {
1690    let args = op
1691        .get("MkOpToSet")
1692        .ok_or(error!("MkOpToSet missing"))?
1693        .as_array()
1694        .ok_or(error!("MkOpToSet is not an array"))?;
1695    let second = args
1696        .get(1)
1697        .ok_or(error!("MkOpToSet missing second argument"))?;
1698    let inner = parse_expression(second, scope)?;
1699    Ok(Expression::ToSet(Metadata::new(), Moo::new(inner)))
1700}
1701
1702fn parse_flatten_op(
1703    op: &serde_json::Map<String, Value>,
1704    scope: &SymbolTablePtr,
1705) -> Result<Expression> {
1706    let args = op
1707        .get("MkOpFlatten")
1708        .ok_or(error!("MkOpFlatten missing"))?
1709        .as_array()
1710        .ok_or(error!("MkOpFlatten is not an array"))?;
1711
1712    let first = args
1713        .first()
1714        .ok_or(error!("MkOpFlatten missing first argument"))?;
1715    let second = args
1716        .get(1)
1717        .ok_or(error!("MkOpFlatten missing second argument"))?;
1718    let n = parse_expression(first, scope).ok();
1719    let matrix = parse_expression(second, scope)?;
1720
1721    if let Some(n) = n {
1722        Ok(Expression::Flatten(
1723            Metadata::new(),
1724            Some(Moo::new(n)),
1725            Moo::new(matrix),
1726        ))
1727    } else {
1728        Ok(Expression::Flatten(Metadata::new(), None, Moo::new(matrix)))
1729    }
1730}
1731
1732fn parse_unary_op(
1733    un_op: &serde_json::Map<String, Value>,
1734    scope: &SymbolTablePtr,
1735) -> Result<Expression> {
1736    let fail = |stage: &str| -> Error {
1737        Error::Parse(format!("Could not parse unary op at stage `{stage}`"))
1738    };
1739
1740    let (key, value) = un_op
1741        .iter()
1742        .next()
1743        .ok_or_else(|| fail("un_op.iter().next"))?;
1744
1745    // unops are the main things that contain comprehensions
1746    //
1747    // if the current expr is a quantifier like and/or/sum and it contains a comprehension, let the comprehension know what it is inside.
1748    let arg = match value {
1749        Value::Object(comprehension) if comprehension.contains_key("Comprehension") => {
1750            parse_comprehension(comprehension, scope.clone())
1751                .map_err(|_| fail("value.Comprehension.parse_comprehension"))
1752        }
1753        _ => parse_expression(value, scope).map_err(|_| fail("value.parse_expression")),
1754    }
1755    .map_err(|_| fail("arg"))?;
1756
1757    let skip_operator = unary_skip_operator(key.as_str());
1758    let arg = set_comprehension_skip_operator(arg, skip_operator);
1759
1760    let constructor =
1761        unary_operator(key.as_str(), Some(&arg)).ok_or_else(|| fail("unary_operator"))?;
1762
1763    Ok(constructor(Metadata::new(), Moo::new(arg)))
1764}
1765
1766// Takes in { AbstractLiteral: .... }
1767fn parse_abstract_matrix_as_expr(
1768    value: &serde_json::Value,
1769    scope: &SymbolTablePtr,
1770) -> Result<Expression> {
1771    parser_trace!("trying to parse an abstract literal matrix");
1772    let (values, domain_name, domain_value) =
1773        if let Some(abs_lit_matrix) = value.pointer("/AbstractLiteral/AbsLitMatrix") {
1774            parser_trace!(".. found JSON pointer /AbstractLiteral/AbstractLitMatrix");
1775            let (domain_name, domain_value) = abs_lit_matrix
1776                .pointer("/0")
1777                .and_then(Value::as_object)
1778                .and_then(|x| x.iter().next())
1779                .ok_or(error!("AbsLitMatrix missing domain"))?;
1780            let values = abs_lit_matrix
1781                .pointer("/1")
1782                .ok_or(error!("AbsLitMatrix missing values"))?;
1783
1784            Some((values, domain_name, domain_value))
1785        }
1786        // the input of this expression is constant - e.g. or([]), or([false]), min([2]), etc.
1787        else if let Some(const_abs_lit_matrix) =
1788            value.pointer("/Constant/ConstantAbstract/AbsLitMatrix")
1789        {
1790            parser_trace!(".. found JSON pointer /Constant/ConstantAbstract/AbsLitMatrix");
1791            let (domain_name, domain_value) = const_abs_lit_matrix
1792                .pointer("/0")
1793                .and_then(Value::as_object)
1794                .and_then(|x| x.iter().next())
1795                .ok_or(error!("ConstantAbstract AbsLitMatrix missing domain"))?;
1796            let values = const_abs_lit_matrix
1797                .pointer("/1")
1798                .ok_or(error!("ConstantAbstract AbsLitMatrix missing values"))?;
1799
1800            Some((values, domain_name, domain_value))
1801        } else if let Some(const_abs_lit_matrix) = value.pointer("/ConstantAbstract/AbsLitMatrix") {
1802            parser_trace!(".. found JSON pointer /ConstantAbstract/AbsLitMatrix");
1803            let (domain_name, domain_value) = const_abs_lit_matrix
1804                .pointer("/0")
1805                .and_then(Value::as_object)
1806                .and_then(|x| x.iter().next())
1807                .ok_or(error!("ConstantAbstract/AbsLitMatrix missing domain"))?;
1808            let values = const_abs_lit_matrix
1809                .pointer("/1")
1810                .ok_or(error!("ConstantAbstract/AbsLitMatrix missing values"))?;
1811            Some((values, domain_name, domain_value))
1812        } else {
1813            None
1814        }
1815        .ok_or(error!("Could not parse abstract literal matrix"))?;
1816
1817    parser_trace!(".. found in domain and values in JSON:");
1818    parser_trace!(".. .. index domain name {domain_name}");
1819    parser_trace!(".. .. values {value}");
1820
1821    let args_parsed = values
1822        .as_array()
1823        .ok_or(error!("Matrix values are not an array"))?
1824        .iter()
1825        .map(|x| parse_expression(x, scope))
1826        .collect::<Result<Vec<Expression>>>()?;
1827
1828    if !args_parsed.is_empty() {
1829        parser_trace!(
1830            ".. successfully parsed values as expressions: {}, ... ",
1831            args_parsed[0]
1832        );
1833    } else {
1834        parser_trace!(".. successfully parsed empty values ",);
1835    }
1836
1837    let mut symbols = scope.write();
1838    match parse_domain(domain_name, domain_value, &mut symbols) {
1839        Ok(domain) => {
1840            parser_trace!("... sucessfully parsed domain as {domain}");
1841            Ok(into_matrix_expr![args_parsed;domain])
1842        }
1843        Err(_) => {
1844            parser_trace!("... failed to parse domain, creating a matrix without one.");
1845            Ok(into_matrix_expr![args_parsed])
1846        }
1847    }
1848}
1849
1850fn parse_constant(
1851    constant: &serde_json::Map<String, Value>,
1852    scope: &SymbolTablePtr,
1853) -> Result<Expression> {
1854    match &constant.get("Constant") {
1855        Some(Value::Object(int)) if int.contains_key("ConstantInt") => {
1856            let int_32: i32 = match int["ConstantInt"]
1857                .as_array()
1858                .ok_or(error!("ConstantInt is not an array"))?[1]
1859                .as_i64()
1860                .ok_or(error!("ConstantInt does not contain int"))?
1861                .try_into()
1862            {
1863                Ok(x) => x,
1864                Err(_) => return Err(error!("ConstantInt cannot be represented as i32")),
1865            };
1866
1867            Ok(Expression::Atomic(
1868                Metadata::new(),
1869                Atom::Literal(Literal::Int(int_32)),
1870            ))
1871        }
1872
1873        Some(Value::Object(b)) if b.contains_key("ConstantBool") => {
1874            let b: bool = b["ConstantBool"]
1875                .as_bool()
1876                .ok_or(error!("ConstantBool does not contain bool"))?;
1877            Ok(Expression::Atomic(
1878                Metadata::new(),
1879                Atom::Literal(Literal::Bool(b)),
1880            ))
1881        }
1882
1883        Some(Value::Object(int)) if int.contains_key("ConstantAbstract") => {
1884            if let Some(Value::Object(obj)) = int.get("ConstantAbstract") {
1885                if let Some(arr) = obj.get("AbsLitSet") {
1886                    return parse_abs_lit(arr, scope);
1887                } else if let Some(arr) = obj.get("AbsLitMSet") {
1888                    return parse_abs_mset(arr, scope);
1889                } else if let Some(arr) = obj.get("AbsLitMatrix") {
1890                    return parse_abstract_matrix_as_expr(arr, scope);
1891                } else if let Some(arr) = obj.get("AbsLitTuple") {
1892                    return parse_abs_tuple(arr, scope);
1893                } else if let Some(arr) = obj.get("AbsLitRecord") {
1894                    return parse_abs_record(arr, scope);
1895                } else if let Some(arr) = obj.get("AbsLitPartition") {
1896                    return parse_abs_partition(arr, scope);
1897                } else if let Some(arr) = obj.get("AbsLitPermutation") {
1898                    return parse_abs_permutation(arr, scope);
1899                } else if let Some(arr) = obj.get("AbsLitFunction") {
1900                    return parse_abs_function(arr, scope);
1901                } else if let Some(arr) = obj.get("AbsLitVariant") {
1902                    return parse_abs_variant(arr, scope);
1903                } else if let Some(arr) = obj.get("AbsLitRelation") {
1904                    return parse_abs_relation(arr, scope);
1905                } else if let Some(arr) = obj.get("AbsLitSequence") {
1906                    return parse_abs_sequence(arr, scope);
1907                }
1908            }
1909            Err(error!("Unhandled ConstantAbstract literal type"))
1910        }
1911
1912        // sometimes (e.g. constant matrices) we can have a ConstantInt / Constant bool that is
1913        // not wrapped in Constant
1914        None => {
1915            let int_expr = constant
1916                .get("ConstantInt")
1917                .and_then(|x| x.as_array())
1918                .and_then(|x| x[1].as_i64())
1919                .and_then(|x| x.try_into().ok())
1920                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(x))));
1921
1922            if let Some(expr) = int_expr {
1923                return Ok(expr);
1924            }
1925
1926            let bool_expr = constant
1927                .get("ConstantBool")
1928                .and_then(|x| x.as_bool())
1929                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(x))));
1930
1931            if let Some(expr) = bool_expr {
1932                return Ok(expr);
1933            }
1934
1935            Err(error!(format!("Unhandled parse_constant {constant:#?}")))
1936        }
1937        otherwise => Err(error!(format!("Unhandled parse_constant {otherwise:#?}"))),
1938    }
1939}
1940
1941#[cfg(test)]
1942mod tests {
1943    use super::*;
1944    use crate::ast::HasDomain;
1945    use crate::{domain_int, range};
1946    use serde_json::json;
1947
1948    #[test]
1949    fn parses_record_index() {
1950        let scope = SymbolTablePtr::new();
1951        scope.write().insert(DeclarationPtr::new_find(
1952            Name::user("x"),
1953            Domain::record(vec![Field {
1954                name: Name::user("a"),
1955                value: Domain::bool(),
1956            }]),
1957        ));
1958
1959        let value = json!({
1960            "Op": {
1961                "MkOpIndexing": [
1962                    {
1963                        "Reference": [
1964                            {
1965                                "Name": "x"
1966                            },
1967                            null
1968                        ]
1969                    },
1970                    {
1971                        "Reference": [
1972                            {
1973                                "Name": "a"
1974                            },
1975                            null
1976                        ]
1977                    }
1978                ]
1979            }
1980        });
1981
1982        let expr = parse_expression(&value, &scope).expect("record index should parse");
1983        let Expression::RecordField(_, rec_expr, field_name) = expr else {
1984            panic!("expected record field access");
1985        };
1986        let Expression::Atomic(_, Atom::Reference(re)) = rec_expr.as_ref() else {
1987            panic!("expected LHS to be a record reference");
1988        };
1989        assert_eq!(re.name().clone(), Name::user("x"));
1990        assert!(re.domain_of().as_record().is_some());
1991        assert_eq!(field_name, Name::user("a"));
1992    }
1993
1994    #[test]
1995    fn parses_nested_constant_abstract_sets() {
1996        let scope = SymbolTablePtr::new();
1997        let value = json!({
1998            "ConstantAbstract": {
1999                "AbsLitSet": [
2000                    {
2001                        "ConstantAbstract": {
2002                            "AbsLitSet": [
2003                                { "ConstantInt": [{ "TagInt": [] }, 1] },
2004                                { "ConstantInt": [{ "TagInt": [] }, 2] }
2005                            ]
2006                        }
2007                    },
2008                    {
2009                        "ConstantAbstract": {
2010                            "AbsLitSet": [
2011                                { "ConstantInt": [{ "TagInt": [] }, 3] }
2012                            ]
2013                        }
2014                    }
2015                ]
2016            }
2017        });
2018
2019        let expr = parse_expression(&value, &scope).expect("nested constant sets should parse");
2020        let Expression::AbstractLiteral(_, AbstractLiteral::Set(outer_values)) = expr else {
2021            panic!("expected an outer set literal");
2022        };
2023        assert_eq!(outer_values.len(), 2);
2024        assert!(outer_values.iter().all(|value| matches!(
2025            value,
2026            Expression::AbstractLiteral(_, AbstractLiteral::Set(_))
2027        )));
2028    }
2029
2030    #[test]
2031    fn parses_abstract_literal_wrapped_partition_with_non_constant_elements() {
2032        // Conjure emits a partition literal under the bare `AbstractLiteral` wrapper (rather
2033        // than `Constant`/`ConstantAbstract`) whenever one of its elements is not itself a
2034        // constant, e.g. `partition({x,2},{y,4})` where x, y are decision variables. Captured
2035        // verbatim (modulo whitespace) from `conjure pretty --output-format=astjson` on such a
2036        // model.
2037        let scope = SymbolTablePtr::new();
2038        scope
2039            .write()
2040            .insert(DeclarationPtr::new_find(Name::user("x"), domain_int!(1..4)));
2041        scope
2042            .write()
2043            .insert(DeclarationPtr::new_find(Name::user("y"), domain_int!(1..4)));
2044
2045        let value = json!({
2046            "AbstractLiteral": {
2047                "AbsLitPartition": [
2048                    [
2049                        { "Reference": [{ "Name": "x" }, null] },
2050                        { "Constant": { "ConstantInt": [{ "TagInt": [] }, 2] } }
2051                    ],
2052                    [
2053                        { "Reference": [{ "Name": "y" }, null] },
2054                        { "Constant": { "ConstantInt": [{ "TagInt": [] }, 4] } }
2055                    ]
2056                ]
2057            }
2058        });
2059
2060        let expr = parse_expression(&value, &scope)
2061            .expect("AbstractLiteral-wrapped partition should parse");
2062        let Expression::AbstractLiteral(_, AbstractLiteral::Partition(parts)) = expr else {
2063            panic!("expected a partition literal, got {expr:?}");
2064        };
2065        assert_eq!(parts.len(), 2);
2066        assert_eq!(parts[0].len(), 2);
2067        assert_eq!(parts[1].len(), 2);
2068    }
2069}