wesl 0.6.0-pre2

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 (110) hide show
  1. package/dist/index.cjs +2617 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.js +2617 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/linker/packages/linker/src/AbstractElems.d.ts +104 -0
  6. package/dist/linker/packages/linker/src/BindIdents.d.ts +16 -0
  7. package/dist/linker/packages/linker/src/CommentsGrammar.d.ts +6 -0
  8. package/dist/linker/packages/linker/src/FlattenTreeImport.d.ts +11 -0
  9. package/dist/linker/packages/linker/src/ImportGrammar.d.ts +13 -0
  10. package/dist/linker/packages/linker/src/ImportTree.d.ts +17 -0
  11. package/dist/linker/packages/linker/src/Linker.d.ts +26 -0
  12. package/dist/linker/packages/linker/src/LowerAndEmit.d.ts +25 -0
  13. package/dist/linker/packages/linker/src/ParseWESL.d.ts +36 -0
  14. package/dist/linker/packages/linker/src/ParsedRegistry.d.ts +26 -0
  15. package/dist/linker/packages/linker/src/PathUtil.d.ts +9 -0
  16. package/dist/linker/packages/linker/src/Scope.d.ts +55 -0
  17. package/dist/linker/packages/linker/src/Slicer.d.ts +26 -0
  18. package/dist/linker/packages/linker/src/StandardTypes.d.ts +6 -0
  19. package/dist/linker/packages/linker/src/Util.d.ts +26 -0
  20. package/dist/linker/packages/linker/src/WESLCollect.d.ts +29 -0
  21. package/dist/linker/packages/linker/src/WESLGrammar.d.ts +23 -0
  22. package/dist/linker/packages/linker/src/WESLTokens.d.ts +42 -0
  23. package/dist/linker/packages/linker/src/WgslBundle.d.ts +13 -0
  24. package/dist/linker/packages/linker/src/debug/ASTtoString.d.ts +3 -0
  25. package/dist/linker/packages/linker/src/debug/ImportToString.d.ts +2 -0
  26. package/dist/linker/packages/linker/src/debug/LineWrapper.d.ts +21 -0
  27. package/dist/linker/packages/linker/src/debug/ScopeToString.d.ts +4 -0
  28. package/dist/linker/packages/linker/src/index.d.ts +7 -0
  29. package/dist/linker/packages/linker/src/test/ErrorLogging.test.d.ts +1 -0
  30. package/dist/linker/packages/linker/src/test/Expression.test.d.ts +1 -0
  31. package/dist/linker/packages/linker/src/test/FlattenTreeImport.test.d.ts +1 -0
  32. package/dist/linker/packages/linker/src/test/ImportCases.test.d.ts +1 -0
  33. package/dist/linker/packages/linker/src/test/ImportSyntaxCases.test.d.ts +1 -0
  34. package/dist/linker/packages/linker/src/test/LinkGlob.test.d.ts +1 -0
  35. package/dist/linker/packages/linker/src/test/LinkPackage.test.d.ts +1 -0
  36. package/dist/linker/packages/linker/src/test/Linker.test.d.ts +1 -0
  37. package/dist/linker/packages/linker/src/test/MatchWgslD.test.d.ts +1 -0
  38. package/dist/linker/packages/linker/src/test/ParseComments.test.d.ts +1 -0
  39. package/dist/linker/packages/linker/src/test/ParseWESL.test.d.ts +1 -0
  40. package/dist/linker/packages/linker/src/test/PathUtil.test.d.ts +1 -0
  41. package/dist/linker/packages/linker/src/test/PrettyGrammar.test.d.ts +1 -0
  42. package/dist/linker/packages/linker/src/test/ScopeWESL.test.d.ts +1 -0
  43. package/dist/linker/packages/linker/src/test/Slicer.test.d.ts +1 -0
  44. package/dist/linker/packages/linker/src/test/TestSetup.d.ts +1 -0
  45. package/dist/linker/packages/linker/src/test/TestUtil.d.ts +15 -0
  46. package/dist/linker/packages/linker/src/test/Util.test.d.ts +1 -0
  47. package/dist/linker/packages/linker/src/test/WgslTests.d.ts +0 -0
  48. package/dist/linker/packages/linker/src/test/shared/StringUtil.d.ts +8 -0
  49. package/dist/linker/packages/linker/src/test/shared/test/StringUtil.test.d.ts +1 -0
  50. package/dist/minified.cjs +2 -0
  51. package/dist/minified.cjs.map +1 -0
  52. package/dist/minified.js +2617 -0
  53. package/dist/minified.js.map +1 -0
  54. package/dist/wesl-testsuite/src/test-cases/BulkTests.d.ts +4 -0
  55. package/dist/wesl-testsuite/src/test-cases/ImportCases.d.ts +3 -0
  56. package/dist/wesl-testsuite/src/test-cases/ImportSyntaxCases.d.ts +3 -0
  57. package/package.json +45 -0
  58. package/src/AbstractElems.ts +148 -0
  59. package/src/BindIdents.ts +277 -0
  60. package/src/CommentsGrammar.ts +44 -0
  61. package/src/FlattenTreeImport.ts +59 -0
  62. package/src/ImportGrammar.ts +142 -0
  63. package/src/ImportTree.ts +19 -0
  64. package/src/Linker.ts +151 -0
  65. package/src/LowerAndEmit.ts +143 -0
  66. package/src/ParseWESL.ts +106 -0
  67. package/src/ParsedRegistry.ts +97 -0
  68. package/src/PathUtil.ts +52 -0
  69. package/src/Scope.ts +100 -0
  70. package/src/Slicer.ts +127 -0
  71. package/src/StandardTypes.ts +66 -0
  72. package/src/Util.ts +112 -0
  73. package/src/WESLCollect.ts +336 -0
  74. package/src/WESLGrammar.ts +538 -0
  75. package/src/WESLTokens.ts +97 -0
  76. package/src/WgslBundle.ts +16 -0
  77. package/src/debug/ASTtoString.ts +149 -0
  78. package/src/debug/ImportToString.ts +21 -0
  79. package/src/debug/LineWrapper.ts +65 -0
  80. package/src/debug/ScopeToString.ts +51 -0
  81. package/src/index.ts +7 -0
  82. package/src/test/ErrorLogging.test.ts +14 -0
  83. package/src/test/Expression.test.ts +22 -0
  84. package/src/test/FlattenTreeImport.test.ts +56 -0
  85. package/src/test/ImportCases.test.ts +440 -0
  86. package/src/test/ImportSyntaxCases.test.ts +22 -0
  87. package/src/test/LinkGlob.test.ts +25 -0
  88. package/src/test/LinkPackage.test.ts +26 -0
  89. package/src/test/Linker.test.ts +120 -0
  90. package/src/test/MatchWgslD.test.ts +16 -0
  91. package/src/test/ParseComments.test.ts +74 -0
  92. package/src/test/ParseWESL.test.ts +902 -0
  93. package/src/test/PathUtil.test.ts +34 -0
  94. package/src/test/PrettyGrammar.test.ts +21 -0
  95. package/src/test/ScopeWESL.test.ts +272 -0
  96. package/src/test/Slicer.test.ts +103 -0
  97. package/src/test/TestSetup.ts +4 -0
  98. package/src/test/TestUtil.ts +52 -0
  99. package/src/test/Util.test.ts +22 -0
  100. package/src/test/WgslTests.ts +0 -0
  101. package/src/test/__snapshots__/ParseDirectives.test.ts.snap +25 -0
  102. package/src/test/__snapshots__/ParseWESL.test.ts.snap +119 -0
  103. package/src/test/__snapshots__/ParseWESL2.test.ts.snap +67 -0
  104. package/src/test/__snapshots__/RustDirective.test.ts.snap +359 -0
  105. package/src/test/shared/StringUtil.ts +59 -0
  106. package/src/test/shared/test/StringUtil.test.ts +32 -0
  107. package/src/test/wgsl_1/main.wgsl +3 -0
  108. package/src/test/wgsl_1/util.wgsl +1 -0
  109. package/src/test/wgsl_2/main2.wgsl +3 -0
  110. package/src/test/wgsl_2/util2.wgsl +1 -0
