1use crate::Parser;
4use cl_ast::{ast_visitor::Fold, *};
5use cl_lexer::Lexer;
6use std::path::{Path, PathBuf};
7
8pub type IoErrs = Vec<(PathBuf, std::io::Error)>;
9pub type ParseErrs = Vec<(PathBuf, crate::error::Error)>;
10
11pub struct ModuleInliner {
12 path: PathBuf,
13 io_errs: IoErrs,
14 parse_errs: ParseErrs,
15}
16
17impl ModuleInliner {
18 pub fn new(root: impl AsRef<Path>) -> Self {
20 Self {
21 path: root.as_ref().to_path_buf(),
22 io_errs: Default::default(),
23 parse_errs: Default::default(),
24 }
25 }
26
27 pub fn has_errors(&self) -> bool {
29 !(self.io_errs.is_empty() && self.parse_errs.is_empty())
30 }
31
32 pub fn into_errs(self) -> Option<(IoErrs, ParseErrs)> {
34 self.has_errors().then_some((self.io_errs, self.parse_errs))
35 }
36
37 pub fn inline(mut self, file: File) -> Result<File, (File, IoErrs, ParseErrs)> {
42 let file = self.fold_file(file);
43
44 match self.into_errs() {
45 Some((io, parse)) => Err((file, io, parse)),
46 None => Ok(file),
47 }
48 }
49
50 fn handle_io_error(&mut self, error: std::io::Error) -> Option<File> {
52 self.io_errs.push((self.path.clone(), error));
53 None
54 }
55
56 fn handle_parse_error(&mut self, error: crate::error::Error) -> Option<File> {
58 self.parse_errs.push((self.path.clone(), error));
59 None
60 }
61}
62
63impl Fold for ModuleInliner {
64 fn fold_module(&mut self, m: Module) -> Module {
66 let Module { name, file } = m;
67 self.path.push(&*name); let file = self.fold_module_kind(file);
70
71 self.path.pop(); Module { name, file }
73 }
74}
75
76impl ModuleInliner {
77 fn fold_module_kind(&mut self, m: Option<File>) -> Option<File> {
79 use std::borrow::Cow;
80 if let Some(f) = m {
81 return Some(self.fold_file(f));
82 }
83
84 self.path.set_extension("cl");
86 let mut used_path: Cow<Path> = Cow::Borrowed(&self.path);
87
88 let file = match std::fs::read_to_string(&self.path) {
89 Err(error) => {
90 let Some(basename) = self.path.file_name() else {
91 return self.handle_io_error(error);
92 };
93 used_path = Cow::Owned(
94 self.path
95 .parent()
96 .and_then(Path::parent)
97 .map(|path| path.join(basename))
98 .unwrap_or_default(),
99 );
100
101 match std::fs::read_to_string(&used_path) {
102 Err(error) => return self.handle_io_error(error),
103 Ok(file) => file,
104 }
105 }
106 Ok(file) => file,
107 };
108
109 match Parser::new(used_path.display().to_string(), Lexer::new(&file)).parse() {
110 Err(e) => self.handle_parse_error(e),
111 Ok(file) => {
112 self.path.set_extension("");
113 Some(self.fold_file(file))
115 }
116 }
117 }
118}