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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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