1use std::{cell::RefCell, collections::HashMap, path::PathBuf};
4
5use wgsl_parse::{span::Span, syntax::TypeExpression};
6
7use crate::{ModulePath, error::ResolveError, mangler::Mangler, resolver::Resolver};
8
9pub trait SourceMap {
20 fn item(&self, decl: &str) -> Option<&SourceMapEntry>;
22 fn source(&self, path: &ModulePath) -> Option<&str>;
24 fn display_name(&self, path: &ModulePath) -> Option<&str>;
26 fn default_source(&self) -> Option<&str> {
28 None
29 }
30}
31
32#[derive(Clone, Debug)]
33pub struct SourceMapEntry {
34 pub path: ModulePath,
35 pub name: String,
36 pub span: Option<Span>,
37}
38
39#[derive(Clone, Debug)]
40pub struct SourceMapFile {
41 pub source: String,
42 pub display_name: Option<String>,
43 pub path: Option<PathBuf>,
44}
45
46#[derive(Clone, Debug, Default)]
48pub struct BasicSourceMap {
49 mappings: HashMap<String, SourceMapEntry>,
50 sources: HashMap<ModulePath, SourceMapFile>,
51 default_source: Option<String>,
52}
53
54impl BasicSourceMap {
55 pub fn new() -> Self {
56 Default::default()
57 }
58 pub fn add_item(&mut self, decl: String, entry: SourceMapEntry) {
59 self.mappings.insert(decl, entry);
60 }
61 pub fn file(&self, path: &ModulePath) -> Option<&SourceMapFile> {
62 self.sources.get(path)
63 }
64 pub fn add_file(&mut self, path: ModulePath, file: SourceMapFile) {
65 self.sources.insert(path, file);
66 }
67 pub fn set_default_source(&mut self, source: String) {
68 self.default_source = Some(source);
69 }
70}
71
72impl SourceMap for BasicSourceMap {
73 fn item(&self, decl: &str) -> Option<&SourceMapEntry> {
74 self.mappings.get(decl)
75 }
76 fn source(&self, path: &ModulePath) -> Option<&str> {
77 self.sources.get(path).map(|file| file.source.as_str())
78 }
79 fn display_name(&self, path: &ModulePath) -> Option<&str> {
80 self.sources
81 .get(path)
82 .and_then(|file| file.display_name.as_deref())
83 }
84 fn default_source(&self) -> Option<&str> {
85 self.default_source.as_deref()
86 }
87}
88
89impl<T: SourceMap> SourceMap for Option<T> {
90 fn item(&self, decl: &str) -> Option<&SourceMapEntry> {
91 self.as_ref().and_then(|map| map.item(decl))
92 }
93 fn source(&self, path: &ModulePath) -> Option<&str> {
94 self.as_ref().and_then(|map| map.source(path))
95 }
96 fn display_name(&self, path: &ModulePath) -> Option<&str> {
97 self.as_ref().and_then(|map| map.display_name(path))
98 }
99 fn default_source(&self) -> Option<&str> {
100 self.as_ref().and_then(|map| map.default_source())
101 }
102}
103
104pub struct NoSourceMap;
109
110impl SourceMap for NoSourceMap {
111 fn item(&self, _decl: &str) -> Option<&SourceMapEntry> {
112 None
113 }
114 fn source(&self, _path: &ModulePath) -> Option<&str> {
115 None
116 }
117 fn display_name(&self, _path: &ModulePath) -> Option<&str> {
118 None
119 }
120 fn default_source(&self) -> Option<&str> {
121 None
122 }
123}
124
125pub struct SourceMapper<'a> {
132 pub main_path: ModulePath,
133 pub resolver: &'a dyn Resolver,
134 pub mangler: &'a dyn Mangler,
135 pub sourcemap: RefCell<BasicSourceMap>,
136}
137
138impl<'a> SourceMapper<'a> {
139 pub fn new(
141 main_path: ModulePath,
142 resolver: &'a dyn Resolver,
143 mangler: &'a dyn Mangler,
144 ) -> Self {
145 Self {
146 main_path,
147 resolver,
148 mangler,
149 sourcemap: Default::default(),
150 }
151 }
152 pub fn finish(self) -> BasicSourceMap {
154 let mut sourcemap = self.sourcemap.into_inner();
155 if let Some(file) = sourcemap.file(&self.main_path) {
156 sourcemap.set_default_source(file.source.to_string());
157 }
158 sourcemap
159 }
160}
161
162impl<'a> Resolver for SourceMapper<'a> {
163 fn resolve_source(&self, path: &ModulePath) -> Result<std::borrow::Cow<'a, str>, ResolveError> {
164 let res = self.resolver.resolve_source(path)?;
165 let mut sourcemap = self.sourcemap.borrow_mut();
166 sourcemap.add_file(
167 path.clone(),
168 SourceMapFile {
169 source: res.clone().into(),
170 display_name: self.resolver.display_name(path),
171 path: self.resolver.fs_path(path).ok(),
172 },
173 );
174 Ok(res)
175 }
176 fn display_name(&self, path: &ModulePath) -> Option<String> {
177 self.resolver.display_name(path)
178 }
179 fn fs_path(&self, path: &ModulePath) -> Result<PathBuf, ResolveError> {
180 self.resolver.fs_path(path)
181 }
182 fn canonical_path(&self, path: &ModulePath) -> ModulePath {
183 self.resolver.canonical_path(path)
184 }
185}
186
187impl<'a> Mangler for SourceMapper<'a> {
188 fn mangle(&self, path: &ModulePath, item: &str) -> String {
189 let res = self.mangler.mangle(path, item);
190 let mut sourcemap = self.sourcemap.borrow_mut();
191 let entry = SourceMapEntry {
192 path: path.clone(),
193 name: item.to_string(),
194 span: None,
195 };
196 sourcemap.add_item(res.clone(), entry);
197 res
198 }
199 fn unmangle(&self, mangled: &str) -> Option<(ModulePath, String)> {
200 self.mangler.unmangle(mangled)
201 }
202 fn mangle_types(&self, item: &str, variant: u32, types: &[TypeExpression]) -> String {
203 self.mangler.mangle_types(item, variant, types)
204 }
205}