wesl 0.7.26 → 0.7.28

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 (67) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +283 -147
  3. package/dist/index.js +1765 -1143
  4. package/package.json +2 -2
  5. package/src/AbstractElems.ts +264 -82
  6. package/src/ClickableError.ts +8 -1
  7. package/src/Linker.ts +63 -67
  8. package/src/LinkerUtil.ts +141 -7
  9. package/src/LowerAndEmit.ts +660 -304
  10. package/src/Mangler.ts +1 -1
  11. package/src/ModuleResolver.ts +15 -4
  12. package/src/ParseWESL.ts +21 -33
  13. package/src/SrcMap.ts +7 -19
  14. package/src/StandardTypes.ts +1 -1
  15. package/src/WeslDevice.ts +1 -0
  16. package/src/debug/ASTtoString.ts +92 -76
  17. package/src/index.ts +1 -1
  18. package/src/parse/AttachComments.ts +289 -0
  19. package/src/parse/ExpressionUtil.ts +3 -3
  20. package/src/parse/Keywords.ts +1 -1
  21. package/src/parse/ParseAttribute.ts +49 -71
  22. package/src/parse/ParseCall.ts +3 -4
  23. package/src/parse/ParseControlFlow.ts +100 -56
  24. package/src/parse/ParseDirective.ts +9 -8
  25. package/src/parse/ParseDoBlock.ts +63 -0
  26. package/src/parse/ParseExpression.ts +11 -10
  27. package/src/parse/ParseFn.ts +11 -33
  28. package/src/parse/ParseGlobalVar.ts +36 -27
  29. package/src/parse/ParseIdent.ts +4 -5
  30. package/src/parse/ParseLocalVar.ts +16 -12
  31. package/src/parse/ParseLoop.ts +76 -39
  32. package/src/parse/ParseModule.ts +65 -19
  33. package/src/parse/ParseSimpleStatement.ts +112 -66
  34. package/src/parse/ParseStatement.ts +40 -67
  35. package/src/parse/ParseStruct.ts +8 -22
  36. package/src/parse/ParseType.ts +10 -13
  37. package/src/parse/ParseUtil.ts +26 -12
  38. package/src/parse/ParseValueDeclaration.ts +18 -31
  39. package/src/parse/ParseWesl.ts +11 -14
  40. package/src/parse/ParsingContext.ts +11 -9
  41. package/src/parse/WeslStream.ts +138 -121
  42. package/src/parse/stream/RegexMatchers.ts +45 -0
  43. package/src/parse/stream/WeslLexer.ts +249 -0
  44. package/src/test/BevyLink.test.ts +18 -11
  45. package/src/test/ConditionalElif.test.ts +4 -2
  46. package/src/test/DeclCommentEmit.test.ts +122 -0
  47. package/src/test/DoBlock.test.ts +164 -0
  48. package/src/test/FilterValidElements.test.ts +4 -6
  49. package/src/test/Linker.test.ts +23 -7
  50. package/src/test/Mangling.test.ts +8 -4
  51. package/src/test/ParseComments.test.ts +234 -6
  52. package/src/test/ParseConditionsV2.test.ts +47 -175
  53. package/src/test/ParseElifV2.test.ts +12 -33
  54. package/src/test/ParseErrorV2.test.ts +0 -0
  55. package/src/test/ParseWeslV2.test.ts +247 -626
  56. package/src/test/StatementEmit.test.ts +143 -0
  57. package/src/test/StripWesl.ts +24 -3
  58. package/src/test/TestLink.ts +19 -3
  59. package/src/test/TestUtil.ts +18 -8
  60. package/src/test/Tokenizer.test.ts +96 -0
  61. package/src/test/__snapshots__/ParseWeslV2.test.ts.snap +10 -42
  62. package/src/RawEmit.ts +0 -103
  63. package/src/Reflection.ts +0 -336
  64. package/src/TransformBindingStructs.ts +0 -320
  65. package/src/parse/ContentsHelpers.ts +0 -70
  66. package/src/parse/stream/CachingStream.ts +0 -48
  67. package/src/parse/stream/MatchersStream.ts +0 -85
