prune_lang/cli/
pipeline.rs1use 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}