1use std::collections::{HashMap, HashSet};
2
3use wgsl_parse::syntax::{Ident, ModulePath, TranslationUnit, Visibility};
4
5use crate::{
6 SyntaxUtil,
7 error::{Diagnostic, Error},
8 pass::{self, CompileResult, CompilerDriver, Module, UsedItems},
9 resolver::{AsyncResolver, Resolver},
10};
11
12pub fn main_entry_points(main_module: &TranslationUnit) -> HashSet<Ident> {
13 main_module.entry_points().collect()
14}
15
16pub fn load_module(path: &ModulePath, resolver: &impl Resolver) -> Result<TranslationUnit, Error> {
18 let source = resolver.resolve_source(path)?;
19
20 let module: TranslationUnit = source.parse().map_err(|e| {
21 Diagnostic::from(e)
22 .with_module_path(path.clone(), resolver.display_name(path))
23 .with_source(source.to_string())
24 })?;
25
26 Ok(module)
27}
28
29pub async fn load_module_async(
30 path: &ModulePath,
31 resolver: &impl AsyncResolver,
32) -> Result<TranslationUnit, Error> {
33 let source = resolver.resolve_source_async(path).await?;
34
35 let mut module: TranslationUnit = source.parse().map_err(|e| {
36 Diagnostic::from(e)
37 .with_module_path(path.clone(), resolver.display_name(path))
38 .with_source(source.to_string())
39 })?;
40
41 pass::retarget_idents(&mut module);
42
43 Ok(module)
44}
45
46pub fn compile(driver: &mut impl CompilerDriver) -> Result<CompileResult, Error> {
48 let main_path = driver.main_path().clone();
49 let main_module = driver.load_module(&main_path)?;
50 let main_entrypoints = driver
51 .main_entry_points(&main_module)?
52 .into_iter()
53 .map(|ident| (ident, Visibility::Private)) .collect::<HashMap<Ident, Visibility>>();
55
56 let mut modules = Vec::new();
57 modules.push(Module::new(main_path.clone(), main_module));
58
59 let mut used_items = UsedItems::new();
60 let mut to_analyze = UsedItems::new();
61 to_analyze.insert_module(main_path, main_entrypoints);
62
63 loop {
64 let mut next_to_analyze = UsedItems::new();
65
66 for (path, items_to_analyze) in to_analyze.iter() {
67 let path = driver.canonical_path(path);
68 let module = match modules.iter().find(|module| module.path == path) {
69 Some(module) => module,
70 None => {
71 let module = driver.load_module(&path)?;
72 modules.push_mut(Module::new(path, module))
73 }
74 };
75
76 driver.module_usage_analysis(module, &mut used_items, &mut next_to_analyze)?;
77
78 for (item, min_vis) in items_to_analyze {
79 driver.usage_analysis(
80 module,
81 &item.name(),
82 *min_vis,
83 &mut used_items,
84 &mut next_to_analyze,
85 )?;
86 }
87 }
88
89 if next_to_analyze.is_empty() {
90 break;
91 }
92
93 to_analyze = next_to_analyze;
94 }
95
96 let final_module = driver.link(&mut modules, &used_items)?;
97
98 Ok(CompileResult {
99 syntax: final_module,
100 modules,
101 used_items,
102 })
103}
104
105pub async fn compile_async(driver: &mut impl CompilerDriver) -> Result<CompileResult, Error> {
106 let main_path = driver.main_path().clone();
107 let main_module = driver.load_module(&main_path)?;
108 let main_entrypoints = driver
109 .main_entry_points(&main_module)?
110 .into_iter()
111 .map(|ident| (ident, Visibility::Private)) .collect::<HashMap<Ident, Visibility>>();
113
114 let mut modules = Vec::new();
115 modules.push(Module::new(main_path.clone(), main_module));
116
117 let mut used_items = UsedItems::new();
118 let mut to_analyze = UsedItems::new();
119 to_analyze.insert_module(main_path, main_entrypoints);
120
121 loop {
122 let mut next_to_analyze = UsedItems::new();
123
124 for (path, items_to_analyze) in to_analyze.iter() {
125 let path = driver.canonical_path(path);
126 let module = match modules.iter().find(|module| module.path == path) {
127 Some(module) => module,
128 None => {
129 let module = driver.load_module_async(&path).await?;
130 modules.push_mut(Module::new(path, module))
131 }
132 };
133
134 driver.module_usage_analysis(module, &mut used_items, &mut next_to_analyze)?;
135
136 for (item, min_vis) in items_to_analyze {
137 driver.usage_analysis(
138 module,
139 &item.name(),
140 *min_vis,
141 &mut used_items,
142 &mut next_to_analyze,
143 )?;
144 }
145 }
146
147 if next_to_analyze.is_empty() {
148 break;
149 }
150
151 to_analyze = next_to_analyze;
152 }
153
154 let final_module = driver.link(&mut modules, &used_items)?;
155
156 Ok(CompileResult {
157 syntax: final_module,
158 modules,
159 used_items,
160 })
161}