@@ -10,13 +10,9 @@ test("parse fn with line comment", () => {
10
10
  const parsed = parseWESL(src);
11
11
  expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
12
12
  "module
13
- text '
14
- '
15
13
  fn binaryOp()
16
14
  decl %binaryOp
17
- statement
18
- text '{ // binOpImpl
19
- }'"
15
+ block inner['// binOpImpl']"
20
16
  `);
21
17
  });
22
18
 
@@ -28,8 +24,240 @@ test("parse empty line comment", () => {
28
24
  });
29
25
 
30
26
  test("parse line comment with #replace", () => {
31
- const src = `
27
+ const src = `
32
28
  const workgroupThreads= 4; // #replace 4=workgroupThreads
33
29
  `;
34
30
  expectNoLog(() => parseWESL(src));
35
31
  });
32
+
33
+ test("attach leading and trailing comments to a statement", () => {
34
+ const src = `
35
+ fn f() {
36
+ // leading
37
+ let x = 1; // trailing
38
+ }`;
39
+ const parsed = parseWESL(src);
40
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
41
+ "module
42
+ fn f()
43
+ decl %f
44
+ block
45
+ let %x before['// leading'] after['// trailing']
46
+ typeDecl %x
47
+ decl %x
48
+ literal literal(1)"
49
+ `);
50
+ });
51
+
52
+ test("split comments between two statements", () => {
53
+ const src = `
54
+ fn f() {
55
+ let x = 1; // after x
56
+ // before y
57
+ let y = 2;
58
+ }`;
59
+ const parsed = parseWESL(src);
60
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
61
+ "module
62
+ fn f()
63
+ decl %f
64
+ block
65
+ let %x after['// after x']
66
+ typeDecl %x
67
+ decl %x
68
+ literal literal(1)
69
+ let %y before['// before y']
70
+ typeDecl %y
71
+ decl %y
72
+ literal literal(2)"
73
+ `);
74
+ });
75
+
76
+ test("attach a dangling comment before the closing brace", () => {
77
+ const src = `
78
+ fn f() {
79
+ let x = 1;
80
+ // dangling
81
+ }`;
82
+ const parsed = parseWESL(src);
83
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
84
+ "module
85
+ fn f()
86
+ decl %f
87
+ block
88
+ let %x after['// dangling']
89
+ typeDecl %x
90
+ decl %x
91
+ literal literal(1)"
92
+ `);
93
+ });
94
+
95
+ test("preserve a blank line above a module declaration comment", () => {
96
+ const src = `const x = 1;
97
+
98
+ // y comment
99
+ const y = 2;`;
100
+ const parsed = parseWESL(src);
101
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
102
+ "module
103
+ const %x
104
+ typeDecl %x
105
+ decl %x
106
+ literal literal(1)
107
+ const %y before['// y comment'(blank)]
108
+ typeDecl %y
109
+ decl %y
110
+ literal literal(2)"
111
+ `);
112
+ });
113
+
114
+ test("attach a nested block comment", () => {
115
+ const src = `
116
+ fn f() {
117
+ /* outer /* inner */ outer */
118
+ let x = 1;
119
+ }`;
120
+ const parsed = parseWESL(src);
121
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
122
+ "module
123
+ fn f()
124
+ decl %f
125
+ block
126
+ let %x before['/* outer /* inner */ outer */']
127
+ typeDecl %x
128
+ decl %x
129
+ literal literal(1)"
130
+ `);
131
+ });
132
+
133
+ test("attach a multi-line block comment", () => {
134
+ const src = `
135
+ fn f() {
136
+ /* one
137
+ two */
138
+ let x = 1;
139
+ }`;
140
+ const parsed = parseWESL(src);
141
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
142
+ "module
143
+ fn f()
144
+ decl %f
145
+ block
146
+ let %x before['/* one
147
+ two */']
148
+ typeDecl %x
149
+ decl %x
150
+ literal literal(1)"
151
+ `);
152
+ });
153
+
154
+ test("attach a leading comment to a control-flow statement", () => {
155
+ const src = `
156
+ fn f() {
157
+ // before if
158
+ if true { }
159
+ // before for
160
+ for (var i = 0; i < 1; i++) { }
161
+ }`;
162
+ const parsed = parseWESL(src);
163
+ const out = astToString(parsed.moduleElem);
164
+ expect(out).toContain("if before['// before if']");
165
+ expect(out).toContain("for before['// before for']");
166
+ });
167
+
168
+ test("keep a comment between switch clauses", () => {
169
+ const src = `
170
+ fn f() {
171
+ switch 0 {
172
+ case 0: { }
173
+ // between clauses
174
+ default: { }
175
+ }
176
+ }`;
177
+ const parsed = parseWESL(src);
178
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
179
+ "module
180
+ fn f()
181
+ decl %f
182
+ block
183
+ switch
184
+ literal literal(0)
185
+ switch-clause
186
+ literal literal(0)
187
+ block
188
+ switch-clause before['// between clauses']
189
+ block"
190
+ `);
191
+ });
192
+
193
+ test("attach a comment before 'else if' to the else branch", () => {
194
+ // The else-if branch starts at the 'else' keyword, so a leading comment falls
195
+ // in the gap and leads the branch instead of being swallowed by its condition.
196
+ const src = `
197
+ fn f() {
198
+ if (a) { }
199
+ // before else
200
+ else if (b) { }
201
+ }`;
202
+ const parsed = parseWESL(src);
203
+ expect(astToString(parsed.moduleElem)).toContain(
204
+ "if before['// before else']",
205
+ );
206
+ });
207
+
208
+ test("attach an inline comment to the following call argument", () => {
209
+ const src = `const x = max(1, /* big */ 2);`;
210
+ const parsed = parseWESL(src);
211
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
212
+ "module
213
+ const %x
214
+ typeDecl %x
215
+ decl %x
216
+ call-expression call
217
+ ref max
218
+ literal literal(1)
219
+ literal literal(2) before['/* big */']"
220
+ `);
221
+ });
222
+
223
+ test("attach an inline comment hugging the previous call argument", () => {
224
+ const src = `const x = max(1 /* big */, 2);`;
225
+ const parsed = parseWESL(src);
226
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
227
+ "module
228
+ const %x
229
+ typeDecl %x
230
+ decl %x
231
+ call-expression call
232
+ ref max
233
+ literal literal(1) after['/* big */']
234
+ literal literal(2)"
235
+ `);
236
+ });
237
+
238
+ test("attach an inline comment between binary operands", () => {
239
+ const src = `const x = 1 + /* mid */ 2;`;
240
+ const parsed = parseWESL(src);
241
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
242
+ "module
243
+ const %x
244
+ typeDecl %x
245
+ decl %x
246
+ binary-expression binop(+)
247
+ literal literal(1)
248
+ literal literal(2) before['/* mid */']"
249
+ `);
250
+ });
251
+
252
+ test("attach a comment inside parentheses", () => {
253
+ const src = `const x = ( /* inner */ 1);`;
254
+ const parsed = parseWESL(src);
255
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
256
+ "module
257
+ const %x
258
+ typeDecl %x
259
+ decl %x
260
+ parenthesized-expression parens
261
+ literal literal(1) before['/* inner */']"
262
+ `);
263
+ });
@@ -1,6 +1,12 @@
1
1
  import { expect, test } from "vitest";
2
2
  import { astToString } from "../debug/ASTtoString.ts";
3
- import { parseTest } from "./TestUtil.ts";
3
+ import { parseTest, parseWESL } from "./TestUtil.ts";
4
+
5
+ test("@if() with an empty condition is a parse error", () => {
6
+ // Past `@if(` the parser is committed: a missing condition must error rather
7
+ // than silently return null on a half-consumed stream.
8
+ expect(() => parseWESL("@if() fn a() {}")).toThrow(/Expected expression/);
9
+ });
4
10
 
5
11
  test("parse complex condition", () => {
6
12
  const ast = parseTest("@if(true || (!foo&&!!false) )\nfn a() {}");
@@ -9,8 +15,7 @@ test("parse complex condition", () => {
9
15
  fn a() @if
10
16
  attribute @if(true || (!foo && !!false))
11
17
  decl %a
12
- statement
13
- text '{}'"
18
+ block"
14
19
  `);
15
20
  });
