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