Skip to main content

wesl/pass/
compile.rs

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
16/// Note: it does not call [`pass::retarget_idents`], because that must be done right after [`pass::condcomp`].
17pub 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
46/// Default implementation of [`CompilerDriver::compile`]
47pub 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)) // No visibility requirements for entry points
54        .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)) // No visibility requirements for entry points
112        .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}