16
21
 
@@ -22,11 +27,8 @@ test("@if(false) enable f16", () => {
22
27
  const astString = astToString(ast.moduleElem);
23
28
  expect(astString).toMatchInlineSnapshot(`
24
29
  "module
25
- text '
26
- '
27
30
  directive enable f16 @if
28
- text '
29
- '"
31
+ attribute @if(false)"
30
32
  `);
31
33
  });
32
34
 
@@ -38,13 +40,9 @@ test("@if(false) const_assert true;", () => {
38
40
  const astString = astToString(ast.moduleElem);
39
41
  expect(astString).toMatchInlineSnapshot(`
40
42
  "module
41
- text '
42
- '
43
43
  assert
44
44
  attribute @if(false)
45
- text ' const_assert true;'
46
- text '
47
- '"
45
+ literal literal(true)"
48
46
  `);
49
47
  });
50
48
 
@@ -56,16 +54,11 @@ test("@if(true) var x = 7", () => {
56
54
  const astString = astToString(ast.moduleElem);
57
55
  expect(astString).toMatchInlineSnapshot(`
58
56
  "module
59
- text '
60
- '
61
57
  gvar %x @if
62
58
  attribute @if(true)
63
- text ' var '
64
59
  typeDecl %x
65
60
  decl %x
66
- text ' = 7;'
67
- text '
68
- '"
61
+ literal literal(7)"
69
62
  `);
70
63
  });
