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

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

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

            
62
570
    Ok(m)
63
570
}
64

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

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

            
200
3480
    let unary_operators: HashMap<&str, UnaryOp> = [(
201
3480
        "MkOpNot",
202
3480
        Box::new(Expression::Not) as Box<dyn Fn(_, _) -> _>,
203
3480
    )]
204
3480
    .into_iter()
205
3480
    .collect();
206
3480

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

            
233
7395
    let mut binary_operator_names = binary_operators.iter().map(|x| x.0);
234
3480
    let mut unary_operator_names = unary_operators.iter().map(|x| x.0);
235
3480
    let mut vec_operator_names = vec_operators.iter().map(|x| x.0);
236

            
237
    match obj {
238
3480
        Value::Object(op) if op.contains_key("Op") => match &op["Op"] {
239
7395
            Value::Object(bin_op) if binary_operator_names.any(|key| bin_op.contains_key(*key)) => {
240
660
                parse_bin_op(bin_op, binary_operators)
241
            }
242
735
            Value::Object(un_op) if unary_operator_names.any(|key| un_op.contains_key(*key)) => {
243
30
                parse_unary_op(un_op, unary_operators)
244
            }
245
2295
            Value::Object(vec_op) if vec_operator_names.any(|key| vec_op.contains_key(*key)) => {
246
705
                parse_vec_op(vec_op, vec_operators)
247
            }
248
            otherwise => bug!("Unhandled Op {:#?}", otherwise),
249
        },
250
2085
        Value::Object(refe) if refe.contains_key("Reference") => {
251
1365
            let name = refe["Reference"].as_array()?[0].as_object()?["Name"].as_str()?;
252
1365
            Some(Expression::FactorE(
253
1365
                Metadata::new(),
254
1365
                Factor::Reference(Name::UserName(name.to_string())),
255
1365
            ))
256
        }
257
720
        Value::Object(constant) if constant.contains_key("Constant") => parse_constant(constant),
258
120
        Value::Object(constant) if constant.contains_key("ConstantInt") => parse_constant(constant),
259
        Value::Object(constant) if constant.contains_key("ConstantBool") => {
260
            parse_constant(constant)
261
        }
262
        otherwise => bug!("Unhandled Expression {:#?}", otherwise),
263
    }
264
3480
}
265

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

            
274
660
    let constructor = binary_operators.get(key.as_str())?;
275

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

            
286
30
fn parse_unary_op(
287
30
    un_op: &serde_json::Map<String, Value>,
288
30
    unary_operators: HashMap<&str, UnaryOp>,
289
30
) -> Option<Expression> {
290
30
    let (key, value) = un_op.into_iter().next()?;
291
30
    let constructor = unary_operators.get(key.as_str())?;
292

            
293
30
    let arg = parse_expression(value)?;
294
30
    Some(constructor(Metadata::new(), Box::new(arg)))
295
30
}
296

            
297
705
fn parse_vec_op(
298
705
    vec_op: &serde_json::Map<String, Value>,
299
705
    vec_operators: HashMap<&str, VecOp>,
300
705
) -> Option<Expression> {
301
705
    let (key, value) = vec_op.into_iter().next()?;
302
705
    let constructor = vec_operators.get(key.as_str())?;
303

            
304
    parser_debug!("Trying to parse vec_op: {key} ...");
305

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

            
327
705
    let args_parsed = args_parsed?;
328

            
329
705
    let number_of_args = args_parsed.len();
330
    parser_debug!("... with {number_of_args} args {args_parsed:#?}");
331

            
332
705
    let valid_args: Vec<Expression> = args_parsed.into_iter().flatten().collect();
333
705
    if number_of_args != valid_args.len() {
334
        None
335
    } else {
336
        parser_debug!("... success!");
337
705
        Some(constructor(Metadata::new(), valid_args))
338
    }
339
705
}
340

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

            
355
480
            Some(Expression::FactorE(
356
480
                Metadata::new(),
357
480
                Factor::Literal(Literal::Int(int_32)),
358
480
            ))
359
        }
360

            
361
120
        Some(Value::Object(b)) if b.contains_key("ConstantBool") => {
362
120
            let b: bool = b["ConstantBool"].as_bool().unwrap();
363
120
            Some(Expression::FactorE(
364
120
                Metadata::new(),
365
120
                Factor::Literal(Literal::Bool(b)),
366
120
            ))
367
        }
368

            
369
        // sometimes (e.g. constant matrices) we can have a ConstantInt / Constant bool that is
370
        // not wrapped in Constant
371
        None => {
372
120
            let int_expr = constant["ConstantInt"]
373
120
                .as_array()
374
120
                .and_then(|x| x[1].as_i64())
375
120
                .and_then(|x| x.try_into().ok())
376
120
                .map(|x| Expression::FactorE(Metadata::new(), Factor::Literal(Literal::Int(x))));
377

            
378
120
            if let e @ Some(_) = int_expr {
379
120
                return e;
380
            }
381

            
382
            let bool_expr = constant["ConstantBool"]
383
                .as_bool()
384
                .map(|x| Expression::FactorE(Metadata::new(), Factor::Literal(Literal::Bool(x))));
385

            
386
            if let e @ Some(_) = bool_expr {
387
                return e;
388
            }
389

            
390
            bug!("Unhandled parse_constant {:#?}", constant);
391
        }
392
        otherwise => bug!("Unhandled parse_constant {:#?}", otherwise),
393
    }
394
720
}