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::{Constant, DecisionVariable, Domain, Expression, Name, Range};
8
use crate::context::Context;
9
use crate::error::{Error, Result};
10
use crate::metadata::Metadata;
11
use crate::Model;
12

            
13
pub fn model_from_json(str: &str, context: Arc<RwLock<Context<'static>>>) -> Result<Model> {
14
    let mut m = Model::new_empty(context);
15
    let v: JsonValue = serde_json::from_str(str)?;
16
    let statements = v["mStatements"]
17
        .as_array()
18
        .ok_or(Error::Parse("mStatements is not an array".to_owned()))?;
19

            
20
    for statement in statements {
21
        let entry = statement
22
            .as_object()
23
            .ok_or(Error::Parse("mStatements contains a non-object".to_owned()))?
24
            .iter()
25
            .next()
26
            .ok_or(Error::Parse(
27
                "mStatements contains an empty object".to_owned(),
28
            ))?;
29
        match entry.0.as_str() {
30
            "Declaration" => {
31
                let (name, var) = parse_variable(entry.1)?;
32
                m.add_variable(name, var);
33
            }
34
            "SuchThat" => {
35
                let constraints_arr = match entry.1.as_array() {
36
                    Some(x) => x,
37
                    None => {
38
                        return Err(Error::Parse("SuchThat is not a vector".to_owned()));
39
                    }
40
                };
41

            
42
                let constraints: Vec<Expression> =
43
                    constraints_arr.iter().flat_map(parse_expression).collect();
44
                m.add_constraints(constraints);
45
                // println!("Nb constraints {}", m.constraints.len());
46
            }
47
            otherwise => panic!("Unhandled Statement {:#?}", otherwise),
48
        }
49
    }
50

            
51
    Ok(m)
52
}
53

            
54
fn parse_variable(v: &JsonValue) -> Result<(Name, DecisionVariable)> {
55
    let arr = v
56
        .as_object()
57
        .ok_or(Error::Parse("Declaration is not an object".to_owned()))?["FindOrGiven"]
58
        .as_array()
59
        .ok_or(Error::Parse("FindOrGiven is not an array".to_owned()))?;
60
    let name = arr[1]
61
        .as_object()
62
        .ok_or(Error::Parse("FindOrGiven[1] is not an object".to_owned()))?["Name"]
63
        .as_str()
64
        .ok_or(Error::Parse(
65
            "FindOrGiven[1].Name is not a string".to_owned(),
66
        ))?;
67
    let name = Name::UserName(name.to_owned());
68
    let domain = arr[2]
69
        .as_object()
70
        .ok_or(Error::Parse("FindOrGiven[2] is not an object".to_owned()))?
71
        .iter()
72
        .next()
73
        .ok_or(Error::Parse("FindOrGiven[2] is an empty object".to_owned()))?;
74
    let domain = match domain.0.as_str() {
75
        "DomainInt" => Ok(parse_int_domain(domain.1)?),
76
        "DomainBool" => Ok(Domain::BoolDomain),
77
        _ => Err(Error::Parse(
78
            "FindOrGiven[2] is an unknown object".to_owned(),
79
        )),
80
    }?;
81
    Ok((name, DecisionVariable { domain }))
82
}
83

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

            
142
// this needs an explicit type signature to force the closures to have the same type
143
type BinOp = Box<dyn Fn(Metadata, Box<Expression>, Box<Expression>) -> Expression>;
144
type UnaryOp = Box<dyn Fn(Metadata, Box<Expression>) -> Expression>;
145
type VecOp = Box<dyn Fn(Metadata, Vec<Expression>) -> Expression>;
146

            
147
fn parse_expression(obj: &JsonValue) -> Option<Expression> {
148
    let binary_operators: HashMap<&str, BinOp> = [
149
        (
150
            "MkOpEq",
151
            Box::new(Expression::Eq) as Box<dyn Fn(_, _, _) -> _>,
152
        ),
153
        (
154
            "MkOpNeq",
155
            Box::new(Expression::Neq) as Box<dyn Fn(_, _, _) -> _>,
156
        ),
157
        (
158
            "MkOpGeq",
159
            Box::new(Expression::Geq) as Box<dyn Fn(_, _, _) -> _>,
160
        ),
161
        (
162
            "MkOpLeq",
163
            Box::new(Expression::Leq) as Box<dyn Fn(_, _, _) -> _>,
164
        ),
165
        (
166
            "MkOpGt",
167
            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
168
        ),
169
        (
170
            "MkOpLt",
171
            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
172
        ),
173
        (
174
            "MkOpGt",
175
            Box::new(Expression::Gt) as Box<dyn Fn(_, _, _) -> _>,
176
        ),
177
        (
178
            "MkOpLt",
179
            Box::new(Expression::Lt) as Box<dyn Fn(_, _, _) -> _>,
180
        ),
181
        (
182
            "MkOpDiv",
183
            Box::new(Expression::UnsafeDiv) as Box<dyn Fn(_, _, _) -> _>,
184
        ),
185
    ]
186
    .into_iter()
187
    .collect();
188

            
189
    let unary_operators: HashMap<&str, UnaryOp> = [(
190
        "MkOpNot",
191
        Box::new(Expression::Not) as Box<dyn Fn(_, _) -> _>,
192
    )]
193
    .into_iter()
194
    .collect();
195

            
196
    let vec_operators: HashMap<&str, VecOp> = [
197
        (
198
            "MkOpSum",
199
            Box::new(Expression::Sum) as Box<dyn Fn(_, _) -> _>,
200
        ),
201
        (
202
            "MkOpAnd",
203
            Box::new(Expression::And) as Box<dyn Fn(_, _) -> _>,
204
        ),
205
        ("MkOpOr", Box::new(Expression::Or) as Box<dyn Fn(_, _) -> _>),
206
        (
207
            "MkOpMin",
208
            Box::new(Expression::Min) as Box<dyn Fn(_, _) -> _>,
209
        ),
210
    ]
211
    .into_iter()
212
    .collect();
213

            
214
    let mut binary_operator_names = binary_operators.iter().map(|x| x.0);
215
    let mut unary_operator_names = unary_operators.iter().map(|x| x.0);
216
    let mut vec_operator_names = vec_operators.iter().map(|x| x.0);
217

            
218
    match obj {
219
        Value::Object(op) if op.contains_key("Op") => match &op["Op"] {
220
            Value::Object(bin_op) if binary_operator_names.any(|key| bin_op.contains_key(*key)) => {
221
                parse_bin_op(bin_op, binary_operators)
222
            }
223
            Value::Object(un_op) if unary_operator_names.any(|key| un_op.contains_key(*key)) => {
224
                parse_unary_op(un_op, unary_operators)
225
            }
226
            Value::Object(vec_op) if vec_operator_names.any(|key| vec_op.contains_key(*key)) => {
227
                parse_vec_op(vec_op, vec_operators)
228
            }
229
            otherwise => panic!("Unhandled Op {:#?}", otherwise),
230
        },
231
        Value::Object(refe) if refe.contains_key("Reference") => {
232
            let name = refe["Reference"].as_array()?[0].as_object()?["Name"].as_str()?;
233
            Some(Expression::Reference(
234
                Metadata::new(),
235
                Name::UserName(name.to_string()),
236
            ))
237
        }
238
        Value::Object(constant) if constant.contains_key("Constant") => parse_constant(constant),
239
        otherwise => panic!("Unhandled Expression {:#?}", otherwise),
240
    }
241
}
242

            
243
fn parse_bin_op(
244
    bin_op: &serde_json::Map<String, Value>,
245
    binary_operators: HashMap<&str, BinOp>,
246
) -> Option<Expression> {
247
    // we know there is a single key value pair in this object
248
    // extract the value, ignore the key
249
    let (key, value) = bin_op.into_iter().next()?;
250

            
251
    let constructor = binary_operators.get(key.as_str())?;
252

            
253
    match &value {
254
        Value::Array(bin_op_args) if bin_op_args.len() == 2 => {
255
            let arg1 = parse_expression(&bin_op_args[0])?;
256
            let arg2 = parse_expression(&bin_op_args[1])?;
257
            Some(constructor(Metadata::new(), Box::new(arg1), Box::new(arg2)))
258
        }
259
        otherwise => panic!("Unhandled parse_bin_op {:#?}", otherwise),
260
    }
261
}
262

            
263
fn parse_unary_op(
264
    un_op: &serde_json::Map<String, Value>,
265
    unary_operators: HashMap<&str, UnaryOp>,
266
) -> Option<Expression> {
267
    let (key, value) = un_op.into_iter().next()?;
268
    let constructor = unary_operators.get(key.as_str())?;
269

            
270
    let arg = parse_expression(value)?;
271
    Some(constructor(Metadata::new(), Box::new(arg)))
272
}
273

            
274
fn parse_vec_op(
275
    vec_op: &serde_json::Map<String, Value>,
276
    vec_operators: HashMap<&str, VecOp>,
277
) -> Option<Expression> {
278
    let (key, value) = vec_op.into_iter().next()?;
279
    let constructor = vec_operators.get(key.as_str())?;
280

            
281
    let args_parsed: Vec<Option<Expression>> = value["AbstractLiteral"]["AbsLitMatrix"][1]
282
        .as_array()?
283
        .iter()
284
        .map(parse_expression)
285
        .collect();
286

            
287
    let number_of_args = args_parsed.len();
288
    let valid_args: Vec<Expression> = args_parsed.into_iter().flatten().collect();
289
    if number_of_args != valid_args.len() {
290
        None
291
    } else {
292
        Some(constructor(Metadata::new(), valid_args))
293
    }
294
}
295

            
296
fn parse_constant(constant: &serde_json::Map<String, Value>) -> Option<Expression> {
297
    match &constant["Constant"] {
298
        Value::Object(int) if int.contains_key("ConstantInt") => {
299
            let int_32: i32 = match int["ConstantInt"].as_array()?[1].as_i64()?.try_into() {
300
                Ok(x) => x,
301
                Err(_) => {
302
                    println!(
303
                        "Could not convert integer constant to i32: {:#?}",
304
                        int["ConstantInt"]
305
                    );
306
                    return None;
307
                }
308
            };
309

            
310
            Some(Expression::Constant(Metadata::new(), Constant::Int(int_32)))
311
        }
312
        otherwise => panic!("Unhandled parse_constant {:#?}", otherwise),
313
    }
314
}