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::{Arena, FastIndexSet, Handle, Span};
8
9#[derive(Debug, Default)]
10pub struct TranslationUnit<'a> {
11    pub enable_extensions: EnableExtensions,
12    pub decls: Arena<GlobalDecl<'a>>,
13    /// The common expressions arena for the entire translation unit.
14    ///
15    /// All functions, global initializers, array lengths, etc. store their
16    /// expressions here. We apportion these out to individual Naga
17    /// [`Function`]s' expression arenas at lowering time. Keeping them all in a
18    /// single arena simplifies handling of things like array lengths (which are
19    /// effectively global and thus don't clearly belong to any function) and
20    /// initializers (which can appear in both function-local and module-scope
21    /// contexts).
22    ///
23    /// [`Function`]: crate::Function
24    pub expressions: Arena<Expression<'a>>,
25
26    /// Arena for all diagnostic filter rules parsed in this module, including those in functions.
27    ///
28    /// See [`DiagnosticFilterNode`] for details on how the tree is represented and used in
29    /// validation.
30    pub diagnostic_filters: Arena<DiagnosticFilterNode>,
31    /// The leaf of all `diagnostic(…)` directives in this module.
32    ///
33    /// See [`DiagnosticFilterNode`] for details on how the tree is represented and used in
34    /// validation.
35    pub diagnostic_filter_leaf: Option<Handle<DiagnosticFilterNode>>,
36
37    /// Doc comments appearing first in the file.
38    /// This serves as documentation for the whole TranslationUnit.
39    pub doc_comments: Vec<&'a str>,
40}
41
42#[derive(Debug, Clone, Copy)]
43pub struct Ident<'a> {
44    pub name: &'a str,
45    pub span: Span,
46}
47
48/// An identifier that [resolves] to some declaration.
49///
50/// This does not cover context-dependent names: attributes, built-in values,
51/// and so on. We map those to their Naga IR equivalents as soon as they're
52/// parsed, so they never need to appear as identifiers in the AST.
53///
54/// [resolves]: https://gpuweb.github.io/gpuweb/wgsl/#resolves
55#[derive(Debug)]
56pub enum IdentExpr<'a> {
57    /// An identifier referring to a module-scope declaration or predeclared
58    /// object.
59    ///
60    /// We need to collect the entire module before we can resolve this, to
61    /// distinguish between predeclared objects and module-scope declarations
62    /// that appear after their uses.
63    ///
64    /// Whenever you create one of these values, you almost certainly want to
65    /// insert the `&str` into [`ExpressionContext::unresolved`][ECu], to ensure
66    /// that [indexing] knows that the name's declaration must be lowered before
67    /// the one containing this use. Using [`Parser::ident_expr`][ie] to build
68    /// `IdentExpr` will take care of that for you.
69    ///
70    /// [ECu]: super::ExpressionContext::unresolved
71    /// [ie]: super::Parser::ident_expr
72    /// [indexing]: crate::front::wgsl::index::Index::generate
73    Unresolved(&'a str),
74
75    /// An identifier that has been resolved to a non-module-scope declaration.
76    Local(Handle<Local>),
77}
78
79/// An identifier with optional template parameters.
80///
81/// Following the WGSL specification (see the [`template_list`] non-terminal),
82/// `TemplateElaboratedIdent` represents all template parameters as expressions:
83/// even parameters to type generators, like the `f32` in `vec3<f32>`, are [Type
84/// Expressions].
85///
86/// # Examples
87///
88/// - A use of a global variable `colors` would be an [`Expression::Ident(v)`][EI],
89///   where `v` is an `TemplateElaboratedIdent` whose `ident` is
90///   [`IdentExpr::Unresolved("colors")`][IEU]. Lowering will resolve this to a
91///   reference to the global variable.
92///
93/// - The type `f32` in a variable declaration is represented as a
94///   `TemplateElaboratedIdent` whose `ident` is
95///   [`IdentExpr::Unresolved("f32")`][IEU]. Lowering will resolve this to
96///   WGSL's predeclared `f32` type.
97///
98/// - The type `vec3<f32>` can be represented as a `TemplateElaboratedIdent`
99///   whose `ident` is [`IdentExpr::Unresolved("vec3")`][IEU], and whose
100///   `template_list` has one element: an [`ExpressionIdent(v)`][EI] where `v` is a
101///   nested `TemplateElaboratedIdent` representing `f32` as described above.
102///
103/// - The type `array<vec3<f32>, 4>` has `"array"` as its `ident`, and then
104///   a two-element `template_list`:
105///
106///     - `template_list[0]` is an [`Expression::Ident(v)`][EI] where `v` is a nested
107///       `TemplateElaboratedIdent` representing `vec3<f32>` as described above.
108///
109///     - `template_list[1]` is an [`Expression`] representing `4`.
110///
111/// After [indexing] the module to ensure that declarations appear before uses,
112/// lowering can see which declaration a given `TemplateElaboratedIdent`s
113/// `ident` refers to. The declaration then determines how to interpret the
114/// `template_list`.
115///
116/// [`template_list`]: https://gpuweb.github.io/gpuweb/wgsl/#syntax-template_list
117/// [Type Expressions]: https://gpuweb.github.io/gpuweb/wgsl/#type-expr
118/// [IEU]: IdentExpr::Unresolved
119/// [EI]: Expression::Ident
120/// [indexing]: crate::front::wgsl::index::Index::generate
121#[derive(Debug)]
122pub struct TemplateElaboratedIdent<'a> {
123    pub ident: IdentExpr<'a>,
124    pub ident_span: Span,
125
126    /// If non-empty, the template parameters following the identifier.
127    pub template_list: Vec<Handle<Expression<'a>>>,
128    pub template_list_span: Span,
129}
130
131/// A function call or value constructor expression.
132///
133/// We can't tell whether an expression like `IDENTIFIER(EXPR, ...)` is a
134/// construction expression or a function call until we know `IDENTIFIER`'s
135/// definition, so we represent everything of that form as one of these
136/// expressions until lowering. At that point, [`Lowerer::call`] has
137/// everything's definition in hand, and can decide whether to emit a Naga
138/// [`Constant`], [`As`], [`Splat`], or [`Compose`] expression.
139///
140/// [`Lowerer::call`]: Lowerer::call
141/// [`Constant`]: crate::Expression::Constant
142/// [`As`]: crate::Expression::As
143/// [`Splat`]: crate::Expression::Splat
144/// [`Compose`]: crate::Expression::Compose
145#[derive(Debug)]
146pub struct CallPhrase<'a> {
147    pub function: TemplateElaboratedIdent<'a>,
148    pub arguments: Vec<Handle<Expression<'a>>>,
149}
150
151/// A reference to a module-scope definition or predeclared object.
152///
153/// Each [`GlobalDecl`] holds a set of these values, to be resolved to
154/// specific definitions later. To support de-duplication, `Eq` and
155/// `Hash` on a `Dependency` value consider only the name, not the
156/// source location at which the reference occurs.
157#[derive(Debug)]
158pub struct Dependency<'a> {
159    /// The name referred to.
160    pub ident: &'a str,
161
162    /// The location at which the reference to that name occurs.
163    pub usage: Span,
164}
165
166impl Hash for Dependency<'_> {
167    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
168        self.ident.hash(state);
169    }
170}
171
172impl PartialEq for Dependency<'_> {
173    fn eq(&self, other: &Self) -> bool {
174        self.ident == other.ident
175    }
176}
177
178impl Eq for Dependency<'_> {}
179
180/// A module-scope declaration.
181#[derive(Debug)]
182pub struct GlobalDecl<'a> {
183    pub kind: GlobalDeclKind<'a>,
184
185    /// Names of all module-scope or predeclared objects this
186    /// declaration uses.
187    pub dependencies: FastIndexSet<Dependency<'a>>,
188}
189
190#[derive(Debug)]
191pub enum GlobalDeclKind<'a> {
192    Fn(Function<'a>),
193    Var(GlobalVariable<'a>),
194    Const(Const<'a>),
195    Override(Override<'a>),
196    Struct(Struct<'a>),
197    Type(TypeAlias<'a>),
198    ConstAssert(Handle<Expression<'a>>),
199}
200
201#[derive(Debug)]
202pub struct FunctionArgument<'a> {
203    pub name: Ident<'a>,
204    pub ty: TemplateElaboratedIdent<'a>,
205    pub binding: Option<Binding<'a>>,
206    pub handle: Handle<Local>,
207}
208
209#[derive(Debug)]
210pub struct FunctionResult<'a> {
211    pub ty: TemplateElaboratedIdent<'a>,
212    pub binding: Option<Binding<'a>>,
213    pub must_use: bool,
214}
215
216#[derive(Debug)]
217pub struct EntryPoint<'a> {
218    pub stage: crate::ShaderStage,
219    pub early_depth_test: Option<crate::EarlyDepthTest>,
220    pub workgroup_size: Option<[Option<Handle<Expression<'a>>>; 3]>,
221    pub mesh_output_variable: Option<(&'a str, Span)>,
222    pub task_payload: Option<(&'a str, Span)>,
223    pub ray_incoming_payload: Option<(&'a str, Span)>,
224}
225
226#[cfg(doc)]
227use crate::front::wgsl::lower::{LocalExpressionContext, StatementContext};
228
229#[derive(Debug)]
230pub struct Function<'a> {
231    pub entry_point: Option<EntryPoint<'a>>,
232    pub name: Ident<'a>,
233    pub arguments: Vec<FunctionArgument<'a>>,
234    pub result: Option<FunctionResult<'a>>,
235    pub body: Block<'a>,
236    pub diagnostic_filter_leaf: Option<Handle<DiagnosticFilterNode>>,
237    pub doc_comments: Vec<&'a str>,
238}
239
240#[derive(Debug)]
241pub enum Binding<'a> {
242    BuiltIn(crate::BuiltIn),
243    Location {
244        location: Handle<Expression<'a>>,
245        interpolation: Option<crate::Interpolation>,
246        sampling: Option<crate::Sampling>,
247        blend_src: Option<Handle<Expression<'a>>>,
248        per_primitive: bool,
249    },
250}
251
252#[derive(Debug)]
253pub struct ResourceBinding<'a> {
254    pub group: Handle<Expression<'a>>,
255    pub binding: Handle<Expression<'a>>,
256}
257
258#[derive(Debug)]
259pub struct GlobalVariable<'a> {
260    pub name: Ident<'a>,
261
262    /// The template list parameters for the `var`, giving the variable's
263    /// address space and access mode, if present.
264    pub template_list: Vec<Handle<Expression<'a>>>,
265
266    /// The `@group` and `@binding` attributes, if present.
267    pub binding: Option<ResourceBinding<'a>>,
268
269    pub ty: Option<TemplateElaboratedIdent<'a>>,
270    pub init: Option<Handle<Expression<'a>>>,
271    pub doc_comments: Vec<&'a str>,
272
273    /// Memory decorations for this variable (`@coherent`, `@volatile`).
274    pub memory_decorations: crate::MemoryDecorations,
275}
276
277#[derive(Debug)]
278pub struct StructMember<'a> {
279    pub name: Ident<'a>,
280    pub ty: TemplateElaboratedIdent<'a>,
281    pub binding: Option<Binding<'a>>,
282    pub align: Option<Handle<Expression<'a>>>,
283    pub size: Option<Handle<Expression<'a>>>,
284    pub doc_comments: Vec<&'a str>,
285}
286
287#[derive(Debug)]
288pub struct Struct<'a> {
289    pub name: Ident<'a>,
290    pub members: Vec<StructMember<'a>>,
291    pub doc_comments: Vec<&'a str>,
292}
293
294#[derive(Debug)]
295pub struct TypeAlias<'a> {
296    pub name: Ident<'a>,
297    pub ty: TemplateElaboratedIdent<'a>,
298}
299
300#[derive(Debug)]
301pub struct Const<'a> {
302    pub name: Ident<'a>,
303    pub ty: Option<TemplateElaboratedIdent<'a>>,
304    pub init: Handle<Expression<'a>>,
305    pub doc_comments: Vec<&'a str>,
306}
307
308#[derive(Debug)]
309pub struct Override<'a> {
310    pub name: Ident<'a>,
311    pub id: Option<Handle<Expression<'a>>>,
312    pub ty: Option<TemplateElaboratedIdent<'a>>,
313    pub init: Option<Handle<Expression<'a>>>,
314}
315
316#[derive(Debug, Default)]
317pub struct Block<'a> {
318    pub stmts: Vec<Statement<'a>>,
319}
320
321#[derive(Debug)]
322pub struct Statement<'a> {
323    pub kind: StatementKind<'a>,
324    pub span: Span,
325}
326
327#[derive(Debug)]
328pub enum StatementKind<'a> {
329    LocalDecl(LocalDecl<'a>),
330    Block(Block<'a>),
331    If {
332        condition: Handle<Expression<'a>>,
333        accept: Block<'a>,
334        reject: Block<'a>,
335    },
336    Switch {
337        selector: Handle<Expression<'a>>,
338        cases: Vec<SwitchCase<'a>>,
339    },
340    Loop {
341        body: Block<'a>,
342        continuing: Block<'a>,
343        break_if: Option<Handle<Expression<'a>>>,
344    },
345    Break,
346    Continue,
347    Return {
348        value: Option<Handle<Expression<'a>>>,
349    },
350    Kill,
351    Call(CallPhrase<'a>),
352    Assign {
353        target: Handle<Expression<'a>>,
354        op: Option<crate::BinaryOperator>,
355        value: Handle<Expression<'a>>,
356    },
357    Increment(Handle<Expression<'a>>),
358    Decrement(Handle<Expression<'a>>),
359    Phony(Handle<Expression<'a>>),
360    ConstAssert(Handle<Expression<'a>>),
361}
362
363#[derive(Debug)]
364pub enum SwitchValue<'a> {
365    Expr(Handle<Expression<'a>>),
366    Default,
367}
368
369#[derive(Debug)]
370pub struct SwitchCase<'a> {
371    pub value: SwitchValue<'a>,
372    pub body: Block<'a>,
373    pub fall_through: bool,
374}
375
376#[derive(Debug, Copy, Clone)]
377pub enum Literal {
378    Bool(bool),
379    Number(Number),
380}
381
382#[cfg(doc)]
383use crate::front::wgsl::lower::Lowerer;
384
385#[derive(Debug)]
386pub enum Expression<'a> {
387    Literal(Literal),
388    Ident(TemplateElaboratedIdent<'a>),
389    Unary {
390        op: crate::UnaryOperator,
391        expr: Handle<Expression<'a>>,
392    },
393    AddrOf(Handle<Expression<'a>>),
394    Deref(Handle<Expression<'a>>),
395    Binary {
396        op: crate::BinaryOperator,
397        left: Handle<Expression<'a>>,
398        right: Handle<Expression<'a>>,
399    },
400    Call(CallPhrase<'a>),
401    Index {
402        base: Handle<Expression<'a>>,
403        index: Handle<Expression<'a>>,
404    },
405    Member {
406        base: Handle<Expression<'a>>,
407        field: Ident<'a>,
408    },
409}
410
411#[derive(Debug)]
412pub struct LocalVariable<'a> {
413    pub name: Ident<'a>,
414    pub ty: Option<TemplateElaboratedIdent<'a>>,
415    pub init: Option<Handle<Expression<'a>>>,
416    pub handle: Handle<Local>,
417}
418
419#[derive(Debug)]
420pub struct Let<'a> {
421    pub name: Ident<'a>,
422    pub ty: Option<TemplateElaboratedIdent<'a>>,
423    pub init: Handle<Expression<'a>>,
424    pub handle: Handle<Local>,
425}
426
427#[derive(Debug)]
428pub struct LocalConst<'a> {
429    pub name: Ident<'a>,
430    pub ty: Option<TemplateElaboratedIdent<'a>>,
431    pub init: Handle<Expression<'a>>,
432    pub handle: Handle<Local>,
433}
434
435#[derive(Debug)]
436pub enum LocalDecl<'a> {
437    Var(LocalVariable<'a>),
438    Let(Let<'a>),
439    Const(LocalConst<'a>),
440}
441
442#[derive(Debug)]
443/// A placeholder for a local variable declaration.
444///
445/// See [`super::ExpressionContext::locals`] for more information.
446pub struct Local;