wesl 0.6.0-pre10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +31 -0
  2. package/dist/index.js +4468 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/minified.js +3426 -0
  5. package/dist/minified.js.map +1 -0
  6. package/dist/tools/packages/wesl/src/AbstractElems.d.ts +322 -0
  7. package/dist/tools/packages/wesl/src/Assertions.d.ts +27 -0
  8. package/dist/tools/packages/wesl/src/BindIdents.d.ts +70 -0
  9. package/dist/tools/packages/wesl/src/Conditions.d.ts +6 -0
  10. package/dist/tools/packages/wesl/src/FlattenTreeImport.d.ts +11 -0
  11. package/dist/tools/packages/wesl/src/LinkedWesl.d.ts +50 -0
  12. package/dist/tools/packages/wesl/src/Linker.d.ts +87 -0
  13. package/dist/tools/packages/wesl/src/LinkerUtil.d.ts +3 -0
  14. package/dist/tools/packages/wesl/src/LiveDeclarations.d.ts +12 -0
  15. package/dist/tools/packages/wesl/src/LowerAndEmit.d.ts +31 -0
  16. package/dist/tools/packages/wesl/src/Mangler.d.ts +39 -0
  17. package/dist/tools/packages/wesl/src/ParseWESL.d.ts +60 -0
  18. package/dist/tools/packages/wesl/src/ParsedRegistry.d.ts +29 -0
  19. package/dist/tools/packages/wesl/src/PathUtil.d.ts +6 -0
  20. package/dist/tools/packages/wesl/src/RawEmit.d.ts +6 -0
  21. package/dist/tools/packages/wesl/src/Reflection.d.ts +45 -0
  22. package/dist/tools/packages/wesl/src/Scope.d.ts +81 -0
  23. package/dist/tools/packages/wesl/src/StandardTypes.d.ts +13 -0
  24. package/dist/tools/packages/wesl/src/TransformBindingStructs.d.ts +52 -0
  25. package/dist/tools/packages/wesl/src/Util.d.ts +43 -0
  26. package/dist/tools/packages/wesl/src/WESLCollect.d.ts +94 -0
  27. package/dist/tools/packages/wesl/src/WeslBundle.d.ts +13 -0
  28. package/dist/tools/packages/wesl/src/WeslDevice.d.ts +25 -0
  29. package/dist/tools/packages/wesl/src/debug/ASTtoString.d.ts +5 -0
  30. package/dist/tools/packages/wesl/src/debug/ImportToString.d.ts +2 -0
  31. package/dist/tools/packages/wesl/src/debug/LineWrapper.d.ts +21 -0
  32. package/dist/tools/packages/wesl/src/debug/ScopeToString.d.ts +6 -0
  33. package/dist/tools/packages/wesl/src/index.d.ts +11 -0
  34. package/dist/tools/packages/wesl/src/parse/ImportGrammar.d.ts +5 -0
  35. package/dist/tools/packages/wesl/src/parse/Keywords.d.ts +4 -0
  36. package/dist/tools/packages/wesl/src/parse/WeslBaseGrammar.d.ts +5 -0
  37. package/dist/tools/packages/wesl/src/parse/WeslExpression.d.ts +13 -0
  38. package/dist/tools/packages/wesl/src/parse/WeslGrammar.d.ts +80 -0
  39. package/dist/tools/packages/wesl/src/parse/WeslStream.d.ts +44 -0
  40. package/dist/tools/packages/wesl/src/test/BindWESL.test.d.ts +1 -0
  41. package/dist/tools/packages/wesl/src/test/ConditionLinking.test.d.ts +1 -0
  42. package/dist/tools/packages/wesl/src/test/ConditionalTranslationCases.test.d.ts +1 -0
  43. package/dist/tools/packages/wesl/src/test/ErrorLogging.test.d.ts +1 -0
  44. package/dist/tools/packages/wesl/src/test/Expression.test.d.ts +1 -0
  45. package/dist/tools/packages/wesl/src/test/FlattenTreeImport.test.d.ts +1 -0
  46. package/dist/tools/packages/wesl/src/test/ImportCases.test.d.ts +1 -0
  47. package/dist/tools/packages/wesl/src/test/ImportSyntaxCases.test.d.ts +1 -0
  48. package/dist/tools/packages/wesl/src/test/LinkGlob.test.d.ts +1 -0
  49. package/dist/tools/packages/wesl/src/test/LinkPackage.test.d.ts +1 -0
  50. package/dist/tools/packages/wesl/src/test/Linker.test.d.ts +1 -0
  51. package/dist/tools/packages/wesl/src/test/Mangling.test.d.ts +1 -0
  52. package/dist/tools/packages/wesl/src/test/ParseComments.test.d.ts +1 -0
  53. package/dist/tools/packages/wesl/src/test/ParseConditions.test.d.ts +1 -0
  54. package/dist/tools/packages/wesl/src/test/ParseError.test.d.ts +1 -0
  55. package/dist/tools/packages/wesl/src/test/ParseWESL.test.d.ts +1 -0
  56. package/dist/tools/packages/wesl/src/test/PathUtil.test.d.ts +1 -0
  57. package/dist/tools/packages/wesl/src/test/PrettyGrammar.test.d.ts +1 -0
  58. package/dist/tools/packages/wesl/src/test/Reflection.test.d.ts +1 -0
  59. package/dist/tools/packages/wesl/src/test/ScopeWESL.test.d.ts +1 -0
  60. package/dist/tools/packages/wesl/src/test/TestLink.d.ts +21 -0
  61. package/dist/tools/packages/wesl/src/test/TestSetup.d.ts +1 -0
  62. package/dist/tools/packages/wesl/src/test/TestUtil.d.ts +40 -0
  63. package/dist/tools/packages/wesl/src/test/Tokenizer.test.d.ts +1 -0
  64. package/dist/tools/packages/wesl/src/test/TransformBindingStructs.test.d.ts +1 -0
  65. package/dist/tools/packages/wesl/src/test/Util.test.d.ts +1 -0
  66. package/dist/tools/packages/wesl/src/test/VirtualModules.test.d.ts +1 -0
  67. package/dist/tools/packages/wesl/src/test/WeslDevice.test.d.ts +1 -0
  68. package/dist/tools/packages/wesl/src/test/WgslTests.d.ts +0 -0
  69. package/dist/tools/packages/wesl/src/vlq/vlq.d.ts +11 -0
  70. package/package.json +46 -0
  71. package/src/AbstractElems.ts +446 -0
  72. package/src/Assertions.ts +51 -0
  73. package/src/BindIdents.ts +523 -0
  74. package/src/Conditions.ts +74 -0
  75. package/src/FlattenTreeImport.ts +55 -0
  76. package/src/LinkedWesl.ts +184 -0
  77. package/src/Linker.ts +284 -0
  78. package/src/LinkerUtil.ts +29 -0
  79. package/src/LiveDeclarations.ts +31 -0
  80. package/src/LowerAndEmit.ts +413 -0
  81. package/src/Mangler.ts +94 -0
  82. package/src/ParseWESL.ts +157 -0
  83. package/src/ParsedRegistry.ts +120 -0
  84. package/src/PathUtil.ts +31 -0
  85. package/src/RawEmit.ts +102 -0
  86. package/src/Reflection.ts +334 -0
  87. package/src/Scope.ts +162 -0
  88. package/src/StandardTypes.ts +97 -0
  89. package/src/TransformBindingStructs.ts +319 -0
  90. package/src/Util.ts +194 -0
  91. package/src/WESLCollect.ts +614 -0
  92. package/src/WeslBundle.ts +16 -0
  93. package/src/WeslDevice.ts +209 -0
  94. package/src/debug/ASTtoString.ts +290 -0
  95. package/src/debug/ImportToString.ts +29 -0
  96. package/src/debug/LineWrapper.ts +70 -0
  97. package/src/debug/ScopeToString.ts +79 -0
  98. package/src/index.ts +11 -0
  99. package/src/parse/ImportGrammar.ts +157 -0
  100. package/src/parse/Keywords.ts +26 -0
  101. package/src/parse/WeslBaseGrammar.ts +8 -0
  102. package/src/parse/WeslExpression.ts +207 -0
  103. package/src/parse/WeslGrammar.ts +856 -0
  104. package/src/parse/WeslStream.ts +279 -0
  105. package/src/test/BindWESL.test.ts +57 -0
  106. package/src/test/ConditionLinking.test.ts +91 -0
  107. package/src/test/ConditionalTranslationCases.test.ts +56 -0
  108. package/src/test/ErrorLogging.test.ts +30 -0
  109. package/src/test/Expression.test.ts +22 -0
  110. package/src/test/FlattenTreeImport.test.ts +74 -0
  111. package/src/test/ImportCases.test.ts +56 -0
  112. package/src/test/ImportSyntaxCases.test.ts +24 -0
  113. package/src/test/LinkGlob.test.ts +25 -0
  114. package/src/test/LinkPackage.test.ts +26 -0
  115. package/src/test/Linker.test.ts +125 -0
  116. package/src/test/Mangling.test.ts +45 -0
  117. package/src/test/ParseComments.test.ts +36 -0
  118. package/src/test/ParseConditions.test.ts +183 -0
  119. package/src/test/ParseError.test.ts +36 -0
  120. package/src/test/ParseWESL.test.ts +1572 -0
  121. package/src/test/PathUtil.test.ts +34 -0
  122. package/src/test/PrettyGrammar.test.ts +20 -0
  123. package/src/test/Reflection.test.ts +172 -0
  124. package/src/test/ScopeWESL.test.ts +462 -0
  125. package/src/test/TestLink.ts +82 -0
  126. package/src/test/TestSetup.ts +4 -0
  127. package/src/test/TestUtil.ts +126 -0
  128. package/src/test/Tokenizer.test.ts +135 -0
  129. package/src/test/TransformBindingStructs.test.ts +230 -0
  130. package/src/test/Util.test.ts +22 -0
  131. package/src/test/VirtualModules.test.ts +37 -0
  132. package/src/test/WeslDevice.test.ts +265 -0
  133. package/src/test/WgslTests.ts +0 -0
  134. package/src/test/__snapshots__/ParseDirectives.test.ts.snap +25 -0
  135. package/src/test/__snapshots__/ParseWESL.test.ts.snap +119 -0
  136. package/src/test/__snapshots__/RustDirective.test.ts.snap +359 -0
  137. package/src/test/wgsl_1/main.wgsl +3 -0
  138. package/src/test/wgsl_1/util.wgsl +1 -0
  139. package/src/test/wgsl_2/main2.wgsl +3 -0
  140. package/src/test/wgsl_2/util2.wgsl +1 -0
  141. package/src/vlq/vlq.ts +94 -0
