1
use std::fs;
2
use std::path::Path;
3
use std::path::PathBuf;
4
use std::str::FromStr;
5

            
6
use pest::Parser;
7
use pest_derive::Parser;
8

            
9
use merc_aterm::ATerm;
10
use merc_aterm::storage::THREAD_TERM_POOL;
11
use merc_pest_consume::Error;
12
use merc_pest_consume::Node;
13
use merc_pest_consume::match_nodes;
14
use merc_utilities::MercError;
15

            
16
use crate::syntax::ConditionSyntax;
17
use crate::syntax::RewriteRuleSyntax;
18
use crate::syntax::RewriteSpecificationSyntax;
19

            
20
#[derive(Parser)]
21
#[grammar = "rec_grammar.pest"]
22
pub struct RecParser;
23

            
24
type ParseResult<T> = Result<T, Error<Rule>>;
25
type ParseNode<'i> = Node<'i, Rule, ()>;
26

            
27
/// Result of parsing a REC specification containing all extracted components
28
#[derive(Debug)]
29
struct RecSpecResult {
30
    /// Name of the specification
31
    _name: String,
32
    /// List of included files
33
    include_files: Vec<String>,
34
    /// Constructor symbols with their arities
35
    constructors: Vec<(String, usize)>,
36
    /// Variable declarations
37
    variables: Vec<String>,
38
    /// Rewrite rules
39
    rewrite_rules: Vec<RewriteRuleSyntax>,
40
    /// Terms to evaluate
41
    eval_terms: Vec<ATerm>,
42
}
43

            
44
/// Load a REC specification from a specified file.
45
pub fn load_rec_from_file(file: &Path) -> Result<(RewriteSpecificationSyntax, Vec<ATerm>), MercError> {
46
    let contents = fs::read_to_string(file)?;
47
    parse_rec(&contents, Some(file))
48
}
49

            
50
/// Load and join multiple REC specifications
51
31
pub fn load_rec_from_strings(specs: &[&str]) -> Result<(RewriteSpecificationSyntax, Vec<ATerm>), MercError> {
52
31
    let mut rewrite_spec = RewriteSpecificationSyntax::default();
53
31
    let mut terms = vec![];
54

            
55
45
    for spec in specs {
56
45
        let (include_spec, include_terms) = parse_rec(spec, None)?;
57
45
        rewrite_spec.merge(&include_spec);
58
45
        terms.extend_from_slice(&include_terms);
59
    }
60

            
61
31
    Ok((rewrite_spec, terms))
62
31
}
63

            
64
/// Parses a REC specification. REC files can import other REC files.
65
/// Returns a RewriteSpec containing all the rewrite rules and a list of terms that need to be rewritten.
66
46
fn parse_rec(contents: &str, path: Option<&Path>) -> Result<(RewriteSpecificationSyntax, Vec<ATerm>), MercError> {
67
    // Initialize return result
68
46
    let mut rewrite_spec = RewriteSpecificationSyntax::default();
69
46
    let mut terms = vec![];
70

            
71
    // Use Pest parser (generated automatically from the grammar.pest file)
72
46
    let mut parse_result = RecParser::parse(Rule::rec_spec, contents)?;
73
46
    let root = parse_result.next().ok_or("Could not parse REC specification")?;
74
46
    let parse_node = ParseNode::new(root);
75

            
76
    // Parse using the consumed-based implementation
77
46
    let result = RecParser::rec_spec(parse_node)?;
78

            
79
46
    rewrite_spec.rewrite_rules = result.rewrite_rules;
80
46
    rewrite_spec.constructors = result.constructors;
81
46
    rewrite_spec.variables = result.variables;
82

            
83
46
    if !result.eval_terms.is_empty() {
84
31
        terms.extend_from_slice(&result.eval_terms);
85
32
    }
86

            
87
    // REC files can import other REC files. Import all referenced by the header.
88
46
    for file in result.include_files {
89
14
        if let Some(p) = &path {
90
            let include_path = p.parent().unwrap();
91
            let file_name = PathBuf::from_str(&(file.to_lowercase() + ".rec")).unwrap();
92
            let load_file = include_path.join(file_name);
93
            let contents = fs::read_to_string(load_file)?;
94
            let (include_spec, include_terms) = parse_rec(&contents, path)?;
95

            
96
            // Add rewrite rules and terms to the result.
97
            terms.extend_from_slice(&include_terms);
98
            rewrite_spec
99
                .rewrite_rules
100
                .extend_from_slice(&include_spec.rewrite_rules);
101
            rewrite_spec.constructors.extend_from_slice(&include_spec.constructors);
102
            for s in include_spec.variables {
103
                if !rewrite_spec.variables.contains(&s) {
104
                    rewrite_spec.variables.push(s);
105
                }
106
            }
107
14
        }
108
    }
109

            
110
46
    Ok((rewrite_spec, terms))
111
46
}
112

            
113
#[merc_pest_consume::parser]
114
impl RecParser {
115
    /// Parse a REC specification, returns structured result with all components
116
    fn rec_spec(spec: ParseNode) -> ParseResult<RecSpecResult> {
117
        // Extract all sections of the REC file
118
        match_nodes!(spec.into_children();
119
            [header((name, include_files)), _sorts, cons(constructors), _opns, vars(variables), rules(rewrite_rules), eval(eval_terms), EOI(_)] => {
120
                Ok(RecSpecResult {
121
                    _name: name,
122
                    include_files,
123
                    constructors,
124
                    variables,
125
                    rewrite_rules,
126
                    eval_terms,
127
                })
128
            },
129
            [header((name, include_files)), _sorts, cons(constructors), _opns, vars(variables), rules(rewrite_rules), EOI(_)] => {
130
                Ok(RecSpecResult {
131
                    _name: name,
132
                    include_files,
133
                    constructors,
134
                    variables,
135
                    rewrite_rules,
136
                    eval_terms: Vec::new(),
137
                })
138
            }
139
        )
140
    }
141

            
142
    /// Extracts data from parsed header of REC spec. Returns name and include files.
143
    fn header(header: ParseNode) -> ParseResult<(String, Vec<String>)> {
144
        match_nodes!(header.into_children();
145
            [identifier(name), identifier(include_files)..] => {
146
                Ok((name, include_files.collect()))
147
            }
148
        )
149
    }
150

            
151
    /// Extracts data from parsed constructor section, derives the arity of symbols. Types are ignored.
152
    fn cons(cons: ParseNode) -> ParseResult<Vec<(String, usize)>> {
153
        let mut constructors = Vec::new();
154

            
155
        match_nodes!(cons.into_children();
156
            [cons_decl(decls)..] => {
157
                constructors.extend(decls);
158
                Ok(constructors)
159
            }
160
        )
161
    }
162

            
163
    /// Parse a constructor declaration
164
    fn cons_decl(decl: ParseNode) -> ParseResult<(String, usize)> {
165
        match_nodes!(decl.into_children();
166
            [identifier(symbol), identifier(params).., identifier(_)] => {
167
                Ok((symbol, params.len()))
168
            }
169
        )
170
    }
171

            
172
    /// Extracts data from parsed rewrite rules. Returns list of rewrite rules
173
    fn rules(rules: ParseNode) -> ParseResult<Vec<RewriteRuleSyntax>> {
174
        match_nodes!(rules.into_children();
175
            [rewrite_rule(rule_nodes)..] => {
176
                Ok(rule_nodes.collect())
177
            }
178
        )
179
    }
180

            
181
    /// Parse a rewrite rule
182
    fn rewrite_rule(rule: ParseNode) -> ParseResult<RewriteRuleSyntax> {
183
        match_nodes!(rule.into_children();
184
            [term(lhs), term(rhs), condition(conditions)..] => {
185
                Ok(RewriteRuleSyntax {
186
                    lhs,
187
                    rhs,
188
                    conditions: conditions.collect(),
189
                })
190
            },
191
            [term(lhs), term(rhs)] => {
192
                Ok(RewriteRuleSyntax {
193
                    lhs,
194
                    rhs,
195
                    conditions: vec![],
196
                })
197
            }
198
        )
199
    }
200

            
201
    /// Parse a single rewrite rule
202
    fn single_rewrite_rule(rule: ParseNode) -> ParseResult<RewriteRuleSyntax> {
203
        match_nodes!(rule.into_children();
204
            [rewrite_rule(rule), EOI(_)] => {
205
                Ok(rule)
206
            },
207
        )
208
    }
209

            
210
    /// Parse a condition in a rewrite rule
211
    fn condition(condition: ParseNode) -> ParseResult<ConditionSyntax> {
212
        match_nodes!(condition.into_children();
213
            [term(lhs), comparison(equality), term(rhs)] => {
214
                Ok(ConditionSyntax {
215
                    lhs,
216
                    rhs,
217
                    equality,
218
                })
219
            }
220
        )
221
    }
222

            
223
    /// Parse a comparison operator
224
    fn comparison(comparison: ParseNode) -> ParseResult<bool> {
225
        match comparison.as_str() {
226
            "=" => Ok(true),
227
            "<>" => Ok(false),
228
            _ => panic!("Unknown comparison operator"),
229
        }
230
    }
231

            
232
    /// Extracts data from the variable VARS block. Types are ignored.
233
    fn vars(vars: ParseNode) -> ParseResult<Vec<String>> {
234
        let mut variables = vec![];
235

            
236
        match_nodes!(vars.into_children();
237
            [var_decl(var_lists)..] => {
238
                for var_list in var_lists {
239
                    variables.extend(var_list);
240
                }
241
                Ok(variables)
242
            }
243
        )
244
    }
245

            
246
    /// Parse a variable declaration
247
    fn var_decl(var_decl: ParseNode) -> ParseResult<Vec<String>> {
248
        match_nodes!(var_decl.into_children();
249
            [identifier(vars).., identifier(_type)] => {
250
                // The last identifier is the type, so we exclude it
251
                Ok(vars.collect())
252
            }
253
        )
254
    }
255

            
256
    /// Extracts data from parsed EVAL section, returns a list of terms that need to be rewritten.
257
    fn eval(eval: ParseNode) -> ParseResult<Vec<ATerm>> {
258
        match_nodes!(eval.into_children();
259
            [term(terms)..] => {
260
                Ok(terms.collect())
261
            }
262
        )
263
    }
264

            
265
    /// Parse a term
266
    fn term(term: ParseNode) -> ParseResult<ATerm> {
267
        match_nodes!(term.into_children();
268
            [identifier(head_symbol), args(arguments)] => {
269
3893
                THREAD_TERM_POOL.with_borrow(|tp| {
270
3893
                    let symbol = tp.create_symbol(&head_symbol, arguments.len());
271
3893
                    Ok(tp.create_term_iter(&symbol, arguments))
272
3893
                })
273
            },
274
            [identifier(head_symbol)] => {
275
4337
                THREAD_TERM_POOL.with_borrow(|tp| {
276
4337
                    let symbol = tp.create_symbol(&head_symbol, 0);
277
4337
                    Ok(tp.create_constant(&symbol))
278
4337
                })
279
            }
280
        )
281
    }
282

            
283
    /// Parse arguments of a term
284
    fn args(args: ParseNode) -> ParseResult<Vec<ATerm>> {
285
        match_nodes!(args.into_children();
286
            [term(term_args)..] => {
287
                Ok(term_args.collect())
288
            }
289
        )
290
    }
291

            
292
    /// Parse an identifier
293
    fn identifier(id: ParseNode) -> ParseResult<String> {
294
        Ok(id.as_str().to_string())
295
    }
296

            
297
    /// Ignored rules
298
    fn EOI(_eof: ParseNode) -> ParseResult<()> {
299
        Ok(())
300
    }
301

            
302
    fn sorts(_sorts: ParseNode) -> ParseResult<()> {
303
        Ok(())
304
    }
305

            
306
    fn opns(_opns: ParseNode) -> ParseResult<()> {
307
        Ok(())
308
    }
309
}
310

            
311
#[cfg(test)]
312
mod tests {
313
    use super::*;
314

            
315
    #[test]
316
1
    fn test_raw_parsing() {
317
1
        assert!(RecParser::parse(Rule::single_term, "f(a").is_err());
318
1
        assert!(RecParser::parse(Rule::single_term, "f()").is_err());
319
1
        assert!(RecParser::parse(Rule::single_term, "f(a,)").is_err());
320
1
        assert!(RecParser::parse(Rule::single_term, "f").is_ok());
321
1
        assert!(RecParser::parse(Rule::single_term, "f(a)").is_ok());
322
1
        assert!(RecParser::parse(Rule::single_term, "f(a,b)").is_ok());
323
1
        assert!(RecParser::parse(Rule::single_rewrite_rule, "f(a,b) = g(x)").is_ok());
324
1
        assert!(RecParser::parse(Rule::single_rewrite_rule, "f(a,b) = g(x) if x = a").is_ok());
325
1
        assert!(RecParser::parse(Rule::single_rewrite_rule, "f(a,b) = g(x) if x<> a").is_ok());
326
1
        assert!(RecParser::parse(Rule::single_rewrite_rule, "f(a,b) = g(x) if x <= a").is_err());
327
1
        assert!(RecParser::parse(Rule::single_rewrite_rule, "f(a,b) = ").is_err());
328
1
    }
329

            
330
    #[test]
331
1
    fn test_parsing_rewrite_rule() {
332
1
        let expected = RewriteRuleSyntax {
333
1
            lhs: ATerm::from_string("f(x,b)").unwrap(),
334
1
            rhs: ATerm::from_string("g(x)").unwrap(),
335
1
            conditions: vec![
336
1
                ConditionSyntax {
337
1
                    lhs: ATerm::from_string("x").unwrap(),
338
1
                    rhs: ATerm::from_string("a").unwrap(),
339
1
                    equality: true,
340
1
                },
341
1
                ConditionSyntax {
342
1
                    lhs: ATerm::from_string("b").unwrap(),
343
1
                    rhs: ATerm::from_string("b").unwrap(),
344
1
                    equality: true,
345
1
                },
346
1
            ],
347
1
        };
348

            
349
1
        let mut parse_result =
350
1
            RecParser::parse(Rule::single_rewrite_rule, "f(x,b) = g(x) if x = a and-if b = b").unwrap();
351
1
        let node = ParseNode::new(parse_result.next().unwrap());
352
1
        let actual = RecParser::single_rewrite_rule(node).unwrap();
353

            
354
1
        assert_eq!(actual, expected);
355
1
    }
356

            
357
    #[test]
358
1
    fn test_variable_parsing() {
359
1
        let mut parse_result = RecParser::parse(Rule::var_decl, "X Y Val Max : Nat").unwrap();
360
1
        let node = ParseNode::new(parse_result.next().unwrap());
361
1
        let result = RecParser::var_decl(node).unwrap();
362

            
363
1
        assert_eq!(result, vec!["X", "Y", "Val", "Max"]);
364
1
    }
365

            
366
    #[test]
367
1
    fn test_parsing_rec() {
368
1
        assert!(
369
1
            RecParser::parse(
370
1
                Rule::rec_spec,
371
1
                include_str!("../../../examples/REC/rec/missionaries.rec")
372
1
            )
373
1
            .is_ok()
374
        );
375
1
    }
376

            
377
    #[test]
378
1
    fn loading_rec() {
379
1
        let _ = parse_rec(include_str!("../../../examples/REC/rec/missionaries.rec"), None);
380
1
    }
381
}