@@ -0,0 +1,440 @@
1
+ import { afterAll, expect, test } from "vitest";
2
+ import { importCases } from "wesl-testsuite";
3
+ import { linkWeslFiles } from "../Linker.js";
4
+ import { matchTrimmed, trimSrc } from "./shared/StringUtil.js";
5
+
6
+ /** so vitest triggers when this file changes */
7
+ import("../../../../../wesl-testsuite/src/test-cases/ImportCases.js");
8
+
9
+ interface LinkExpectation {
10
+ includes?: string[];
11
+ excludes?: string[];
12
+ linked?: string;
13
+ }
14
+
15
+ // wgsl example src, indexed by name
16
+ const examplesByName = new Map(importCases.map(t => [t.name, t.src]));
17
+
18
+ test("import ./bar/foo", ctx => {
19
+ linkTest2(ctx.task.name, {
20
+ linked: `
21
+ fn main() {
22
+ foo();
23
+ }
24
+
25
+ fn foo() { }
26
+ `,
27
+ });
28
+ });
29
+
30
+ test("main has other root elements", ctx => {
31
+ linkTest2(ctx.task.name, {
32
+ linked: `
33
+ struct Uniforms {
34
+ a: u32
35
+ }
36
+
37
+ @group(0) @binding(0) var<uniform> u: Uniforms;
38
+
39
+ fn main() { }
40
+ `,
41
+ });
42
+ });
43
+
44
+ test("import foo as bar", ctx => {
45
+ linkTest2(ctx.task.name, {
46
+ linked: `
47
+ fn main() {
48
+ bar();
49
+ }
50
+
51
+ fn bar() { /* fooImpl */ }
52
+ `,
53
+ });
54
+ });
55
+
56
+ test("import twice doesn't get two copies", ctx => {
57
+ linkTest2(ctx.task.name, {
58
+ linked: `
59
+ fn main() {
60
+ foo();
61
+ bar();
62
+ }
63
+
64
+ fn foo() { /* fooImpl */ }
65
+
66
+ fn bar() { foo(); }
67
+ `,
68
+ });
69
+ });
70
+
71
+ test("imported fn calls support fn with root conflict", ctx => {
72
+ linkTest2(ctx.task.name, {
73
+ linked: `
74
+ fn main() { foo(); }
75
+
76
+ fn conflicted() { }
77
+
78
+ fn foo() {
79
+ conflicted0(0);
80
+ conflicted0(1);
81
+ }
82
+
83
+ fn conflicted0(a:i32) {}
84
+ `,
85
+ });
86
+ });
87
+
88
+ test("import twice with two as names", ctx => {
89
+ linkTest2(ctx.task.name, {
90
+ linked: `
91
+ fn main() { bar(); bar(); }
92
+
93
+ fn bar() { }
94
+ `,
95
+ });
96
+ });
97
+
98
+ test("import transitive conflicts with main", ctx => {
99
+ linkTest2(ctx.task.name, {
100
+ linked: `
101
+ fn main() {
102
+ mid();
103
+ }
104
+
105
+ fn grand() {
106
+ /* main impl */
107
+ }
108
+
109
+ fn mid() { grand0(); }
110
+
111
+ fn grand0() { /* grandImpl */ }
112
+ `,
113
+ });
114
+ });
115
+
116
+ test("multiple exports from the same module", ctx => {
117
+ linkTest2(ctx.task.name, {
118
+ linked: `
119
+ fn main() {
120
+ foo();
121
+ bar();
122
+ }
123
+
124
+ fn foo() { }
125
+
126
+ fn bar() { }
127
+ `,
128
+ });
129
+ });
130
+
131
+ test("import and resolve conflicting support function", ctx => {
132
+ linkTest2(ctx.task.name, {
133
+ linked: `
134
+ fn support() {
135
+ bar();
136
+ }
137
+
138
+ fn bar() {
139
+ support0();
140
+ }
141
+
142
+ fn support0() { }
143
+ `,
144
+ });
145
+ });
146
+
147
+ test("import support fn that references another import", ctx => {
148
+ linkTest2(ctx.task.name, {
149
+ linked: `
150
+ fn support() {
151
+ foo();
152
+ }
153
+
154
+ fn foo() {
155
+ support0();
156
+ bar();
157
+ }
158
+
159
+ fn support0() { }
160
+
161
+ fn bar() {
162
+ support1();
163
+ }
164
+
165
+ fn support1() { }
166
+ `,
167
+ });
168
+ });
169
+
170
+ test("import support fn from two exports", ctx => {
171
+ linkTest2(ctx.task.name, {
172
+ linked: `
173
+ fn main() {
174
+ foo();
175
+ bar();
176
+ }
177
+
178
+ fn foo() {
179
+ support();
180
+ }
181
+
182
+ fn bar() {
183
+ support();
184
+ }
185
+
186
+ fn support() { }
187
+ `,
188
+ });
189
+ });
190
+
191
+ test("import a struct", ctx => {
192
+ linkTest2(ctx.task.name, {
193
+ linked: `
194
+ fn main() {
195
+ let a = AStruct(1u);
196
+ }
197
+
198
+ struct AStruct {
199
+ x: u32,
200
+ }
201
+ `,
202
+ });
203
+ });
204
+
205
+ test("struct referenced by a fn param", ctx => {
206
+ linkTest2(ctx.task.name, {
207
+ linked: `
208
+ fn main() { foo(); }
209
+
210
+ fn foo(a: AStruct) {
211
+ let b = a.x;
212
+ }
213
+
214
+ struct AStruct {
215
+ x: u32
216
+ }
217
+ `,
218
+ });
219
+ });
220
+
221
+ test("import fn with support struct constructor", ctx => {
222
+ linkTest2(ctx.task.name, {
223
+ linked: `
224
+ fn main() {
225
+ let ze = elemOne();
226
+ }
227
+
228
+ fn elemOne() -> Elem {
229
+ return Elem(1u);
230
+ }
231
+
232
+ struct Elem {
233
+ sum: u32
234
+ }
235
+ `,
236
+ });
237
+ });
238
+
239
+ test("import a transitive struct", ctx => {
240
+ linkTest2(ctx.task.name, {
241
+ linked: `
242
+ struct SrcStruct {
243
+ a: AStruct,
244
+ }
245
+
246
+ struct AStruct {
247
+ s: BStruct,
248
+ }
249
+
250
+ struct BStruct {
251
+ x: u32,
252
+ }
253
+ `,
254
+ });
255
+ });
256
+
257
+ test("'import as' a struct", ctx => {
258
+ linkTest2(ctx.task.name, {
259
+ linked: `
260
+ fn foo (a: AA) { }
261
+
262
+ struct AA { x: u32 }
263
+ `,
264
+ });
265
+ });
266
+
267
+ test("import a struct with name conflicting support struct", ctx => {
268
+ linkTest2(ctx.task.name, {
269
+ linked: `
270
+ struct Base {
271
+ b: i32
272
+ }
273
+
274
+ fn foo() -> AStruct {var a:AStruct; return a;}
275
+
276
+ struct AStruct {
277
+ x: Base0
278
+ }
279
+
280
+ struct Base0 {
281
+ x: u32
282
+ }
283
+ `,
284
+ });
285
+ });
286
+
287
+ test("copy alias to output", ctx => {
288
+ linkTest2(ctx.task.name, {
289
+ linked: `
290
+ alias MyType = u32;
291
+ `,
292
+ });
293
+ });
294
+
295
+ test("copy diagnostics to output", ctx => {
296
+ linkTest2(ctx.task.name, {
297
+ linked: `
298
+ diagnostic(off,derivative_uniformity);
299
+ `,
300
+ });
301
+ });
302
+
303
+ test("const referenced by imported fn", ctx => {
304
+ linkTest2(ctx.task.name, {
305
+ linked: `
306
+ fn main() { foo(); }
307
+
308
+ fn foo() {
309
+ let a = conA;
310
+ }
311
+
312
+ const conA = 7;
313
+ `,
314
+ });
315
+ });
316
+
317
+ test.skip("fn call with a separator", ctx => {
318
+ linkTest2(ctx.task.name, {
319
+ linked: `
320
+ fn main() { bar(); }
321
+
322
+ fn bar() { }
323
+ `,
324
+ });
325
+ });
326
+
327
+ test("local var to struct", ctx => {
328
+ linkTest2(ctx.task.name, {
329
+ linked: `
330
+ fn main() {
331
+ var a: AStruct;
332
+ }
333
+ struct AStruct { x: u32 }
334
+ `,
335
+ });
336
+ });
337
+
338
+ test("global var to struct", ctx => {
339
+ linkTest2(ctx.task.name, {
340
+ linked: `
341
+ @group(0) @binding(0) var<uniform> u: Uniforms;
342
+ struct Uniforms { model: mat4x4<f32> }
343
+ `,
344
+ });
345
+ });
346
+
347
+ test("return type of function", ctx => {
348
+ linkTest2(ctx.task.name, {
349
+ linked: `
350
+ fn b() -> A { }
351
+ struct A { y: i32 }
352
+ `,
353
+ });
354
+ });
355
+
356
+ test("import a const", ctx => {
357
+ linkTest2(ctx.task.name, {
358
+ linked: `
359
+ fn m() { let a = conA; }
360
+ const conA = 11;
361
+ `,
362
+ });
363
+ });
364
+
365
+ test("import an alias", ctx => {
366
+ linkTest2(ctx.task.name, {
367
+ linked: `
368
+ fn m() { let a: aliasA = 4; }
369
+ alias aliasA = u32;
370
+ `,
371
+ });
372
+ });
373
+
374
+ // test(, ctx => {
375
+ // linkTest2(ctx.task.name, {
376
+ // linked: `
377
+ // `,
378
+ // });
379
+ // });
380
+
381
+ // test(, ctx => {
382
+ // linkTest2(ctx.task.name, {
383
+ // linked: `
384
+ // `,
385
+ // });
386
+ // });
387
+
388
+ // test(, ctx => {
389
+ // linkTest2(ctx.task.name, {
390
+ // linked: `
391
+ // `,
392
+ // });
393
+ // });
394
+
395
+ // TODO add case for const_assert in non root module
396
+ // TODO add case for diagnostic in non-root module (should fail?)
397
+
398
+ afterAll(c => {
399
+ const testNameSet = new Set(c.tasks.map(t => t.name));
400
+ const cases = importCases.map(c => c.name);
401
+ const missing = cases.filter(name => !testNameSet.has(name));
402
+ if (missing.length) {
403
+ console.error("Missing tests for cases:", missing);
404
+ expect("missing test: " + missing.toString()).toBe("");
405
+ }
406
+ });
407
+
408
+ function linkTest2(name: string, expectation: LinkExpectation): void {
409
+ /* -- find and trim source texts -- */
410
+ const exampleSrc = examplesByName.get(name);
411
+ if (!exampleSrc) {
412
+ throw new Error(`Skipping test "${name}"\nNo example found.`);
413
+ }
414
+ const srcs = Object.entries(exampleSrc).map(([name, wgsl]) => {
415
+ const trimmedSrc = trimSrc(wgsl);
416
+ return [name, trimmedSrc] as [string, string];
417
+ });
418
+
419
+ const wesl = Object.fromEntries(srcs);
420
+
421
+ /* -- link -- */
422
+ const resultMap = linkWeslFiles(wesl, srcs[0][0]);
423
+ const result = resultMap.dest;
424
+
425
+ /* -- trim and verify results line by line -- */
426
+ const { linked, includes, excludes } = expectation;
427
+ if (linked !== undefined) {
428
+ matchTrimmed(result, linked);
429
+ }
430
+ if (includes !== undefined) {
431
+ includes.forEach(inc => {
432
+ expect(result).toContain(inc);
433
+ });
434
+ }
435
+ if (excludes !== undefined) {
436
+ excludes.forEach(exc => {
437
+ expect(result).not.toContain(exc);
438
+ });
439
+ }
440
+ }
@@ -0,0 +1,22 @@
1
+ import { expect, test } from "vitest";
2
+ import { importSyntaxCases } from "wesl-testsuite";
3
+ import { weslImport } from "../ImportGrammar.js";
4
+ import { testAppParse } from "./TestUtil.js";
5
+
6
+ function expectParseFail(src: string): void {
7
+ const result = testAppParse(weslImport, src);
8
+ expect(result.stable.imports).toEqual([]); // TODO tighten test, shouldn't parse
9
+ }
10
+
11
+ function expectParses(src: string): void {
12
+ const result = testAppParse(weslImport, src);
13
+ expect(result.stable.imports.length).toBeGreaterThan(0);
14
+ }
15
+
16
+ importSyntaxCases.forEach(c => {
17
+ if (c.fails) {
18
+ test(c.src, () => expectParseFail(c.src));
19
+ } else {
20
+ test(c.src, () => expectParses(c.src));
21
+ }
22
+ });
@@ -0,0 +1,25 @@
1
+ /// <reference types="vite/client" />
2
+ import { expect, test } from "vitest";
3
+ import { linkWeslFiles } from "../Linker.js";
4
+
5
+ const wgsl1: Record<string, string> = import.meta.glob("./wgsl_1/*.wgsl", {
6
+ query: "?raw",
7
+ eager: true,
8
+ import: "default",
9
+ });
10
+
11
+ const wgsl2: Record<string, string> = import.meta.glob("./wgsl_2/*.wgsl", {
12
+ query: "?raw",
13
+ eager: true,
14
+ import: "default",
15
+ });
16
+
17
+ test("basic import glob", async () => {
18
+ const linked = linkWeslFiles(wgsl1, "wgsl_1/main");
19
+ expect(linked.dest).toContain("fn bar()");
20
+ });
21
+
22
+ test("#import from path ./util", async () => {
23
+ const linked = linkWeslFiles(wgsl2, "wgsl_2/main2");
24
+ expect(linked.dest).toContain("fn bar()");
25
+ });
@@ -0,0 +1,26 @@
1
+ import { expectNoLog } from "mini-parse/test-util";
2
+ import { expect, test } from "vitest";
3
+ import lib from "random_wgsl";
4
+ import { linkWeslFiles } from "../Linker.ts";
5
+
6
+ test("import rand() from a package", () => {
7
+ const src = `
8
+ import random_wgsl/pcg_2u_3f;
9
+
10
+ struct Uniforms { frame: u32 }
11
+ @binding(0) @group(0) var<uniform> u: Uniforms;
12
+
13
+ @fragment
14
+ fn fragmentMain(@builtin(position) pos: vec4f) -> @location(0) vec4f {
15
+ let rand = pcg_2u_3f(vec2u(pos.xy) + u.frame);
16
+ return vec4(rand, 1f);
17
+ }
18
+ `;
19
+
20
+ const wgsl = { "./main.wesl": src };
21
+ const result = expectNoLog(() =>
22
+ linkWeslFiles(wgsl, "./main.wesl", {}, [lib]),
23
+ );
24
+ expect(result.dest).toContain("fn pcg_2u_3f");
25
+ expect(result.dest).not.toContain("sinRand");
26
+ });
@@ -0,0 +1,120 @@
1
+ import { expect, test } from "vitest";
2
+ import { link2Test } from "./TestUtil.js";
3
+ import { matchTrimmed } from "./shared/StringUtil.js";
4
+ import { dlog } from "berry-pretty";
5
+
6
+ test("link global var", () => {
7
+ const src = `var x: i32 = 1;`;
8
+ const result = link2Test(src);
9
+ matchTrimmed(result, src);
10
+ });
11
+
12
+ test("link an alias", () => {
13
+ const src = `
14
+ alias Num = f32;
15
+
16
+ fn main() { Num(1.0); }
17
+ `;
18
+ const result = link2Test(src);
19
+ matchTrimmed(result, src);
20
+ });
21
+
22
+ test("link a const_assert", () => {
23
+ const src = `
24
+ var x = 1;
25
+ var y = 2;
26
+ const_assert x < y;
27
+ `;
28
+ const result = link2Test(src);
29
+ matchTrimmed(result, src);
30
+ });
31
+
32
+ test("link a struct", () => {
33
+ const src = `
34
+ struct Point {
35
+ x: i32,
36
+ y: i32,
37
+ }
38
+ `;
39
+ const result = link2Test(src);
40
+ matchTrimmed(result, src);
41
+ });
42
+
43
+ test("link a fn", () => {
44
+ const src = `
45
+ fn foo(x: i32, y: u32) -> f32 {
46
+ return 1.0;
47
+ }`;
48
+ const result = link2Test(src);
49
+ matchTrimmed(result, src);
50
+ });
51
+
52
+ test("handle a ptr type", () => {
53
+ const src = `
54
+ fn uint_bitfieldExtract_u1_i1_i1_(
55
+ value: ptr<function, u32>,
56
+ bits: ptr<function, i32>) -> u32 { }
57
+ `;
58
+ const result = link2Test(src);
59
+ matchTrimmed(result, src);
60
+ });
61
+
62
+ test("struct after var", () => {
63
+ const src = `
64
+ var config: TwoPassConfig;
65
+
66
+ struct TwoPassConfig {
67
+ x: u32,
68
+ }
69
+ `;
70
+ const result = link2Test(src);
71
+ matchTrimmed(result, src);
72
+ });
73
+
74
+ test("type inside fn with same name as fn", () => {
75
+ // illegal but shouldn't hang
76
+ const src = `
77
+ fn foo() {
78
+ var a:foo;
79
+ }
80
+ fn bar() {}
81
+ `;
82
+ const result = link2Test(src);
83
+ matchTrimmed(result, src);
84
+ });
85
+
86
+ test("call cross reference", () => {
87
+ const src = `
88
+ fn foo() {
89
+ bar();
90
+ }
91
+
92
+ fn bar() {
93
+ foo();
94
+ }
95
+ `;
96
+
97
+ const result = link2Test(src);
98
+ matchTrimmed(result, src);
99
+ });
100
+
101
+ test("struct self reference", () => {
102
+ const src = `
103
+ struct A {
104
+ a: A,
105
+ b: B,
106
+ }
107
+ struct B {
108
+ f: f32,
109
+ }
110
+ `;
111
+
112
+ const result = link2Test(src);
113
+ matchTrimmed(result, src);
114
+ });
115
+
116
+ test("parse texture_storage_2d with texture format in typical type position", () => {
117
+ const src = `var t: texture_storage_2d<rgba8unorm, write>;`;
118
+ const result = link2Test(src);
119
+ matchTrimmed(result, src);
120
+ });
@@ -0,0 +1,16 @@
1
+ import { matchingLexer } from "mini-parse";
2
+ import { expect, test } from "vitest";
3
+ import { mainTokens } from "../WESLTokens.js";
4
+
5
+ test("lex #import foo", () => {
6
+ const lexer = matchingLexer(`#import foo`, mainTokens);
7
+ const tokens = [1, 2].map(lexer.next);
8
+ expect(tokens.map(t => t?.kind)).toEqual(["directive", "ident"]);
9
+ });
10
+
11
+ test("/* foo */", () => {
12
+ const lexer = matchingLexer(`/* foo */`, mainTokens);
13
+ const tokens = [1, 2, 3].map(lexer.next);
14
+ const tokenKinds = tokens.map(t => t?.kind);
15
+ expect(tokenKinds).toEqual(["symbol", "ident", "symbol"]);
16
+ });
@@ -0,0 +1,74 @@
1
+ import { expectNoLog } from "mini-parse/test-util";
2
+
3
+ import { expect, test } from "vitest";
4
+ import { blockComment, lineComment } from "../CommentsGrammar.js";
5
+ import { parseWESL } from "../ParseWESL.js";
6
+ import { testAppParse } from "./TestUtil.js";
7
+ import { astToString } from "../debug/ASTtoString.js";
8
+
9
+ test("lineComment parse // foo bar", () => {
10
+ const src = "// foo bar";
11
+ const { position } = testAppParse(lineComment, src);
12
+ expect(position).toBe(src.length);
13
+ });
14
+
15
+ test("lineComment parse // foo bar \\n", () => {
16
+ const src = "// foo bar\n";
17
+ const { position } = testAppParse(lineComment, src);
18
+ expect(position).toBe(src.length);
19
+ });
20
+
21
+ test("blockComment parses /* comment */", () => {
22
+ const src = "/* comment */";
23
+ expectNoLog(() => {
24
+ const { parsed } = testAppParse(blockComment, src);
25
+ expect(parsed?.value).toMatchInlineSnapshot(`
26
+ [
27
+ "/*",
28
+ [
29
+ {
30
+ "kind": "ident",
31
+ "text": "comment",
32
+ },
33
+ ],
34
+ "*/",
35
+ ]
36
+ `);
37
+ });
38
+ });
39
+
40
+ test("skipBlockComment parses nested comment", () => {
41
+ const src = "/** comment1 /* comment2 */ */";
42
+ expectNoLog(() => testAppParse(blockComment, src));
43
+ });
44
+
45
+ test("parse fn with line comment", () => {
46
+ const src = `
47
+ fn binaryOp() { // binOpImpl
48
+ }`;
49
+ const parsed = parseWESL(src);
50
+ expect(astToString(parsed.moduleElem)).toMatchInlineSnapshot(`
51
+ "module
52
+ text '
53
+ '
54
+ fn binaryOp()
55
+ text 'fn '
56
+ decl %binaryOp
57
+ text '() { // binOpImpl
58
+ }'"
59
+ `);
60
+ });
61
+
62
+ test("parse empty line comment", () => {
63
+ const src = `
64
+ var workgroupThreads= 4; //
65
+ `;
66
+ expectNoLog(() => parseWESL(src));
67
+ });
68
+
69
+ test("parse line comment with #replace", () => {
70
+ const src = `
71
+ const workgroupThreads= 4; // #replace 4=workgroupThreads
72
+ `;
73
+ expectNoLog(() => parseWESL(src));
74
+ });