@@ -0,0 +1,856 @@
1
+ import {
2
+ delimited,
3
+ eof,
4
+ fn,
5
+ opt,
6
+ or,
7
+ Parser,
8
+ preceded,
9
+ repeat,
10
+ repeatPlus,
11
+ req,
12
+ separated_pair,
13
+ seq,
14
+ Span,
15
+ span,
16
+ Stream,
17
+ tagScope,
18
+ terminated,
19
+ text,
20
+ token,
21
+ tokenKind,
22
+ tokenOf,
23
+ tracing,
24
+ withSep,
25
+ withSepPlus,
26
+ yes,
27
+ } from "mini-parse";
28
+ import {
29
+ BinaryExpression,
30
+ BinaryOperator,
31
+ BuiltinAttribute,
32
+ DiagnosticAttribute,
33
+ DiagnosticDirective,
34
+ EnableDirective,
35
+ ExpressionElem,
36
+ IfAttribute,
37
+ InterpolateAttribute,
38
+ Literal,
39
+ NameElem,
40
+ ParenthesizedExpression,
41
+ RequiresDirective,
42
+ StandardAttribute,
43
+ TranslateTimeExpressionElem,
44
+ TranslateTimeFeature,
45
+ UnaryExpression,
46
+ UnaryOperator,
47
+ UnknownExpressionElem,
48
+ } from "../AbstractElems.ts";
49
+ import {
50
+ aliasCollect,
51
+ assertCollect,
52
+ collectAttribute,
53
+ collectFnParam,
54
+ collectModule,
55
+ collectStruct,
56
+ collectStructMember,
57
+ collectVarLike,
58
+ declCollect,
59
+ directiveCollect,
60
+ expressionCollect,
61
+ fnCollect,
62
+ globalAssertCollect,
63
+ globalDeclCollect,
64
+ nameCollect,
65
+ partialScopeCollect,
66
+ refIdent,
67
+ scopeCollect,
68
+ specialAttribute,
69
+ statementCollect,
70
+ switchClauseCollect,
71
+ typedDecl,
72
+ } from "../WESLCollect.ts";
73
+ import { weslImports } from "./ImportGrammar.ts";
74
+ import { qualified_ident, word } from "./WeslBaseGrammar.ts";
75
+ import {
76
+ argument_expression_list,
77
+ component_or_swizzle,
78
+ expression,
79
+ opt_template_list,
80
+ simple_component_reference,
81
+ type_specifier,
82
+ } from "./WeslExpression.ts";
83
+ import { weslExtension, WeslToken } from "./WeslStream.ts";
84
+
85
+ const name = tokenKind("word").map(makeName);
86
+
87
+ const diagnostic_rule_name = seq(
88
+ name,
89
+ opt(preceded(".", req(name, "invalid diagnostic rule name, expected name"))),
90
+ );
91
+ const diagnostic_control = delimited(
92
+ "(",
93
+ req(
94
+ separated_pair(name, ",", diagnostic_rule_name),
95
+ "invalid diagnostic control, expected rule name",
96
+ ),
97
+ seq(opt(","), req(")", "invalid diagnostic control, expected ')'")),
98
+ );
99
+
100
+ /** list of words that aren't identifiers (e.g. for @interpolate) */
101
+ const name_list = withSep(",", name, { requireOne: true });
102
+
103
+ // LATER Add proper error reporting here. e.g. @3 should throw an error pointing at the 3
104
+ // Currently it's not possible, since we neither accumulate the necessary context,
105
+ // nor can we add a `req` parser, since this here relies on backtracking
106
+ // prettier-ignore
107
+ const special_attribute = tagScope(
108
+ preceded("@",
109
+ or(
110
+ // These attributes have no arguments
111
+ or("compute", "const", "fragment", "invariant", "must_use", "vertex")
112
+ .map(name => makeStandardAttribute([name, []])),
113
+
114
+ // These attributes have arguments, but the argument doesn't have any identifiers
115
+ preceded("interpolate", req(delimited("(", name_list, ")"), "invalid @interpolate, expected '('"))
116
+ .map(makeInterpolateAttribute),
117
+ preceded("builtin", req(delimited("(", name, ")"), "invalid @builtin, expected '('"))
118
+ .map(makeBuiltinAttribute),
119
+ preceded("diagnostic", req(diagnostic_control, "invalid @diagnostic, expected '('"))
120
+ .map(makeDiagnosticAttribute),
121
+ ) .ptag("attr_variant")
122
+ ) .collect(specialAttribute)
123
+ );
124
+
125
+ // prettier-ignore
126
+ const if_attribute = tagScope(
127
+ preceded(seq("@", weslExtension("if")),
128
+ span(
129
+ delimited(
130
+ "(",
131
+ fn(() => attribute_if_expression),
132
+ seq(opt(","), ")"),
133
+ ),
134
+ ) .map(makeTranslateTimeExpressionElem),
135
+ ) .map(makeIfAttribute)
136
+ .ptag("attr_variant")
137
+ .collect(specialAttribute)
138
+ );
139
+
140
+ // prettier-ignore
141
+ const normal_attribute = tagScope(
142
+ preceded("@",
143
+ or(
144
+ // These are normal attributes, with required arguments
145
+ seq(
146
+ or(
147
+ "workgroup_size",
148
+ "align",
149
+ "binding",
150
+ "blend_src",
151
+ "group",
152
+ "id",
153
+ "location",
154
+ "size",
155
+ ) .ptag("name"),
156
+ req(() => attribute_argument_list, "invalid attribute, expected '('"),
157
+ ),
158
+
159
+ // Everything else is also a normal attribute, optional expression list
160
+ seq(
161
+ // we don't want this to interfere with if_attribute,
162
+ // but not("if") isn't necessary for now, since 'if' is a keyword, not a word
163
+ word .ptag("name"),
164
+ opt(() => attribute_argument_list),
165
+ ),
166
+ ),
167
+ ) .collect(collectAttribute),
168
+ );
169
+
170
+ // prettier-ignore
171
+ const attribute_argument_list = delimited(
172
+ "(",
173
+ withSep(
174
+ ",",
175
+ span(fn(() => expression)) .collect(expressionCollect, "attrParam"), // LATER These unknown expressions have decls inside of them, that's why they're tough to replace!
176
+ ),
177
+ req(")", "invalid attribute arguments, expected ')'"),
178
+ );
179
+
180
+ // separate statements with if from statements
181
+
182
+ // prettier-ignore
183
+ const attribute_no_if = or(
184
+ special_attribute,
185
+ normal_attribute
186
+ ) .ctag("attribute");
187
+
188
+ // prettier-ignore
189
+ const attribute_incl_if = or(
190
+ if_attribute,
191
+ special_attribute,
192
+ normal_attribute,
193
+ ) .ctag("attribute");
194
+
195
+ const opt_attributes = repeat(attribute_incl_if);
196
+
197
+ const opt_attributes_no_if = repeat(attribute_no_if);
198
+
199
+ // prettier-ignore
200
+ const globalTypeNameDecl =
201
+ req(
202
+ word .collect(globalDeclCollect, "type_name"),
203
+ "invalid type name, expected a name"
204
+ );
205
+
206
+ // prettier-ignore
207
+ const fnNameDecl =
208
+ req(
209
+ word .collect(globalDeclCollect, "fn_name"),
210
+ "missing fn name",
211
+ );
212
+
213
+ // prettier-ignore
214
+ const optionally_typed_ident = tagScope(
215
+ seq(
216
+ word .collect(declCollect, "decl_elem"),
217
+ opt(seq(":", type_specifier)),
218
+ ) .collect(typedDecl)
219
+ ) .ctag("var_name");
220
+
221
+ const req_optionally_typed_ident = req(optionally_typed_ident, "invalid ident");
222
+
223
+ // prettier-ignore
224
+ const global_ident = tagScope(
225
+ req(
226
+ seq(
227
+ word .collect(globalDeclCollect, "decl_elem"),
228
+ opt(seq(":", type_specifier)),
229
+ ) .collect(typedDecl),
230
+ "expected identifier"
231
+ )
232
+ ) .ctag("var_name");
233
+
234
+ // prettier-ignore
235
+ const struct_member = tagScope(
236
+ seq(
237
+ opt_attributes,
238
+ word .collect(nameCollect, "nameElem"),
239
+ req(":", "invalid struct member, expected ':'"),
240
+ req(type_specifier, "invalid struct member, expected type specifier"),
241
+ ) .collect(collectStructMember)
242
+ ) .ctag("members");
243
+
244
+ // prettier-ignore
245
+ const struct_decl = seq(
246
+ weslExtension(opt_attributes) .collect((cc) => cc.tags.attribute, "attributes"),
247
+ "struct",
248
+ req(globalTypeNameDecl, "invalid struct, expected name"),
249
+ seq(
250
+ req("{", "invalid struct, expected '{'"),
251
+ withSepPlus(",", struct_member),
252
+ req("}", "invalid struct, expected '}'"),
253
+ ) .collect(scopeCollect, "struct_scope"),
254
+ ) .collect(collectStruct);
255
+
256
+ /** Also covers func_call_statement.post.ident */
257
+ // prettier-ignore
258
+ const fn_call = seq(
259
+ qualified_ident .collect(refIdent),
260
+ () => opt_template_list,
261
+ argument_expression_list,
262
+ );
263
+
264
+ // prettier-ignore
265
+ const fnParam = tagScope(
266
+ seq(
267
+ opt_attributes .collect((cc) => cc.tags.attribute, "attributes"),
268
+ word .collect(declCollect, "decl_elem"),
269
+ opt(seq(":", req(type_specifier, "invalid fn parameter, expected type specifier")))
270
+ .collect(typedDecl, "param_name"),
271
+ ) .collect(collectFnParam),
272
+ ) .ctag("fn_param");
273
+
274
+ const fnParamList = seq("(", withSep(",", fnParam), ")");
275
+
276
+ // prettier-ignore
277
+ const local_variable_decl = seq(
278
+ "var",
279
+ () => opt_template_list,
280
+ req_optionally_typed_ident,
281
+ opt(seq("=", () => expression)), // no decl_scope, but I think that's ok
282
+ ) .collect(collectVarLike("var"));
283
+
284
+ // prettier-ignore
285
+ const global_variable_decl = seq(
286
+ "var",
287
+ () => opt_template_list,
288
+ global_ident,
289
+ // TODO shouldn't decl_scope include the ident type?
290
+ opt(seq("=", () => expression .collect(scopeCollect, "decl_scope"))),
291
+ );
292
+
293
+ const attribute_if_primary_expression: Parser<
294
+ Stream<WeslToken>,
295
+ Literal | ParenthesizedExpression | TranslateTimeFeature
296
+ > = or(
297
+ tokenOf("keyword", ["true", "false"]).map(makeLiteral),
298
+ delimited(
299
+ token("symbol", "("),
300
+ fn(() => attribute_if_expression),
301
+ token("symbol", ")"),
302
+ ).map(makeParenthesizedExpression),
303
+ tokenKind("word").map(makeTranslateTimeFeature),
304
+ );
305
+
306
+ const attribute_if_unary_expression: Parser<
307
+ Stream<WeslToken>,
308
+ ExpressionElem
309
+ > = or(
310
+ seq(
311
+ token("symbol", "!").map(makeUnaryOperator),
312
+ fn(() => attribute_if_unary_expression),
313
+ ).map(makeUnaryExpression),
314
+ attribute_if_primary_expression,
315
+ );
316
+
317
+ const attribute_if_expression: Parser<
318
+ Stream<WeslToken>,
319
+ ExpressionElem
320
+ > = weslExtension(
321
+ seq(
322
+ attribute_if_unary_expression,
323
+ or(
324
+ repeatPlus(
325
+ seq(
326
+ token("symbol", "||").map(makeBinaryOperator),
327
+ req(
328
+ attribute_if_unary_expression,
329
+ "invalid expression, expected expression",
330
+ ),
331
+ ),
332
+ ),
333
+ repeatPlus(
334
+ seq(
335
+ token("symbol", "&&").map(makeBinaryOperator),
336
+ req(
337
+ attribute_if_unary_expression,
338
+ "invalid expression, expected expression",
339
+ ),
340
+ ),
341
+ ),
342
+ yes().map(() => []),
343
+ ),
344
+ ).map(makeRepeatingBinaryExpression),
345
+ );
346
+
347
+ const unscoped_compound_statement = seq(
348
+ opt_attributes,
349
+ text("{"),
350
+ repeat(() => statement),
351
+ req("}", "invalid block, expected }"),
352
+ ).collect(statementCollect);
353
+
354
+ // prettier-ignore
355
+ const compound_statement = tagScope(
356
+ seq(
357
+ opt_attributes,
358
+ seq(
359
+ text("{"),
360
+ repeat(() => statement),
361
+ req("}", "invalid block, expected '}'"),
362
+ ) .collect(scopeCollect),
363
+ ) .collect(statementCollect)
364
+ );
365
+
366
+ const for_init = seq(
367
+ opt_attributes,
368
+ or(
369
+ fn_call,
370
+ () => variable_or_value_statement,
371
+ () => variable_updating_statement,
372
+ ),
373
+ );
374
+
375
+ const for_update = seq(
376
+ opt_attributes,
377
+ or(fn_call, () => variable_updating_statement),
378
+ );
379
+
380
+ // prettier-ignore
381
+ const for_statement = seq( // LATER consider allowing @if on for_init, expression and for_update
382
+ "for",
383
+ seq(
384
+ req("(", "invalid for loop, expected '('"),
385
+ opt(for_init),
386
+ req(";", "invalid for loop, expected ';'"),
387
+ opt(expression),
388
+ req(";", "invalid for loop, expected ';'"),
389
+ opt(for_update),
390
+ req(")", "invalid for loop, expected ')'"),
391
+ unscoped_compound_statement,
392
+ ) .collect(scopeCollect),
393
+ );
394
+
395
+ const if_statement = seq(
396
+ "if",
397
+ req(seq(expression, compound_statement), "invalid if statement"),
398
+ repeat(
399
+ seq(
400
+ "else",
401
+ "if",
402
+ req(seq(expression, compound_statement), "invalid else if branch"),
403
+ ),
404
+ ),
405
+ opt(
406
+ seq("else", req(compound_statement, "invalid else branch, expected '{'")),
407
+ ),
408
+ );
409
+
410
+ // prettier-ignore
411
+ const loop_statement = seq(
412
+ "loop",
413
+ opt_attributes_no_if,
414
+ req(
415
+ seq(
416
+ "{",
417
+ repeat(() => statement),
418
+ opt(
419
+ tagScope(
420
+ seq(
421
+ opt_attributes,
422
+ "continuing",
423
+ opt_attributes_no_if,
424
+ "{",
425
+ repeat(() => statement),
426
+ tagScope(
427
+ opt(
428
+ seq(
429
+ opt_attributes,
430
+ seq("break", "if", expression, ";")
431
+ ) .collect(statementCollect)
432
+ )
433
+ ),
434
+ "}",
435
+ ) .collect(statementCollect)
436
+ .collect(scopeCollect)
437
+ ),
438
+ ),
439
+ "}",
440
+ ),
441
+ "invalid loop statement"
442
+ ),
443
+ ) .collect(scopeCollect);
444
+
445
+ const case_selector = or("default", expression);
446
+
447
+ // prettier-ignore
448
+ const switch_clause = tagScope(
449
+ seq(
450
+ opt_attributes,
451
+ or(
452
+ seq(
453
+ "case",
454
+ withSep(",", case_selector, { requireOne: true }),
455
+ opt(":"),
456
+ compound_statement,
457
+ ),
458
+ seq("default", opt(":"), compound_statement),
459
+ ). collect(switchClauseCollect),
460
+ )
461
+ );
462
+ const switch_body = seq(opt_attributes, "{", repeatPlus(switch_clause), "}");
463
+ const switch_statement = seq("switch", expression, switch_body);
464
+
465
+ const while_statement = seq("while", expression, compound_statement);
466
+
467
+ const regular_statement = or(
468
+ for_statement,
469
+ if_statement,
470
+ loop_statement,
471
+ switch_statement,
472
+ while_statement,
473
+ seq("break", ";"), // ambiguous with break if
474
+ seq("continue", req(";", "invalid statement, expected ';'")),
475
+ seq(";"), // LATER this one cannot have attributes in front of it
476
+ () => const_assert,
477
+ seq("discard", req(";", "invalid statement, expected ';'")),
478
+ seq("return", opt(expression), req(";", "invalid statement, expected ';'")),
479
+ seq(fn_call, req(";", "invalid statement, expected ';'")),
480
+ seq(
481
+ () => variable_or_value_statement,
482
+ req(";", "invalid statement, expected ';'"),
483
+ ),
484
+ seq(
485
+ () => variable_updating_statement,
486
+ req(";", "invalid statement, expected ';'"),
487
+ ),
488
+ );
489
+
490
+ // prettier-ignore
491
+ const conditional_statement = tagScope(
492
+ seq(
493
+ opt_attributes,
494
+ regular_statement
495
+ ) .collect(statementCollect)
496
+ .collect(partialScopeCollect));
497
+
498
+ // prettier-ignore
499
+ const unconditional_statement = tagScope(
500
+ seq(
501
+ opt_attributes_no_if,
502
+ regular_statement,
503
+ )
504
+ );
505
+
506
+ // prettier-ignore
507
+ const statement: Parser<Stream<WeslToken>, any> = or(
508
+ compound_statement,
509
+ unconditional_statement,
510
+ conditional_statement
511
+ );
512
+
513
+ // prettier-ignore
514
+ const lhs_expression: Parser<Stream<WeslToken>,any> = or(
515
+ simple_component_reference,
516
+ seq(
517
+ qualified_ident .collect(refIdent),
518
+ opt(component_or_swizzle)
519
+ ),
520
+ seq(
521
+ "(",
522
+ () => lhs_expression,
523
+ ")",
524
+ opt(component_or_swizzle) // LATER this doesn't find member references.
525
+ ),
526
+ seq("&", () => lhs_expression),
527
+ seq("*", () => lhs_expression),
528
+ );
529
+
530
+ // prettier-ignore
531
+ const variable_or_value_statement = tagScope( // LATER consider collecting these as var elems and scopes
532
+ or(
533
+ // Also covers the = expression case
534
+ local_variable_decl,
535
+ seq("const", req_optionally_typed_ident, req("=", "invalid const declaration, expected '='"), expression),
536
+ seq(
537
+ "let",
538
+ req_optionally_typed_ident,
539
+ req("=", "invalid let declaration, expected '='"),
540
+ expression
541
+ )
542
+ )
543
+ );
544
+
545
+ const variable_updating_statement = or(
546
+ seq(
547
+ lhs_expression,
548
+ or("=", "<<=", ">>=", "%=", "&=", "*=", "+=", "-=", "/=", "^=", "|="),
549
+ expression,
550
+ ),
551
+ seq(lhs_expression, or("++", "--")),
552
+ seq("_", "=", expression),
553
+ );
554
+
555
+ // prettier-ignore
556
+ const fn_decl = seq(
557
+ tagScope(
558
+ opt_attributes .collect((cc) => cc.tags.attribute || []),
559
+ ) .ctag("fn_attributes"),
560
+ text("fn"),
561
+ req(fnNameDecl, "invalid fn, expected function name"),
562
+ seq(
563
+ req(fnParamList, "invalid fn, expected function parameters")
564
+ .collect(scopeCollect, "header_scope"),
565
+ opt(seq(
566
+ "->",
567
+ opt_attributes .collect((cc) => cc.tags.attribute, "return_attributes"),
568
+ type_specifier .ctag("return_type")
569
+ .collect(scopeCollect, "return_scope")
570
+ )),
571
+ req(
572
+ unscoped_compound_statement,
573
+ "invalid fn, expected function body"
574
+ ) .ctag("body_statement")
575
+ .collect(scopeCollect, "body_scope"),
576
+ )
577
+ ) .collect(partialScopeCollect, "fn_partial_scope")
578
+ .collect(fnCollect);
579
+
580
+ // prettier-ignore
581
+ const global_value_decl = or(
582
+ seq(
583
+ opt_attributes,
584
+ "override",
585
+ global_ident,
586
+ seq(opt(seq("=", expression .collect(scopeCollect, "decl_scope")))), // TODO partial scopes for decl_scopes?
587
+ ";",
588
+ ) .collect(collectVarLike("override")),
589
+ seq(
590
+ opt_attributes,
591
+ "const",
592
+ global_ident,
593
+ "=",
594
+ seq(expression) .collect(scopeCollect, "decl_scope"),
595
+ ";",
596
+ ) .collect(collectVarLike("const")),
597
+ );
598
+
599
+ // prettier-ignore
600
+ const global_alias = seq(
601
+ weslExtension(opt_attributes) .collect((cc) => cc.tags.attribute, "attributes"),
602
+ "alias",
603
+ req(word, "invalid alias, expected name") .collect(globalDeclCollect, "alias_name"),
604
+ req("=", "invalid alias, expected '='"),
605
+ req(type_specifier, "invalid alias, expected type") .collect(scopeCollect, "alias_scope"),
606
+ req(";", "invalid alias, expected ';'"),
607
+ ) .collect(aliasCollect);
608
+
609
+ // prettier-ignore
610
+ const const_assert = tagScope(
611
+ seq(
612
+ opt_attributes,
613
+ "const_assert",
614
+ req(expression, "invalid const_assert, expected expression"),
615
+ req(";", "invalid statement, expected ';'")
616
+ ) .collect(assertCollect)
617
+ ) .ctag("const_assert");
618
+
619
+ // prettier-ignore
620
+ const global_directive = tagScope(
621
+ seq(
622
+ opt_attributes,
623
+ terminated(
624
+ or(
625
+ preceded("diagnostic", diagnostic_control) .map(makeDiagnosticDirective),
626
+ preceded("enable", name_list) .map(makeEnableDirective),
627
+ preceded("requires", name_list) .map(makeRequiresDirective),
628
+ ) .ptag("directive"),
629
+ ";",
630
+ ),
631
+ ) .collect(directiveCollect)
632
+ );
633
+
634
+ // prettier-ignore
635
+ const global_decl = tagScope(
636
+ or(
637
+ fn_decl,
638
+ seq(
639
+ opt_attributes,
640
+ global_variable_decl,
641
+ ";") .collect(collectVarLike("gvar")),
642
+ global_value_decl,
643
+ ";",
644
+ global_alias,
645
+ const_assert .collect(globalAssertCollect),
646
+ struct_decl,
647
+ ),
648
+ );
649
+
650
+ // prettier-ignore
651
+ export const weslRoot = seq(
652
+ weslExtension(weslImports),
653
+ repeat(global_directive),
654
+ repeat(global_decl),
655
+ req(eof(), "invalid WESL, expected EOF"),
656
+ ) .collect(collectModule, "collectModule");
657
+
658
+ function makeDiagnosticDirective([severity, rule]: readonly [
659
+ NameElem,
660
+ [NameElem, NameElem | null],
661
+ ]): DiagnosticDirective {
662
+ return { kind: "diagnostic", severity, rule };
663
+ }
664
+
665
+ function makeEnableDirective(extensions: NameElem[]): EnableDirective {
666
+ return { kind: "enable", extensions };
667
+ }
668
+
669
+ function makeRequiresDirective(extensions: NameElem[]): RequiresDirective {
670
+ return { kind: "requires", extensions };
671
+ }
672
+
673
+ function makeStandardAttribute([name, params]: [
674
+ string,
675
+ UnknownExpressionElem[],
676
+ ]): StandardAttribute {
677
+ return {
678
+ kind: "@attribute",
679
+ name,
680
+ params,
681
+ };
682
+ }
683
+
684
+ function makeInterpolateAttribute(params: NameElem[]): InterpolateAttribute {
685
+ return {
686
+ kind: "@interpolate",
687
+ params,
688
+ };
689
+ }
690
+
691
+ function makeBuiltinAttribute(param: NameElem): BuiltinAttribute {
692
+ return {
693
+ kind: "@builtin",
694
+ param,
695
+ };
696
+ }
697
+
698
+ function makeDiagnosticAttribute([severity, rule]: readonly [
699
+ NameElem,
700
+ [NameElem, NameElem | null],
701
+ ]): DiagnosticAttribute {
702
+ return {
703
+ kind: "@diagnostic",
704
+ severity,
705
+ rule,
706
+ };
707
+ }
708
+
709
+ function makeIfAttribute(param: TranslateTimeExpressionElem): IfAttribute {
710
+ return {
711
+ kind: "@if",
712
+ param,
713
+ };
714
+ }
715
+
716
+ function makeTranslateTimeExpressionElem(args: {
717
+ value: ExpressionElem;
718
+ span: Span;
719
+ }): TranslateTimeExpressionElem {
720
+ return {
721
+ kind: "translate-time-expression",
722
+ expression: args.value,
723
+ span: args.span,
724
+ };
725
+ }
726
+
727
+ function makeName(token: WeslToken<"word">): NameElem {
728
+ return {
729
+ kind: "name",
730
+ name: token.text,
731
+ start: token.span[0],
732
+ end: token.span[1],
733
+ };
734
+ }
735
+
736
+ function makeLiteral(token: WeslToken<"keyword" | "number">): Literal {
737
+ return {
738
+ kind: "literal",
739
+ value: token.text,
740
+ span: token.span,
741
+ };
742
+ }
743
+
744
+ function makeTranslateTimeFeature(
745
+ token: WeslToken<"word">,
746
+ ): TranslateTimeFeature {
747
+ return {
748
+ kind: "translate-time-feature",
749
+ name: token.text,
750
+ span: token.span,
751
+ };
752
+ }
753
+
754
+ function makeParenthesizedExpression(
755
+ expression: ExpressionElem,
756
+ ): ParenthesizedExpression {
757
+ return {
758
+ kind: "parenthesized-expression",
759
+ expression,
760
+ };
761
+ }
762
+
763
+ function makeUnaryOperator(token: WeslToken<"symbol">): UnaryOperator {
764
+ return {
765
+ value: token.text as any,
766
+ span: token.span,
767
+ };
768
+ }
769
+
770
+ function makeBinaryOperator(token: WeslToken<"symbol">): BinaryOperator {
771
+ return {
772
+ value: token.text as any,
773
+ span: token.span,
774
+ };
775
+ }
776
+
777
+ function makeUnaryExpression([operator, expression]: [
778
+ UnaryOperator,
779
+ ExpressionElem,
780
+ ]): UnaryExpression {
781
+ return {
782
+ kind: "unary-expression",
783
+ operator,
784
+ expression,
785
+ };
786
+ }
787
+
788
+ /** A list of left-to-right associative binary expressions */
789
+ function makeRepeatingBinaryExpression([start, repeating]: [
790
+ ExpressionElem,
791
+ [BinaryOperator, ExpressionElem][],
792
+ ]): ExpressionElem {
793
+ let result: ExpressionElem = start;
794
+ for (const [op, left] of repeating) {
795
+ result = makeBinaryExpression([result, op, left]);
796
+ }
797
+ return result;
798
+ }
799
+
800
+ function makeBinaryExpression([left, operator, right]: [
801
+ ExpressionElem,
802
+ BinaryOperator,
803
+ ExpressionElem,
804
+ ]): BinaryExpression {
805
+ return {
806
+ kind: "binary-expression",
807
+ operator,
808
+ left,
809
+ right,
810
+ };
811
+ }
812
+
813
+ if (tracing) {
814
+ const names: Record<string, Parser<Stream<WeslToken>, unknown>> = {
815
+ qualified_ident,
816
+ diagnostic_rule_name,
817
+ diagnostic_control,
818
+ opt_attributes,
819
+ globalTypeNameDecl,
820
+ fnNameDecl,
821
+ optionally_typed_ident,
822
+ struct_member,
823
+ struct_decl,
824
+ fn_call,
825
+ fnParam,
826
+ fnParamList,
827
+ local_variable_decl,
828
+ global_variable_decl,
829
+ compound_statement,
830
+ for_init,
831
+ for_update,
832
+ for_statement,
833
+ if_statement,
834
+ loop_statement,
835
+ case_selector,
836
+ switch_clause,
837
+ switch_body,
838
+ switch_statement,
839
+ while_statement,
840
+ statement,
841
+ lhs_expression,
842
+ variable_or_value_statement,
843
+ variable_updating_statement,
844
+ fn_decl,
845
+ global_value_decl,
846
+ global_alias,
847
+ const_assert,
848
+ global_directive,
849
+ global_decl,
850
+ weslRoot,
851
+ };
852
+
853
+ Object.entries(names).forEach(([name, parser]) => {
854
+ parser.setTraceName(name);
855
+ });
856
+ }