1use std::{
2 collections::{hash_map::Entry, HashMap},
3 path::{Path, PathBuf},
4};
5
6use bimap::BiHashMap;
7
8use lang_util::{
9 located::{FileIdResolver, Located, LocatedBuilder},
10 FileId,
11};
12
13use crate::{
14 last::LocatedIterator,
15 parser::{Ast, Parser},
16 types::path::{ParsedPath, PathType},
17};
18
19use super::{
20 event::{Event, ProcessingErrorKind},
21 expand::{ExpandEvent, ExpandOne},
22 ProcessorState,
23};
24
25pub trait FileSystem {
26 type Error: std::error::Error + 'static;
27
28 fn canonicalize(&self, path: &Path) -> Result<PathBuf, Self::Error>;
29 fn exists(&self, path: &Path) -> bool;
30 fn read(&self, path: &Path) -> Result<std::borrow::Cow<'_, str>, Self::Error>;
31}
32
33#[derive(Default, Debug, Clone, Copy)]
34pub struct Std;
35
36impl FileSystem for Std {
37 type Error = std::io::Error;
38
39 fn canonicalize(&self, path: &Path) -> Result<PathBuf, Self::Error> {
40 std::fs::canonicalize(path)
41 }
42
43 fn exists(&self, path: &Path) -> bool {
44 path.exists()
45 }
46
47 fn read(&self, path: &Path) -> Result<std::borrow::Cow<'_, str>, Self::Error> {
48 std::fs::read_to_string(path).map(Into::into)
49 }
50}
51
52pub type StdProcessor = Processor<Std>;
53
54pub struct ExpandStack<'p, F: FileSystem> {
55 processor: &'p mut Processor<F>,
56 stack: Vec<ExpandOne>,
57 state: Option<ProcessorState>,
58}
59
60impl<'p, F: FileSystem> ExpandStack<'p, F> {
61 pub fn tokenize(
62 self,
63 current_version: u16,
64 target_vulkan: bool,
65 registry: &crate::exts::Registry,
66 ) -> crate::last::Tokenizer<'_, Self> {
67 crate::last::Tokenizer::new(self, current_version, target_vulkan, registry)
68 }
69
70 pub fn into_state(self) -> Option<ProcessorState> {
71 self.state
72 }
73}
74
75impl<'p, F: FileSystem> Iterator for ExpandStack<'p, F> {
76 type Item = Result<Event, Located<F::Error>>;
77
78 fn next(&mut self) -> Option<Self::Item> {
79 loop {
80 if let Some(mut expand) = self.stack.pop() {
81 let result = expand.next();
82
83 if let Some(event) = result {
84 match event {
85 ExpandEvent::Event(event) => {
86 self.stack.push(expand);
88
89 return Some(match event {
90 Event::EnterFile { file_id, .. } => {
91 if let Some((canonical_path, input_path)) =
92 self.processor.get_paths(file_id)
93 {
94 Ok(Event::EnterFile {
95 file_id,
96 path: input_path.to_owned(),
97 canonical_path: canonical_path.to_owned(),
98 })
99 } else {
100 Ok(Event::EnterFile {
102 file_id,
103 path: Default::default(),
104 canonical_path: Default::default(),
105 })
106 }
107 }
108 other => Ok(other),
109 });
110 }
111 ExpandEvent::EnterFile(node, path) => {
112 let state = expand.state().unwrap().clone();
113
114 self.stack.push(expand);
116
117 let location = self.stack.last().unwrap().location();
119
120 if let Some(resolved_path) = self
123 .processor
124 .resolve_relative_to_id(location.current_file(), &path)
125 {
126 match self.processor.parse(&resolved_path) {
128 Ok(parsed) => {
129 self.stack.push(parsed.expand_one(state));
130 }
131 Err(error) => {
132 return Some(Err(LocatedBuilder::new()
135 .pos(node.text_range())
136 .path(resolved_path)
137 .resolve_file(location)
138 .finish(error)));
139 }
140 }
141 } else {
142 return Some(Ok(Event::error(
145 ProcessingErrorKind::IncludeNotFound { path },
146 node.text_range(),
147 location,
148 false,
149 )));
150 }
151 }
152 ExpandEvent::Completed(state) => {
153 if let Some(last) = self.stack.last_mut() {
154 last.set_state(state);
156 } else {
157 self.state = Some(state);
159 }
160 }
161 }
162 }
163 } else {
164 return None;
165 }
166 }
167 }
168}
169
170impl<'p, F: FileSystem> FileIdResolver for ExpandStack<'p, F> {
171 fn resolve(&self, file_id: FileId) -> Option<&Path> {
172 <Processor<F> as FileIdResolver>::resolve(self.processor, file_id)
173 }
174}
175
176#[derive(Debug)]
177pub struct ParsedFile<'p, F: FileSystem> {
178 processor: &'p mut Processor<F>,
179 file_id: FileId,
180}
181
182impl<'p, F: FileSystem> ParsedFile<'p, F> {
183 pub fn file_id(&self) -> FileId {
184 self.file_id
185 }
186
187 pub fn process(self, initial_state: ProcessorState) -> ExpandStack<'p, F> {
188 let ast = self.ast();
189
190 ExpandStack {
191 processor: self.processor,
192 stack: vec![ExpandOne::new((self.file_id, ast), initial_state)],
193 state: None,
194 }
195 }
196
197 pub fn ast(&self) -> Ast {
198 self.processor
199 .file_cache
200 .get(&self.file_id)
201 .unwrap()
202 .clone()
203 }
204
205 fn expand_one(self, initial_state: ProcessorState) -> ExpandOne {
206 ExpandOne::new(self, initial_state)
207 }
208}
209
210impl<'p, F: FileSystem> From<ParsedFile<'p, F>> for (FileId, Ast) {
211 fn from(parsed_file: ParsedFile<'p, F>) -> Self {
212 let ast = parsed_file.ast();
213 (parsed_file.file_id, ast)
214 }
215}
216
217impl<'p, F: FileSystem> IntoIterator for ParsedFile<'p, F> {
218 type Item = <ExpandStack<'p, F> as Iterator>::Item;
219 type IntoIter = ExpandStack<'p, F>;
220
221 fn into_iter(self) -> Self::IntoIter {
222 self.process(ProcessorState::default())
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, derive_more::From)]
227enum PathOrSource {
228 Source(usize, PathBuf),
229 Path(PathBuf),
230}
231
232impl PathOrSource {
233 fn as_path(&self) -> Option<&PathBuf> {
234 match self {
235 PathOrSource::Source(_, _) => None,
236 PathOrSource::Path(path) => Some(path),
237 }
238 }
239}
240
241#[derive(Debug)]
243pub struct Processor<F: FileSystem> {
244 file_cache: HashMap<FileId, Ast>,
246 file_ids: BiHashMap<PathOrSource, FileId>,
248 canonical_paths: BiHashMap<PathBuf, PathBuf>,
250 system_paths: Vec<PathBuf>,
252 fs: F,
254}
255
256impl<F: FileSystem> Processor<F> {
257 pub fn new_with_fs(fs: F) -> Self {
258 Self {
259 file_cache: HashMap::with_capacity(1),
260 file_ids: BiHashMap::with_capacity(1),
261 canonical_paths: BiHashMap::with_capacity(1),
262 system_paths: Vec::new(),
263 fs,
264 }
265 }
266
267 fn get_paths(&self, file_id: FileId) -> Option<(&PathBuf, &PathBuf)> {
268 let canonical_path = self.file_ids.get_by_right(&file_id)?;
270
271 let canonical_path = match canonical_path {
272 PathOrSource::Source(_, _) => {
273 return None;
274 }
275 PathOrSource::Path(path) => path,
276 };
277
278 let input_path = self.canonical_paths.get_by_right(canonical_path)?;
280
281 Some((canonical_path, input_path))
282 }
283
284 pub fn system_paths(&self) -> &Vec<PathBuf> {
285 &self.system_paths
286 }
287
288 pub fn system_paths_mut(&mut self) -> &mut Vec<PathBuf> {
289 &mut self.system_paths
290 }
291
292 fn resolve_relative_to_id(&self, relative_to: FileId, path: &ParsedPath) -> Option<PathBuf> {
293 let parent = self
294 .file_ids
295 .get_by_right(&relative_to)
296 .and_then(|key| match key {
297 PathOrSource::Source(_, dir) => Some(dir.as_path()),
298 PathOrSource::Path(path) => self
299 .canonical_paths
300 .get_by_right(path)
301 .and_then(|path| path.parent()),
302 })?;
303
304 self.resolve_relative_to_path(parent, path)
305 }
306
307 pub fn resolve_relative_to_path(
308 &self,
309 parent: impl AsRef<Path>,
310 path: &ParsedPath,
311 ) -> Option<PathBuf> {
312 let path_as_pathbuf = PathBuf::from(&path.path);
314
315 if path_as_pathbuf.is_absolute() {
316 return Some(path_as_pathbuf);
318 }
319
320 match path.ty {
322 PathType::Angle => self.system_paths.iter().find_map(|system_path| {
323 let full_path = system_path.join(&path_as_pathbuf);
324 self.fs.exists(&full_path).then_some(full_path)
325 }),
326 PathType::Quote => Some(parent.as_ref().join(path_as_pathbuf)),
327 }
328 }
329
330 pub fn parse(&mut self, path: &Path) -> Result<ParsedFile<F>, F::Error> {
331 let canonical_path = if let Some(canonical_path) = self.canonical_paths.get_by_left(path) {
333 canonical_path
334 } else {
335 let canonical_path = self.fs.canonicalize(path)?;
336 self.canonical_paths.insert(path.to_owned(), canonical_path);
337 self.canonical_paths.get_by_left(path).unwrap()
338 };
339
340 let key: PathOrSource = canonical_path.to_owned().into();
342 let file_id = if let Some(file_id) = self.file_ids.get_by_left(&key) {
343 *file_id
344 } else {
345 let file_id = FileId::new(self.file_ids.len() as _);
346 self.file_ids.insert(key, file_id);
347 file_id
348 };
349
350 match self.file_cache.entry(file_id) {
351 Entry::Occupied(_) => Ok(ParsedFile {
352 processor: self,
353 file_id,
354 }),
355 Entry::Vacant(entry) => {
356 let input = self.fs.read(canonical_path)?;
358 let ast = Parser::new(&input).parse();
360 debug_assert_eq!(u32::from(ast.green_node().text_len()), input.len() as u32);
362 entry.insert(ast);
364
365 Ok(ParsedFile {
366 processor: self,
367 file_id,
368 })
369 }
370 }
371 }
372
373 pub fn parse_source(&mut self, source: &str, path: &Path) -> ParsedFile<F> {
380 let key = PathOrSource::Source(self.file_ids.len(), path.to_owned());
382
383 let file_id = FileId::new(self.file_ids.len() as _);
385 self.file_ids.insert(key, file_id);
386
387 let ast = Parser::new(source).parse();
389 debug_assert_eq!(u32::from(ast.green_node().text_len()), source.len() as u32);
391 self.file_cache.insert(file_id, ast);
393
394 ParsedFile {
395 processor: self,
396 file_id,
397 }
398 }
399}
400
401impl<F: FileSystem + Default> Processor<F> {
402 pub fn new() -> Self {
403 Self::default()
404 }
405}
406
407impl<F: FileSystem + Default> Default for Processor<F> {
408 fn default() -> Self {
409 Self::new_with_fs(F::default())
410 }
411}
412
413impl<F: FileSystem> FileIdResolver for Processor<F> {
414 fn resolve(&self, file_id: FileId) -> Option<&Path> {
415 self.file_ids
416 .get_by_right(&file_id)
417 .and_then(PathOrSource::as_path)
418 .and_then(|canonical_path| self.canonical_paths.get_by_right(canonical_path))
419 .map(|pathbuf| pathbuf.as_path())
420 }
421}
422
423impl<'p, F: FileSystem> LocatedIterator for ExpandStack<'p, F> {
424 fn location(&self) -> &crate::processor::expand::ExpandLocation {
425 self.stack.last().unwrap().location()
426 }
427}