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

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

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

            
62
468
    Ok(m)
63
468
}
64

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

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

            
153
// this needs an explicit type signature to force the closures to have the same type
154
type BinOp = Box<dyn Fn(Metadata, Box<Expression>, Box<Expression>) -> Expression>;
155
type UnaryOp = Box<dyn Fn(Metadata, Box<Expression>) -> Expression>;
156
type VecOp = Box<dyn Fn(Metadata, Vec<Expression>) -> Expression>;
157

            
158
2889
fn parse_expression(obj: &JsonValue) -> Option<Expression> {
159
2889
    let binary_operators: HashMap<&str, BinOp> = [
160
2889
        (
161
2889
            "MkOpEq",
162
2889
            Box::new(Expression::Eq) as Box<dyn Fn(_, _, _) -> _>,
163
2889
        ),
164
2889
        (
165
2889
            "MkOpNeq",
166
2889
            Box::new(Expression::Neq) as Box<dyn Fn(_, _, _) -> _>,
167
2889
        ),
168
2889
        (
169
2889
            "MkOpGeq",
170
2889
            Box::new(Expression::Geq) as Box<dyn Fn(_, _, _) -> _>,
171
2889
        ),
172
2889
        (
173
2889
            "MkOpLeq",
174
2889
            Box::new(Expression::Leq) as Box<dyn Fn(_, _, _) -> _>,
175
2889
        ),
176
2889
        (
177
2889
            "MkOpGt",
178
2889
            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
179
2889
        ),
180
2889
        (
181
2889
            "MkOpLt",
182
2889
            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
183
2889
        ),
184
2889
        (
185
2889
            "MkOpGt",
186
2889
            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
187
2889
        ),
188
2889
        (
189
2889
            "MkOpLt",
190
2889
            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
191
2889
        ),
192
2889
        (
193
2889
            "MkOpDiv",
194
2889
            Box::new(Expression::UnsafeDiv) as Box<dyn Fn(_, _, _) -> _>,
195
2889
        ),
196
2889
        (
197
2889
            "MkOpMod",
198
2889
            Box::new(Expression::UnsafeMod) as Box<dyn Fn(_, _, _) -> _>,
199
2889
        ),
200
2889
    ]
201
2889
    .into_iter()
202
2889
    .collect();
203
2889

            
204
2889
    let unary_operators: HashMap<&str, UnaryOp> = [(
205
2889
        "MkOpNot",
206
2889
        Box::new(Expression::Not) as Box<dyn Fn(_, _) -> _>,
207
2889
    )]
208
2889
    .into_iter()
209
2889
    .collect();
210
2889

            
211
2889
    let vec_operators: HashMap<&str, VecOp> = [
212
2889
        (
213
2889
            "MkOpSum",
214
2889
            Box::new(Expression::Sum) as Box<dyn Fn(_, _) -> _>,
215
2889
        ),
216
2889
        (
217
2889
            "MkOpAnd",
218
2889
            Box::new(Expression::And) as Box<dyn Fn(_, _) -> _>,
219
2889
        ),
220
2889
        ("MkOpOr", Box::new(Expression::Or) as Box<dyn Fn(_, _) -> _>),
221
2889
        (
222
2889
            "MkOpMin",
223
2889
            Box::new(Expression::Min) as Box<dyn Fn(_, _) -> _>,
224
2889
        ),
225
2889
        (
226
2889
            "MkOpMax",
227
2889
            Box::new(Expression::Max) as Box<dyn Fn(_, _) -> _>,
228
2889
        ),
229
2889
        (
230
2889
            "MkOpAllDiff",
231
2889
            Box::new(Expression::AllDiff) as Box<dyn Fn(_, _) -> _>,
232
2889
        ),
233
2889
    ]
234
2889
    .into_iter()
235
2889
    .collect();
236
2889

            
237
7101
    let mut binary_operator_names = binary_operators.iter().map(|x| x.0);
238
2889
    let mut unary_operator_names = unary_operators.iter().map(|x| x.0);
239
2889
    let mut vec_operator_names = vec_operators.iter().map(|x| x.0);
240

            
241
    match obj {
242
2889
        Value::Object(op) if op.contains_key("Op") => match &op["Op"] {
243
7101
            Value::Object(bin_op) if binary_operator_names.any(|key| bin_op.contains_key(*key)) => {
244
711
                parse_bin_op(bin_op, binary_operators)
245
            }
246
486
            Value::Object(un_op) if unary_operator_names.any(|key| un_op.contains_key(*key)) => {
247
63
                parse_unary_op(un_op, unary_operators)
248
            }
249
1476
            Value::Object(vec_op) if vec_operator_names.any(|key| vec_op.contains_key(*key)) => {
250
423
                parse_vec_op(vec_op, vec_operators)
251
            }
252
            otherwise => bug!("Unhandled Op {:#?}", otherwise),
253
        },
254
1692
        Value::Object(refe) if refe.contains_key("Reference") => {
255
1152
            let name = refe["Reference"].as_array()?[0].as_object()?["Name"].as_str()?;
256
1152
            Some(Expression::Atomic(
257
1152
                Metadata::new(),
258
1152
                Atom::Reference(Name::UserName(name.to_string())),
259
1152
            ))
260
        }
261
540
        Value::Object(constant) if constant.contains_key("Constant") => parse_constant(constant),
262
72
        Value::Object(constant) if constant.contains_key("ConstantInt") => parse_constant(constant),
263
        Value::Object(constant) if constant.contains_key("ConstantBool") => {
264
            parse_constant(constant)
265
        }
266
        otherwise => bug!("Unhandled Expression {:#?}", otherwise),
267
    }
268
2889
}
269

            
270
711
fn parse_bin_op(
271
711
    bin_op: &serde_json::Map<String, Value>,
272
711
    binary_operators: HashMap<&str, BinOp>,
273
711
) -> Option<Expression> {
274
    // we know there is a single key value pair in this object
275
    // extract the value, ignore the key
276
711
    let (key, value) = bin_op.into_iter().next()?;
277

            
278
711
    let constructor = binary_operators.get(key.as_str())?;
279

            
280
711
    match &value {
281
711
        Value::Array(bin_op_args) if bin_op_args.len() == 2 => {
282
711
            let arg1 = parse_expression(&bin_op_args[0])?;
283
711
            let arg2 = parse_expression(&bin_op_args[1])?;
284
711
            Some(constructor(Metadata::new(), Box::new(arg1), Box::new(arg2)))
285
        }
286
        otherwise => bug!("Unhandled parse_bin_op {:#?}", otherwise),
287
    }
288
711
}
289

            
290
63
fn parse_unary_op(
291
63
    un_op: &serde_json::Map<String, Value>,
292
63
    unary_operators: HashMap<&str, UnaryOp>,
293
63
) -> Option<Expression> {
294
63
    let (key, value) = un_op.into_iter().next()?;
295
63
    let constructor = unary_operators.get(key.as_str())?;
296

            
297
63
    let arg = parse_expression(value)?;
298
63
    Some(constructor(Metadata::new(), Box::new(arg)))
299
63
}
300

            
301
423
fn parse_vec_op(
302
423
    vec_op: &serde_json::Map<String, Value>,
303
423
    vec_operators: HashMap<&str, VecOp>,
304
423
) -> Option<Expression> {
305
423
    let (key, value) = vec_op.into_iter().next()?;
306
423
    let constructor = vec_operators.get(key.as_str())?;
307

            
308
    parser_debug!("Trying to parse vec_op: {key} ...");
309

            
310
423
    let mut args_parsed: Option<Vec<Option<Expression>>> = None;
311
423
    if let Some(abs_lit_matrix) = value.pointer("/AbstractLiteral/AbsLitMatrix/1") {
312
387
        parser_trace!("... containing a matrix of literals");
313
387
        args_parsed = abs_lit_matrix.as_array().map(|x| {
314
387
            x.iter()
315
387
                .map(parse_expression)
316
387
                .collect::<Vec<Option<Expression>>>()
317
387
        });
318
387
    }
319
    // the input of this expression is constant - e.g. or([]), or([false]), min([2]), etc.
320
36
    else if let Some(const_abs_lit_matrix) =
321
36
        value.pointer("/Constant/ConstantAbstract/AbsLitMatrix/1")
322
    {
323
36
        parser_trace!("... containing a matrix of constants");
324
36
        args_parsed = const_abs_lit_matrix.as_array().map(|x| {
325
36
            x.iter()
326
36
                .map(parse_expression)
327
36
                .collect::<Vec<Option<Expression>>>()
328
36
        });
329
36
    }
330

            
331
423
    let args_parsed = args_parsed?;
332

            
333
423
    let number_of_args = args_parsed.len();
334
    parser_debug!("... with {number_of_args} args {args_parsed:#?}");
335

            
336
423
    let valid_args: Vec<Expression> = args_parsed.into_iter().flatten().collect();
337
423
    if number_of_args != valid_args.len() {
338
        None
339
    } else {
340
        parser_debug!("... success!");
341
423
        Some(constructor(Metadata::new(), valid_args))
342
    }
343
423
}
344

            
345
540
fn parse_constant(constant: &serde_json::Map<String, Value>) -> Option<Expression> {
346
540
    match &constant.get("Constant") {
347
468
        Some(Value::Object(int)) if int.contains_key("ConstantInt") => {
348
396
            let int_32: i32 = match int["ConstantInt"].as_array()?[1].as_i64()?.try_into() {
349
396
                Ok(x) => x,
350
                Err(_) => {
351
                    println!(
352
                        "Could not convert integer constant to i32: {:#?}",
353
                        int["ConstantInt"]
354
                    );
355
                    return None;
356
                }
357
            };
358

            
359
396
            Some(Expression::Atomic(
360
396
                Metadata::new(),
361
396
                Atom::Literal(Literal::Int(int_32)),
362
396
            ))
363
        }
364

            
365
72
        Some(Value::Object(b)) if b.contains_key("ConstantBool") => {
366
72
            let b: bool = b["ConstantBool"].as_bool()?;
367
72
            Some(Expression::Atomic(
368
72
                Metadata::new(),
369
72
                Atom::Literal(Literal::Bool(b)),
370
72
            ))
371
        }
372

            
373
        // sometimes (e.g. constant matrices) we can have a ConstantInt / Constant bool that is
374
        // not wrapped in Constant
375
        None => {
376
72
            let int_expr = constant["ConstantInt"]
377
72
                .as_array()
378
72
                .and_then(|x| x[1].as_i64())
379
72
                .and_then(|x| x.try_into().ok())
380
72
                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(x))));
381

            
382
72
            if let e @ Some(_) = int_expr {
383
72
                return e;
384
            }
385

            
386
            let bool_expr = constant["ConstantBool"]
387
                .as_bool()
388
                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(x))));
389

            
390
            if let e @ Some(_) = bool_expr {
391
                return e;
392
            }
393

            
394
            bug!("Unhandled parse_constant {:#?}", constant);
395
        }
396
        otherwise => bug!("Unhandled parse_constant {:#?}", otherwise),
397
    }
398
540
}