71
64
 
@@ -80,29 +73,17 @@ test("conditional statement", () => {
80
73
  const astString = astToString(ast.moduleElem);
81
74
  expect(astString).toMatchInlineSnapshot(`
82
75
  "module
83
- text '
84
- '
85
76
  fn main()
86
77
  decl %main
87
- statement
88
- text '{
89
- '
78
+ block
90
79
  var %x
91
- text 'var '
92
80
  typeDecl %x
93
81
  decl %x
94
- text ' = 1;'
95
- text '
96
- '
97
- statement @if
82
+ literal literal(1)
83
+ assign @if
98
84
  attribute @if(true)
99
- text ' '
100
85
  ref x
101
- text ' = 2 ;'
102
- text '
103
- }'
104
- text '
105
- '"
86
+ literal literal(2)"
106
87
  `);
107
88
  });
108
89
 
@@ -118,28 +99,15 @@ test("compound statement", () => {
118
99
  const astString = astToString(ast.moduleElem);
119
100
  expect(astString).toMatchInlineSnapshot(`
120
101
  "module
121
- text '
122
- '
123
102
  fn main()
124
103
  decl %main
125
- statement
126
- text '{
127
- '
128
- statement @if
104
+ block
105
+ block @if
129
106
  attribute @if(false)
130
- text ' {
131
- '
132
107
  let %x
133
- text 'let '
134
108
  typeDecl %x
135
109
  decl %x
136
- text ' = 1;'
137
- text '
138
- }'
139
- text '
140
- }'
141
- text '
142
- '"
110
+ literal literal(1)"
143
111
  `);
144
112
  });
145
113
 
