wesl 0.6.48 → 0.7.0

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 (95) hide show
  1. package/dist/index.d.ts +295 -214
  2. package/dist/index.js +2947 -1550
  3. package/package.json +6 -8
  4. package/src/AbstractElems.ts +81 -81
  5. package/src/Assertions.ts +5 -5
  6. package/src/BindIdents.ts +193 -319
  7. package/src/ClickableError.ts +3 -2
  8. package/src/Conditions.ts +2 -2
  9. package/src/LinkedWesl.ts +1 -1
  10. package/src/Linker.ts +4 -3
  11. package/src/LinkerUtil.ts +1 -1
  12. package/src/Logging.ts +165 -0
  13. package/src/LowerAndEmit.ts +278 -110
  14. package/src/ModulePathUtil.ts +59 -0
  15. package/src/ModuleResolver.ts +26 -62
  16. package/src/ParseError.ts +9 -0
  17. package/src/ParseWESL.ts +30 -94
  18. package/src/RawEmit.ts +1 -4
  19. package/src/Reflection.ts +1 -1
  20. package/src/Scope.ts +3 -0
  21. package/src/Span.ts +2 -0
  22. package/src/SrcMap.ts +208 -0
  23. package/src/Stream.ts +30 -0
  24. package/src/TransformBindingStructs.ts +2 -2
  25. package/src/Util.ts +1 -1
  26. package/src/debug/ASTtoString.ts +84 -135
  27. package/src/discovery/FindUnboundIdents.ts +14 -5
  28. package/src/index.ts +5 -0
  29. package/src/parse/ContentsHelpers.ts +70 -0
  30. package/src/parse/ExpressionUtil.ts +121 -0
  31. package/src/parse/Keywords.ts +12 -12
  32. package/src/parse/OperatorBinding.ts +146 -0
  33. package/src/parse/ParseAttribute.ts +272 -0
  34. package/src/parse/ParseCall.ts +77 -0
  35. package/src/parse/ParseControlFlow.ts +129 -0
  36. package/src/parse/ParseDirective.ts +105 -0
  37. package/src/parse/ParseExpression.ts +288 -0
  38. package/src/parse/ParseFn.ts +151 -0
  39. package/src/parse/ParseGlobalVar.ts +131 -0
  40. package/src/parse/ParseIdent.ts +77 -0
  41. package/src/parse/ParseImport.ts +160 -0
  42. package/src/parse/ParseLocalVar.ts +69 -0
  43. package/src/parse/ParseLoop.ts +112 -0
  44. package/src/parse/ParseModule.ts +116 -0
  45. package/src/parse/ParseSimpleStatement.ts +162 -0
  46. package/src/parse/ParseStatement.ts +215 -0
  47. package/src/parse/ParseStruct.ts +89 -0
  48. package/src/parse/ParseType.ts +71 -0
  49. package/src/parse/ParseUtil.ts +174 -0
  50. package/src/parse/ParseValueDeclaration.ts +130 -0
  51. package/src/parse/ParseWesl.ts +51 -0
  52. package/src/parse/ParsingContext.ts +93 -0
  53. package/src/parse/WeslStream.ts +63 -20
  54. package/src/parse/stream/CachingStream.ts +48 -0
  55. package/src/parse/stream/MatchersStream.ts +85 -0
  56. package/src/parse/stream/RegexHelpers.ts +38 -0
  57. package/src/test/BevyLink.test.ts +100 -0
  58. package/src/test/BindStdTypes.test.ts +110 -0
  59. package/src/test/{BindWESL.test.ts → BindWESLV2.test.ts} +21 -22
  60. package/src/test/BulkTests.test.ts +11 -12
  61. package/src/test/ConditionLinking.test.ts +107 -0
  62. package/src/test/ConditionalElif.test.ts +1 -13
  63. package/src/test/ConditionalTranslationCases.test.ts +5 -0
  64. package/src/test/ErrorLogging.test.ts +2 -2
  65. package/src/test/ImportCasesV2.test.ts +63 -0
  66. package/src/test/LinkFails.test.ts +69 -0
  67. package/src/test/LinkPackage.test.ts +1 -1
  68. package/src/test/Linker.test.ts +75 -2
  69. package/src/test/LogCatcher.ts +53 -0
  70. package/src/test/Mangling.test.ts +1 -1
  71. package/src/test/ParseComments.test.ts +1 -2
  72. package/src/test/{ParseConditions.test.ts → ParseConditionsV2.test.ts} +57 -49
  73. package/src/test/ParseErrorV2.test.ts +73 -0
  74. package/src/test/{ParseWESL.test.ts → ParseWeslV2.test.ts} +288 -370
  75. package/src/test/{ScopeWESL.test.ts → ScopeWESLV2.test.ts} +205 -176
  76. package/src/test/TestLink.ts +51 -51
  77. package/src/test/TestSetup.ts +9 -3
  78. package/src/test/TestUtil.ts +47 -77
  79. package/src/test/TrimmedMatch.ts +40 -0
  80. package/src/test/VirtualModules.test.ts +33 -2
  81. package/src/test/WeslDevice.test.ts +9 -2
  82. package/src/test/__snapshots__/ParseWeslV2.test.ts.snap +67 -0
  83. package/src/test-util.ts +7 -0
  84. package/src/WESLCollect.ts +0 -656
  85. package/src/parse/AttributeGrammar.ts +0 -232
  86. package/src/parse/ImportGrammar.ts +0 -195
  87. package/src/parse/WeslBaseGrammar.ts +0 -11
  88. package/src/parse/WeslExpression.ts +0 -231
  89. package/src/parse/WeslGrammar.ts +0 -739
  90. package/src/test/Expression.test.ts +0 -22
  91. package/src/test/ImportSyntaxCases.test.ts +0 -24
  92. package/src/test/ParseError.test.ts +0 -45
  93. package/src/test/Reflection.test.ts +0 -176
  94. package/src/test/TransformBindingStructs.test.ts +0 -238
  95. /package/src/test/{ParseElif.test.ts → ParseElifV2.test.ts} +0 -0
