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