1use alloc::format;
2
3use super::{context::Context, Error, ErrorKind, Result, Span};
4use crate::{
5 proc::ResolveContext, Expression, Handle, ImageClass, ImageDimension, Scalar, ScalarKind, Type,
6 TypeInner, VectorSize,
7};
8
9pub fn parse_type(type_name: &str) -> Option<Type> {
10 match type_name {
11 "bool" => Some(Type {
12 name: None,
13 inner: TypeInner::Scalar(Scalar::BOOL),
14 }),
15 "float16_t" => Some(Type {
16 name: None,
17 inner: TypeInner::Scalar(Scalar::F16),
18 }),
19 "float" => Some(Type {
20 name: None,
21 inner: TypeInner::Scalar(Scalar::F32),
22 }),
23 "double" => Some(Type {
24 name: None,
25 inner: TypeInner::Scalar(Scalar::F64),
26 }),
27 "int" => Some(Type {
28 name: None,
29 inner: TypeInner::Scalar(Scalar::I32),
30 }),
31 "uint" => Some(Type {
32 name: None,
33 inner: TypeInner::Scalar(Scalar::U32),
34 }),
35 "sampler" | "samplerShadow" => Some(Type {
36 name: None,
37 inner: TypeInner::Sampler {
38 comparison: type_name == "samplerShadow",
39 },
40 }),
41 word => {
42 fn kind_width_parse(ty: &str) -> Option<Scalar> {
43 Some(match ty {
44 "" => Scalar::F32,
45 "b" => Scalar::BOOL,
46 "i" => Scalar::I32,
47 "u" => Scalar::U32,
48 "d" => Scalar::F64,
49 "f16" => Scalar::F16,
50 _ => return None,
51 })
52 }
53
54 fn size_parse(n: &str) -> Option<VectorSize> {
55 Some(match n {
56 "2" => VectorSize::Bi,
57 "3" => VectorSize::Tri,
58 "4" => VectorSize::Quad,
59 _ => return None,
60 })
61 }
62
63 let vec_parse = |word: &str| {
64 let mut iter = word.split("vec");
65
66 let kind = iter.next()?;
67 let size = iter.next()?;
68 let scalar = kind_width_parse(kind)?;
69 let size = size_parse(size)?;
70
71 Some(Type {
72 name: None,
73 inner: TypeInner::Vector { size, scalar },
74 })
75 };
76
77 let mat_parse = |word: &str| {
78 let mut iter = word.split("mat");
79
80 let kind = iter.next()?;
81 let size = iter.next()?;
82 let scalar = kind_width_parse(kind)?;
83
84 let (columns, rows) = if let Some(size) = size_parse(size) {
85 (size, size)
86 } else {
87 let mut iter = size.split('x');
88 match (iter.next()?, iter.next()?, iter.next()) {
89 (col, row, None) => (size_parse(col)?, size_parse(row)?),
90 _ => return None,
91 }
92 };
93
94 Some(Type {
95 name: None,
96 inner: TypeInner::Matrix {
97 columns,
98 rows,
99 scalar,
100 },
101 })
102 };
103
104 let texture_parse = |word: &str| {
105 let mut iter = word.split("texture");
106
107 let texture_kind = |ty| {
108 Some(match ty {
109 "" => ScalarKind::Float,
110 "i" => ScalarKind::Sint,
111 "u" => ScalarKind::Uint,
112 _ => return None,
113 })
114 };
115
116 let kind = iter.next()?;
117 let size = iter.next()?;
118 let kind = texture_kind(kind)?;
119
120 let sampled = |multi| ImageClass::Sampled { kind, multi };
121
122 let (dim, arrayed, class) = match size {
123 "1D" => (ImageDimension::D1, false, sampled(false)),
124 "1DArray" => (ImageDimension::D1, true, sampled(false)),
125 "2D" => (ImageDimension::D2, false, sampled(false)),
126 "2DArray" => (ImageDimension::D2, true, sampled(false)),
127 "2DMS" => (ImageDimension::D2, false, sampled(true)),
128 "2DMSArray" => (ImageDimension::D2, true, sampled(true)),
129 "3D" => (ImageDimension::D3, false, sampled(false)),
130 "Cube" => (ImageDimension::Cube, false, sampled(false)),
131 "CubeArray" => (ImageDimension::Cube, true, sampled(false)),
132 _ => return None,
133 };
134
135 Some(Type {
136 name: None,
137 inner: TypeInner::Image {
138 dim,
139 arrayed,
140 class,
141 },
142 })
143 };
144
145 let image_parse = |word: &str| {
146 let mut iter = word.split("image");
147
148 let texture_kind = |ty| {
149 Some(match ty {
150 "" => ScalarKind::Float,
151 "i" => ScalarKind::Sint,
152 "u" => ScalarKind::Uint,
153 _ => return None,
154 })
155 };
156
157 let kind = iter.next()?;
158 let size = iter.next()?;
159 let _ = texture_kind(kind)?;
161
162 let class = ImageClass::Storage {
163 format: crate::StorageFormat::R8Uint,
164 access: crate::StorageAccess::LOAD | crate::StorageAccess::STORE,
165 };
166
167 let (dim, arrayed) = match size {
169 "1D" => (ImageDimension::D1, false),
170 "1DArray" => (ImageDimension::D1, true),
171 "2D" => (ImageDimension::D2, false),
172 "2DArray" => (ImageDimension::D2, true),
173 "3D" => (ImageDimension::D3, false),
174 _ => return None,
179 };
180
181 Some(Type {
182 name: None,
183 inner: TypeInner::Image {
184 dim,
185 arrayed,
186 class,
187 },
188 })
189 };
190
191 vec_parse(word)
192 .or_else(|| mat_parse(word))
193 .or_else(|| texture_parse(word))
194 .or_else(|| image_parse(word))
195 }
196 }
197}
198
199pub const fn scalar_components(ty: &TypeInner) -> Option<Scalar> {
200 match *ty {
201 TypeInner::Scalar(scalar)
202 | TypeInner::Vector { scalar, .. }
203 | TypeInner::ValuePointer { scalar, .. }
204 | TypeInner::Matrix { scalar, .. } => Some(scalar),
205 _ => None,
206 }
207}
208
209pub const fn type_power(scalar: Scalar) -> Option<u32> {
210 Some(match scalar.kind {
211 ScalarKind::Sint => 0,
212 ScalarKind::Uint => 1,
213 ScalarKind::Float if scalar.width == 4 => 2,
214 ScalarKind::Float => 3,
215 ScalarKind::Bool | ScalarKind::AbstractInt | ScalarKind::AbstractFloat => return None,
216 })
217}
218
219impl Context<'_> {
220 pub(crate) fn typifier_grow(&mut self, expr: Handle<Expression>, meta: Span) -> Result<()> {
234 let resolve_ctx = ResolveContext::with_locals(self.module, &self.locals, &self.arguments);
235
236 let typifier = if self.is_const {
237 &mut self.const_typifier
238 } else {
239 &mut self.typifier
240 };
241
242 let expressions = if self.is_const {
243 &self.module.global_expressions
244 } else {
245 &self.expressions
246 };
247
248 typifier
249 .grow(expr, expressions, &resolve_ctx)
250 .map_err(|error| Error {
251 kind: ErrorKind::SemanticError(format!("Can't resolve type: {error:?}").into()),
252 meta,
253 })
254 }
255
256 pub(crate) fn get_type(&self, expr: Handle<Expression>) -> &TypeInner {
257 let typifier = if self.is_const {
258 &self.const_typifier
259 } else {
260 &self.typifier
261 };
262
263 typifier.get(expr, &self.module.types)
264 }
265
266 pub(crate) fn resolve_type(
274 &mut self,
275 expr: Handle<Expression>,
276 meta: Span,
277 ) -> Result<&TypeInner> {
278 self.typifier_grow(expr, meta)?;
279 Ok(self.get_type(expr))
280 }
281
282 pub(crate) fn resolve_type_handle(
298 &mut self,
299 expr: Handle<Expression>,
300 meta: Span,
301 ) -> Result<Handle<Type>> {
302 self.typifier_grow(expr, meta)?;
303
304 let typifier = if self.is_const {
305 &mut self.const_typifier
306 } else {
307 &mut self.typifier
308 };
309
310 Ok(typifier.register_type(expr, &mut self.module.types))
311 }
312
313 pub(crate) fn invalidate_expression(
315 &mut self,
316 expr: Handle<Expression>,
317 meta: Span,
318 ) -> Result<()> {
319 let resolve_ctx = ResolveContext::with_locals(self.module, &self.locals, &self.arguments);
320
321 let typifier = if self.is_const {
322 &mut self.const_typifier
323 } else {
324 &mut self.typifier
325 };
326
327 typifier
328 .invalidate(expr, &self.expressions, &resolve_ctx)
329 .map_err(|error| Error {
330 kind: ErrorKind::SemanticError(format!("Can't resolve type: {error:?}").into()),
331 meta,
332 })
333 }
334
335 pub(crate) fn lift_up_const_expression(
336 &mut self,
337 expr: Handle<Expression>,
338 ) -> Result<Handle<Expression>> {
339 let meta = self.expressions.get_span(expr);
340 let h = match self.expressions[expr] {
341 ref expr @ (Expression::Literal(_)
342 | Expression::Constant(_)
343 | Expression::ZeroValue(_)) => {
344 self.module.global_expressions.append(expr.clone(), meta)
345 }
346 Expression::Compose { ty, ref components } => {
347 let mut components = components.clone();
348 for component in &mut components {
349 *component = self.lift_up_const_expression(*component)?;
350 }
351 self.module
352 .global_expressions
353 .append(Expression::Compose { ty, components }, meta)
354 }
355 Expression::Splat { size, value } => {
356 let value = self.lift_up_const_expression(value)?;
357 self.module
358 .global_expressions
359 .append(Expression::Splat { size, value }, meta)
360 }
361 _ => {
362 return Err(Error {
363 kind: ErrorKind::SemanticError("Expression is not const-expression".into()),
364 meta,
365 })
366 }
367 };
368 self.global_expression_kind_tracker
369 .insert(h, crate::proc::ExpressionKind::Const);
370 Ok(h)
371 }
372}