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::ac_operators::ACOperatorKind;
12use crate::ast::comprehension::ComprehensionBuilder;
13use crate::ast::records::RecordValue;
14use crate::ast::{
15    AbstractLiteral, Atom, DeclarationPtr, Domain, Expression, FuncAttr, IntVal, JectivityAttr,
16    Literal, MSetAttr, Name, PartialityAttr, Range, RecordEntry, SetAttr, SymbolTable,
17    SymbolTablePtr,
18};
19use crate::ast::{DomainPtr, Metadata};
20use crate::context::Context;
21use crate::error::{Error, Result};
22use crate::{Model, bug, error, into_matrix_expr, throw_error};
23
24#[allow(unused_macros)]
25macro_rules! parser_trace {
26    ($($arg:tt)+) => {
27        log::trace!(target:"jsonparser",$($arg)+)
28    };
29}
30
31#[allow(unused_macros)]
32macro_rules! parser_debug {
33    ($($arg:tt)+) => {
34        log::debug!(target:"jsonparser",$($arg)+)
35    };
36}
37
38pub fn model_from_json(str: &str, context: Arc<RwLock<Context<'static>>>) -> Result<Model> {
39    let mut m = Model::new(context);
40    let v: JsonValue = serde_json::from_str(str)?;
41    let statements = v["mStatements"]
42        .as_array()
43        .ok_or(error!("mStatements is not an array"))?;
44
45    for statement in statements {
46        let entry = statement
47            .as_object()
48            .ok_or(error!("mStatements contains a non-object"))?
49            .iter()
50            .next()
51            .ok_or(error!("mStatements contains an empty object"))?;
52
53        match entry.0.as_str() {
54            "Declaration" => {
55                let decl = entry
56                    .1
57                    .as_object()
58                    .ok_or(error!("Declaration is not an object".to_owned()))?;
59
60                // One field in the declaration should tell us what kind it is.
61                //
62                // Find it, ignoring the other fields.
63                //
64                // e.g. FindOrGiven,
65
66                let mut valid_decl: bool = false;
67                let scope = m.symbols_ptr_unchecked().clone();
68                let model = &mut m;
69                for (kind, value) in decl {
70                    match kind.as_str() {
71                        "FindOrGiven" => {
72                            parse_variable(value, &mut model.symbols_mut())?;
73                            valid_decl = true;
74                            break;
75                        }
76                        "Letting" => {
77                            parse_letting(value, &scope)?;
78                            valid_decl = true;
79                            break;
80                        }
81                        _ => continue,
82                    }
83                }
84
85                if !valid_decl {
86                    throw_error!("Declaration is not a valid kind")?;
87                }
88            }
89            "SuchThat" => {
90                let constraints_arr = match entry.1.as_array() {
91                    Some(x) => x,
92                    None => bug!("SuchThat is not a vector"),
93                };
94
95                let constraints: Vec<Expression> = constraints_arr
96                    .iter()
97                    .map(|x| parse_expression(x, m.symbols_ptr_unchecked()))
98                    .collect::<Result<Vec<_>>>()?;
99                m.add_constraints(constraints);
100            }
101            otherwise => bug!("Unhandled Statement {:#?}", otherwise),
102        }
103    }
104    Ok(m)
105}
106
107fn parse_variable(v: &JsonValue, symtab: &mut SymbolTable) -> Result<()> {
108    let arr = v.as_array().ok_or(error!("FindOrGiven is not an array"))?;
109
110    let variable_type = arr[0]
111        .as_str()
112        .ok_or(error!("FindOrGiven[0] is not a string"))?;
113
114    let name = arr[1]
115        .as_object()
116        .ok_or(error!("FindOrGiven[1] is not an object"))?["Name"]
117        .as_str()
118        .ok_or(error!("FindOrGiven[1].Name is not a string"))?;
119
120    let name = Name::User(Ustr::from(name));
121
122    let domain = arr[2]
123        .as_object()
124        .ok_or(error!("FindOrGiven[2] is not an object"))?
125        .iter()
126        .next()
127        .ok_or(error!("FindOrGiven[2] is an empty object"))?;
128
129    let domain = parse_domain(domain.0, domain.1, symtab)?;
130
131    let decl = match variable_type {
132        "Find" => DeclarationPtr::new_find(name.clone(), domain),
133        "Given" => DeclarationPtr::new_given(name.clone(), domain),
134        _ => {
135            return Err(error!("FindOrGiven[0] is not 'Find' or 'Given'"));
136        }
137    };
138
139    symtab.insert(decl).ok_or(Error::Parse(format!(
140        "Could not add {name} to symbol table as it already exists"
141    )))
142}
143
144fn parse_letting(v: &JsonValue, scope: &SymbolTablePtr) -> Result<()> {
145    let arr = v.as_array().ok_or(error!("Letting is not an array"))?;
146    let name = arr[0]
147        .as_object()
148        .ok_or(error!("Letting[0] is not an object"))?["Name"]
149        .as_str()
150        .ok_or(error!("Letting[0].Name is not a string"))?;
151    let name = Name::User(Ustr::from(name));
152    // value letting
153    if let Ok(value) = parse_expression(&arr[1], scope) {
154        let mut symtab = scope.write();
155        symtab
156            .insert(DeclarationPtr::new_value_letting(name.clone(), value))
157            .ok_or(Error::Parse(format!(
158                "Could not add {name} to symbol table as it already exists"
159            )))
160    } else {
161        // domain letting
162        let domain = &arr[1]
163            .as_object()
164            .ok_or(error!("Letting[1] is not an object".to_owned()))?["Domain"]
165            .as_object()
166            .ok_or(error!("Letting[1].Domain is not an object"))?
167            .iter()
168            .next()
169            .ok_or(error!("Letting[1].Domain is an empty object"))?;
170
171        let mut symtab = scope.write();
172        let domain = parse_domain(domain.0, domain.1, &mut symtab)?;
173
174        symtab
175            .insert(DeclarationPtr::new_domain_letting(name.clone(), domain))
176            .ok_or(Error::Parse(format!(
177                "Could not add {name} to symbol table as it already exists"
178            )))
179    }
180}
181
182fn parse_domain(
183    domain_name: &str,
184    domain_value: &JsonValue,
185    symbols: &mut SymbolTable,
186) -> Result<DomainPtr> {
187    match domain_name {
188        "DomainInt" => Ok(parse_int_domain(domain_value, symbols)?),
189        "DomainBool" => Ok(Domain::bool()),
190        "DomainReference" => {
191            let name = Name::user(
192                domain_value
193                    .as_array()
194                    .ok_or(error!("DomainReference is not an array"))?[0]
195                    .as_object()
196                    .ok_or(error!("DomainReference[0] is not an object"))?["Name"]
197                    .as_str()
198                    .ok_or(error!("DomainReference[0].Name is not a string"))?,
199            );
200            let ptr = symbols
201                .lookup(&name)
202                .ok_or(error!(format!("Name {name} not found")))?;
203            let dom =
204                Domain::reference(ptr).ok_or(error!("Could not construct reference domain"))?;
205            Ok(dom)
206        }
207        "DomainSet" => {
208            let dom = domain_value.get(2).and_then(|v| v.as_object());
209            let domain_obj = dom.ok_or(error!("DomainSet is missing domain object"))?;
210            let domain = domain_obj
211                .iter()
212                .next()
213                .ok_or(Error::Parse("DomainSet is an empty object".to_owned()))?;
214            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
215            let size = domain_value
216                .get(1)
217                .and_then(|v| v.as_object())
218                .ok_or(error!("Set size attributes is not an object"))?;
219            let size = parse_size_attr(size, symbols)?;
220            let attr: SetAttr<IntVal> = SetAttr { size };
221            Ok(Domain::set(attr, domain))
222        }
223        "DomainMSet" => {
224            let dom = domain_value
225                .get(2)
226                .and_then(|v| v.as_object())
227                .expect("domain object exists");
228            let domain = dom
229                .iter()
230                .next()
231                .ok_or(Error::Parse("DomainMSet is an empty object".to_owned()))?;
232            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
233
234            // Parse Attributes
235            let attributes = domain_value
236                .get(1)
237                .and_then(|v| v.as_array())
238                .ok_or(error!("MSet attributes is not a json array"))?;
239
240            let size = attributes
241                .first()
242                .and_then(|v| v.as_object())
243                .ok_or(error!("MSet size attributes is not an object"))?;
244            let size = parse_size_attr(size, symbols)?;
245
246            let occurrence = attributes
247                .get(1)
248                .and_then(|v| v.as_object())
249                .ok_or(error!("MSet occurrence attributes is not an object"))?;
250            let occurrence = parse_occur_attr(occurrence, symbols)?;
251
252            let attr: MSetAttr<IntVal> = MSetAttr { size, occurrence };
253            Ok(Domain::mset(attr, domain))
254        }
255
256        "DomainMatrix" => {
257            let domain_value = domain_value
258                .as_array()
259                .ok_or(error!("Domain matrix is not an array"))?;
260
261            let indexed_by_domain = domain_value[0].clone();
262            let (index_domain_name, index_domain_value) = indexed_by_domain
263                .as_object()
264                .ok_or(error!("DomainMatrix[0] is not an object"))?
265                .iter()
266                .next()
267                .ok_or(error!(""))?;
268
269            let (value_domain_name, value_domain_value) = domain_value[1]
270                .as_object()
271                .ok_or(error!(""))?
272                .iter()
273                .next()
274                .ok_or(error!(""))?;
275
276            // Conjure stores a 2-d matrix as a matrix of a matrix.
277            //
278            // Therefore, the index is always a Domain.
279
280            let mut index_domains: Vec<DomainPtr> = vec![];
281
282            index_domains.push(parse_domain(
283                index_domain_name,
284                index_domain_value,
285                symbols,
286            )?);
287
288            // We want to store 2-d matrices as a matrix with two index domains, not a matrix in a
289            // matrix.
290            //
291            // Walk through the value domain until it is not a DomainMatrix, adding the index to
292            // our list of indices.
293            let mut value_domain = parse_domain(value_domain_name, value_domain_value, symbols)?;
294            while let Some((new_value_domain, mut indices)) = value_domain.as_matrix() {
295                index_domains.append(&mut indices);
296                value_domain = new_value_domain.clone()
297            }
298
299            Ok(Domain::matrix(value_domain, index_domains))
300        }
301        "DomainTuple" => {
302            let domain_value = domain_value
303                .as_array()
304                .ok_or(error!("Domain tuple is not an array"))?;
305
306            //iterate through the array and parse each domain
307            let domain = domain_value
308                .iter()
309                .map(|x| {
310                    let domain = x
311                        .as_object()
312                        .ok_or(error!("DomainTuple[0] is not an object"))?
313                        .iter()
314                        .next()
315                        .ok_or(error!("DomainTuple[0] is an empty object"))?;
316                    parse_domain(domain.0, domain.1, symbols)
317                })
318                .collect::<Result<Vec<DomainPtr>>>()?;
319
320            Ok(Domain::tuple(domain))
321        }
322        "DomainRecord" => {
323            let domain_value = domain_value
324                .as_array()
325                .ok_or(error!("Domain Record is not a json array"))?;
326
327            let mut record_entries = vec![];
328
329            for item in domain_value {
330                //collect the name of the record field
331                let name = item[0]
332                    .as_object()
333                    .ok_or(error!("FindOrGiven[1] is not an object"))?["Name"]
334                    .as_str()
335                    .ok_or(error!("FindOrGiven[1].Name is not a string"))?;
336
337                let name = Name::User(Ustr::from(name));
338                // then collect the domain of the record field
339                let domain = item[1]
340                    .as_object()
341                    .ok_or(error!("FindOrGiven[2] is not an object"))?
342                    .iter()
343                    .next()
344                    .ok_or(error!("FindOrGiven[2] is an empty object"))?;
345
346                let domain = parse_domain(domain.0, domain.1, symbols)?;
347
348                let rec = RecordEntry { name, domain };
349
350                record_entries.push(rec);
351            }
352
353            // add record fields to symbol table
354            for decl in record_entries
355                .iter()
356                .cloned()
357                .map(DeclarationPtr::new_record_field)
358            {
359                symbols.insert(decl).ok_or(error!(
360                    "record field should not already be in the symbol table"
361                ))?;
362            }
363
364            Ok(Domain::record(record_entries))
365        }
366        "DomainFunction" => {
367            let domain = domain_value
368                .get(2)
369                .and_then(|v| v.as_object())
370                .ok_or(error!("Function domain is not an object"))?;
371            let domain = domain
372                .iter()
373                .next()
374                .ok_or(Error::Parse("DomainSet is an empty object".to_owned()))?;
375            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
376
377            let codomain = domain_value
378                .get(3)
379                .and_then(|v| v.as_object())
380                .ok_or(error!("Function codomain is not an object"))?;
381            let codomain = codomain
382                .iter()
383                .next()
384                .ok_or(Error::Parse("DomainSet is an empty object".to_owned()))?;
385            let codomain = parse_domain(codomain.0.as_str(), codomain.1, symbols)?;
386
387            // Attribute parsing
388            let attributes = domain_value
389                .get(1)
390                .and_then(|v| v.as_array())
391                .ok_or(error!("Function attributes is not a json array"))?;
392            let size = attributes
393                .first()
394                .and_then(|v| v.as_object())
395                .ok_or(error!("Function size attributes is not an object"))?;
396            let size = parse_size_attr(size, symbols)?;
397            let partiality = attributes
398                .get(1)
399                .and_then(|v| v.as_str())
400                .ok_or(error!("Function partiality is not a string"))?;
401            let partiality = match partiality {
402                "PartialityAttr_Partial" => Some(PartialityAttr::Partial),
403                "PartialityAttr_Total" => Some(PartialityAttr::Total),
404                _ => None,
405            };
406            let partiality =
407                partiality.ok_or(Error::Parse("Partiality is an unknown type".to_owned()))?;
408            let jectivity = attributes
409                .get(2)
410                .and_then(|v| v.as_str())
411                .ok_or(error!("Function jectivity is not a string"))?;
412            let jectivity = match jectivity {
413                "JectivityAttr_Injective" => Some(JectivityAttr::Injective),
414                "JectivityAttr_Surjective" => Some(JectivityAttr::Surjective),
415                "JectivityAttr_Bijective" => Some(JectivityAttr::Bijective),
416                "JectivityAttr_None" => Some(JectivityAttr::None),
417                _ => None,
418            };
419            let jectivity =
420                jectivity.ok_or(Error::Parse("Jectivity is an unknown type".to_owned()))?;
421
422            let attr: FuncAttr<IntVal> = FuncAttr {
423                size,
424                partiality,
425                jectivity,
426            };
427
428            Ok(Domain::function(attr, domain, codomain))
429        }
430        _ => Err(Error::Parse(
431            "FindOrGiven[2] is an unknown object".to_owned(), // consider covered
432        )),
433    }
434}
435
436fn parse_size_attr(
437    attr_map: &JsonMap<String, JsonValue>,
438    symbols: &mut SymbolTable,
439) -> Result<Range<IntVal>> {
440    let scope = SymbolTablePtr::new();
441    *scope.write() = symbols.clone();
442
443    let attr_obj = attr_map
444        .iter()
445        .next()
446        .ok_or(Error::Parse("SizeAttr is an empty object".to_owned()))?;
447    match attr_obj.0.as_str() {
448        "SizeAttr_None" => Ok(Range::Unbounded),
449        "SizeAttr_MinSize" => {
450            let size = parse_expression_to_int_val(attr_obj.1, &scope)?;
451            Ok(Range::UnboundedR(size))
452        }
453        "SizeAttr_MaxSize" => {
454            let size = parse_expression_to_int_val(attr_obj.1, &scope)?;
455            Ok(Range::UnboundedL(size))
456        }
457        "SizeAttr_MinMaxSize" => {
458            let min_max = attr_obj
459                .1
460                .as_array()
461                .ok_or(error!("SizeAttr MinMaxSize is not a json array"))?;
462            let min = min_max
463                .first()
464                .ok_or(error!("SizeAttr Min is not present"))?;
465            let min_int = parse_expression_to_int_val(min, &scope)?;
466            let max = min_max
467                .get(1)
468                .ok_or(error!("SizeAttr Max is not present"))?;
469            let max_int = parse_expression_to_int_val(max, &scope)?;
470            Ok(Range::Bounded(min_int, max_int))
471        }
472        "SizeAttr_Size" => {
473            let size = parse_expression_to_int_val(attr_obj.1, &scope)?;
474            Ok(Range::Single(size))
475        }
476        _ => Err(Error::Parse("SizeAttr is an unknown type".to_owned())),
477    }
478}
479
480fn parse_occur_attr(
481    attr_map: &JsonMap<String, JsonValue>,
482    symbols: &mut SymbolTable,
483) -> Result<Range<IntVal>> {
484    let scope = SymbolTablePtr::new();
485    *scope.write() = symbols.clone();
486    let attr_obj = attr_map
487        .iter()
488        .next()
489        .ok_or(Error::Parse("OccurAttr is an empty object".to_owned()))?;
490    match attr_obj.0.as_str() {
491        "OccurAttr_None" => Ok(Range::Unbounded),
492        "OccurAttr_MinOccur" => {
493            let size_int = parse_expression_to_int_val(attr_obj.1, &scope)?;
494            Ok(Range::UnboundedR(size_int))
495        }
496        "OccurAttr_MaxOccur" => {
497            let size_int = parse_expression_to_int_val(attr_obj.1, &scope)?;
498            Ok(Range::UnboundedL(size_int))
499        }
500        "OccurAttr_MinMaxOccur" => {
501            let min_max = attr_obj
502                .1
503                .as_array()
504                .ok_or(error!("OccurAttr MinMaxOccur is not a json array"))?;
505            let min = min_max
506                .first()
507                .ok_or(error!("OccurAttr Min is not present"))?;
508            let min_int = parse_expression_to_int_val(min, &scope)?;
509            let max = min_max
510                .get(1)
511                .ok_or(error!("OccurAttr Max is not present"))?;
512            let max_int = parse_expression_to_int_val(max, &scope)?;
513            Ok(Range::Bounded(min_int, max_int))
514        }
515        "OccurAttr_Size" => {
516            let size_int = parse_expression_to_int_val(attr_obj.1, &scope)?;
517            Ok(Range::Single(size_int))
518        }
519        _ => Err(Error::Parse("OccurAttr is an unknown type".to_owned())),
520    }
521}
522
523fn parse_int_domain(v: &JsonValue, symbols: &SymbolTable) -> Result<DomainPtr> {
524    let scope = SymbolTablePtr::new();
525    *scope.write() = symbols.clone();
526
527    let mut ranges = Vec::new();
528    let arr = v
529        .as_array()
530        .ok_or(error!("DomainInt is not an array".to_owned()))?[1]
531        .as_array()
532        .ok_or(error!("DomainInt[1] is not an array".to_owned()))?;
533    for range in arr {
534        let range = range
535            .as_object()
536            .ok_or(error!("DomainInt[1] contains a non-object"))?
537            .iter()
538            .next()
539            .ok_or(error!("DomainInt[1] contains an empty object"))?;
540        match range.0.as_str() {
541            "RangeBounded" => {
542                let arr = range
543                    .1
544                    .as_array()
545                    .ok_or(error!("RangeBounded is not an array".to_owned()))?;
546                let mut nums = Vec::new();
547                for item in arr.iter() {
548                    let num = parse_expression_to_int_val(item, &scope)?;
549                    nums.push(num);
550                }
551                let lower = nums
552                    .first()
553                    .cloned()
554                    .ok_or(error!("RangeBounded lower bound missing"))?;
555                let upper = nums
556                    .get(1)
557                    .cloned()
558                    .ok_or(error!("RangeBounded upper bound missing"))?;
559                ranges.push(Range::Bounded(lower, upper));
560            }
561            "RangeSingle" => {
562                let num = parse_expression_to_int_val(range.1, &scope)?;
563                ranges.push(Range::Single(num));
564            }
565            _ => return throw_error!("DomainInt[1] contains an unknown object"),
566        }
567    }
568    Ok(Domain::int(ranges))
569}
570
571fn parse_expression_to_int_val(obj: &JsonValue, scope: &SymbolTablePtr) -> Result<IntVal> {
572    parser_trace!("trying to parse domain value as expression: {}", obj);
573    let expr = parse_expression(obj, scope)?;
574
575    if let Some(Literal::Int(i)) = expr.clone().into_literal() {
576        return Ok(IntVal::Const(i));
577    }
578
579    if let Expression::Atomic(_, Atom::Reference(reference)) = &expr
580        && let Some(reference_val) = IntVal::new_ref(reference)
581    {
582        return Ok(reference_val);
583    }
584
585    IntVal::new_expr(Moo::new(expr)).ok_or(error!("Could not parse integer expression"))
586}
587
588type BinOp = fn(Metadata, Moo<Expression>, Moo<Expression>) -> Expression;
589type UnaryOp = fn(Metadata, Moo<Expression>) -> Expression;
590
591fn binary_operator(op_name: &str) -> Option<BinOp> {
592    match op_name {
593        "MkOpIn" => Some(Expression::In),
594        "MkOpUnion" => Some(Expression::Union),
595        "MkOpIntersect" => Some(Expression::Intersect),
596        "MkOpSupset" => Some(Expression::Supset),
597        "MkOpSupsetEq" => Some(Expression::SupsetEq),
598        "MkOpSubset" => Some(Expression::Subset),
599        "MkOpSubsetEq" => Some(Expression::SubsetEq),
600        "MkOpEq" => Some(Expression::Eq),
601        "MkOpNeq" => Some(Expression::Neq),
602        "MkOpGeq" => Some(Expression::Geq),
603        "MkOpLeq" => Some(Expression::Leq),
604        "MkOpGt" => Some(Expression::Gt),
605        "MkOpLt" => Some(Expression::Lt),
606        "MkOpLexLt" => Some(Expression::LexLt),
607        "MkOpLexGt" => Some(Expression::LexGt),
608        "MkOpLexLeq" => Some(Expression::LexLeq),
609        "MkOpLexGeq" => Some(Expression::LexGeq),
610        "MkOpDiv" => Some(Expression::UnsafeDiv),
611        "MkOpMod" => Some(Expression::UnsafeMod),
612        "MkOpMinus" => Some(Expression::Minus),
613        "MkOpImply" => Some(Expression::Imply),
614        "MkOpIff" => Some(Expression::Iff),
615        "MkOpPow" => Some(Expression::UnsafePow),
616        "MkOpImage" => Some(Expression::Image),
617        "MkOpImageSet" => Some(Expression::ImageSet),
618        "MkOpPreImage" => Some(Expression::PreImage),
619        "MkOpInverse" => Some(Expression::Inverse),
620        "MkOpRestrict" => Some(Expression::Restrict),
621        _ => None,
622    }
623}
624
625fn unary_operator(op_name: &str) -> Option<UnaryOp> {
626    match op_name {
627        "MkOpNot" => Some(Expression::Not),
628        "MkOpNegate" => Some(Expression::Neg),
629        "MkOpTwoBars" => Some(Expression::Abs),
630        "MkOpAnd" => Some(Expression::And),
631        "MkOpSum" => Some(Expression::Sum),
632        "MkOpProduct" => Some(Expression::Product),
633        "MkOpOr" => Some(Expression::Or),
634        "MkOpMin" => Some(Expression::Min),
635        "MkOpMax" => Some(Expression::Max),
636        "MkOpAllDiff" => Some(Expression::AllDiff),
637        "MkOpToInt" => Some(Expression::ToInt),
638        "MkOpDefined" => Some(Expression::Defined),
639        "MkOpRange" => Some(Expression::Range),
640        "MkOpFactorial" => Some(Expression::Factorial),
641        _ => None,
642    }
643}
644
645pub fn parse_expression(obj: &JsonValue, scope: &SymbolTablePtr) -> Result<Expression> {
646    let fail = |stage: &str| -> Error {
647        Error::Parse(format!(
648            "Could not parse expression at stage `{stage}` for json `{obj}`"
649        ))
650    };
651
652    match obj {
653        Value::Object(op) if op.contains_key("Op") => {
654            let op_obj = op
655                .get("Op")
656                .and_then(Value::as_object)
657                .ok_or_else(|| fail("Op.as_object"))?;
658            let (op_name, _) = op_obj.iter().next().ok_or_else(|| fail("Op.iter().next"))?;
659
660            if op_obj.contains_key("MkOpFlatten") {
661                parse_flatten_op(op_obj, scope)
662            } else if op_obj.contains_key("MkOpTable") {
663                parse_table_op(op_obj, scope)
664            } else if op_obj.contains_key("MkOpIndexing") || op_obj.contains_key("MkOpSlicing") {
665                parse_indexing_slicing_op(op_obj, scope)
666            } else if binary_operator(op_name).is_some() {
667                parse_bin_op(op_obj, scope)
668            } else if unary_operator(op_name).is_some() {
669                parse_unary_op(op_obj, scope)
670            } else {
671                Err(fail("Op.unknown"))
672            }
673        }
674        Value::Object(comprehension) if comprehension.contains_key("Comprehension") => {
675            parse_comprehension(comprehension, scope.clone(), None)
676        }
677        Value::Object(refe) if refe.contains_key("Reference") => {
678            let ref_arr = refe["Reference"]
679                .as_array()
680                .ok_or_else(|| fail("Reference.as_array"))?;
681            let ref_obj = ref_arr
682                .first()
683                .and_then(|x| x.as_object())
684                .ok_or_else(|| fail("Reference[0].as_object"))?;
685            let name = ref_obj
686                .get("Name")
687                .and_then(|x| x.as_str())
688                .ok_or_else(|| fail("Reference[0].Name.as_str"))?;
689            let user_name = Name::User(Ustr::from(name));
690
691            let declaration: DeclarationPtr = scope
692                .read()
693                .lookup(&user_name)
694                .ok_or_else(|| fail("Reference.lookup"))?;
695
696            Ok(Expression::Atomic(
697                Metadata::new(),
698                Atom::Reference(crate::ast::Reference::new(declaration)),
699            ))
700        }
701        Value::Object(abslit) if abslit.contains_key("AbstractLiteral") => {
702            let abstract_literal = abslit["AbstractLiteral"]
703                .as_object()
704                .ok_or_else(|| fail("AbstractLiteral.as_object"))?;
705
706            if abstract_literal.contains_key("AbsLitSet") {
707                parse_abs_lit(&abslit["AbstractLiteral"]["AbsLitSet"], scope)
708            } else if abstract_literal.contains_key("AbsLitFunction") {
709                parse_abs_function(&abslit["AbstractLiteral"]["AbsLitFunction"], scope)
710            } else if abstract_literal.contains_key("AbsLitMSet") {
711                parse_abs_mset(&abslit["AbstractLiteral"]["AbsLitMSet"], scope)
712            } else {
713                parse_abstract_matrix_as_expr(obj, scope)
714            }
715        }
716
717        Value::Object(constant) if constant.contains_key("Constant") => {
718            parse_constant(constant, scope).or_else(|_| parse_abstract_matrix_as_expr(obj, scope))
719        }
720
721        Value::Object(constant) if constant.contains_key("ConstantAbstract") => {
722            parse_abstract_matrix_as_expr(obj, scope)
723        }
724
725        Value::Object(constant) if constant.contains_key("ConstantInt") => {
726            parse_constant(constant, scope)
727        }
728        Value::Object(constant) if constant.contains_key("ConstantBool") => {
729            parse_constant(constant, scope)
730        }
731
732        _ => Err(fail("no_match")),
733    }
734}
735
736fn parse_abs_lit(abs_set: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
737    let values = abs_set
738        .as_array()
739        .ok_or(error!("AbsLitSet is not an array"))?;
740    let expressions = values
741        .iter()
742        .map(|values| parse_expression(values, scope))
743        .collect::<Result<Vec<_>>>()?;
744
745    Ok(Expression::AbstractLiteral(
746        Metadata::new(),
747        AbstractLiteral::Set(expressions),
748    ))
749}
750
751fn parse_abs_mset(abs_mset: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
752    let values = abs_mset
753        .as_array()
754        .ok_or(error!("AbsLitMSet is not an array"))?;
755    let expressions = values
756        .iter()
757        .map(|values| parse_expression(values, scope))
758        .collect::<Result<Vec<_>>>()?;
759
760    Ok(Expression::AbstractLiteral(
761        Metadata::new(),
762        AbstractLiteral::MSet(expressions),
763    ))
764}
765
766fn parse_abs_tuple(abs_tuple: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
767    let values = abs_tuple
768        .as_array()
769        .ok_or(error!("AbsLitTuple is not an array"))?;
770    let expressions = values
771        .iter()
772        .map(|values| parse_expression(values, scope))
773        .collect::<Result<Vec<_>>>()?;
774
775    Ok(Expression::AbstractLiteral(
776        Metadata::new(),
777        AbstractLiteral::Tuple(expressions),
778    ))
779}
780
781//parses an abstract record as an expression
782fn parse_abs_record(abs_record: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
783    let entries = abs_record
784        .as_array()
785        .ok_or(error!("AbsLitRecord is not an array"))?;
786    let mut rec = vec![];
787
788    for entry in entries {
789        let entry = entry
790            .as_array()
791            .ok_or(error!("AbsLitRecord entry is not an array"))?;
792        let name = entry[0]
793            .as_object()
794            .ok_or(error!("AbsLitRecord field name is not an object"))?["Name"]
795            .as_str()
796            .ok_or(error!("AbsLitRecord field name is not a string"))?;
797
798        let value = parse_expression(&entry[1], scope)?;
799
800        let name = Name::User(Ustr::from(name));
801        let rec_entry = RecordValue {
802            name: name.clone(),
803            value,
804        };
805        rec.push(rec_entry);
806    }
807
808    Ok(Expression::AbstractLiteral(
809        Metadata::new(),
810        AbstractLiteral::Record(rec),
811    ))
812}
813
814//parses an abstract function as an expression
815fn parse_abs_function(abs_function: &Value, scope: &SymbolTablePtr) -> Result<Expression> {
816    let entries = abs_function
817        .as_array()
818        .ok_or(error!("AbsLitFunction is not an array"))?;
819    let mut assignments = vec![];
820
821    for entry in entries {
822        let entry = entry
823            .as_array()
824            .ok_or(error!("Explicit function assignment is not an array"))?;
825        let expression = entry
826            .iter()
827            .map(|values| parse_expression(values, scope))
828            .collect::<Result<Vec<_>>>()?;
829        let domain_value = expression
830            .first()
831            .ok_or(error!("Invalid function domain"))?;
832        let codomain_value = expression
833            .get(1)
834            .ok_or(error!("Invalid function codomain"))?;
835        let tuple = (domain_value.clone(), codomain_value.clone());
836        assignments.push(tuple);
837    }
838    Ok(Expression::AbstractLiteral(
839        Metadata::new(),
840        AbstractLiteral::Function(assignments),
841    ))
842}
843
844fn parse_comprehension(
845    comprehension: &serde_json::Map<String, Value>,
846    scope: SymbolTablePtr,
847    comprehension_kind: Option<ACOperatorKind>,
848) -> Result<Expression> {
849    let fail = |stage: &str| -> Error {
850        Error::Parse(format!("Could not parse comprehension at stage `{stage}`"))
851    };
852
853    let value = &comprehension["Comprehension"];
854    let mut comprehension = ComprehensionBuilder::new(scope.clone());
855    let generator_symboltable = comprehension.generator_symboltable();
856    let return_expr_symboltable = comprehension.return_expr_symboltable();
857
858    let generators_and_guards_array = value
859        .pointer("/1")
860        .and_then(Value::as_array)
861        .ok_or_else(|| fail("Comprehension.pointer(/1).as_array"))?;
862    let generators_and_guards = generators_and_guards_array.iter();
863
864    for gen_or_guard in generators_and_guards {
865        let gen_or_guard_obj = gen_or_guard
866            .as_object()
867            .ok_or_else(|| fail("generator_or_guard.as_object"))?;
868        let (name, inner) = gen_or_guard_obj
869            .iter()
870            .next()
871            .ok_or_else(|| fail("generator_or_guard.iter().next"))?;
872        comprehension = match name.as_str() {
873            "Generator" => {
874                // TODO: more things than GenDomainNoRepr and Single names here?
875                let generator_obj = inner
876                    .as_object()
877                    .ok_or_else(|| fail("Generator.inner.as_object"))?;
878                let (name, gen_inner) = generator_obj
879                    .iter()
880                    .next()
881                    .ok_or_else(|| fail("Generator.inner.iter().next"))?;
882                match name.as_str() {
883                    "GenDomainNoRepr" => {
884                        let name = gen_inner
885                            .pointer("/0/Single/Name")
886                            .and_then(Value::as_str)
887                            .ok_or_else(|| {
888                                fail("GenDomainNoRepr.pointer(/0/Single/Name).as_str")
889                            })?;
890                        let domain_obj = gen_inner
891                            .pointer("/1")
892                            .and_then(Value::as_object)
893                            .ok_or_else(|| fail("GenDomainNoRepr.pointer(/1).as_object"))?;
894                        let (domain_name, domain_value) = domain_obj
895                            .iter()
896                            .next()
897                            .ok_or_else(|| fail("GenDomainNoRepr.domain.iter().next"))?;
898                        let domain = parse_domain(
899                            domain_name,
900                            domain_value,
901                            &mut generator_symboltable.write(),
902                        )?;
903                        comprehension.generator(DeclarationPtr::new_find(name.into(), domain))
904                    }
905                    "GenInExpr" => {
906                        let name = gen_inner
907                            .pointer("/0/Single/Name")
908                            .and_then(Value::as_str)
909                            .ok_or_else(|| {
910                                fail("GenDomainNoRepr.pointer(/0/Single/Name).as_str")
911                            })?;
912                        let generator_expr = gen_inner
913                            .pointer("/1")
914                            .ok_or_else(|| fail("GenInExpr.pointer(/1)"))?;
915                        let expr = parse_expression(generator_expr, &scope)
916                            .map_err(|_| fail("GenInExpr.parse_expression"))?;
917                        comprehension.expression_generator(name.into(), expr)
918                    }
919                    _ => {
920                        bug!("unknown generator type inside comprehension {name}");
921                    }
922                }
923            }
924
925            "Condition" => {
926                let expr = parse_expression(inner, &generator_symboltable)
927                    .map_err(|_| fail("Condition.parse_expression"))?;
928                comprehension.guard(expr)
929            }
930
931            x => {
932                bug!("unknown field inside comprehension {x}");
933            }
934        }
935    }
936
937    let return_expr_value = value
938        .pointer("/0")
939        .ok_or_else(|| fail("Comprehension.pointer(/0)"))?;
940    let expr = parse_expression(return_expr_value, &return_expr_symboltable)
941        .map_err(|_| fail("Comprehension.return_expr.parse_expression"))?;
942
943    Ok(Expression::Comprehension(
944        Metadata::new(),
945        Moo::new(comprehension.with_return_value(expr, comprehension_kind)),
946    ))
947}
948
949fn parse_bin_op(
950    bin_op: &serde_json::Map<String, Value>,
951    scope: &SymbolTablePtr,
952) -> Result<Expression> {
953    // we know there is a single key value pair in this object
954    // extract the value, ignore the key
955    let (key, value) = bin_op
956        .into_iter()
957        .next()
958        .ok_or(error!("Binary op object is empty"))?;
959
960    let constructor = binary_operator(key.as_str())
961        .ok_or(error!(format!("Unknown binary operator `{}`", key)))?;
962
963    match &value {
964        Value::Array(bin_op_args) if bin_op_args.len() == 2 => {
965            let arg1 = parse_expression(&bin_op_args[0], scope)?;
966            let arg2 = parse_expression(&bin_op_args[1], scope)?;
967            Ok(constructor(Metadata::new(), Moo::new(arg1), Moo::new(arg2)))
968        }
969        _ => Err(error!("Binary operator arguments are not a 2-array")),
970    }
971}
972
973fn parse_table_op(
974    op: &serde_json::Map<String, Value>,
975    scope: &SymbolTablePtr,
976) -> Result<Expression> {
977    let args = op
978        .get("MkOpTable")
979        .ok_or(error!("MkOpTable missing"))?
980        .as_array()
981        .ok_or(error!("MkOpTable is not an array"))?;
982
983    if args.len() != 2 {
984        return Err(error!("MkOpTable arguments are not a 2-array"));
985    }
986
987    let tuple_expr = parse_expression(&args[0], scope)?;
988    let allowed_rows_expr = parse_expression(&args[1], scope)?;
989
990    let (tuple_elems, _) = tuple_expr
991        .clone()
992        .unwrap_matrix_unchecked()
993        .ok_or(error!("MkOpTable first argument is not a matrix"))?;
994    let (allowed_rows, _) = allowed_rows_expr
995        .clone()
996        .unwrap_matrix_unchecked()
997        .ok_or(error!("MkOpTable second argument is not a matrix"))?;
998
999    for row_expr in allowed_rows {
1000        let (row_elems, _) = row_expr
1001            .unwrap_matrix_unchecked()
1002            .ok_or(error!("MkOpTable row is not a matrix"))?;
1003
1004        if row_elems.len() != tuple_elems.len() {
1005            return Err(error!("MkOpTable row width does not match tuple width"));
1006        }
1007    }
1008
1009    Ok(Expression::Table(
1010        Metadata::new(),
1011        Moo::new(tuple_expr),
1012        Moo::new(allowed_rows_expr),
1013    ))
1014}
1015
1016fn parse_indexing_slicing_op(
1017    op: &serde_json::Map<String, Value>,
1018    scope: &SymbolTablePtr,
1019) -> Result<Expression> {
1020    // we know there is a single key value pair in this object
1021    // extract the value, ignore the key
1022    let (key, value) = op
1023        .into_iter()
1024        .next()
1025        .ok_or(error!("Indexing/Slicing op object is empty"))?;
1026
1027    // we know that this is meant to be a mkopindexing, so anything that goes wrong from here is a
1028    // bug!
1029
1030    // Conjure does a[1,2,3] as MkOpIndexing(MkOpIndexing(MkOpIndexing(a,3),2),1).
1031    //
1032    // And  a[1,..,3] as MkOpIndexing(MkOpSlicing(MkOpIndexing(a,3)),1).
1033    //
1034    // However, we want this in a flattened form: Index(a, [1,2,3])
1035    let mut target: Expression;
1036    let mut indices: Vec<Option<Expression>> = vec![];
1037
1038    // true if this has no slicing, false otherwise.
1039    let mut all_known = true;
1040
1041    match key.as_str() {
1042        "MkOpIndexing" => {
1043            match &value {
1044                Value::Array(op_args) if op_args.len() == 2 => {
1045                    target = parse_expression(&op_args[0], scope)?;
1046                    indices.push(Some(parse_expression(&op_args[1], scope)?));
1047                }
1048                _ => return Err(error!("Unknown object inside MkOpIndexing")),
1049            };
1050        }
1051
1052        "MkOpSlicing" => {
1053            all_known = false;
1054            match &value {
1055                Value::Array(op_args) if op_args.len() == 3 => {
1056                    target = parse_expression(&op_args[0], scope)?;
1057                    indices.push(None);
1058                }
1059                _ => return Err(error!("Unknown object inside MkOpSlicing")),
1060            };
1061        }
1062
1063        _ => return Err(error!("Unknown indexing/slicing operator")),
1064    }
1065
1066    loop {
1067        match &mut target {
1068            Expression::UnsafeIndex(_, new_target, new_indices) => {
1069                indices.extend(new_indices.iter().cloned().rev().map(Some));
1070                target = Moo::unwrap_or_clone(new_target.clone());
1071            }
1072
1073            Expression::UnsafeSlice(_, new_target, new_indices) => {
1074                all_known = false;
1075                indices.extend(new_indices.iter().cloned().rev());
1076                target = Moo::unwrap_or_clone(new_target.clone());
1077            }
1078
1079            _ => {
1080                // not a slice or an index, we have reached the target.
1081                break;
1082            }
1083        }
1084    }
1085
1086    indices.reverse();
1087
1088    if all_known {
1089        Ok(Expression::UnsafeIndex(
1090            Metadata::new(),
1091            Moo::new(target),
1092            indices
1093                .into_iter()
1094                .collect::<Option<Vec<_>>>()
1095                .ok_or(error!("Missing index in fully-known indexing operation"))?,
1096        ))
1097    } else {
1098        Ok(Expression::UnsafeSlice(
1099            Metadata::new(),
1100            Moo::new(target),
1101            indices,
1102        ))
1103    }
1104}
1105
1106fn parse_flatten_op(
1107    op: &serde_json::Map<String, Value>,
1108    scope: &SymbolTablePtr,
1109) -> Result<Expression> {
1110    let args = op
1111        .get("MkOpFlatten")
1112        .ok_or(error!("MkOpFlatten missing"))?
1113        .as_array()
1114        .ok_or(error!("MkOpFlatten is not an array"))?;
1115
1116    let first = args
1117        .first()
1118        .ok_or(error!("MkOpFlatten missing first argument"))?;
1119    let second = args
1120        .get(1)
1121        .ok_or(error!("MkOpFlatten missing second argument"))?;
1122    let n = parse_expression(first, scope).ok();
1123    let matrix = parse_expression(second, scope)?;
1124
1125    if let Some(n) = n {
1126        Ok(Expression::Flatten(
1127            Metadata::new(),
1128            Some(Moo::new(n)),
1129            Moo::new(matrix),
1130        ))
1131    } else {
1132        Ok(Expression::Flatten(Metadata::new(), None, Moo::new(matrix)))
1133    }
1134}
1135
1136fn parse_unary_op(
1137    un_op: &serde_json::Map<String, Value>,
1138    scope: &SymbolTablePtr,
1139) -> Result<Expression> {
1140    let fail = |stage: &str| -> Error {
1141        Error::Parse(format!("Could not parse unary op at stage `{stage}`"))
1142    };
1143
1144    let (key, value) = un_op
1145        .iter()
1146        .next()
1147        .ok_or_else(|| fail("un_op.iter().next"))?;
1148    let constructor = unary_operator(key.as_str()).ok_or_else(|| fail("unary_operator"))?;
1149
1150    // unops are the main things that contain comprehensions
1151    //
1152    // if the current expr is a quantifier like and/or/sum and it contains a comprehension, let the comprehension know what it is inside.
1153    let arg = match value {
1154        Value::Object(comprehension) if comprehension.contains_key("Comprehension") => {
1155            let comprehension_kind = match key.as_str() {
1156                "MkOpOr" => Some(ACOperatorKind::Or),
1157                "MkOpAnd" => Some(ACOperatorKind::And),
1158                "MkOpSum" => Some(ACOperatorKind::Sum),
1159                "MkOpProduct" => Some(ACOperatorKind::Product),
1160                _ => None,
1161            };
1162            parse_comprehension(comprehension, scope.clone(), comprehension_kind)
1163                .map_err(|_| fail("value.Comprehension.parse_comprehension"))
1164        }
1165        _ => parse_expression(value, scope).map_err(|_| fail("value.parse_expression")),
1166    }
1167    .map_err(|_| fail("arg"))?;
1168
1169    Ok(constructor(Metadata::new(), Moo::new(arg)))
1170}
1171
1172// Takes in { AbstractLiteral: .... }
1173fn parse_abstract_matrix_as_expr(
1174    value: &serde_json::Value,
1175    scope: &SymbolTablePtr,
1176) -> Result<Expression> {
1177    parser_trace!("trying to parse an abstract literal matrix");
1178    let (values, domain_name, domain_value) =
1179        if let Some(abs_lit_matrix) = value.pointer("/AbstractLiteral/AbsLitMatrix") {
1180            parser_trace!(".. found JSON pointer /AbstractLiteral/AbstractLitMatrix");
1181            let (domain_name, domain_value) = abs_lit_matrix
1182                .pointer("/0")
1183                .and_then(Value::as_object)
1184                .and_then(|x| x.iter().next())
1185                .ok_or(error!("AbsLitMatrix missing domain"))?;
1186            let values = abs_lit_matrix
1187                .pointer("/1")
1188                .ok_or(error!("AbsLitMatrix missing values"))?;
1189
1190            Some((values, domain_name, domain_value))
1191        }
1192        // the input of this expression is constant - e.g. or([]), or([false]), min([2]), etc.
1193        else if let Some(const_abs_lit_matrix) =
1194            value.pointer("/Constant/ConstantAbstract/AbsLitMatrix")
1195        {
1196            parser_trace!(".. found JSON pointer /Constant/ConstantAbstract/AbsLitMatrix");
1197            let (domain_name, domain_value) = const_abs_lit_matrix
1198                .pointer("/0")
1199                .and_then(Value::as_object)
1200                .and_then(|x| x.iter().next())
1201                .ok_or(error!("ConstantAbstract AbsLitMatrix missing domain"))?;
1202            let values = const_abs_lit_matrix
1203                .pointer("/1")
1204                .ok_or(error!("ConstantAbstract AbsLitMatrix missing values"))?;
1205
1206            Some((values, domain_name, domain_value))
1207        } else if let Some(const_abs_lit_matrix) = value.pointer("/ConstantAbstract/AbsLitMatrix") {
1208            parser_trace!(".. found JSON pointer /ConstantAbstract/AbsLitMatrix");
1209            let (domain_name, domain_value) = const_abs_lit_matrix
1210                .pointer("/0")
1211                .and_then(Value::as_object)
1212                .and_then(|x| x.iter().next())
1213                .ok_or(error!("ConstantAbstract/AbsLitMatrix missing domain"))?;
1214            let values = const_abs_lit_matrix
1215                .pointer("/1")
1216                .ok_or(error!("ConstantAbstract/AbsLitMatrix missing values"))?;
1217            Some((values, domain_name, domain_value))
1218        } else {
1219            None
1220        }
1221        .ok_or(error!("Could not parse abstract literal matrix"))?;
1222
1223    parser_trace!(".. found in domain and values in JSON:");
1224    parser_trace!(".. .. index domain name {domain_name}");
1225    parser_trace!(".. .. values {value}");
1226
1227    let args_parsed = values
1228        .as_array()
1229        .ok_or(error!("Matrix values are not an array"))?
1230        .iter()
1231        .map(|x| parse_expression(x, scope))
1232        .collect::<Result<Vec<Expression>>>()?;
1233
1234    if !args_parsed.is_empty() {
1235        parser_trace!(
1236            ".. successfully parsed values as expressions: {}, ... ",
1237            args_parsed[0]
1238        );
1239    } else {
1240        parser_trace!(".. successfully parsed empty values ",);
1241    }
1242
1243    let mut symbols = scope.write();
1244    match parse_domain(domain_name, domain_value, &mut symbols) {
1245        Ok(domain) => {
1246            parser_trace!("... sucessfully parsed domain as {domain}");
1247            Ok(into_matrix_expr![args_parsed;domain])
1248        }
1249        Err(_) => {
1250            parser_trace!("... failed to parse domain, creating a matrix without one.");
1251            Ok(into_matrix_expr![args_parsed])
1252        }
1253    }
1254}
1255
1256fn parse_constant(
1257    constant: &serde_json::Map<String, Value>,
1258    scope: &SymbolTablePtr,
1259) -> Result<Expression> {
1260    match &constant.get("Constant") {
1261        Some(Value::Object(int)) if int.contains_key("ConstantInt") => {
1262            let int_32: i32 = match int["ConstantInt"]
1263                .as_array()
1264                .ok_or(error!("ConstantInt is not an array"))?[1]
1265                .as_i64()
1266                .ok_or(error!("ConstantInt does not contain int"))?
1267                .try_into()
1268            {
1269                Ok(x) => x,
1270                Err(_) => return Err(error!("ConstantInt cannot be represented as i32")),
1271            };
1272
1273            Ok(Expression::Atomic(
1274                Metadata::new(),
1275                Atom::Literal(Literal::Int(int_32)),
1276            ))
1277        }
1278
1279        Some(Value::Object(b)) if b.contains_key("ConstantBool") => {
1280            let b: bool = b["ConstantBool"]
1281                .as_bool()
1282                .ok_or(error!("ConstantBool does not contain bool"))?;
1283            Ok(Expression::Atomic(
1284                Metadata::new(),
1285                Atom::Literal(Literal::Bool(b)),
1286            ))
1287        }
1288
1289        Some(Value::Object(int)) if int.contains_key("ConstantAbstract") => {
1290            if let Some(Value::Object(obj)) = int.get("ConstantAbstract") {
1291                if let Some(arr) = obj.get("AbsLitSet") {
1292                    return parse_abs_lit(arr, scope);
1293                } else if let Some(arr) = obj.get("AbsLitMSet") {
1294                    return parse_abs_mset(arr, scope);
1295                } else if let Some(arr) = obj.get("AbsLitMatrix") {
1296                    return parse_abstract_matrix_as_expr(arr, scope);
1297                } else if let Some(arr) = obj.get("AbsLitTuple") {
1298                    return parse_abs_tuple(arr, scope);
1299                } else if let Some(arr) = obj.get("AbsLitRecord") {
1300                    return parse_abs_record(arr, scope);
1301                } else if let Some(arr) = obj.get("AbsLitFunction") {
1302                    return parse_abs_function(arr, scope);
1303                }
1304            }
1305            Err(error!("Unhandled ConstantAbstract literal type"))
1306        }
1307
1308        // sometimes (e.g. constant matrices) we can have a ConstantInt / Constant bool that is
1309        // not wrapped in Constant
1310        None => {
1311            let int_expr = constant
1312                .get("ConstantInt")
1313                .and_then(|x| x.as_array())
1314                .and_then(|x| x[1].as_i64())
1315                .and_then(|x| x.try_into().ok())
1316                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(x))));
1317
1318            if let Some(expr) = int_expr {
1319                return Ok(expr);
1320            }
1321
1322            let bool_expr = constant
1323                .get("ConstantBool")
1324                .and_then(|x| x.as_bool())
1325                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(x))));
1326
1327            if let Some(expr) = bool_expr {
1328                return Ok(expr);
1329            }
1330
1331            Err(error!(format!("Unhandled parse_constant {constant:#?}")))
1332        }
1333        otherwise => Err(error!(format!("Unhandled parse_constant {otherwise:#?}"))),
1334    }
1335}