1
use std::ffi::OsStr;
2
use std::fs::File;
3
use std::io::Write;
4
use std::path::PathBuf;
5
use std::process::ExitCode;
6

            
7
use clap::Parser;
8
use clap::Subcommand;
9

            
10
use merc_rec_tests::load_rec_from_file;
11
use merc_tools::VerbosityFlag;
12
use merc_tools::Version;
13
use merc_tools::VersionFlag;
14
use merc_unsafety::print_allocator_metrics;
15
use merc_utilities::MercError;
16

            
17
use merc_rewrite::Rewriter;
18
use merc_rewrite::rewrite_rec;
19

            
20
mod trs_format;
21

            
22
use merc_utilities::Timing;
23
pub use trs_format::*;
24

            
25
/// A command line rewriting tool
26
#[derive(clap::Parser, Debug)]
27
#[command(arg_required_else_help = true)]
28
struct Cli {
29
    #[command(flatten)]
30
    version: VersionFlag,
31

            
32
    #[command(flatten)]
33
    verbosity: VerbosityFlag,
34

            
35
    #[command(subcommand)]
36
    commands: Option<Commands>,
37
}
38

            
39
#[derive(Debug, Subcommand)]
40
enum Commands {
41
    Rewrite(RewriteArgs),
42
    Convert(ConvertArgs),
43
}
44

            
45
/// Rewrite mCRL2 data specifications and REC files
46
#[derive(clap::Args, Debug)]
47
#[command()]
48
struct RewriteArgs {
49
    rewriter: Rewriter,
50

            
51
    /// The REC specification that contains the rewrite rules.
52
    #[arg(value_name = "SPEC")]
53
    specification: PathBuf,
54

            
55
    /// File containing the terms to be rewritten.
56
    terms: Option<String>,
57

            
58
    /// Print the rewritten term(s)
59
    #[arg(long)]
60
    output: bool,
61
}
62

            
63
/// Convert input rewrite system to the TRS format"
64
#[derive(clap::Args, Debug)]
65
#[command()]
66
struct ConvertArgs {
67
    /// The REC specification that contains the rewrite rules.
68
    #[arg(value_name = "SPEC")]
69
    specification: PathBuf,
70

            
71
    output: String,
72
}
73

            
74
fn main() -> Result<ExitCode, MercError> {
75
    let cli = Cli::parse();
76

            
77
    env_logger::Builder::new()
78
        .filter_level(cli.verbosity.log_level_filter())
79
        .parse_default_env()
80
        .init();
81

            
82
    if cli.version.into() {
83
        eprintln!("{}", Version);
84
        return Ok(ExitCode::SUCCESS);
85
    }
86

            
87
    let timing = Timing::new();
88

            
89
    if let Some(command) = cli.commands {
90
        match command {
91
            Commands::Rewrite(args) => {
92
                if args.specification.extension() == Some(OsStr::new("rec")) {
93
                    assert!(args.terms.is_none());
94
                    rewrite_rec(args.rewriter, &args.specification, args.output, &timing)?;
95
                }
96
            }
97
            Commands::Convert(args) => {
98
                if args.specification.extension() == Some(OsStr::new("rec")) {
99
                    // Read the data specification
100
                    let (spec_text, _) = load_rec_from_file(&args.specification)?;
101
                    let spec = spec_text.to_rewrite_spec();
102

            
103
                    let mut output = File::create(args.output)?;
104
                    write!(output, "{}", TrsFormatter::new(&spec))?;
105
                }
106
            }
107
        }
108
    }
109

            
110
    timing.print();
111

            
112
    print_allocator_metrics();
113
    Ok(ExitCode::SUCCESS)
114
}