@@ -1,22 +0,0 @@
1
- import { eof, seq } from "mini-parse";
2
- import { expect, test } from "vitest";
3
- import { expression } from "../parse/WeslExpression.ts";
4
- import { testAppParse } from "./TestUtil.ts";
5
-
6
- test("parse number", () => {
7
- const src = "3";
8
- const { parsed } = testAppParse(seq(expression, eof), src);
9
- expect(parsed).not.toBeNull();
10
- });
11
-
12
- test("parse comparisons with && ||", () => {
13
- const src = "a<3 && 4>(5)";
14
- const { parsed } = testAppParse(seq(expression, eof), src);
15
- expect(parsed).not.toBeNull();
16
- });
17
-
18
- test("parse vec templated type", () => {
19
- const src = "vec2<f32>";
20
- const { parsed } = testAppParse(seq(expression, eof), src);
21
- expect(parsed).not.toBeNull();
22
- });
@@ -1,24 +0,0 @@
1
- import { withLogSpy } from "mini-parse/test-util";
2
- import { expect, test } from "vitest";
3
- import { importSyntaxCases } from "wesl-testsuite";
4
- import { weslImports } from "../parse/ImportGrammar.ts";
5
- import { testAppParse } from "./TestUtil.ts";
6
-
7
- function expectParseFail(src: string): void {
8
- withLogSpy(() => {
9
- expect(() => testAppParse(weslImports, src)).toThrow(); // LATER catch specific error only
10
- });
11
- }
12
-
13
- function expectParses(src: string): void {
14
- const result = testAppParse(weslImports, src);
15
- expect(result.stable.imports.length).toBeGreaterThan(0);
16
- }
17
-
18
- importSyntaxCases.forEach(c => {
19
- if (c.fails) {
20
- test(c.src, () => expectParseFail(c.src));
21
- } else {
22
- test(c.src, () => expectParses(c.src));
23
- }
24
- });
@@ -1,45 +0,0 @@
1
- import { expect, test } from "vitest";
2
- import { errorHighlight } from "../Util.ts";
3
- import { parseTest } from "./TestUtil.ts";
4
-
5
- test("parse fn foo() { invalid }", () => {
6
- const src = "fn foo() { let }";
7
- expect(() => parseTest(src)).toThrowErrorMatchingInlineSnapshot(`
8
- [Error: ./test.wesl:1:15 error: invalid ident
9
- fn foo() { let }
10
- ^^]
11
- `);
12
- });
13
-
14
- test("parse invalid if", () => {
15
- const src = `fn foo() {
16
- let a = 3;
17
- if(1<1) { 🐈‍⬛ } else { }
18
- }`;
19
- expect(() => parseTest(src)).toThrowErrorMatchingInlineSnapshot(`
20
- [Error: ./test.wesl:3:13 error: Invalid token 🐈
21
-
22
- if(1<1) { 🐈‍⬛ } else { }
23
- ^^]
24
- `);
25
- });
26
-
27
- test("parse invalid name", () => {
28
- const src = "var package = 3;";
29
- expect(() => parseTest(src)).toThrowErrorMatchingInlineSnapshot(`
30
- [Error: ./test.wesl:1:4 error: expected identifier
31
- var package = 3;
32
- ^^^^^^^^]
33
- `);
34
- });
35
-
36
- test("error highlight", () => {
37
- expect(errorHighlight("foo", [0, 2]).join("\n")).toBe(`foo
38
- ^^`);
39
- expect(errorHighlight("foo", [0, 1]).join("\n")).toBe(`foo
40
- ^`);
41
- expect(errorHighlight("foo", [0, 0]).join("\n")).toBe(`foo
42
- ^`);
43
- expect(errorHighlight("foo", [1, 2]).join("\n")).toBe(`foo
44
- ^`);
45
- });
@@ -1,176 +0,0 @@
1
- import { expect, test } from "vitest";
2
- import type { BindingStructElem, StructElem } from "../AbstractElems.ts";
3
- import { astToString } from "../debug/ASTtoString.ts";
4
- import {
5
- bindingGroupLayoutTs,
6
- reportBindingStructsPlugin,
7
- } from "../Reflection.ts";
8
- import { bindingStructsPlugin } from "../TransformBindingStructs.ts";
9
- import { linkTestOpts } from "./TestUtil.ts";
10
-
11
- test("extract binding struct", () => {
12
- const src = `
13
- struct Bindings {
14
- @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
15
- }
16
-
17
- @compute fn main(b: Bindings) {
18
- let x = b.particles;
19
- }
20
- `;
21
- let found: StructElem[] | undefined;
22
- const config = {
23
- plugins: [
24
- bindingStructsPlugin(),
25
- reportBindingStructsPlugin(report => {
26
- found = report;
27
- }),
28
- ],
29
- };
30
- linkTestOpts({ config }, src);
31
-
32
- // verify struct found
33
- expect(found).toBeDefined();
34
- const s = found?.[0] as StructElem;
35
- expect(s).toBeDefined();
36
- expect(astToString(s)).toMatchInlineSnapshot(`
37
- "struct Bindings
38
- text 'struct '
39
- decl %Bindings
40
- text ' {
41
- '
42
- member @group @binding particles: ptr<storage, array<f32>, read_write>
43
- attribute @group('0')
44
- expression '0'
45
- text '0'
46
- text ' '
47
- attribute @binding('0')
48
- expression '0'
49
- text '0'
50
- text ' '
51
- name particles
52
- text ': '
53
- type ptr<storage, array<f32>, read_write>
54
- ref ptr
55
- text '<'
56
- type storage
57
- ref storage
58
- text ', '
59
- type array<f32>
60
- ref array
61
- text '<'
62
- type f32
63
- ref f32
64
- text '>'
65
- text ', '
66
- type read_write
67
- ref read_write
68
- text '>'
69
- text ',
70
- }'"
71
- `);
72
- expect(s.bindingStruct).toBeTruthy();
73
- expect((s as BindingStructElem).entryFn).toBeDefined();
74
-
75
- // verify struct members
76
- const members = s.members.filter(e => e.kind === "member");
77
- const membersAst = members.map(e => astToString(e)).join("\n");
78
- expect(membersAst).toMatchInlineSnapshot(
79
- `
80
- "member @group @binding particles: ptr<storage, array<f32>, read_write>
81
- attribute @group('0')
82
- expression '0'
83
- text '0'
84
- text ' '
85
- attribute @binding('0')
86
- expression '0'
87
- text '0'
88
- text ' '
89
- name particles
90
- text ': '
91
- type ptr<storage, array<f32>, read_write>
92
- ref ptr
93
- text '<'
94
- type storage
95
- ref storage
96
- text ', '
97
- type array<f32>
98
- ref array
99
- text '<'
100
- type f32
101
- ref f32
102
- text '>'
103
- text ', '
104
- type read_write
105
- ref read_write
106
- text '>'"
107
- `,
108
- );
109
- });
110
-
111
- test("binding struct to ts", () => {
112
- const src = `
113
- struct Uniforms {
114
- foo: u32
115
- }
116
- struct MyBindings {
117
- @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
118
- @group(0) @binding(1) uniforms: ptr<uniform, Uniforms>,
119
- @group(0) @binding(2) tex: texture_2d<f32>,
120
- @group(0) @binding(3) samp: sampler,
121
- @group(0) @binding(4) stTex: texture_storage_2d<rgba8unorm, read>,
122
- }
123
- @compute fn main(b: MyBindings) {
124
- let x = b.particles;
125
- }
126
- `;
127
- let found: StructElem[] | undefined;
128
- const config = {
129
- plugins: [
130
- bindingStructsPlugin(),
131
- reportBindingStructsPlugin(report => {
132
- found = report;
133
- }),
134
- ],
135
- };
136
- linkTestOpts({ config }, src);
137
- const ts = bindingGroupLayoutTs(found?.[0] as BindingStructElem);
138
- expect(ts).toMatchInlineSnapshot(`
139
- "
140
- const myBindingsEntries = [
141
- {
142
- binding: 0,
143
- visibility: GPUShaderStage.COMPUTE,
144
- buffer: { type: "storage" }
145
- },
146
- {
147
- binding: 1,
148
- visibility: GPUShaderStage.COMPUTE,
149
- buffer: { type: "uniform" }
150
- },
151
- {
152
- binding: 2,
153
- visibility: GPUShaderStage.COMPUTE,
154
- texture: { sampleType: "float" }
155
- },
156
- {
157
- binding: 3,
158
- visibility: GPUShaderStage.COMPUTE,
159
- sampler: { type: "filtering" }
160
- },
161
- {
162
- binding: 4,
163
- visibility: GPUShaderStage.COMPUTE,
164
- storageTexture: { format: "rgba8unorm", sampleType: "float", access: "read-only" }
165
- } ];
166
- function myBindingsLayout(device: GPUDevice): GPUBindGroupLayout {
167
- return device.createBindGroupLayout({
168
- entries: myBindingsEntries
169
- });
170
- }
171
-
172
- export const layoutFunctions = { myBindingsLayout };
173
- export const layouts = { myBindingsEntries };
174
- "
175
- `);
176
- });
@@ -1,238 +0,0 @@
1
- import { SrcMapBuilder } from "mini-parse";
2
- import { expectTrimmedMatch } from "mini-parse/vitest-util";
3
- import { expect, test } from "vitest";
4
- import { bindIdents } from "../BindIdents.ts";
5
- import { astToString } from "../debug/ASTtoString.ts";
6
- import { lowerAndEmit } from "../LowerAndEmit.ts";
7
- import { RecordResolver } from "../ModuleResolver.ts";
8
- import {
9
- bindingStructsPlugin,
10
- findRefsToBindingStructs,
11
- lowerBindingStructs,
12
- markBindingStructs,
13
- transformBindingReference,
14
- transformBindingStruct,
15
- } from "../TransformBindingStructs.ts";
16
- import { linkTestOpts, parseTest } from "./TestUtil.ts";
17
-
18
- test("markBindingStructs true", () => {
19
- const src = `
20
- struct Bindings {
21
- @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
22
- }
23
- `;
24
-
25
- const ast = parseTest(src);
26
- const structs = markBindingStructs(ast.moduleElem);
27
- expect(structs.length).toBe(1);
28
- expect(structs[0].bindingStruct).toBe(true);
29
- });
30
-
31
- test("markBindingStructs false", () => {
32
- const src = `
33
- struct Bindings {
34
- particles: ptr<storage, array<f32>, read_write>,
35
- }
36
- `;
37
-
38
- const ast = parseTest(src);
39
- const structs = markBindingStructs(ast.moduleElem);
40
- expect(structs.length).toBe(0);
41
- });
42
-
43
- test("transformBindingStruct", () => {
44
- const src = `
45
- struct Bindings {
46
- @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
47
- }
48
- `;
49
-
50
- const rootAst = parseTest(src);
51
- bindIdents({ rootAst, resolver: new RecordResolver({}) });
52
- const bindingStruct = markBindingStructs(rootAst.moduleElem)[0];
53
- const newVars = transformBindingStruct(bindingStruct, new Set());
54
-
55
- const srcBuilder = new SrcMapBuilder({ text: rootAst.srcModule.src });
56
- lowerAndEmit({ srcBuilder, rootElems: newVars, conditions: {} });
57
- const linked = SrcMapBuilder.build([srcBuilder]).dest.text;
58
- expect(linked).toMatchInlineSnapshot(
59
- `
60
- "@group(0) @binding(0) var<storage, read_write> particles : array<f32>;
61
- "
62
- `,
63
- );
64
- });
65
-
66
- test("findRefsToBindingStructs", () => {
67
- const src = `
68
- struct Bindings {
69
- @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
70
- }
71
- struct NotBindings { a: i32 }
72
- var y: NotBindings;
73
-
74
- fn main(b: Bindings) {
75
- let x = b.particles;
76
- let z = y.a;
77
- }
78
- `;
79
-
80
- const rootAst = parseTest(src);
81
- bindIdents({ rootAst, resolver: new RecordResolver({}) });
82
- markBindingStructs(rootAst.moduleElem);
83
- const found = findRefsToBindingStructs(rootAst.moduleElem);
84
- expect(found.length).toBe(1);
85
- const foundAst = astToString(found[0].memberRef);
86
- expect(foundAst).toMatchInlineSnapshot(`
87
- "memberRef b.particles
88
- ref b
89
- text '.'
90
- name particles"
91
- `);
92
- });
93
-
94
- test("transformBindingReference", () => {
95
- const src = `
96
- struct Bindings {
97
- @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
98
- }
99
- fn main(b: Bindings) {
100
- let x = b.particles;
101
- }
102
- `;
103
-
104
- const rootAst = parseTest(src);
105
- bindIdents({ rootAst, resolver: new RecordResolver({}) });
106
- const bindingStruct = markBindingStructs(rootAst.moduleElem)[0];
107
- transformBindingStruct(bindingStruct, new Set());
108
- const found = findRefsToBindingStructs(rootAst.moduleElem);
109
- expect(found.length).toBe(1);
110
- const { memberRef, struct } = found[0];
111
- const synthElem = transformBindingReference(memberRef, struct);
112
- const synthAst = astToString(synthElem);
113
- expect(synthAst).toMatchInlineSnapshot(`"synthetic 'particles'"`);
114
- });
115
-
116
- test("lower binding structs", () => {
117
- const src = `
118
- struct Bindings {
119
- @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
120
- }
121
- fn main(b: Bindings) {
122
- let x = b.particles;
123
- }
124
- `;
125
-
126
- const expected = `
127
- @group(0) @binding(0) var<storage, read_write> particles : array<f32>;
128
-
129
- fn main() {
130
- let x = particles;
131
- }
132
- `;
133
- const rootAst = parseTest(src);
134
- const { globalNames } = bindIdents({
135
- rootAst,
136
- resolver: new RecordResolver({}),
137
- });
138
- const tAst = { ...rootAst, globalNames, notableElems: {} };
139
- const lowered = lowerBindingStructs(tAst);
140
-
141
- const loweredAst = astToString(lowered.moduleElem);
142
- expect(loweredAst).toMatchInlineSnapshot(`
143
- "module
144
- synthetic '@group(0) @binding(0) var<storage, read_write> particles : array<f32>;
145
- '
146
- text '
147
- '
148
- text '
149
- '
150
- fn main(b: Bindings)
151
- decl %main
152
- param
153
- statement
154
- text '{
155
- let '
156
- typeDecl %x
157
- decl %x
158
- text ' = '
159
- memberRef b.particles
160
- synthetic 'particles'
161
- text ';
162
- }'
163
- text '
164
- '"
165
- `);
166
-
167
- const srcBuilder = new SrcMapBuilder({ text: lowered.srcModule.src });
168
- lowerAndEmit({
169
- srcBuilder,
170
- rootElems: [lowered.moduleElem],
171
- conditions: {},
172
- extracting: false,
173
- });
174
- const linked = SrcMapBuilder.build([srcBuilder]).dest.text;
175
- expectTrimmedMatch(linked, expected);
176
- });
177
-
178
- test("lower binding structs with conflicting root name", async () => {
179
- const src = `
180
- struct Bindings {
181
- @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
182
- }
183
- const particles = 7;
184
- fn main(b: Bindings) {
185
- let x = b.particles;
186
- }
187
- `;
188
-
189
- const expected = `
190
- @group(0) @binding(0) var<storage, read_write> particles0 : array<f32>;
191
-
192
- const particles = 7;
193
- fn main() {
194
- let x = particles0;
195
- }
196
- `;
197
-
198
- const opts = { config: { plugins: [bindingStructsPlugin()] } };
199
- const linked = await linkTestOpts(opts, src);
200
- expectTrimmedMatch(linked, expected);
201
- });
202
-
203
- test("lower 5 bindings", async () => {
204
- const src = `
205
- struct Uniforms {
206
- foo: u32
207
- }
208
-
209
- struct MyBindings {
210
- @group(0) @binding(0) particles: ptr<storage, array<u32>, read_write>,
211
- @group(0) @binding(1) uniforms: ptr<uniform, Uniforms>,
212
- @group(0) @binding(2) tex: texture_2d<rgba8unorm>,
213
- @group(0) @binding(3) samp: sampler,
214
- @group(0) @binding(4) stTex: texture_storage_2d<rgba8unorm, read>,
215
- }
216
-
217
- @compute fn main(b: MyBindings) {
218
- b.particles[0] = b.uniforms.foo;
219
- }
220
- `;
221
-
222
- const expected = `
223
- @group(0) @binding(0) var<storage, read_write> particles : array<u32>;
224
- @group(0) @binding(1) var<uniform> uniforms : Uniforms;
225
- @group(0) @binding(2) var tex : texture_2d<rgba8unorm>;
226
- @group(0) @binding(3) var samp : sampler;
227
- @group(0) @binding(4) var stTex : texture_storage_2d<rgba8unorm, read>;
228
-
229
- struct Uniforms { foo: u32 }
230
- @compute fn main() {
231
- particles[0] = uniforms.foo;
232
- }
233
- `;
234
-
235
- const opts = { config: { plugins: [bindingStructsPlugin()] } };
236
- const linked = await linkTestOpts(opts, src);
237
- expectTrimmedMatch(linked, expected);
238
- });