naga/front/wgsl/parse/
ast.rs

1use alloc::vec::Vec;
2use core::hash::Hash;
3
4use crate::diagnostic_filter::DiagnosticFilterNode;
5use crate::front::wgsl::parse::directive::enable_extension::EnableExtensions;
6use crate::front::wgsl::parse::number::Number;
7use crate::front::wgsl::Scalar;
8use crate::{Arena, FastIndexSet, Handle, Span};
9
10#[derive(Debug, Default)]
11pub struct TranslationUnit<'a> {
12    pub enable_extensions: EnableExtensions,
13    pub decls: Arena<GlobalDecl<'a>>,
14    /// The common expressions arena for the entire translation unit.
15    ///
16    /// All functions, global initializers, array lengths, etc. store their
17    /// expressions here. We apportion these out to individual Naga
18    /// [`Function`]s' expression arenas at lowering time. Keeping them all in a
19    /// single arena simplifies handling of things like array lengths (which are
20    /// effectively global and thus don't clearly belong to any function) and
21    /// initializers (which can appear in both function-local and module-scope
22    /// contexts).
23    ///
24    /// [`Function`]: crate::Function
25    pub expressions: Arena<Expression<'a>>,
26
27    /// Non-user-defined types, like `vec4<f32>` or `array<i32, 10>`.
28    ///
29    /// These are referred to by `Handle<ast::Type<'a>>` values.
30    /// User-defined types are referred to by name until lowering.
31    pub types: Arena<Type<'a>>,
32
33    /// Arena for all diagnostic filter rules parsed in this module, including those in functions.
34    ///
35    /// See [`DiagnosticFilterNode`] for details on how the tree is represented and used in
36    /// validation.
37    pub diagnostic_filters: Arena<DiagnosticFilterNode>,
38    /// The leaf of all `diagnostic(…)` directives in this module.
39    ///
40    /// See [`DiagnosticFilterNode`] for details on how the tree is represented and used in
41    /// validation.
42    pub diagnostic_filter_leaf: Option<Handle<DiagnosticFilterNode>>,
43
44    /// Doc comments appearing first in the file.
45    /// This serves as documentation for the whole TranslationUnit.
46    pub doc_comments: Vec<&'a str>,
47}
48
49#[derive(Debug, Clone, Copy)]
50pub struct Ident<'a> {
51    pub name: &'a str,
52    pub span: Span,
53}
54
55#[derive(Debug)]
56pub enum IdentExpr<'a> {
57    Unresolved(&'a str),
58    Local(Handle<Local>),
59}
60
61/// A reference to a module-scope definition or predeclared object.
62///
63/// Each [`GlobalDecl`] holds a set of these values, to be resolved to
64/// specific definitions later. To support de-duplication, `Eq` and
65/// `Hash` on a `Dependency` value consider only the name, not the
66/// source location at which the reference occurs.
67#[derive(Debug)]
68pub struct Dependency<'a> {
69    /// The name referred to.
70    pub ident: &'a str,
71
72    /// The location at which the reference to that name occurs.
73    pub usage: Span,
74}
75
76impl Hash for Dependency<'_> {
77    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
78        self.ident.hash(state);
79    }
80}
81
82impl PartialEq for Dependency<'_> {
83    fn eq(&self, other: &Self) -> bool {
84        self.ident == other.ident
85    }
86}
87
88impl Eq for Dependency<'_> {}
89
90/// A module-scope declaration.
91#[derive(Debug)]
92pub struct GlobalDecl<'a> {
93    pub kind: GlobalDeclKind<'a>,
94
95    /// Names of all module-scope or predeclared objects this
96    /// declaration uses.
97    pub dependencies: FastIndexSet<Dependency<'a>>,
98}
99
100#[derive(Debug)]
101pub enum GlobalDeclKind<'a> {
102    Fn(Function<'a>),
103    Var(GlobalVariable<'a>),
104    Const(Const<'a>),
105    Override(Override<'a>),
106    Struct(Struct<'a>),
107    Type(TypeAlias<'a>),
108    ConstAssert(Handle<Expression<'a>>),
109}
110
111#[derive(Debug)]
112pub struct FunctionArgument<'a> {
113    pub name: Ident<'a>,
114    pub ty: Handle<Type<'a>>,
115    pub binding: Option<Binding<'a>>,
116    pub handle: Handle<Local>,
117}
118
119#[derive(Debug)]
120pub struct FunctionResult<'a> {
121    pub ty: Handle<Type<'a>>,
122    pub binding: Option<Binding<'a>>,
123    pub must_use: bool,
124}
125
126#[derive(Debug)]
127pub struct EntryPoint<'a> {
128    pub stage: crate::ShaderStage,
129    pub early_depth_test: Option<crate::EarlyDepthTest>,
130    pub workgroup_size: Option<[Option<Handle<Expression<'a>>>; 3]>,
131    pub mesh_output_variable: Option<(&'a str, Span)>,
132    pub task_payload: Option<(&'a str, Span)>,
133}
134
135#[cfg(doc)]
136use crate::front::wgsl::lower::{LocalExpressionContext, StatementContext};
137
138#[derive(Debug)]
139pub struct Function<'a> {
140    pub entry_point: Option<EntryPoint<'a>>,
141    pub name: Ident<'a>,
142    pub arguments: Vec<FunctionArgument<'a>>,
143    pub result: Option<FunctionResult<'a>>,
144    pub body: Block<'a>,
145    pub diagnostic_filter_leaf: Option<Handle<DiagnosticFilterNode>>,
146    pub doc_comments: Vec<&'a str>,
147}
148
149#[derive(Debug)]
150pub enum Binding<'a> {
151    BuiltIn(crate::BuiltIn),
152    Location {
153        location: Handle<Expression<'a>>,
154        interpolation: Option<crate::Interpolation>,
155        sampling: Option<crate::Sampling>,
156        blend_src: Option<Handle<Expression<'a>>>,
157        per_primitive: bool,
158    },
159}
160
161#[derive(Debug)]
162pub struct ResourceBinding<'a> {
163    pub group: Handle<Expression<'a>>,
164    pub binding: Handle<Expression<'a>>,
165}
166
167#[derive(Debug)]
168pub struct GlobalVariable<'a> {
169    pub name: Ident<'a>,
170    pub space: crate::AddressSpace,
171    pub binding: Option<ResourceBinding<'a>>,
172    pub ty: Option<Handle<Type<'a>>>,
173    pub init: Option<Handle<Expression<'a>>>,
174    pub doc_comments: Vec<&'a str>,
175}
176
177#[derive(Debug)]
178pub struct StructMember<'a> {
179    pub name: Ident<'a>,
180    pub ty: Handle<Type<'a>>,
181    pub binding: Option<Binding<'a>>,
182    pub align: Option<Handle<Expression<'a>>>,
183    pub size: Option<Handle<Expression<'a>>>,
184    pub doc_comments: Vec<&'a str>,
185}
186
187#[derive(Debug)]
188pub struct Struct<'a> {
189    pub name: Ident<'a>,
190    pub members: Vec<StructMember<'a>>,
191    pub doc_comments: Vec<&'a str>,
192}
193
194#[derive(Debug)]
195pub struct TypeAlias<'a> {
196    pub name: Ident<'a>,
197    pub ty: Handle<Type<'a>>,
198}
199
200#[derive(Debug)]
201pub struct Const<'a> {
202    pub name: Ident<'a>,
203    pub ty: Option<Handle<Type<'a>>>,
204    pub init: Handle<Expression<'a>>,
205    pub doc_comments: Vec<&'a str>,
206}
207
208#[derive(Debug)]
209pub struct Override<'a> {
210    pub name: Ident<'a>,
211    pub id: Option<Handle<Expression<'a>>>,
212    pub ty: Option<Handle<Type<'a>>>,
213    pub init: Option<Handle<Expression<'a>>>,
214}
215
216/// The size of an [`Array`] or [`BindingArray`].
217///
218/// [`Array`]: Type::Array
219/// [`BindingArray`]: Type::BindingArray
220#[derive(Debug, Copy, Clone)]
221pub enum ArraySize<'a> {
222    /// The length as a constant expression.
223    Constant(Handle<Expression<'a>>),
224    Dynamic,
225}
226
227#[derive(Debug)]
228pub enum Type<'a> {
229    Scalar(Scalar),
230    Vector {
231        size: crate::VectorSize,
232        ty: Handle<Type<'a>>,
233        ty_span: Span,
234    },
235    Matrix {
236        columns: crate::VectorSize,
237        rows: crate::VectorSize,
238        ty: Handle<Type<'a>>,
239        ty_span: Span,
240    },
241    Atomic(Scalar),
242    Pointer {
243        base: Handle<Type<'a>>,
244        space: crate::AddressSpace,
245    },
246    Array {
247        base: Handle<Type<'a>>,
248        size: ArraySize<'a>,
249    },
250    Image {
251        dim: crate::ImageDimension,
252        arrayed: bool,
253        class: crate::ImageClass,
254    },
255    Sampler {
256        comparison: bool,
257    },
258    AccelerationStructure {
259        vertex_return: bool,
260    },
261    RayQuery {
262        vertex_return: bool,
263    },
264    RayDesc,
265    RayIntersection,
266    BindingArray {
267        base: Handle<Type<'a>>,
268        size: ArraySize<'a>,
269    },
270
271    /// A user-defined type, like a struct or a type alias.
272    User(Ident<'a>),
273}
274
275#[derive(Debug, Default)]
276pub struct Block<'a> {
277    pub stmts: Vec<Statement<'a>>,
278}
279
280#[derive(Debug)]
281pub struct Statement<'a> {
282    pub kind: StatementKind<'a>,
283    pub span: Span,
284}
285
286#[derive(Debug)]
287pub enum StatementKind<'a> {
288    LocalDecl(LocalDecl<'a>),
289    Block(Block<'a>),
290    If {
291        condition: Handle<Expression<'a>>,
292        accept: Block<'a>,
293        reject: Block<'a>,
294    },
295    Switch {
296        selector: Handle<Expression<'a>>,
297        cases: Vec<SwitchCase<'a>>,
298    },
299    Loop {
300        body: Block<'a>,
301        continuing: Block<'a>,
302        break_if: Option<Handle<Expression<'a>>>,
303    },
304    Break,
305    Continue,
306    Return {
307        value: Option<Handle<Expression<'a>>>,
308    },
309    Kill,
310    Call {
311        function: Ident<'a>,
312        arguments: Vec<Handle<Expression<'a>>>,
313    },
314    Assign {
315        target: Handle<Expression<'a>>,
316        op: Option<crate::BinaryOperator>,
317        value: Handle<Expression<'a>>,
318    },
319    Increment(Handle<Expression<'a>>),
320    Decrement(Handle<Expression<'a>>),
321    Phony(Handle<Expression<'a>>),
322    ConstAssert(Handle<Expression<'a>>),
323}
324
325#[derive(Debug)]
326pub enum SwitchValue<'a> {
327    Expr(Handle<Expression<'a>>),
328    Default,
329}
330
331#[derive(Debug)]
332pub struct SwitchCase<'a> {
333    pub value: SwitchValue<'a>,
334    pub body: Block<'a>,
335    pub fall_through: bool,
336}
337
338/// A type at the head of a [`Construct`] expression.
339///
340/// WGSL has two types of [`type constructor expressions`]:
341///
342/// - Those that fully specify the type being constructed, like
343///   `vec3<f32>(x,y,z)`, which obviously constructs a `vec3<f32>`.
344///
345/// - Those that leave the component type of the composite being constructed
346///   implicit, to be inferred from the argument types, like `vec3(x,y,z)`,
347///   which constructs a `vec3<T>` where `T` is the type of `x`, `y`, and `z`.
348///
349/// This enum represents the head type of both cases. The `PartialFoo` variants
350/// represent the second case, where the component type is implicit.
351///
352/// This does not cover structs or types referred to by type aliases. See the
353/// documentation for [`Construct`] and [`Call`] expressions for details.
354///
355/// [`Construct`]: Expression::Construct
356/// [`type constructor expressions`]: https://gpuweb.github.io/gpuweb/wgsl/#type-constructor-expr
357/// [`Call`]: Expression::Call
358#[derive(Debug)]
359pub enum ConstructorType<'a> {
360    /// A scalar type or conversion: `f32(1)`.
361    Scalar(Scalar),
362
363    /// A vector construction whose component type is inferred from the
364    /// argument: `vec3(1.0)`.
365    PartialVector { size: crate::VectorSize },
366
367    /// A vector construction whose component type is written out:
368    /// `vec3<f32>(1.0)`.
369    Vector {
370        size: crate::VectorSize,
371        ty: Handle<Type<'a>>,
372        ty_span: Span,
373    },
374
375    /// A matrix construction whose component type is inferred from the
376    /// argument: `mat2x2(1,2,3,4)`.
377    PartialMatrix {
378        columns: crate::VectorSize,
379        rows: crate::VectorSize,
380    },
381
382    /// A matrix construction whose component type is written out:
383    /// `mat2x2<f32>(1,2,3,4)`.
384    Matrix {
385        columns: crate::VectorSize,
386        rows: crate::VectorSize,
387        ty: Handle<Type<'a>>,
388        ty_span: Span,
389    },
390
391    /// An array whose component type and size are inferred from the arguments:
392    /// `array(3,4,5)`.
393    PartialArray,
394
395    /// An array whose component type and size are written out:
396    /// `array<u32, 4>(3,4,5)`.
397    Array {
398        base: Handle<Type<'a>>,
399        size: ArraySize<'a>,
400    },
401
402    /// Constructing a value of a known Naga IR type.
403    ///
404    /// This variant is produced only during lowering, when we have Naga types
405    /// available, never during parsing.
406    Type(Handle<crate::Type>),
407}
408
409#[derive(Debug, Copy, Clone)]
410pub enum Literal {
411    Bool(bool),
412    Number(Number),
413}
414
415#[cfg(doc)]
416use crate::front::wgsl::lower::Lowerer;
417
418#[derive(Debug)]
419pub enum Expression<'a> {
420    Literal(Literal),
421    Ident(IdentExpr<'a>),
422
423    /// A type constructor expression.
424    ///
425    /// This is only used for expressions like `KEYWORD(EXPR...)` and
426    /// `KEYWORD<PARAM>(EXPR...)`, where `KEYWORD` is a [type-defining keyword] like
427    /// `vec3`. These keywords cannot be shadowed by user definitions, so we can
428    /// tell that such an expression is a construction immediately.
429    ///
430    /// For ordinary identifiers, we can't tell whether an expression like
431    /// `IDENTIFIER(EXPR, ...)` is a construction expression or a function call
432    /// until we know `IDENTIFIER`'s definition, so we represent those as
433    /// [`Call`] expressions.
434    ///
435    /// [type-defining keyword]: https://gpuweb.github.io/gpuweb/wgsl/#type-defining-keywords
436    /// [`Call`]: Expression::Call
437    Construct {
438        ty: ConstructorType<'a>,
439        ty_span: Span,
440        components: Vec<Handle<Expression<'a>>>,
441    },
442    Unary {
443        op: crate::UnaryOperator,
444        expr: Handle<Expression<'a>>,
445    },
446    AddrOf(Handle<Expression<'a>>),
447    Deref(Handle<Expression<'a>>),
448    Binary {
449        op: crate::BinaryOperator,
450        left: Handle<Expression<'a>>,
451        right: Handle<Expression<'a>>,
452    },
453
454    /// A function call or type constructor expression.
455    ///
456    /// We can't tell whether an expression like `IDENTIFIER(EXPR, ...)` is a
457    /// construction expression or a function call until we know `IDENTIFIER`'s
458    /// definition, so we represent everything of that form as one of these
459    /// expressions until lowering. At that point, [`Lowerer::call`] has
460    /// everything's definition in hand, and can decide whether to emit a Naga
461    /// [`Constant`], [`As`], [`Splat`], or [`Compose`] expression.
462    ///
463    /// [`Lowerer::call`]: Lowerer::call
464    /// [`Constant`]: crate::Expression::Constant
465    /// [`As`]: crate::Expression::As
466    /// [`Splat`]: crate::Expression::Splat
467    /// [`Compose`]: crate::Expression::Compose
468    Call {
469        function: Ident<'a>,
470        arguments: Vec<Handle<Expression<'a>>>,
471    },
472    Index {
473        base: Handle<Expression<'a>>,
474        index: Handle<Expression<'a>>,
475    },
476    Member {
477        base: Handle<Expression<'a>>,
478        field: Ident<'a>,
479    },
480    Bitcast {
481        expr: Handle<Expression<'a>>,
482        to: Handle<Type<'a>>,
483        ty_span: Span,
484    },
485}
486
487#[derive(Debug)]
488pub struct LocalVariable<'a> {
489    pub name: Ident<'a>,
490    pub ty: Option<Handle<Type<'a>>>,
491    pub init: Option<Handle<Expression<'a>>>,
492    pub handle: Handle<Local>,
493}
494
495#[derive(Debug)]
496pub struct Let<'a> {
497    pub name: Ident<'a>,
498    pub ty: Option<Handle<Type<'a>>>,
499    pub init: Handle<Expression<'a>>,
500    pub handle: Handle<Local>,
501}
502
503#[derive(Debug)]
504pub struct LocalConst<'a> {
505    pub name: Ident<'a>,
506    pub ty: Option<Handle<Type<'a>>>,
507    pub init: Handle<Expression<'a>>,
508    pub handle: Handle<Local>,
509}
510
511#[derive(Debug)]
512pub enum LocalDecl<'a> {
513    Var(LocalVariable<'a>),
514    Let(Let<'a>),
515    Const(LocalConst<'a>),
516}
517
518#[derive(Debug)]
519/// A placeholder for a local variable declaration.
520///
521/// See [`super::ExpressionContext::locals`] for more information.
522pub struct Local;