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