1
use std::cell::RefCell;
2
use std::fmt::Debug;
3
use std::fs::File;
4
use std::fs::{self};
5
use std::io::BufRead;
6
use std::io::BufReader;
7
use std::rc::Rc;
8
use std::time::Instant;
9

            
10
use ahash::AHashSet;
11
use anyhow::bail;
12
use clap::ValueEnum;
13
use mcrl2::aterm::TermPool;
14
use mcrl2::data::DataExpression;
15
use mcrl2::data::DataSpecification;
16
use mcrl2::data::JittyRewriter;
17
use rec_tests::load_REC_from_file;
18
use sabre::utilities::to_untyped_data_expression;
19
use sabre::InnermostRewriter;
20
use sabre::RewriteEngine;
21
use sabre::RewriteSpecification;
22
use sabre::SabreRewriter;
23

            
24
#[derive(ValueEnum, Debug, Clone)]
25
pub enum Rewriter {
26
    Jitty,
27
    Innermost,
28
    Sabre,
29
}
30

            
31
/// Rewrites the given expressions with the given data specification and optionally prints the result.
32
pub fn rewrite_data_spec(
33
    tp: Rc<RefCell<TermPool>>,
34
    rewriter: Rewriter,
35
    filename_dataspec: &str,
36
    filename_terms: &str,
37
    output: bool,
38
) -> anyhow::Result<()> {
39
    // Read the data specification
40
    let data_spec_text = fs::read_to_string(filename_dataspec)?;
41
    let data_spec = DataSpecification::new(&data_spec_text)?;
42

            
43
    // Open the file in read-only mode.
44
    let file = File::open(filename_terms).unwrap();
45

            
46
    // Read and convert the terms
47
    let terms: Vec<DataExpression> = BufReader::new(file)
48
        .lines()
49
        .map(|x| data_spec.parse(&x.unwrap()).unwrap())
50
        .collect();
51

            
52
    match rewriter {
53
        Rewriter::Jitty => {
54
            // Create a jitty rewriter;
55
            let mut jitty_rewriter = JittyRewriter::new(&data_spec);
56

            
57
            // Read the file line by line, and return an iterator of the lines of the file.
58
            let now = Instant::now();
59
            for term in &terms {
60
                let result = jitty_rewriter.rewrite(term.clone());
61
                if output {
62
                    println!("{}", result)
63
                }
64
            }
65
            println!("Jitty rewrite took {} ms", now.elapsed().as_millis());
66
        }
67
        Rewriter::Innermost => {
68
            let rewrite_spec = RewriteSpecification::from(data_spec.clone());
69
            let mut inner_rewriter = InnermostRewriter::new(tp.clone(), &rewrite_spec);
70

            
71
            // Read the file line by line, and return an iterator of the lines of the file.
72
            let now = Instant::now();
73
            for term in &terms {
74
                let result = inner_rewriter.rewrite(term.clone());
75
                if output {
76
                    println!("{}", result)
77
                }
78
            }
79
            println!("Innermost rewrite took {} ms", now.elapsed().as_millis());
80
        }
81
        Rewriter::Sabre => {
82
            let rewrite_spec = RewriteSpecification::from(data_spec.clone());
83
            let mut sabre_rewriter = SabreRewriter::new(tp.clone(), &rewrite_spec);
84

            
85
            let now = Instant::now();
86
            for term in &terms {
87
                let result = sabre_rewriter.rewrite(term.clone());
88
                if output {
89
                    println!("{}", result)
90
                }
91
            }
92
            println!("Sabre rewrite took {} ms", now.elapsed().as_millis());
93
        }
94
    }
95

            
96
    Ok(())
97
}
98

            
99
/// Rewrites the given REC specification.
100
pub fn rewrite_rec(rewriter: Rewriter, filename_specification: &str, output: bool) -> anyhow::Result<()> {
101
    let tp = Rc::new(RefCell::new(TermPool::new()));
102

            
103
    let (syntax_spec, syntax_terms) = load_REC_from_file(&mut tp.borrow_mut(), filename_specification.into()).unwrap();
104

            
105
    let spec = syntax_spec.to_rewrite_spec(&mut tp.borrow_mut());
106

            
107
    match rewriter {
108
        Rewriter::Innermost => {
109
            let mut inner = InnermostRewriter::new(tp.clone(), &spec);
110

            
111
            let now = Instant::now();
112
            for term in &syntax_terms {
113
                let term = to_untyped_data_expression(&mut tp.borrow_mut(), term, &AHashSet::new());
114
                let result = inner.rewrite(term);
115
                if output {
116
                    println!("{}", result)
117
                }
118
            }
119
            println!("Innermost rewrite took {} ms", now.elapsed().as_millis());
120
        }
121
        Rewriter::Sabre => {
122
            let mut sa = SabreRewriter::new(tp.clone(), &spec);
123

            
124
            let now = Instant::now();
125
            for term in &syntax_terms {
126
                let term = to_untyped_data_expression(&mut tp.borrow_mut(), term, &AHashSet::new());
127
                let result = sa.rewrite(term);
128
                if output {
129
                    println!("{}", result)
130
                }
131
            }
132
            println!("Sabre rewrite took {} ms", now.elapsed().as_millis());
133
        }
134
        Rewriter::Jitty => {
135
            bail!("Cannot use REC specifications with mCRL2's jitty rewriter");
136
        }
137
    }
138

            
139
    Ok(())
140
}