@@ -153,23 +121,14 @@ test("conditional local var", () => {
153
121
  const astString = astToString(ast.moduleElem);
154
122
  expect(astString).toMatchInlineSnapshot(`
155
123
  "module
156
- text '
157
- '
158
124
  fn main()
159
125
  decl %main
160
- statement
161
- text '{
162
- '
126
+ block
163
127
  var %x @if
164
128
  attribute @if(true)
165
- text ' var '
166
129
  typeDecl %x
167
130
  decl %x
168
- text ' = 1;'
169
- text '
170
- }'
171
- text '
172
- '"
131
+ literal literal(1)"
173
132
  `);
174
133
  });
175
134
 
@@ -181,16 +140,11 @@ test("@if(MOBILE) const x = 1", () => {
181
140
  const astString = astToString(ast.moduleElem);
182
141
  expect(astString).toMatchInlineSnapshot(`
183
142
  "module
184
- text '
185
- '
186
143
  const %x @if
187
144
  attribute @if(MOBILE)
188
- text ' const '
189
145
  typeDecl %x
190
146
  decl %x
191
- text ' = 1;'
192
- text '
193
- '"
147
+ literal literal(1)"
194
148
  `);
195
149
  });
196
150
 
@@ -203,24 +157,16 @@ test("@else after @if", () => {
203
157
  const astString = astToString(ast.moduleElem);
204
158
  expect(astString).toMatchInlineSnapshot(`
205
159
  "module
206
- text '
207
- '
208
160
  const %x @if
209
161
  attribute @if(false)
210
- text ' const '
211
162
  typeDecl %x
212
163
  decl %x
213
- text ' = 1;'
214
- text '
215
- '
164
+ literal literal(1)
216
165
  const %x @else
217
166
  attribute @else
218
- text ' const '
219
167
  typeDecl %x
220
168
  decl %x
221
- text ' = 2;'
222
- text '
223
- '"
169
+ literal literal(2)"
224
170
  `);
225
171
  });
226
172
 
@@ -233,28 +179,18 @@ test("@else with function", () => {
233
179
  const astString = astToString(ast.moduleElem);
234
180
  expect(astString).toMatchInlineSnapshot(`
235
181
  "module
236
- text '
237
- '
238
182
  fn foo() @if
239
183
  attribute @if(DEBUG)
240
184
  decl %foo
241
- statement
242
- text '{'
243
- statement
244
- text ' return 1;'
245
- text ' }'
246
- text '
247
- '
185
+ block
186
+ return
187
+ literal literal(1)
248
188
  fn foo() @else
249
189
  attribute @else
250
190
  decl %foo
251
- statement
252
- text '{'
253
- statement
254
- text ' return 2;'
255
- text ' }'
256
- text '
257
- '"
191
+ block
192
+ return
193
+ literal literal(2)"
258
194
  `);
259
195
  });
260
196
 
@@ -269,31 +205,19 @@ test("@else with statement", () => {
269
205
  const astString = astToString(ast.moduleElem);
270
206
  expect(astString).toMatchInlineSnapshot(`
271
207
  "module
272
- text '
273
- '
274
208
  fn main()
275
209
  decl %main
276
- statement
277
- text '{
278
- '
210
+ block
279
211
  let %x @if
280
212
  attribute @if(A)
281
- text ' let '
282
213
  typeDecl %x
283
214
  decl %x
284
- text ' = 1.0;'
285
- text '
286
- '
215
+ literal literal(1.0)
287
216
  let %x @else
288
217
  attribute @else
289
- text ' let '
290
218
  typeDecl %x
291
219
  decl %x
292
- text ' = 2.0;'
293
- text '
294
- }'
295
- text '
296
- '"
220
+ literal literal(2.0)"
297
221
  `);
298
222
  });
299
223
 
