conjure_cp_core/parse/
parse_model.rs

1#![allow(clippy::unwrap_used)]
2#![allow(clippy::expect_used)]
3use std::cell::RefCell;
4use std::collections::HashMap;
5use std::rc::Rc;
6use std::sync::{Arc, RwLock};
7use ustr::Ustr;
8
9use serde_json::Value;
10use serde_json::Value as JsonValue;
11
12use crate::ast::comprehension::{ComprehensionBuilder, ComprehensionKind};
13use crate::ast::records::RecordValue;
14use crate::ast::{
15    AbstractLiteral, Atom, DeclarationPtr, Domain, Expression, Literal, Name, Range, RecordEntry,
16    SetAttr, SymbolTable,
17};
18use crate::ast::{DeclarationKind, Moo};
19use crate::context::Context;
20use crate::error::{Error, Result};
21use crate::metadata::Metadata;
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.as_submodel().symbols_ptr_unchecked().clone();
68                let submodel = m.as_submodel_mut();
69                for (kind, value) in decl {
70                    match kind.as_str() {
71                        "FindOrGiven" => {
72                            parse_variable(value, &mut submodel.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| {
98                        parse_expression(x, m.as_submodel_mut().symbols_ptr_unchecked()).unwrap()
99                    })
100                    .collect();
101                m.as_submodel_mut().add_constraints(constraints);
102                // println!("Nb constraints {}", m.constraints.len());
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    let name = arr[1]
113        .as_object()
114        .ok_or(error!("FindOrGiven[1] is not an object"))?["Name"]
115        .as_str()
116        .ok_or(error!("FindOrGiven[1].Name is not a string"))?;
117
118    let name = Name::User(Ustr::from(name));
119
120    let domain = arr[2]
121        .as_object()
122        .ok_or(error!("FindOrGiven[2] is not an object"))?
123        .iter()
124        .next()
125        .ok_or(error!("FindOrGiven[2] is an empty object"))?;
126
127    let domain = parse_domain(domain.0, domain.1, symtab)?;
128
129    symtab
130        .insert(DeclarationPtr::new_var(name.clone(), domain))
131        .ok_or(Error::Parse(format!(
132            "Could not add {name} to symbol table as it already exists"
133        )))
134}
135
136fn parse_letting(v: &JsonValue, scope: &Rc<RefCell<SymbolTable>>) -> Result<()> {
137    let arr = v.as_array().ok_or(error!("Letting is not an array"))?;
138    let name = arr[0]
139        .as_object()
140        .ok_or(error!("Letting[0] is not an object"))?["Name"]
141        .as_str()
142        .ok_or(error!("Letting[0].Name is not a string"))?;
143    let name = Name::User(Ustr::from(name));
144    // value letting
145    if let Some(value) = parse_expression(&arr[1], scope) {
146        let mut symtab = scope.borrow_mut();
147        symtab
148            .insert(DeclarationPtr::new_value_letting(name.clone(), value))
149            .ok_or(Error::Parse(format!(
150                "Could not add {name} to symbol table as it already exists"
151            )))
152    } else {
153        // domain letting
154        let domain = &arr[1]
155            .as_object()
156            .ok_or(error!("Letting[1] is not an object".to_owned()))?["Domain"]
157            .as_object()
158            .ok_or(error!("Letting[1].Domain is not an object"))?
159            .iter()
160            .next()
161            .ok_or(error!("Letting[1].Domain is an empty object"))?;
162
163        let mut symtab = scope.borrow_mut();
164        let domain = parse_domain(domain.0, domain.1, &mut symtab)?;
165
166        symtab
167            .insert(DeclarationPtr::new_domain_letting(name.clone(), domain))
168            .ok_or(Error::Parse(format!(
169                "Could not add {name} to symbol table as it already exists"
170            )))
171    }
172}
173
174fn parse_domain(
175    domain_name: &str,
176    domain_value: &JsonValue,
177    symbols: &mut SymbolTable,
178) -> Result<Domain> {
179    match domain_name {
180        "DomainInt" => Ok(parse_int_domain(domain_value, symbols)?),
181        "DomainBool" => Ok(Domain::Bool),
182        "DomainReference" => Ok(Domain::Reference(Name::User(
183            domain_value
184                .as_array()
185                .ok_or(error!("DomainReference is not an array"))?[0]
186                .as_object()
187                .ok_or(error!("DomainReference[0] is not an object"))?["Name"]
188                .as_str()
189                .ok_or(error!("DomainReference[0].Name is not a string"))?
190                .into(),
191        ))),
192        "DomainSet" => {
193            let dom = domain_value.get(2).and_then(|v| v.as_object());
194            let domain_obj = dom.expect("domain object exists");
195            let domain = domain_obj
196                .iter()
197                .next()
198                .ok_or(Error::Parse("DomainSet is an empty object".to_owned()))?;
199            let domain = parse_domain(domain.0.as_str(), domain.1, symbols)?;
200            Ok(Domain::Set(SetAttr::None, Box::new(domain)))
201        }
202
203        "DomainMatrix" => {
204            let domain_value = domain_value
205                .as_array()
206                .ok_or(error!("Domain matrix is not an array"))?;
207
208            let indexed_by_domain = domain_value[0].clone();
209            let (index_domain_name, index_domain_value) = indexed_by_domain
210                .as_object()
211                .ok_or(error!("DomainMatrix[0] is not an object"))?
212                .iter()
213                .next()
214                .ok_or(error!(""))?;
215
216            let (value_domain_name, value_domain_value) = domain_value[1]
217                .as_object()
218                .ok_or(error!(""))?
219                .iter()
220                .next()
221                .ok_or(error!(""))?;
222
223            // Conjure stores a 2-d matrix as a matrix of a matrix.
224            //
225            // Therefore, the index is always a Domain.
226
227            let mut index_domains: Vec<Domain> = vec![];
228
229            index_domains.push(parse_domain(
230                index_domain_name,
231                index_domain_value,
232                symbols,
233            )?);
234
235            // We want to store 2-d matrices as a matrix with two index domains, not a matrix in a
236            // matrix.
237            //
238            // Walk through the value domain until it is not a DomainMatrix, adding the index to
239            // our list of indices.
240            let mut value_domain = parse_domain(value_domain_name, value_domain_value, symbols)?;
241            while let Domain::Matrix(new_value_domain, mut indices) = value_domain {
242                index_domains.append(&mut indices);
243                value_domain = *new_value_domain.clone()
244            }
245
246            Ok(Domain::Matrix(Box::new(value_domain), index_domains))
247        }
248        "DomainTuple" => {
249            let domain_value = domain_value
250                .as_array()
251                .ok_or(error!("Domain tuple is not an array"))?;
252
253            //iterate through the array and parse each domain
254            let domain = domain_value
255                .iter()
256                .map(|x| {
257                    let domain = x
258                        .as_object()
259                        .ok_or(error!("DomainTuple[0] is not an object"))?
260                        .iter()
261                        .next()
262                        .ok_or(error!("DomainTuple[0] is an empty object"))?;
263                    parse_domain(domain.0, domain.1, symbols)
264                })
265                .collect::<Result<Vec<Domain>>>()?;
266
267            Ok(Domain::Tuple(domain))
268        }
269        "DomainRecord" => {
270            let domain_value = domain_value
271                .as_array()
272                .ok_or(error!("Domain Record is not a json array"))?;
273
274            let mut record_entries = vec![];
275
276            for item in domain_value {
277                //collect the name of the record field
278                let name = item[0]
279                    .as_object()
280                    .ok_or(error!("FindOrGiven[1] is not an object"))?["Name"]
281                    .as_str()
282                    .ok_or(error!("FindOrGiven[1].Name is not a string"))?;
283
284                let name = Name::User(Ustr::from(name));
285                // then collect the domain of the record field
286                let domain = item[1]
287                    .as_object()
288                    .ok_or(error!("FindOrGiven[2] is not an object"))?
289                    .iter()
290                    .next()
291                    .ok_or(error!("FindOrGiven[2] is an empty object"))?;
292
293                let domain = parse_domain(domain.0, domain.1, symbols)?;
294
295                let rec = RecordEntry { name, domain };
296
297                record_entries.push(rec);
298            }
299
300            // add record fields to symbol table
301            record_entries
302                .iter()
303                .cloned()
304                .map(DeclarationPtr::new_record_field)
305                .for_each(|decl| {
306                    symbols
307                        .insert(decl)
308                        .expect("record field to not already be in the symbol table")
309                });
310
311            Ok(Domain::Record(record_entries))
312        }
313
314        _ => Err(Error::Parse(
315            "FindOrGiven[2] is an unknown object".to_owned(), // consider covered
316        )),
317    }
318}
319
320fn parse_int_domain(v: &JsonValue, symbols: &SymbolTable) -> Result<Domain> {
321    let mut ranges = Vec::new();
322    let arr = v
323        .as_array()
324        .ok_or(error!("DomainInt is not an array".to_owned()))?[1]
325        .as_array()
326        .ok_or(error!("DomainInt[1] is not an array".to_owned()))?;
327    for range in arr {
328        let range = range
329            .as_object()
330            .ok_or(error!("DomainInt[1] contains a non-object"))?
331            .iter()
332            .next()
333            .ok_or(error!("DomainInt[1] contains an empty object"))?;
334        match range.0.as_str() {
335            "RangeBounded" => {
336                let arr = range
337                    .1
338                    .as_array()
339                    .ok_or(error!("RangeBounded is not an array".to_owned()))?;
340                let mut nums = Vec::new();
341                for item in arr.iter() {
342                    let num = parse_domain_value_int(item, symbols)
343                        .ok_or(error!("Could not parse int domain constant"))?;
344                    nums.push(num);
345                }
346                ranges.push(Range::Bounded(nums[0], nums[1]));
347            }
348            "RangeSingle" => {
349                let num = parse_domain_value_int(range.1, symbols)
350                    .ok_or(error!("Could not parse int domain constant"))?;
351                ranges.push(Range::Single(num));
352            }
353            _ => return throw_error!("DomainInt[1] contains an unknown object"),
354        }
355    }
356    Ok(Domain::Int(ranges))
357}
358
359/// Parses a (possibly) integer value inside the range of a domain
360///
361/// 1. (positive number) Constant/ConstantInt/1
362///
363/// 2. (negative number) Op/MkOpNegate/Constant/ConstantInt/1
364///
365/// Unlike `parse_constant` this handles the negation operator. `parse_constant` expects the
366/// negation to already have been handled as an expression; however, here we do not expect domain
367/// values to be part of larger expressions, only negated.
368///
369fn parse_domain_value_int(obj: &JsonValue, symbols: &SymbolTable) -> Option<i32> {
370    parser_trace!("trying to parse domain value: {}", obj);
371
372    fn try_parse_positive_int(obj: &JsonValue) -> Option<i32> {
373        parser_trace!(".. trying as a positive domain value: {}", obj);
374        // Positive number: Constant/ConstantInt/1
375
376        let leaf_node = obj
377            .pointer("/Constant/ConstantInt/1")
378            .or_else(|| obj.pointer("/ConstantInt/1"))?;
379
380        match leaf_node.as_i64()?.try_into() {
381            Ok(x) => {
382                parser_trace!(".. success!");
383                Some(x)
384            }
385            Err(_) => {
386                println!("Could not convert integer constant to i32: {leaf_node:#?}");
387                None
388            }
389        }
390    }
391
392    fn try_parse_negative_int(obj: &JsonValue) -> Option<i32> {
393        // Negative number: Op/MkOpNegate/Constant/ConstantInt/1
394
395        // Unwrap negation operator, giving us a Constant/ConstantInt/1
396        //
397        // This is just a positive constant, so try to parse it as such
398
399        parser_trace!(".. trying as a negative domain value: {}", obj);
400        let inner_constant_node = obj.pointer("/Op/MkOpNegate")?;
401        let inner_num = try_parse_positive_int(inner_constant_node)?;
402
403        parser_trace!(".. success!");
404        Some(-inner_num)
405    }
406
407    // it will be too annoying to store references inside all our int domain ranges, so just
408    // resolve them here.
409    //
410    // this matches savilerow, where lettings must be declared before they are used.
411    //
412    // TODO: we shouldn't do this long term, add support for ranges containing domain references.
413    fn try_parse_reference(obj: &JsonValue, symbols: &SymbolTable) -> Option<i32> {
414        parser_trace!(".. trying as a domain reference: {}", obj);
415        let inner_name = obj.pointer("/Reference/0/Name")?.as_str()?;
416        parser_trace!(
417            ".. found domain reference to {}, trying to resolve it",
418            inner_name
419        );
420        let name = Name::User(Ustr::from(inner_name));
421        let decl = symbols.lookup(&name)?;
422        let DeclarationKind::ValueLetting(d) = &decl.kind() as &DeclarationKind else {
423            parser_trace!(".. name exists but is not a value letting!");
424            return None;
425        };
426
427        let a = d.clone().into_literal()?;
428        let Literal::Int(a) = a else {
429            return None;
430        };
431
432        Some(a)
433    }
434
435    try_parse_positive_int(obj)
436        .or_else(|| try_parse_negative_int(obj))
437        .or_else(|| try_parse_reference(obj, symbols))
438}
439
440// this needs an explicit type signature to force the closures to have the same type
441type BinOp = Box<dyn Fn(Metadata, Moo<Expression>, Moo<Expression>) -> Expression>;
442type UnaryOp = Box<dyn Fn(Metadata, Moo<Expression>) -> Expression>;
443
444pub fn parse_expression(obj: &JsonValue, scope: &Rc<RefCell<SymbolTable>>) -> Option<Expression> {
445    let binary_operators: HashMap<&str, BinOp> = [
446        (
447            "MkOpIn",
448            Box::new(Expression::In) as Box<dyn Fn(_, _, _) -> _>,
449        ),
450        (
451            "MkOpUnion",
452            Box::new(Expression::Union) as Box<dyn Fn(_, _, _) -> _>,
453        ),
454        (
455            "MkOpIntersect",
456            Box::new(Expression::Intersect) as Box<dyn Fn(_, _, _) -> _>,
457        ),
458        (
459            "MkOpSupset",
460            Box::new(Expression::Supset) as Box<dyn Fn(_, _, _) -> _>,
461        ),
462        (
463            "MkOpSupsetEq",
464            Box::new(Expression::SupsetEq) as Box<dyn Fn(_, _, _) -> _>,
465        ),
466        (
467            "MkOpSubset",
468            Box::new(Expression::Subset) as Box<dyn Fn(_, _, _) -> _>,
469        ),
470        (
471            "MkOpSubsetEq",
472            Box::new(Expression::SubsetEq) as Box<dyn Fn(_, _, _) -> _>,
473        ),
474        (
475            "MkOpEq",
476            Box::new(Expression::Eq) as Box<dyn Fn(_, _, _) -> _>,
477        ),
478        (
479            "MkOpNeq",
480            Box::new(Expression::Neq) as Box<dyn Fn(_, _, _) -> _>,
481        ),
482        (
483            "MkOpGeq",
484            Box::new(Expression::Geq) as Box<dyn Fn(_, _, _) -> _>,
485        ),
486        (
487            "MkOpLeq",
488            Box::new(Expression::Leq) as Box<dyn Fn(_, _, _) -> _>,
489        ),
490        (
491            "MkOpGt",
492            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
493        ),
494        (
495            "MkOpLt",
496            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
497        ),
498        (
499            "MkOpGt",
500            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
501        ),
502        (
503            "MkOpLt",
504            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
505        ),
506        (
507            "MkOpDiv",
508            Box::new(Expression::UnsafeDiv) as Box<dyn Fn(_, _, _) -> _>,
509        ),
510        (
511            "MkOpMod",
512            Box::new(Expression::UnsafeMod) as Box<dyn Fn(_, _, _) -> _>,
513        ),
514        (
515            "MkOpMinus",
516            Box::new(Expression::Minus) as Box<dyn Fn(_, _, _) -> _>,
517        ),
518        (
519            "MkOpImply",
520            Box::new(Expression::Imply) as Box<dyn Fn(_, _, _) -> _>,
521        ),
522        (
523            "MkOpIff",
524            Box::new(Expression::Iff) as Box<dyn Fn(_, _, _) -> _>,
525        ),
526        (
527            "MkOpPow",
528            Box::new(Expression::UnsafePow) as Box<dyn Fn(_, _, _) -> _>,
529        ),
530    ]
531    .into_iter()
532    .collect();
533
534    let unary_operators: HashMap<&str, UnaryOp> = [
535        (
536            "MkOpNot",
537            Box::new(Expression::Not) as Box<dyn Fn(_, _) -> _>,
538        ),
539        (
540            "MkOpNegate",
541            Box::new(Expression::Neg) as Box<dyn Fn(_, _) -> _>,
542        ),
543        (
544            "MkOpTwoBars",
545            Box::new(Expression::Abs) as Box<dyn Fn(_, _) -> _>,
546        ),
547        (
548            "MkOpAnd",
549            Box::new(Expression::And) as Box<dyn Fn(_, _) -> _>,
550        ),
551        (
552            "MkOpSum",
553            Box::new(Expression::Sum) as Box<dyn Fn(_, _) -> _>,
554        ),
555        (
556            "MkOpProduct",
557            Box::new(Expression::Product) as Box<dyn Fn(_, _) -> _>,
558        ),
559        ("MkOpOr", Box::new(Expression::Or) as Box<dyn Fn(_, _) -> _>),
560        (
561            "MkOpMin",
562            Box::new(Expression::Min) as Box<dyn Fn(_, _) -> _>,
563        ),
564        (
565            "MkOpMax",
566            Box::new(Expression::Max) as Box<dyn Fn(_, _) -> _>,
567        ),
568        (
569            "MkOpAllDiff",
570            Box::new(Expression::AllDiff) as Box<dyn Fn(_, _) -> _>,
571        ),
572        (
573            "MkOpToInt",
574            Box::new(Expression::ToInt) as Box<dyn Fn(_, _) -> _>,
575        ),
576    ]
577    .into_iter()
578    .collect();
579
580    let mut binary_operator_names = binary_operators.iter().map(|x| x.0);
581    let mut unary_operator_names = unary_operators.iter().map(|x| x.0);
582    #[allow(clippy::unwrap_used)]
583    match obj {
584        Value::Object(op) if op.contains_key("Op") => match &op["Op"] {
585            Value::Object(bin_op) if binary_operator_names.any(|key| bin_op.contains_key(*key)) => {
586                Some(parse_bin_op(bin_op, binary_operators, scope).unwrap())
587            }
588            Value::Object(un_op) if unary_operator_names.any(|key| un_op.contains_key(*key)) => {
589                Some(parse_unary_op(un_op, unary_operators, scope).unwrap())
590            }
591            Value::Object(op)
592                if op.contains_key("MkOpIndexing") || op.contains_key("MkOpSlicing") =>
593            {
594                parse_indexing_slicing_op(op, scope)
595            }
596            otherwise => bug!("Unhandled Op {:#?}", otherwise),
597        },
598        Value::Object(comprehension) if comprehension.contains_key("Comprehension") => {
599            Some(parse_comprehension(comprehension, Rc::clone(scope), None).unwrap())
600        }
601        Value::Object(refe) if refe.contains_key("Reference") => {
602            let name = refe["Reference"].as_array()?[0].as_object()?["Name"].as_str()?;
603            let user_name = Name::User(Ustr::from(name));
604
605            let declaration: DeclarationPtr = scope
606                .borrow()
607                .lookup(&user_name)
608                .or_else(|| bug!("Could not find reference {user_name}"))?;
609
610            Some(Expression::Atomic(
611                Metadata::new(),
612                Atom::Reference(declaration),
613            ))
614        }
615        Value::Object(abslit) if abslit.contains_key("AbstractLiteral") => {
616            if abslit["AbstractLiteral"]
617                .as_object()?
618                .contains_key("AbsLitSet")
619            {
620                Some(parse_abs_lit(&abslit["AbstractLiteral"]["AbsLitSet"], scope).unwrap())
621            } else {
622                Some(parse_abstract_matrix_as_expr(obj, scope).unwrap())
623            }
624        }
625
626        Value::Object(constant) if constant.contains_key("Constant") => Some(
627            parse_constant(constant, scope)
628                .or_else(|| parse_abstract_matrix_as_expr(obj, scope))
629                .unwrap(),
630        ),
631
632        Value::Object(constant) if constant.contains_key("ConstantAbstract") => {
633            Some(parse_abstract_matrix_as_expr(obj, scope).unwrap())
634        }
635
636        Value::Object(constant) if constant.contains_key("ConstantInt") => {
637            Some(parse_constant(constant, scope).unwrap())
638        }
639        Value::Object(constant) if constant.contains_key("ConstantBool") => {
640            Some(parse_constant(constant, scope).unwrap())
641        }
642
643        _ => None,
644    }
645}
646
647fn parse_abs_lit(abs_set: &Value, scope: &Rc<RefCell<SymbolTable>>) -> Option<Expression> {
648    let values = abs_set.as_array()?; // Ensure it's an array
649    let expressions = values
650        .iter()
651        .map(|values| parse_expression(values, scope))
652        .map(|values| values.expect("invalid subexpression")) // Ensure valid expressions
653        .collect::<Vec<Expression>>(); // Collect all expressions
654
655    Some(Expression::AbstractLiteral(
656        Metadata::new(),
657        AbstractLiteral::Set(expressions),
658    ))
659}
660
661fn parse_abs_tuple(abs_tuple: &Value, scope: &Rc<RefCell<SymbolTable>>) -> Option<Expression> {
662    let values = abs_tuple.as_array()?; // Ensure it's an array
663    let expressions = values
664        .iter()
665        .map(|values| parse_expression(values, scope))
666        .map(|values| values.expect("invalid subexpression")) // Ensure valid expressions
667        .collect::<Vec<Expression>>(); // Collect all expressions
668
669    Some(Expression::AbstractLiteral(
670        Metadata::new(),
671        AbstractLiteral::Tuple(expressions),
672    ))
673}
674
675//parses an abstract record as an expression
676fn parse_abs_record(abs_record: &Value, scope: &Rc<RefCell<SymbolTable>>) -> Option<Expression> {
677    let entries = abs_record.as_array()?; // Ensure it's an array
678    let mut rec = vec![];
679
680    for entry in entries {
681        let entry = entry.as_array()?;
682        let name = entry[0].as_object()?["Name"].as_str()?;
683
684        let value = parse_expression(&entry[1], scope)?;
685
686        let name = Name::User(Ustr::from(name));
687        let rec_entry = RecordValue {
688            name: name.clone(),
689            value,
690        };
691        rec.push(rec_entry);
692    }
693
694    Some(Expression::AbstractLiteral(
695        Metadata::new(),
696        AbstractLiteral::Record(rec),
697    ))
698}
699
700fn parse_comprehension(
701    comprehension: &serde_json::Map<String, Value>,
702    scope: Rc<RefCell<SymbolTable>>,
703    comprehension_kind: Option<ComprehensionKind>,
704) -> Option<Expression> {
705    let value = &comprehension["Comprehension"];
706    let mut comprehension = ComprehensionBuilder::new(Rc::clone(&scope));
707    let generator_symboltable = comprehension.generator_symboltable();
708    let return_expr_symboltable = comprehension.return_expr_symboltable();
709
710    let generators_and_guards = value.pointer("/1")?.as_array()?.iter();
711
712    for value in generators_and_guards {
713        let value = value.as_object()?;
714        let (name, value) = value.iter().next()?;
715        comprehension = match name.as_str() {
716            "Generator" => {
717                // TODO: more things than GenDomainNoRepr and Single names here?
718                let name = value.pointer("/GenDomainNoRepr/0/Single/Name")?.as_str()?;
719                let (domain_name, domain_value) = value
720                    .pointer("/GenDomainNoRepr/1")?
721                    .as_object()?
722                    .iter()
723                    .next()?;
724                let domain = parse_domain(
725                    domain_name,
726                    domain_value,
727                    &mut generator_symboltable.borrow_mut(),
728                )
729                .ok()?;
730                comprehension.generator(DeclarationPtr::new_var(
731                    Name::User(Ustr::from(name)),
732                    domain,
733                ))
734            }
735
736            "Condition" => comprehension.guard(parse_expression(value, &generator_symboltable)?),
737
738            x => {
739                bug!("unknown field inside comprehension {x}");
740            }
741        }
742    }
743
744    let expr = parse_expression(value.pointer("/0")?, &return_expr_symboltable)?;
745
746    Some(Expression::Comprehension(
747        Metadata::new(),
748        Moo::new(comprehension.with_return_value(expr, comprehension_kind)),
749    ))
750}
751
752fn parse_bin_op(
753    bin_op: &serde_json::Map<String, Value>,
754    binary_operators: HashMap<&str, BinOp>,
755    scope: &Rc<RefCell<SymbolTable>>,
756) -> Option<Expression> {
757    // we know there is a single key value pair in this object
758    // extract the value, ignore the key
759    let (key, value) = bin_op.into_iter().next()?;
760
761    let constructor = binary_operators.get(key.as_str())?;
762
763    match &value {
764        Value::Array(bin_op_args) if bin_op_args.len() == 2 => {
765            let arg1 = parse_expression(&bin_op_args[0], scope)?;
766            let arg2 = parse_expression(&bin_op_args[1], scope)?;
767            Some(constructor(Metadata::new(), Moo::new(arg1), Moo::new(arg2)))
768        }
769        otherwise => bug!("Unhandled parse_bin_op {:#?}", otherwise),
770    }
771}
772
773fn parse_indexing_slicing_op(
774    op: &serde_json::Map<String, Value>,
775    scope: &Rc<RefCell<SymbolTable>>,
776) -> Option<Expression> {
777    // we know there is a single key value pair in this object
778    // extract the value, ignore the key
779    let (key, value) = op.into_iter().next()?;
780
781    // we know that this is meant to be a mkopindexing, so anything that goes wrong from here is a
782    // bug!
783
784    // Conjure does a[1,2,3] as MkOpIndexing(MkOpIndexing(MkOpIndexing(a,3),2),1).
785    //
786    // And  a[1,..,3] as MkOpIndexing(MkOpSlicing(MkOpIndexing(a,3)),1).
787    //
788    // However, we want this in a flattened form: Index(a, [1,2,3])
789    let mut target: Expression;
790    let mut indices: Vec<Option<Expression>> = vec![];
791
792    // true if this has no slicing, false otherwise.
793    let mut all_known = true;
794
795    match key.as_str() {
796        "MkOpIndexing" => {
797            match &value {
798                Value::Array(op_args) if op_args.len() == 2 => {
799                    target = parse_expression(&op_args[0], scope).expect("expected an expression");
800                    indices.push(Some(
801                        parse_expression(&op_args[1], scope).expect("expected an expression"),
802                    ));
803                }
804                otherwise => bug!("Unknown object inside MkOpIndexing: {:#?}", otherwise),
805            };
806        }
807
808        "MkOpSlicing" => {
809            all_known = false;
810            match &value {
811                Value::Array(op_args) if op_args.len() == 3 => {
812                    target = parse_expression(&op_args[0], scope).expect("expected an expression");
813                    indices.push(None);
814                }
815                otherwise => bug!("Unknown object inside MkOpSlicing: {:#?}", otherwise),
816            };
817        }
818
819        _ => {
820            return None;
821        }
822    }
823
824    loop {
825        match &mut target {
826            Expression::UnsafeIndex(_, new_target, new_indices) => {
827                indices.extend(new_indices.iter().cloned().rev().map(Some));
828                target = Moo::unwrap_or_clone(new_target.clone());
829            }
830
831            Expression::UnsafeSlice(_, new_target, new_indices) => {
832                all_known = false;
833                indices.extend(new_indices.iter().cloned().rev());
834                target = Moo::unwrap_or_clone(new_target.clone());
835            }
836
837            _ => {
838                // not a slice or an index, we have reached the target.
839                break;
840            }
841        }
842    }
843
844    indices.reverse();
845
846    if all_known {
847        Some(Expression::UnsafeIndex(
848            Metadata::new(),
849            Moo::new(target),
850            indices.into_iter().map(|x| x.unwrap()).collect(),
851        ))
852    } else {
853        Some(Expression::UnsafeSlice(
854            Metadata::new(),
855            Moo::new(target),
856            indices,
857        ))
858    }
859}
860
861fn parse_unary_op(
862    un_op: &serde_json::Map<String, Value>,
863    unary_operators: HashMap<&str, UnaryOp>,
864    scope: &Rc<RefCell<SymbolTable>>,
865) -> Option<Expression> {
866    let (key, value) = un_op.into_iter().next()?;
867    let constructor = unary_operators.get(key.as_str())?;
868
869    // unops are the main things that contain comprehensions
870    //
871    // if the current expr is a quantifier like and/or/sum and it contains a comprehension, let the comprehension know what it is inside.
872    let arg = match value {
873        Value::Object(comprehension) if comprehension.contains_key("Comprehension") => {
874            let comprehension_kind = match key.as_str() {
875                "MkOpOr" => Some(ComprehensionKind::Or),
876                "MkOpAnd" => Some(ComprehensionKind::And),
877                "MkOpSum" => Some(ComprehensionKind::Sum),
878                _ => None,
879            };
880            Some(parse_comprehension(comprehension, Rc::clone(scope), comprehension_kind).unwrap())
881        }
882        _ => parse_expression(value, scope),
883    }?;
884
885    Some(constructor(Metadata::new(), Moo::new(arg)))
886}
887
888// Takes in { AbstractLiteral: .... }
889fn parse_abstract_matrix_as_expr(
890    value: &serde_json::Value,
891    scope: &Rc<RefCell<SymbolTable>>,
892) -> Option<Expression> {
893    parser_trace!("trying to parse an abstract literal matrix");
894    let (values, domain_name, domain_value) =
895        if let Some(abs_lit_matrix) = value.pointer("/AbstractLiteral/AbsLitMatrix") {
896            parser_trace!(".. found JSON pointer /AbstractLiteral/AbstractLitMatrix");
897            let (domain_name, domain_value) =
898                abs_lit_matrix.pointer("/0")?.as_object()?.iter().next()?;
899            let values = abs_lit_matrix.pointer("/1")?;
900
901            Some((values, domain_name, domain_value))
902        }
903        // the input of this expression is constant - e.g. or([]), or([false]), min([2]), etc.
904        else if let Some(const_abs_lit_matrix) =
905            value.pointer("/Constant/ConstantAbstract/AbsLitMatrix")
906        {
907            parser_trace!(".. found JSON pointer /Constant/ConstantAbstract/AbsLitMatrix");
908            let (domain_name, domain_value) = const_abs_lit_matrix
909                .pointer("/0")?
910                .as_object()?
911                .iter()
912                .next()?;
913            let values = const_abs_lit_matrix.pointer("/1")?;
914
915            Some((values, domain_name, domain_value))
916        } else if let Some(const_abs_lit_matrix) = value.pointer("/ConstantAbstract/AbsLitMatrix") {
917            parser_trace!(".. found JSON pointer /ConstantAbstract/AbsLitMatrix");
918            let (domain_name, domain_value) = const_abs_lit_matrix
919                .pointer("/0")?
920                .as_object()?
921                .iter()
922                .next()?;
923            let values = const_abs_lit_matrix.pointer("/1")?;
924            Some((values, domain_name, domain_value))
925        } else {
926            None
927        }?;
928
929    parser_trace!(".. found in domain and values in JSON:");
930    parser_trace!(".. .. index domain name {domain_name}");
931    parser_trace!(".. .. values {value}");
932
933    let args_parsed = values.as_array().map(|x| {
934        x.iter()
935            .map(|x| parse_expression(x, scope))
936            .map(|x| x.expect("invalid subexpression"))
937            .collect::<Vec<Expression>>()
938    })?;
939
940    if !args_parsed.is_empty() {
941        parser_trace!(
942            ".. successfully parsed values as expressions: {}, ... ",
943            args_parsed[0]
944        );
945    } else {
946        parser_trace!(".. successfully parsed empty values ",);
947    }
948
949    let mut symbols = scope.borrow_mut();
950    match parse_domain(domain_name, domain_value, &mut symbols) {
951        Ok(domain) => {
952            parser_trace!("... sucessfully parsed domain as {domain}");
953            Some(into_matrix_expr![args_parsed;domain])
954        }
955        Err(_) => {
956            parser_trace!("... failed to parse domain, creating a matrix without one.");
957            Some(into_matrix_expr![args_parsed])
958        }
959    }
960}
961
962fn parse_constant(
963    constant: &serde_json::Map<String, Value>,
964    scope: &Rc<RefCell<SymbolTable>>,
965) -> Option<Expression> {
966    match &constant.get("Constant") {
967        Some(Value::Object(int)) if int.contains_key("ConstantInt") => {
968            let int_32: i32 = match int["ConstantInt"].as_array()?[1].as_i64()?.try_into() {
969                Ok(x) => x,
970                Err(_) => {
971                    println!(
972                        "Could not convert integer constant to i32: {:#?}",
973                        int["ConstantInt"]
974                    );
975                    return None;
976                }
977            };
978
979            Some(Expression::Atomic(
980                Metadata::new(),
981                Atom::Literal(Literal::Int(int_32)),
982            ))
983        }
984
985        Some(Value::Object(b)) if b.contains_key("ConstantBool") => {
986            let b: bool = b["ConstantBool"].as_bool()?;
987            Some(Expression::Atomic(
988                Metadata::new(),
989                Atom::Literal(Literal::Bool(b)),
990            ))
991        }
992
993        Some(Value::Object(int)) if int.contains_key("ConstantAbstract") => {
994            if let Some(Value::Object(obj)) = int.get("ConstantAbstract") {
995                if let Some(arr) = obj.get("AbsLitSet") {
996                    return parse_abs_lit(arr, scope);
997                } else if let Some(arr) = obj.get("AbsLitMatrix") {
998                    return parse_abstract_matrix_as_expr(arr, scope);
999                } else if let Some(arr) = obj.get("AbsLitTuple") {
1000                    return parse_abs_tuple(arr, scope);
1001                } else if let Some(arr) = obj.get("AbsLitRecord") {
1002                    return parse_abs_record(arr, scope);
1003                }
1004            }
1005            None
1006        }
1007
1008        // sometimes (e.g. constant matrices) we can have a ConstantInt / Constant bool that is
1009        // not wrapped in Constant
1010        None => {
1011            let int_expr = constant
1012                .get("ConstantInt")
1013                .and_then(|x| x.as_array())
1014                .and_then(|x| x[1].as_i64())
1015                .and_then(|x| x.try_into().ok())
1016                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(x))));
1017
1018            if let e @ Some(_) = int_expr {
1019                return e;
1020            }
1021
1022            let bool_expr = constant
1023                .get("ConstantBool")
1024                .and_then(|x| x.as_bool())
1025                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(x))));
1026
1027            if let e @ Some(_) = bool_expr {
1028                return e;
1029            }
1030
1031            bug!("Unhandled parse_constant {:#?}", constant);
1032        }
1033        otherwise => bug!("Unhandled parse_constant {:#?}", otherwise),
1034    }
1035}