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,34 @@
1
+ import { expect, test } from "vitest";
2
+ import { normalize } from "../PathUtil.js";
3
+
4
+ // ../../../lib/webgpu-samples/src/anim/anim.wgsl
5
+
6
+ test("normalize ./foo", () => {
7
+ const n = normalize("./foo");
8
+ expect(n).toBe("foo");
9
+ });
10
+
11
+ test("normalize ./foo/./", () => {
12
+ const n = normalize("./foo/./");
13
+ expect(n).toBe("foo");
14
+ });
15
+
16
+ test("normalize foo/bar/..", () => {
17
+ const n = normalize("foo/bar/..");
18
+ expect(n).toBe("foo");
19
+ });
20
+
21
+ test("normalize ./foo/bar/../.", () => {
22
+ const n = normalize("./foo/bar/../.");
23
+ expect(n).toBe("foo");
24
+ });
25
+
26
+ test("normalize ../foo", () => {
27
+ const n = normalize("../foo");
28
+ expect(n).toBe("../foo");
29
+ });
30
+
31
+ test("normalize ../../foo", () => {
32
+ const n = normalize("../../foo");
33
+ expect(n).toBe("../../foo");
34
+ });
@@ -0,0 +1,20 @@
1
+ import { or, parserToString, seq } from "mini-parse";
2
+ import { expect, test } from "vitest";
3
+
4
+ test("print grammar", () => {
5
+ const p: any = or("a", "b", () => p);
6
+ const s = seq("a", "b", () => p);
7
+ const result = parserToString(s);
8
+ expect(result).toMatchInlineSnapshot(`
9
+ "seq
10
+ 'a'
11
+ 'b'
12
+ fn()
13
+ or
14
+ 'a'
15
+ 'b'
16
+ fn()
17
+ ->or
18
+ "
19
+ `);
20
+ });
@@ -0,0 +1,172 @@
1
+ import { expect, test } from "vitest";
2
+ import { 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 => (found = report)),
26
+ ],
27
+ };
28
+ linkTestOpts({ config }, src);
29
+
30
+ // verify struct found
31
+ expect(found).toBeDefined();
32
+ const s = found![0];
33
+ expect(s).toBeDefined();
34
+ expect(astToString(s)).toMatchInlineSnapshot(`
35
+ "struct Bindings
36
+ text 'struct '
37
+ decl %Bindings
38
+ text ' {
39
+ '
40
+ member @group @binding particles: ptr<storage, array<f32>, read_write>
41
+ attribute @group('0')
42
+ expression '0'
43
+ text '0'
44
+ text ' '
45
+ attribute @binding('0')
46
+ expression '0'
47
+ text '0'
48
+ text ' '
49
+ name particles
50
+ text ': '
51
+ type ptr<storage, array<f32>, read_write>
52
+ ref ptr
53
+ text '<'
54
+ type storage
55
+ ref storage
56
+ text ', '
57
+ type array<f32>
58
+ ref array
59
+ text '<'
60
+ type f32
61
+ ref f32
62
+ text '>'
63
+ text ', '
64
+ type read_write
65
+ ref read_write
66
+ text '>'
67
+ text ',
68
+ }'"
69
+ `);
70
+ expect(s.bindingStruct).toBeTruthy();
71
+ expect((s as BindingStructElem).entryFn).toBeDefined();
72
+
73
+ // verify struct members
74
+ const members = s.members.filter(e => e.kind === "member");
75
+ const membersAst = members.map(e => astToString(e)).join("\n");
76
+ expect(membersAst).toMatchInlineSnapshot(
77
+ `
78
+ "member @group @binding particles: ptr<storage, array<f32>, read_write>
79
+ attribute @group('0')
80
+ expression '0'
81
+ text '0'
82
+ text ' '
83
+ attribute @binding('0')
84
+ expression '0'
85
+ text '0'
86
+ text ' '
87
+ name particles
88
+ text ': '
89
+ type ptr<storage, array<f32>, read_write>
90
+ ref ptr
91
+ text '<'
92
+ type storage
93
+ ref storage
94
+ text ', '
95
+ type array<f32>
96
+ ref array
97
+ text '<'
98
+ type f32
99
+ ref f32
100
+ text '>'
101
+ text ', '
102
+ type read_write
103
+ ref read_write
104
+ text '>'"
105
+ `,
106
+ );
107
+ });
108
+
109
+ test("binding struct to ts", () => {
110
+ const src = `
111
+ struct Uniforms {
112
+ foo: u32
113
+ }
114
+ struct MyBindings {
115
+ @group(0) @binding(0) particles: ptr<storage, array<f32>, read_write>,
116
+ @group(0) @binding(1) uniforms: ptr<uniform, Uniforms>,
117
+ @group(0) @binding(2) tex: texture_2d<f32>,
118
+ @group(0) @binding(3) samp: sampler,
119
+ @group(0) @binding(4) stTex: texture_storage_2d<rgba8unorm, read>,
120
+ }
121
+ @compute fn main(b: MyBindings) {
122
+ let x = b.particles;
123
+ }
124
+ `;
125
+ let found: StructElem[] | undefined;
126
+ const config = {
127
+ plugins: [
128
+ bindingStructsPlugin(),
129
+ reportBindingStructsPlugin(report => (found = report)),
130
+ ],
131
+ };
132
+ linkTestOpts({ config }, src);
133
+ const ts = bindingGroupLayoutTs(found![0] as BindingStructElem);
134
+ expect(ts).toMatchInlineSnapshot(`
135
+ "
136
+ const myBindingsEntries = [
137
+ {
138
+ binding: 0,
139
+ visibility: GPUShaderStage.COMPUTE,
140
+ buffer: { type: "storage" }
141
+ },
142
+ {
143
+ binding: 1,
144
+ visibility: GPUShaderStage.COMPUTE,
145
+ buffer: { type: "uniform" }
146
+ },
147
+ {
148
+ binding: 2,
149
+ visibility: GPUShaderStage.COMPUTE,
150
+ texture: { sampleType: "float" }
151
+ },
152
+ {
153
+ binding: 3,
154
+ visibility: GPUShaderStage.COMPUTE,
155
+ sampler: { type: "filtering" }
156
+ },
157
+ {
158
+ binding: 4,
159
+ visibility: GPUShaderStage.COMPUTE,
160
+ storageTexture: { format: "rgba8unorm", sampleType: "float", access: "read-only" }
161
+ } ];
162
+ function myBindingsLayout(device: GPUDevice): GPUBindGroupLayout {
163
+ return device.createBindGroupLayout({
164
+ entries: myBindingsEntries
165
+ });
166
+ }
167
+
168
+ export const layoutFunctions = { myBindingsLayout };
169
+ export const layoutEntries = { myBindingsEntries };
170
+ "
171
+ `);
172
+ });
@@ -0,0 +1,462 @@
1
+ import { expect, test } from "vitest";
2
+ import { findValidRootDecls } from "../BindIdents.ts";
3
+ import { scopeToString } from "../debug/ScopeToString.ts";
4
+ import { parseWESL, WeslAST } from "../ParseWESL.ts";
5
+ import { resetScopeIds } from "../Scope.ts";
6
+
7
+ function testParseWESL(src: string): WeslAST {
8
+ resetScopeIds();
9
+ return parseWESL(src);
10
+ }
11
+
12
+ test("scope from simple fn", () => {
13
+ const src = `
14
+ fn main() {
15
+ var x: i32 = 1;
16
+ }
17
+ `;
18
+ const { rootScope } = testParseWESL(src);
19
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
20
+ "{
21
+ -{ %main
22
+ { %x i32 } #2
23
+ } #1
24
+ } #0"
25
+ `);
26
+ });
27
+
28
+ test("scope from fn with reference", () => {
29
+ const src = `
30
+ fn main() {
31
+ var x: i32 = 1;
32
+ x++;
33
+ }
34
+ `;
35
+ const { rootScope } = testParseWESL(src);
36
+
37
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
38
+ "{
39
+ -{ %main
40
+ { %x i32 x } #2
41
+ } #1
42
+ } #0"
43
+ `);
44
+ });
45
+
46
+ test("two fns", () => {
47
+ const src = `
48
+ fn foo() {}
49
+ fn bar() {}
50
+ `;
51
+ const { rootScope } = testParseWESL(src);
52
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
53
+ "{
54
+ -{ %foo
55
+ { } #2
56
+ } #1
57
+ -{ %bar
58
+ { } #5
59
+ } #4
60
+ } #0"
61
+ `);
62
+ });
63
+
64
+ test("two fns, one with a decl", () => {
65
+ const src = `
66
+ fn foo() {
67
+ var a:u32;
68
+ }
69
+ fn bar() {}
70
+ `;
71
+ const { rootScope } = testParseWESL(src);
72
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
73
+ "{
74
+ -{ %foo
75
+ { %a u32 } #2
76
+ } #1
77
+ -{ %bar
78
+ { } #5
79
+ } #4
80
+ } #0"
81
+ `);
82
+ });
83
+
84
+ test("fn ref", () => {
85
+ const src = `
86
+ fn foo() {
87
+ bar();
88
+ }
89
+ fn bar() {}
90
+ `;
91
+ const { rootScope } = testParseWESL(src);
92
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
93
+ "{
94
+ -{ %foo
95
+ { bar } #2
96
+ } #1
97
+ -{ %bar
98
+ { } #5
99
+ } #4
100
+ } #0"
101
+ `);
102
+ });
103
+
104
+ test("struct", () => {
105
+ const src = `
106
+ struct A {
107
+ a: B,
108
+ }
109
+ `;
110
+ const { rootScope } = testParseWESL(src);
111
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
112
+ "{ %A
113
+ { B } #1
114
+ } #0"
115
+ `);
116
+ });
117
+
118
+ test("alias", () => {
119
+ const src = `
120
+ alias A = B;
121
+ `;
122
+ const { rootScope } = testParseWESL(src);
123
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
124
+ "{ %A
125
+ { B } #1
126
+ } #0"
127
+ `);
128
+ });
129
+
130
+ test("switch", () => {
131
+ const src = `
132
+ fn main() {
133
+ var code = 1u;
134
+ switch ( code ) {
135
+ case 5u: { if 1 > 0 { var x = 7;} }
136
+ default: { break; }
137
+ }
138
+ }`;
139
+ const { rootScope } = testParseWESL(src);
140
+
141
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
142
+ "{
143
+ -{ %main
144
+ { %code code
145
+ {
146
+ { %x } #5
147
+ } #4
148
+ { } #6
149
+ } #2
150
+ } #1
151
+ } #0"
152
+ `);
153
+ });
154
+
155
+ test("for()", () => {
156
+ const src = `
157
+ fn main() {
158
+ var i = 1.0;
159
+ for (var i = 0; i < 10; i++) { }
160
+ }`;
161
+ const { rootScope } = testParseWESL(src);
162
+
163
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
164
+ "{
165
+ -{ %main
166
+ { %i
167
+ { %i i i } #4
168
+ } #2
169
+ } #1
170
+ } #0"
171
+ `);
172
+ });
173
+
174
+ test("fn with param", () => {
175
+ const src = `
176
+ fn main(i: i32) {
177
+ var x = 10 + i;
178
+ for (var i = 0; i < x; i++) { }
179
+ }`;
180
+ const { rootScope } = testParseWESL(src);
181
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
182
+ "{
183
+ -{ %main
184
+ { %i i32 %x i
185
+ { %i i x i } #4
186
+ } #2
187
+ } #1
188
+ } #0"
189
+ `);
190
+ });
191
+
192
+ test("fn decl scope", () => {
193
+ const src = `
194
+ fn main(i: i32) {
195
+ var x = i;
196
+ }`;
197
+ const { rootScope } = testParseWESL(src);
198
+ const decls = findValidRootDecls(rootScope, {});
199
+ const mainIdent = decls[0];
200
+ expect(scopeToString(mainIdent.scope)).toMatchInlineSnapshot(
201
+ `"{ %i i32 %x i } #2"`,
202
+ );
203
+ });
204
+
205
+ test("builtin scope", () => {
206
+ const src = `fn main( @builtin(vertex_index) a: u32) { }`;
207
+ const { rootScope } = testParseWESL(src);
208
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
209
+ "{
210
+ -{ %main
211
+ { %a u32 } #2
212
+ } #1
213
+ } #0"
214
+ `);
215
+ });
216
+
217
+ test("builtin enums", () => {
218
+ const src = `struct read { a: vec2f } var<storage, read_write> storage_buffer: read;`;
219
+ const { rootScope } = testParseWESL(src);
220
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
221
+ "{ %read
222
+ { vec2f } #1
223
+ storage read_write %storage_buffer read
224
+ } #0"
225
+ `);
226
+ });
227
+
228
+ test("texture_storage_2d", () => {
229
+ const src = `
230
+ @binding(3) @group(0) var tex_out : texture_storage_2d<rgba8unorm, write>;
231
+ `;
232
+ const { rootScope } = testParseWESL(src);
233
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(
234
+ `"{ %tex_out texture_storage_2d rgba8unorm write } #0"`,
235
+ );
236
+ });
237
+
238
+ test("ptr 2 params", () => {
239
+ const src = `
240
+ fn foo(ptr: ptr<private, u32>) { }
241
+ `;
242
+ const { rootScope } = testParseWESL(src);
243
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
244
+ "{
245
+ -{ %foo
246
+ { %ptr ptr private u32 } #2
247
+ } #1
248
+ } #0"
249
+ `);
250
+ });
251
+
252
+ test("ptr 3 params", () => {
253
+ const src = `
254
+ fn foo(ptr: ptr<storage, array<u32, 128>, read>) { }
255
+ `;
256
+ const { rootScope } = testParseWESL(src);
257
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
258
+ "{
259
+ -{ %foo
260
+ { %ptr ptr storage array u32 read } #2
261
+ } #1
262
+ } #0"
263
+ `);
264
+ });
265
+
266
+ test("larger example", () => {
267
+ const src = `
268
+ struct UBO { width : u32, }
269
+
270
+ struct Buffer { weights : array<f32>, }
271
+
272
+ @binding(0) @group(0) var<uniform> ubo : UBO;
273
+ @binding(1) @group(0) var<storage, read> buf_in : Buffer;
274
+ @binding(2) @group(0) var<storage, read_write> buf_out : Buffer;
275
+ @binding(3) @group(0) var tex_in : texture_2d<f32>;
276
+ @binding(3) @group(0) var tex_out : texture_storage_2d<rgba8unorm, write>;
277
+
278
+ @compute @workgroup_size(64)
279
+ fn import_level(@builtin(global_invocation_id) coord : vec3u) {
280
+ _ = &buf_in;
281
+ let offset = coord.x + coord.y * ubo.width;
282
+ buf_out.weights[offset] = textureLoad(tex_in, vec2i(coord.xy), 0).w;
283
+ }
284
+
285
+ @compute @workgroup_size(64)
286
+ fn export_level(@builtin(global_invocation_id) coord : vec3u) {
287
+ if (all(coord.xy < vec2u(textureDimensions(tex_out)))) {
288
+ let dst_offset = coord.x + coord.y * ubo.width;
289
+ let src_offset = coord.x*2u + coord.y*2u * ubo.width;
290
+
291
+ let a = buf_in.weights[src_offset + 0u];
292
+ let b = buf_in.weights[src_offset + 1u];
293
+ let c = buf_in.weights[src_offset + 0u + ubo.width];
294
+ let d = buf_in.weights[src_offset + 1u + ubo.width];
295
+ let sum = dot(vec4f(a, b, c, d), vec4f(1.0));
296
+
297
+ buf_out.weights[dst_offset] = sum / 4.0;
298
+
299
+ let probabilities = vec4f(a, a+b, a+b+c, sum) / max(sum, 0.0001);
300
+ textureStore(tex_out, vec2i(coord.xy), probabilities);
301
+ }
302
+ }
303
+ `;
304
+
305
+ const { rootScope } = testParseWESL(src);
306
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
307
+ "{ %UBO
308
+ { u32 } #1
309
+ %Buffer
310
+ { array f32 } #2
311
+ uniform %ubo UBO storage read %buf_in Buffer storage
312
+ read_write %buf_out Buffer %tex_in texture_2d f32 %tex_out
313
+ texture_storage_2d rgba8unorm write
314
+ -{ %import_level
315
+ { %coord vec3u buf_in %offset coord coord ubo buf_out
316
+ offset textureLoad tex_in vec2i coord} #4
317
+ } #3
318
+ -{ %export_level
319
+ { %coord vec3u all coord vec2u textureDimensions tex_out
320
+
321
+ { %dst_offset coord coord ubo %src_offset coord coord
322
+ ubo %a buf_in src_offset %b buf_in src_offset %c
323
+ buf_in src_offset ubo %d buf_in src_offset ubo %sum
324
+ dot vec4f a b c d vec4f buf_out dst_offset sum
325
+ %probabilities vec4f a a b a b c sum max sum
326
+ textureStore tex_out vec2i coord probabilities} #9
327
+ } #7
328
+ } #6
329
+ } #0"
330
+ `);
331
+ });
332
+
333
+ test("scope with an attribute", () => {
334
+ const src = `
335
+ fn main() {
336
+ @if(foo){ }
337
+ }
338
+ `;
339
+ const { rootScope } = testParseWESL(src);
340
+
341
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
342
+ "{
343
+ -{ %main
344
+ {
345
+ @if(foo) { } #4
346
+ } #2
347
+ } #1
348
+ } #0"
349
+ `);
350
+ });
351
+
352
+ test("partial scope", () => {
353
+ const src = `
354
+ fn main() {
355
+ var x = 1;
356
+
357
+ @if(false) y = 2;
358
+ }
359
+ `;
360
+ const { rootScope } = testParseWESL(src);
361
+
362
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
363
+ "{
364
+ -{ %main
365
+ { %x
366
+ @if(false) -{ y } #4
367
+ } #2
368
+ } #1
369
+ } #0"
370
+ `);
371
+ });
372
+
373
+ test("loop scope", () => {
374
+ const src = `
375
+ fn main() {
376
+ let a = 7;
377
+ loop {
378
+ let a = 1;
379
+ continuing {
380
+ let a = 2;
381
+ }
382
+ }
383
+ }
384
+ `;
385
+ const { rootScope } = testParseWESL(src);
386
+
387
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
388
+ "{
389
+ -{ %main
390
+ { %a
391
+ { %a
392
+ { %a } #5
393
+ } #4
394
+ } #2
395
+ } #1
396
+ } #0"
397
+ `);
398
+ });
399
+
400
+ test("nested scope test", () => {
401
+ const src = `
402
+ fn main() {
403
+ let bar = 72;
404
+ if (true) {
405
+ if (true) {
406
+ let new_bar = bar; // Should be 72!
407
+ }
408
+ let bar = 5;
409
+ }
410
+ }
411
+ `;
412
+ const { rootScope } = testParseWESL(src);
413
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
414
+ "{
415
+ -{ %main
416
+ { %bar
417
+ {
418
+ { %new_bar bar } #5
419
+ %bar
420
+ } #4
421
+ } #2
422
+ } #1
423
+ } #0"
424
+ `);
425
+ });
426
+
427
+ test("@if fn", () => {
428
+ const src = `
429
+ const loc = 0;
430
+
431
+ @if(true) @fragment
432
+ fn fragmentMain(@location(0) p: vec3f) -> @location(loc) vec4f {
433
+ let x = p;
434
+ }
435
+ `;
436
+ const { rootScope } = testParseWESL(src);
437
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot(`
438
+ "{ %loc
439
+ { } #1
440
+ @if(true) -{ %fragmentMain loc
441
+ { %p vec3f vec4f %x p } #3
442
+ } #2
443
+ } #0"
444
+ `);
445
+ });
446
+
447
+ test.skip("@if const", () => {
448
+ const src = `
449
+ @if(true) const a = 0;
450
+ `;
451
+ const { rootScope } = testParseWESL(src);
452
+ expect(scopeToString(rootScope)).toMatchInlineSnapshot("tbd");
453
+ });
454
+
455
+ // test("", () => {
456
+ // const src = `
457
+ // `;
458
+ // const { rootScope } = testParseWESL(src);
459
+
460
+ // expect(scopeToString(rootScope)).toMatchInlineSnapshot('tbd');
461
+
462
+ // });