@@ -308,37 +232,21 @@ test("@else compound statement", () => {
308
232
  const astString = astToString(ast.moduleElem);
309
233
  expect(astString).toMatchInlineSnapshot(`
310
234
  "module
311
- text '
312
- '
313
235
  fn test()
314
236
  decl %test
315
- statement
316
- text '{
317
- '
318
- statement @if
237
+ block
238
+ block @if
319
239
  attribute @if(MOBILE)
320
- text ' { '
321
240
  let %a
322
- text 'let '
323
241
  typeDecl %a
324
242
  decl %a
325
- text ' = 1;'
326
- text ' }'
327
- text '
328
- '
329
- statement @else
243
+ literal literal(1)
244
+ block @else
330
245
  attribute @else
331
- text ' { '
332
246
  let %a
333
- text 'let '
334
247
  typeDecl %a
335
248
  decl %a
336
- text ' = 2;'
337
- text ' }'
338
- text '
339
- }'
340
- text '
341
- '"
249
+ literal literal(2)"
342
250
  `);
343
251
  });
344
252
 
@@ -353,36 +261,19 @@ test("@else with struct member", () => {
353
261
  const astString = astToString(ast.moduleElem);
354
262
  expect(astString).toMatchInlineSnapshot(`
355
263
  "module
356
- text '
357
- '
358
264
  struct Point
359
- text 'struct '
360
265
  decl %Point
361
- text ' {
362
- '
363
266
  member @if x: f32
364
267
  attribute @if(DIMENSIONS_2)
365
- text ' '
366
268
  name x
367
- text ': '
368
269
  type f32
369
270
  ref f32
370
- text ',
371
- '
372
- member @else x: vec3<ref f32>
271
+ member @else x: vec3<f32>
373
272
  attribute @else
374
- text ' '
375
273
  name x
376
- text ': '
377
- type vec3<ref f32>
274
+ type vec3<f32>
378
275
  ref vec3
379
- text '<'
380
- ref f32
381
- text '>'
382
- text ',
383
- }'
384
- text '
385
- '"
276
+ ref f32"
386
277
  `);
387
278
  });
388
279
 
@@ -395,11 +286,8 @@ test("@if with import", () => {
395
286
  // Expected output once grammar supports @if on imports:
396
287
  expect(astString).toMatchInlineSnapshot(`
397
288
  "module
398
- text '
399
- '
400
289
  import package::debug; @if
401
- text '
402
- '"
290
+ attribute @if(DEBUG)"
403
291
  `);
404
292
  });
405
293
 
@@ -413,14 +301,10 @@ test("@else with import", () => {
413
301
  // Expected output once grammar supports @if/@else on imports:
414
302
  expect(astString).toMatchInlineSnapshot(`
415
303
  "module
416
- text '
417
- '
418
304
  import package::a; @if
419
- text '
420
- '
305
+ attribute @if(false)
421
306
  import package::b; @else
422
- text '
423
- '"
307
+ attribute @else"
424
308
  `);
425
309
  });
426
310
 
@@ -436,34 +320,22 @@ test("parse @else fn", () => {
436
320
  expect(astString).toMatchInlineSnapshot(
437
321
  `
438
322
  "module
439
- text '
440
- '
441
323
  fn testFn() @if
442
324
  attribute @if(FOO)
443
325
  decl %testFn
444
- statement
445
- text '{ '
326
+ block
446
327
  let %a
447
- text 'let '
448
328
  typeDecl %a
449
329
  decl %a
450
- text ' = 0;'
451
- text ' }'
452
- text '
453
- '
330
+ literal literal(0)
454
331
  fn testFn() @else
455
332
  attribute @else
456
333
  decl %testFn
457
- statement
458
- text '{ '
334
+ block
459
335
  let %a
460
- text 'let '
461
336
  typeDecl %a
462
337
  decl %a
463
- text ' = 1;'
464
- text ' }'
465
- text '
466
- '"
338
+ literal literal(1)"
467
339
  `,
468
340
  );
469
341
  });