prune_lang/cli/
pipeline.rs

1use super::args::CliArgs;
2use super::diagnostic::{DiagLevel, Diagnostic};
3use super::*;
4use crate::{block, logic, sched, syntax, tych};
5
6pub struct PipeIO {
7    pub output: Box<dyn Write>,
8    pub stat_log: Box<dyn Write>,
9}
10
11impl PipeIO {
12    pub fn empty() -> PipeIO {
13        PipeIO {
14            output: Box::new(io::empty()),
15            stat_log: Box::new(io::empty()),
16        }
17    }
18
19    pub fn stdout() -> PipeIO {
20        PipeIO {
21            output: Box::new(io::stdout()),
22            stat_log: Box::new(io::stdout()),
23        }
24    }
25}
26
27pub struct Pipeline<'arg> {
28    pub args: &'arg CliArgs,
29    pub diags: Vec<Diagnostic>,
30}
31
32impl<'arg> Pipeline<'arg> {
33    pub fn new(args: &'arg CliArgs) -> Pipeline<'arg> {
34        Pipeline {
35            args,
36            diags: Vec::new(),
37        }
38    }
39
40    fn emit_diags<D: Into<Diagnostic>>(&mut self, diags: Vec<D>) -> bool {
41        let mut flag = false;
42        for diag in diags.into_iter() {
43            let diag = diag.into();
44            if diag.level == DiagLevel::Error
45                || (self.args.warn_as_err && diag.level == DiagLevel::Warn)
46            {
47                flag = true;
48            }
49            self.diags.push(diag);
50        }
51        flag
52    }
53
54    pub fn run_pipline(
55        &mut self,
56        src: &str,
57        pipe_io: &mut PipeIO,
58    ) -> Result<Vec<usize>, io::Error> {
59        let mut prog = self.parse_program(src)?;
60
61        self.rename_pass(&mut prog)?;
62
63        self.check_pass(&mut prog)?;
64
65        let prog = self.compile_pass(&prog);
66
67        let res = self.run_backend(&prog, pipe_io);
68        Ok(res)
69    }
70
71    pub fn parse_program(&mut self, src: &str) -> Result<syntax::ast::Program, io::Error> {
72        let (prog, errs) = syntax::parser::parse_program(src);
73        if self.emit_diags(errs) {
74            return Err(io::Error::other("failed to parse program!"));
75        }
76        Ok(prog)
77    }
78
79    pub fn rename_pass(&mut self, prog: &mut syntax::ast::Program) -> Result<(), io::Error> {
80        let errs = tych::rename::rename_pass(prog);
81        if self.emit_diags(errs) {
82            return Err(io::Error::other("failed in binding analysis pass!"));
83        }
84        Ok(())
85    }
86
87    pub fn check_pass(&mut self, prog: &mut syntax::ast::Program) -> Result<(), io::Error> {
88        let errs = tych::check::check_pass(prog);
89        if self.emit_diags(errs) {
90            return Err(io::Error::other("failed in type checking pass!"));
91        }
92        Ok(())
93    }
94
95    pub fn compile_pass(&mut self, prog: &syntax::ast::Program) -> block::ast::Program {
96        let mut prog = logic::transform::logic_translation(prog);
97
98        logic::elab::elab_pass(&mut prog);
99
100        block::compile::compile_dict(&prog)
101    }
102
103    pub fn run_backend(&self, prog: &block::ast::Program, pipe_io: &mut PipeIO) -> Vec<usize> {
104        let mut res_vec = Vec::new();
105        let mut wlk = sched::walker::Walker::new(&prog.preds, pipe_io, self.args.backend);
106        for query_decl in &prog.querys {
107            wlk.config_reset_default();
108            for param in query_decl.params.iter() {
109                wlk.config_set_param(param);
110            }
111            let res = wlk.run_loop(query_decl.entry);
112            res_vec.push(res);
113        }
114        res_vec
115    }
116}
117
118pub fn run_pipline(args: &CliArgs) -> Result<Vec<usize>, io::Error> {
119    let src = std::fs::read_to_string(&args.input)?;
120
121    let mut pipe_io = PipeIO::empty();
122
123    if args.mute_output {
124        pipe_io.output = Box::new(std::io::empty());
125    } else if let Some(path) = &args.output {
126        pipe_io.output = Box::new(File::create(path)?);
127    } else {
128        pipe_io.output = Box::new(std::io::stdout());
129    }
130
131    if args.mute_stat_log {
132        pipe_io.stat_log = Box::new(std::io::empty());
133    } else if let Some(path) = &args.stat_log {
134        pipe_io.stat_log = Box::new(File::create(path)?);
135    } else {
136        pipe_io.stat_log = Box::new(std::io::stdout());
137    }
138
139    let mut pipe = Pipeline::new(args);
140    match pipe.run_pipline(&src, &mut pipe_io) {
141        Ok(res) => {
142            for diag in pipe.diags.into_iter() {
143                eprintln!("{}", diag.report(&src, args.verbosity));
144            }
145            Ok(res)
146        }
147        Err(err) => {
148            for diag in pipe.diags.into_iter() {
149                eprintln!("{}", diag.report(&src, args.verbosity));
150            }
151            Err(err)
152        }
153    }
154}
155
156pub fn run_cli() -> Result<Vec<usize>, io::Error> {
157    let args = args::parse_cli_args();
158    let res = pipeline::run_pipline(&args)?;
159    Ok(res)
160}
161
162pub fn run_cli_test(prog_name: PathBuf) -> Result<Vec<usize>, io::Error> {
163    let args = args::get_test_cli_args(prog_name);
164    let res = pipeline::run_pipline(&args)?;
165    Ok(res)
166}