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