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

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

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

            
62
901
    Ok(m)
63
901
}
64

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

            
95
1768
fn parse_int_domain(v: &JsonValue) -> Result<Domain> {
96
1768
    let mut ranges = Vec::new();
97
1768
    let arr = v
98
1768
        .as_array()
99
1768
        .ok_or(Error::Parse("DomainInt is not an array".to_owned()))?[1]
100
1768
        .as_array()
101
1768
        .ok_or(Error::Parse("DomainInt[1] is not an array".to_owned()))?;
102
3536
    for range in arr {
103
1768
        let range = range
104
1768
            .as_object()
105
1768
            .ok_or(Error::Parse(
106
1768
                "DomainInt[1] contains a non-object".to_owned(),
107
1768
            ))?
108
1768
            .iter()
109
1768
            .next()
110
1768
            .ok_or(Error::Parse(
111
1768
                "DomainInt[1] contains an empty object".to_owned(),
112
1768
            ))?;
113
1768
        match range.0.as_str() {
114
1768
            "RangeBounded" => {
115
1751
                let arr = range
116
1751
                    .1
117
1751
                    .as_array()
118
1751
                    .ok_or(Error::Parse("RangeBounded is not an array".to_owned()))?;
119
1751
                let mut nums = Vec::new();
120
3502
                for item in arr.iter() {
121
3502
                    let num = item["Constant"]["ConstantInt"][1]
122
3502
                        .as_i64()
123
3502
                        .ok_or(Error::Parse(
124
3502
                            "Could not parse int domain constant".to_owned(),
125
3502
                        ))?;
126
3502
                    let num32 = i32::try_from(num).map_err(|_| {
127
                        Error::Parse("Could not parse int domain constant".to_owned())
128
3502
                    })?;
129
3502
                    nums.push(num32);
130
                }
131
1751
                ranges.push(Range::Bounded(nums[0], nums[1]));
132
            }
133
17
            "RangeSingle" => {
134
17
                let num = &range.1["Constant"]["ConstantInt"][1]
135
17
                    .as_i64()
136
17
                    .ok_or(Error::Parse(
137
17
                        "Could not parse int domain constant".to_owned(),
138
17
                    ))?;
139
17
                let num32 = i32::try_from(*num)
140
17
                    .map_err(|_| Error::Parse("Could not parse int domain constant".to_owned()))?;
141
17
                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
1768
    Ok(Domain::IntDomain(ranges))
151
1768
}
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
5508
fn parse_expression(obj: &JsonValue) -> Option<Expression> {
159
5508
    let binary_operators: HashMap<&str, BinOp> = [
160
5508
        (
161
5508
            "MkOpEq",
162
5508
            Box::new(Expression::Eq) as Box<dyn Fn(_, _, _) -> _>,
163
5508
        ),
164
5508
        (
165
5508
            "MkOpNeq",
166
5508
            Box::new(Expression::Neq) as Box<dyn Fn(_, _, _) -> _>,
167
5508
        ),
168
5508
        (
169
5508
            "MkOpGeq",
170
5508
            Box::new(Expression::Geq) as Box<dyn Fn(_, _, _) -> _>,
171
5508
        ),
172
5508
        (
173
5508
            "MkOpLeq",
174
5508
            Box::new(Expression::Leq) as Box<dyn Fn(_, _, _) -> _>,
175
5508
        ),
176
5508
        (
177
5508
            "MkOpGt",
178
5508
            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
179
5508
        ),
180
5508
        (
181
5508
            "MkOpLt",
182
5508
            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
183
5508
        ),
184
5508
        (
185
5508
            "MkOpGt",
186
5508
            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
187
5508
        ),
188
5508
        (
189
5508
            "MkOpLt",
190
5508
            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
191
5508
        ),
192
5508
        (
193
5508
            "MkOpDiv",
194
5508
            Box::new(Expression::UnsafeDiv) as Box<dyn Fn(_, _, _) -> _>,
195
5508
        ),
196
5508
        (
197
5508
            "MkOpMod",
198
5508
            Box::new(Expression::UnsafeMod) as Box<dyn Fn(_, _, _) -> _>,
199
5508
        ),
200
5508
    ]
201
5508
    .into_iter()
202
5508
    .collect();
203
5508

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

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

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

            
241
    match obj {
242
5508
        Value::Object(op) if op.contains_key("Op") => match &op["Op"] {
243
12937
            Value::Object(bin_op) if binary_operator_names.any(|key| bin_op.contains_key(*key)) => {
244
1360
                parse_bin_op(bin_op, binary_operators)
245
            }
246
918
            Value::Object(un_op) if unary_operator_names.any(|key| un_op.contains_key(*key)) => {
247
119
                parse_unary_op(un_op, unary_operators)
248
            }
249
2703
            Value::Object(vec_op) if vec_operator_names.any(|key| vec_op.contains_key(*key)) => {
250
799
                parse_vec_op(vec_op, vec_operators)
251
            }
252
            otherwise => bug!("Unhandled Op {:#?}", otherwise),
253
        },
254
3230
        Value::Object(refe) if refe.contains_key("Reference") => {
255
2210
            let name = refe["Reference"].as_array()?[0].as_object()?["Name"].as_str()?;
256
2210
            Some(Expression::Atomic(
257
2210
                Metadata::new(),
258
2210
                Atom::Reference(Name::UserName(name.to_string())),
259
2210
            ))
260
        }
261
1020
        Value::Object(constant) if constant.contains_key("Constant") => parse_constant(constant),
262
136
        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
5508
}
269

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

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

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

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

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

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

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

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

            
331
799
    let args_parsed = args_parsed?;
332

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

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

            
345
1020
fn parse_constant(constant: &serde_json::Map<String, Value>) -> Option<Expression> {
346
1020
    match &constant.get("Constant") {
347
884
        Some(Value::Object(int)) if int.contains_key("ConstantInt") => {
348
748
            let int_32: i32 = match int["ConstantInt"].as_array()?[1].as_i64()?.try_into() {
349
748
                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
748
            Some(Expression::Atomic(
360
748
                Metadata::new(),
361
748
                Atom::Literal(Literal::Int(int_32)),
362
748
            ))
363
        }
364

            
365
136
        Some(Value::Object(b)) if b.contains_key("ConstantBool") => {
366
136
            let b: bool = b["ConstantBool"].as_bool().unwrap();
367
136
            Some(Expression::Atomic(
368
136
                Metadata::new(),
369
136
                Atom::Literal(Literal::Bool(b)),
370
136
            ))
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
136
            let int_expr = constant["ConstantInt"]
377
136
                .as_array()
378
136
                .and_then(|x| x[1].as_i64())
379
136
                .and_then(|x| x.try_into().ok())
380
136
                .map(|x| Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(x))));
381

            
382
136
            if let e @ Some(_) = int_expr {
383
136
                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
1020
}