1
use std::collections::HashMap;
2
use std::sync::{Arc, RwLock};
3

            
4
use serde_json::Value;
5
use serde_json::Value as JsonValue;
6

            
7
use crate::ast::{Atom, DecisionVariable, Domain, Expression, Literal, Name, Range};
8
use crate::bug;
9
use crate::context::Context;
10
use crate::error::{Error, Result};
11
use crate::metadata::Metadata;
12
use crate::Model;
13

            
14
macro_rules! parser_trace {
15
    ($($arg:tt)+) => {
16
        log::trace!(target:"jsonparser",$($arg)+)
17
    };
18
}
19

            
20
macro_rules! parser_debug {
21
    ($($arg:tt)+) => {
22
        log::debug!(target:"jsonparser",$($arg)+)
23
    };
24
}
25

            
26
1479
pub fn model_from_json(str: &str, context: Arc<RwLock<Context<'static>>>) -> Result<Model> {
27
1479
    let mut m = Model::new_empty(context);
28
1479
    let v: JsonValue = serde_json::from_str(str)?;
29
1479
    let statements = v["mStatements"]
30
1479
        .as_array()
31
1479
        .ok_or(Error::Parse("mStatements is not an array".to_owned()))?;
32

            
33
6970
    for statement in statements {
34
5491
        let entry = statement
35
5491
            .as_object()
36
5491
            .ok_or(Error::Parse("mStatements contains a non-object".to_owned()))?
37
5491
            .iter()
38
5491
            .next()
39
5491
            .ok_or(Error::Parse(
40
5491
                "mStatements contains an empty object".to_owned(),
41
5491
            ))?;
42
5491
        match entry.0.as_str() {
43
5491
            "Declaration" => {
44
3995
                let (name, var) = parse_variable(entry.1)?;
45
3995
                m.add_variable(name, var);
46
            }
47
1496
            "SuchThat" => {
48
1496
                let constraints_arr = match entry.1.as_array() {
49
1496
                    Some(x) => x,
50
                    None => bug!("SuchThat is not a vector"),
51
                };
52

            
53
1496
                let constraints: Vec<Expression> =
54
1496
                    constraints_arr.iter().flat_map(parse_expression).collect();
55
1496
                m.add_constraints(constraints);
56
                // println!("Nb constraints {}", m.constraints.len());
57
            }
58
            otherwise => bug!("Unhandled Statement {:#?}", otherwise),
59
        }
60
    }
61

            
62
1479
    Ok(m)
63
1479
}
64

            
65
3995
fn parse_variable(v: &JsonValue) -> Result<(Name, DecisionVariable)> {
66
3995
    let arr = v
67
3995
        .as_object()
68
3995
        .ok_or(Error::Parse("Declaration is not an object".to_owned()))?["FindOrGiven"]
69
3995
        .as_array()
70
3995
        .ok_or(Error::Parse("FindOrGiven is not an array".to_owned()))?;
71
3995
    let name = arr[1]
72
3995
        .as_object()
73
3995
        .ok_or(Error::Parse("FindOrGiven[1] is not an object".to_owned()))?["Name"]
74
3995
        .as_str()
75
3995
        .ok_or(Error::Parse(
76
3995
            "FindOrGiven[1].Name is not a string".to_owned(),
77
3995
        ))?;
78
3995
    let name = Name::UserName(name.to_owned());
79
3995
    let domain = arr[2]
80
3995
        .as_object()
81
3995
        .ok_or(Error::Parse("FindOrGiven[2] is not an object".to_owned()))?
82
3995
        .iter()
83
3995
        .next()
84
3995
        .ok_or(Error::Parse("FindOrGiven[2] is an empty object".to_owned()))?;
85
3995
    let domain = match domain.0.as_str() {
86
3995
        "DomainInt" => Ok(parse_int_domain(domain.1)?),
87
765
        "DomainBool" => Ok(Domain::BoolDomain),
88
        _ => Err(Error::Parse(
89
            "FindOrGiven[2] is an unknown object".to_owned(), // consider covered
90
        )),
91
    }?;
92
3995
    Ok((name, DecisionVariable { domain }))
93
3995
}
94

            
95
3230
fn parse_int_domain(v: &JsonValue) -> Result<Domain> {
96
3230
    let mut ranges = Vec::new();
97
3230
    let arr = v
98
3230
        .as_array()
99
3230
        .ok_or(Error::Parse("DomainInt is not an array".to_owned()))?[1]
100
3230
        .as_array()
101
3230
        .ok_or(Error::Parse("DomainInt[1] is not an array".to_owned()))?;
102
6460
    for range in arr {
103
3230
        let range = range
104
3230
            .as_object()
105
3230
            .ok_or(Error::Parse(
106
3230
                "DomainInt[1] contains a non-object".to_owned(),
107
3230
            ))?
108
3230
            .iter()
109
3230
            .next()
110
3230
            .ok_or(Error::Parse(
111
3230
                "DomainInt[1] contains an empty object".to_owned(),
112
3230
            ))?;
113
3230
        match range.0.as_str() {
114
3230
            "RangeBounded" => {
115
3128
                let arr = range
116
3128
                    .1
117
3128
                    .as_array()
118
3128
                    .ok_or(Error::Parse("RangeBounded is not an array".to_owned()))?;
119
3128
                let mut nums = Vec::new();
120
6256
                for item in arr.iter() {
121
6256
                    let num = parse_domain_value_int(item).ok_or(Error::Parse(
122
6256
                        "Could not parse int domain constant".to_owned(),
123
6256
                    ))?;
124
6256
                    nums.push(num);
125
                }
126
3128
                ranges.push(Range::Bounded(nums[0], nums[1]));
127
            }
128
102
            "RangeSingle" => {
129
102
                let num = parse_domain_value_int(range.1).ok_or(Error::Parse(
130
102
                    "Could not parse int domain constant".to_owned(),
131
102
                ))?;
132
102
                ranges.push(Range::Single(num));
133
            }
134
            _ => {
135
                return Err(Error::Parse(
136
                    "DomainInt[1] contains an unknown object".to_owned(),
137
                ))
138
            }
139
        }
140
    }
141
3230
    Ok(Domain::IntDomain(ranges))
142
3230
}
143

            
144
/// Parses a (possibly) integer value inside the range of a domain
145
///
146
/// 1. (positive number) Constant/ConstantInt/1
147
///
148
/// 2. (negative number) Op/MkOpNegate/Constant/ConstantInt/1
149
///
150
/// Unlike `parse_constant` this handles the negation operator. `parse_constant` expects the
151
/// negation to already have been handled as an expression; however, here we do not expect domain
152
/// values to be part of larger expressions, only negated.
153
///
154
6358
fn parse_domain_value_int(obj: &JsonValue) -> Option<i32> {
155
6358
    parser_trace!("trying to parse domain value: {}", obj);
156

            
157
6800
    fn try_parse_positive_int(obj: &JsonValue) -> Option<i32> {
158
6800
        parser_trace!(".. trying as a positive domain value: {}", obj);
159
        // Positive number: Constant/ConstantInt/1
160

            
161
6800
        let leaf_node = obj.pointer("/Constant/ConstantInt/1")?;
162

            
163
6358
        match leaf_node.as_i64()?.try_into() {
164
6358
            Ok(x) => {
165
6358
                parser_trace!(".. success!");
166
6358
                Some(x)
167
            }
168
            Err(_) => {
169
                println!(
170
                    "Could not convert integer constant to i32: {:#?}",
171
                    leaf_node
172
                );
173
                None
174
            }
175
        }
176
6800
    }
177

            
178
442
    fn try_parse_negative_int(obj: &JsonValue) -> Option<i32> {
179
442
        // Negative number: Op/MkOpNegate/Constant/ConstantInt/1
180
442

            
181
442
        // Unwrap negation operator, giving us a Constant/ConstantInt/1
182
442
        //
183
442
        // This is just a positive constant, so try to parse it as such
184
442

            
185
442
        parser_trace!(".. trying as a negative domain value: {}", obj);
186
442
        let inner_constant_node = obj.pointer("/Op/MkOpNegate")?;
187
442
        let inner_num = try_parse_positive_int(inner_constant_node)?;
188

            
189
442
        parser_trace!(".. success!");
190
442
        Some(-inner_num)
191
442
    }
192

            
193
6358
    try_parse_positive_int(obj).or_else(|| try_parse_negative_int(obj))
194
6358
}
195

            
196
// this needs an explicit type signature to force the closures to have the same type
197
type BinOp = Box<dyn Fn(Metadata, Box<Expression>, Box<Expression>) -> Expression>;
198
type UnaryOp = Box<dyn Fn(Metadata, Box<Expression>) -> Expression>;
199
type VecOp = Box<dyn Fn(Metadata, Vec<Expression>) -> Expression>;
200

            
201
15368
fn parse_expression(obj: &JsonValue) -> Option<Expression> {
202
15368
    let binary_operators: HashMap<&str, BinOp> = [
203
15368
        (
204
15368
            "MkOpEq",
205
15368
            Box::new(Expression::Eq) as Box<dyn Fn(_, _, _) -> _>,
206
15368
        ),
207
15368
        (
208
15368
            "MkOpNeq",
209
15368
            Box::new(Expression::Neq) as Box<dyn Fn(_, _, _) -> _>,
210
15368
        ),
211
15368
        (
212
15368
            "MkOpGeq",
213
15368
            Box::new(Expression::Geq) as Box<dyn Fn(_, _, _) -> _>,
214
15368
        ),
215
15368
        (
216
15368
            "MkOpLeq",
217
15368
            Box::new(Expression::Leq) as Box<dyn Fn(_, _, _) -> _>,
218
15368
        ),
219
15368
        (
220
15368
            "MkOpGt",
221
15368
            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
222
15368
        ),
223
15368
        (
224
15368
            "MkOpLt",
225
15368
            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
226
15368
        ),
227
15368
        (
228
15368
            "MkOpGt",
229
15368
            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
230
15368
        ),
231
15368
        (
232
15368
            "MkOpLt",
233
15368
            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
234
15368
        ),
235
15368
        (
236
15368
            "MkOpDiv",
237
15368
            Box::new(Expression::UnsafeDiv) as Box<dyn Fn(_, _, _) -> _>,
238
15368
        ),
239
15368
        (
240
15368
            "MkOpMod",
241
15368
            Box::new(Expression::UnsafeMod) as Box<dyn Fn(_, _, _) -> _>,
242
15368
        ),
243
15368
        (
244
15368
            "MkOpMinus",
245
15368
            Box::new(Expression::Minus) as Box<dyn Fn(_, _, _) -> _>,
246
15368
        ),
247
15368
        (
248
15368
            "MkOpImply",
249
15368
            Box::new(Expression::Imply) as Box<dyn Fn(_, _, _) -> _>,
250
15368
        ),
251
15368
        (
252
15368
            "MkOpPow",
253
15368
            Box::new(Expression::UnsafePow) as Box<dyn Fn(_, _, _) -> _>,
254
15368
        ),
255
15368
    ]
256
15368
    .into_iter()
257
15368
    .collect();
258
15368

            
259
15368
    let unary_operators: HashMap<&str, UnaryOp> = [
260
15368
        (
261
15368
            "MkOpNot",
262
15368
            Box::new(Expression::Not) as Box<dyn Fn(_, _) -> _>,
263
15368
        ),
264
15368
        (
265
15368
            "MkOpNegate",
266
15368
            Box::new(Expression::Neg) as Box<dyn Fn(_, _) -> _>,
267
15368
        ),
268
15368
        (
269
15368
            "MkOpTwoBars",
270
15368
            Box::new(Expression::Abs) as Box<dyn Fn(_, _) -> _>,
271
15368
        ),
272
15368
    ]
273
15368
    .into_iter()
274
15368
    .collect();
275
15368

            
276
15368
    let vec_operators: HashMap<&str, VecOp> = [
277
15368
        (
278
15368
            "MkOpSum",
279
15368
            Box::new(Expression::Sum) as Box<dyn Fn(_, _) -> _>,
280
15368
        ),
281
15368
        (
282
15368
            "MkOpProduct",
283
15368
            Box::new(Expression::Product) as Box<dyn Fn(_, _) -> _>,
284
15368
        ),
285
15368
        (
286
15368
            "MkOpAnd",
287
15368
            Box::new(Expression::And) as Box<dyn Fn(_, _) -> _>,
288
15368
        ),
289
15368
        ("MkOpOr", Box::new(Expression::Or) as Box<dyn Fn(_, _) -> _>),
290
15368
        (
291
15368
            "MkOpMin",
292
15368
            Box::new(Expression::Min) as Box<dyn Fn(_, _) -> _>,
293
15368
        ),
294
15368
        (
295
15368
            "MkOpMax",
296
15368
            Box::new(Expression::Max) as Box<dyn Fn(_, _) -> _>,
297
15368
        ),
298
15368
        (
299
15368
            "MkOpAllDiff",
300
15368
            Box::new(Expression::AllDiff) as Box<dyn Fn(_, _) -> _>,
301
15368
        ),
302
15368
    ]
303
15368
    .into_iter()
304
15368
    .collect();
305
15368

            
306
59466
    let mut binary_operator_names = binary_operators.iter().map(|x| x.0);
307
15368
    let mut unary_operator_names = unary_operators.iter().map(|x| x.0);
308
15368
    let mut vec_operator_names = vec_operators.iter().map(|x| x.0);
309

            
310
    match obj {
311
15368
        Value::Object(op) if op.contains_key("Op") => match &op["Op"] {
312
59466
            Value::Object(bin_op) if binary_operator_names.any(|key| bin_op.contains_key(*key)) => {
313
4029
                parse_bin_op(bin_op, binary_operators)
314
            }
315
7973
            Value::Object(un_op) if unary_operator_names.any(|key| un_op.contains_key(*key)) => {
316
1088
                parse_unary_op(un_op, unary_operators)
317
            }
318
7242
            Value::Object(vec_op) if vec_operator_names.any(|key| vec_op.contains_key(*key)) => {
319
1972
                parse_vec_op(vec_op, vec_operators)
320
            }
321
            otherwise => bug!("Unhandled Op {:#?}", otherwise),
322
        },
323
8279
        Value::Object(refe) if refe.contains_key("Reference") => {
324
5032
            let name = refe["Reference"].as_array()?[0].as_object()?["Name"].as_str()?;
325
5032
            Some(Expression::Atomic(
326
5032
                Metadata::new(),
327
5032
                Atom::Reference(Name::UserName(name.to_string())),
328
5032
            ))
329
        }
330
3247
        Value::Object(constant) if constant.contains_key("Constant") => parse_constant(constant),
331
170
        Value::Object(constant) if constant.contains_key("ConstantInt") => parse_constant(constant),
332
        Value::Object(constant) if constant.contains_key("ConstantBool") => {
333
            parse_constant(constant)
334
        }
335
        otherwise => bug!("Unhandled Expression {:#?}", otherwise),
336
    }
337
15368
}
338

            
339
4029
fn parse_bin_op(
340
4029
    bin_op: &serde_json::Map<String, Value>,
341
4029
    binary_operators: HashMap<&str, BinOp>,
342
4029
) -> Option<Expression> {
343
    // we know there is a single key value pair in this object
344
    // extract the value, ignore the key
345
4029
    let (key, value) = bin_op.into_iter().next()?;
346

            
347
4029
    let constructor = binary_operators.get(key.as_str())?;
348

            
349
4029
    match &value {
350
4029
        Value::Array(bin_op_args) if bin_op_args.len() == 2 => {
351
4029
            let arg1 = parse_expression(&bin_op_args[0])?;
352
4029
            let arg2 = parse_expression(&bin_op_args[1])?;
353
4029
            Some(constructor(Metadata::new(), Box::new(arg1), Box::new(arg2)))
354
        }
355
        otherwise => bug!("Unhandled parse_bin_op {:#?}", otherwise),
356
    }
357
4029
}
358

            
359
1088
fn parse_unary_op(
360
1088
    un_op: &serde_json::Map<String, Value>,
361
1088
    unary_operators: HashMap<&str, UnaryOp>,
362
1088
) -> Option<Expression> {
363
1088
    let (key, value) = un_op.into_iter().next()?;
364
1088
    let constructor = unary_operators.get(key.as_str())?;
365

            
366
1088
    let arg = parse_expression(value)?;
367
1088
    Some(constructor(Metadata::new(), Box::new(arg)))
368
1088
}
369

            
370
1972
fn parse_vec_op(
371
1972
    vec_op: &serde_json::Map<String, Value>,
372
1972
    vec_operators: HashMap<&str, VecOp>,
373
1972
) -> Option<Expression> {
374
1972
    let (key, value) = vec_op.into_iter().next()?;
375
1972
    let constructor = vec_operators.get(key.as_str())?;
376

            
377
    parser_debug!("Trying to parse vec_op: {key} ...");
378

            
379
1972
    let mut args_parsed: Option<Vec<Option<Expression>>> = None;
380
1972
    if let Some(abs_lit_matrix) = value.pointer("/AbstractLiteral/AbsLitMatrix/1") {
381
1887
        parser_trace!("... containing a matrix of literals");
382
1887
        args_parsed = abs_lit_matrix.as_array().map(|x| {
383
1887
            x.iter()
384
1887
                .map(parse_expression)
385
1887
                .collect::<Vec<Option<Expression>>>()
386
1887
        });
387
1887
    }
388
    // the input of this expression is constant - e.g. or([]), or([false]), min([2]), etc.
389
85
    else if let Some(const_abs_lit_matrix) =
390
85
        value.pointer("/Constant/ConstantAbstract/AbsLitMatrix/1")
391
    {
392
85
        parser_trace!("... containing a matrix of constants");
393
85
        args_parsed = const_abs_lit_matrix.as_array().map(|x| {
394
85
            x.iter()
395
85
                .map(parse_expression)
396
85
                .collect::<Vec<Option<Expression>>>()
397
85
        });
398
85
    }
399

            
400
1972
    let args_parsed = args_parsed?;
401

            
402
1972
    let number_of_args = args_parsed.len();
403
    parser_debug!("... with {number_of_args} args {args_parsed:#?}");
404

            
405
1972
    let valid_args: Vec<Expression> = args_parsed.into_iter().flatten().collect();
406
1972
    if number_of_args != valid_args.len() {
407
        None
408
    } else {
409
        parser_debug!("... success!");
410
1972
        Some(constructor(Metadata::new(), valid_args))
411
    }
412
1972
}
413

            
414
3247
fn parse_constant(constant: &serde_json::Map<String, Value>) -> Option<Expression> {
415
3247
    match &constant.get("Constant") {
416
3077
        Some(Value::Object(int)) if int.contains_key("ConstantInt") => {
417
2907
            let int_32: i32 = match int["ConstantInt"].as_array()?[1].as_i64()?.try_into() {
418
2907
                Ok(x) => x,
419
                Err(_) => {
420
                    println!(
421
                        "Could not convert integer constant to i32: {:#?}",
422
                        int["ConstantInt"]
423
                    );
424
                    return None;
425
                }
426
            };
427

            
428
2907
            Some(Expression::Atomic(
429
2907
                Metadata::new(),
430
2907
                Atom::Literal(Literal::Int(int_32)),
431
2907
            ))
432
        }
433

            
434
170
        Some(Value::Object(b)) if b.contains_key("ConstantBool") => {
435
170
            let b: bool = b["ConstantBool"].as_bool()?;
436
170
            Some(Expression::Atomic(
437
170
                Metadata::new(),
438
170
                Atom::Literal(Literal::Bool(b)),
439
170
            ))
440
        }
441

            
442
        // sometimes (e.g. constant matrices) we can have a ConstantInt / Constant bool that is
443
        // not wrapped in Constant
444
        None => {
445
170
            let int_expr = constant["ConstantInt"]
446
170
                .as_array()
447
170
                .and_then(|x| x[1].as_i64())
448
170
                .and_then(|x| x.try_into().ok())
449
170
                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(x))));
450

            
451
170
            if let e @ Some(_) = int_expr {
452
170
                return e;
453
            }
454

            
455
            let bool_expr = constant["ConstantBool"]
456
                .as_bool()
457
                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(x))));
458

            
459
            if let e @ Some(_) = bool_expr {
460
                return e;
461
            }
462

            
463
            bug!("Unhandled parse_constant {:#?}", constant);
464
        }
465
        otherwise => bug!("Unhandled parse_constant {:#?}", otherwise),
466
    }
467
3247
}