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.
- package/README.md +31 -0
- package/dist/index.js +4468 -0
- package/dist/index.js.map +1 -0
- package/dist/minified.js +3426 -0
- package/dist/minified.js.map +1 -0
- package/dist/tools/packages/wesl/src/AbstractElems.d.ts +322 -0
- package/dist/tools/packages/wesl/src/Assertions.d.ts +27 -0
- package/dist/tools/packages/wesl/src/BindIdents.d.ts +70 -0
- package/dist/tools/packages/wesl/src/Conditions.d.ts +6 -0
- package/dist/tools/packages/wesl/src/FlattenTreeImport.d.ts +11 -0
- package/dist/tools/packages/wesl/src/LinkedWesl.d.ts +50 -0
- package/dist/tools/packages/wesl/src/Linker.d.ts +87 -0
- package/dist/tools/packages/wesl/src/LinkerUtil.d.ts +3 -0
- package/dist/tools/packages/wesl/src/LiveDeclarations.d.ts +12 -0
- package/dist/tools/packages/wesl/src/LowerAndEmit.d.ts +31 -0
- package/dist/tools/packages/wesl/src/Mangler.d.ts +39 -0
- package/dist/tools/packages/wesl/src/ParseWESL.d.ts +60 -0
- package/dist/tools/packages/wesl/src/ParsedRegistry.d.ts +29 -0
- package/dist/tools/packages/wesl/src/PathUtil.d.ts +6 -0
- package/dist/tools/packages/wesl/src/RawEmit.d.ts +6 -0
- package/dist/tools/packages/wesl/src/Reflection.d.ts +45 -0
- package/dist/tools/packages/wesl/src/Scope.d.ts +81 -0
- package/dist/tools/packages/wesl/src/StandardTypes.d.ts +13 -0
- package/dist/tools/packages/wesl/src/TransformBindingStructs.d.ts +52 -0
- package/dist/tools/packages/wesl/src/Util.d.ts +43 -0
- package/dist/tools/packages/wesl/src/WESLCollect.d.ts +94 -0
- package/dist/tools/packages/wesl/src/WeslBundle.d.ts +13 -0
- package/dist/tools/packages/wesl/src/WeslDevice.d.ts +25 -0
- package/dist/tools/packages/wesl/src/debug/ASTtoString.d.ts +5 -0
- package/dist/tools/packages/wesl/src/debug/ImportToString.d.ts +2 -0
- package/dist/tools/packages/wesl/src/debug/LineWrapper.d.ts +21 -0
- package/dist/tools/packages/wesl/src/debug/ScopeToString.d.ts +6 -0
- package/dist/tools/packages/wesl/src/index.d.ts +11 -0
- package/dist/tools/packages/wesl/src/parse/ImportGrammar.d.ts +5 -0
- package/dist/tools/packages/wesl/src/parse/Keywords.d.ts +4 -0
- package/dist/tools/packages/wesl/src/parse/WeslBaseGrammar.d.ts +5 -0
- package/dist/tools/packages/wesl/src/parse/WeslExpression.d.ts +13 -0
- package/dist/tools/packages/wesl/src/parse/WeslGrammar.d.ts +80 -0
- package/dist/tools/packages/wesl/src/parse/WeslStream.d.ts +44 -0
- package/dist/tools/packages/wesl/src/test/BindWESL.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ConditionLinking.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ConditionalTranslationCases.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ErrorLogging.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/Expression.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/FlattenTreeImport.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ImportCases.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ImportSyntaxCases.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/LinkGlob.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/LinkPackage.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/Linker.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/Mangling.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ParseComments.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ParseConditions.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ParseError.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ParseWESL.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/PathUtil.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/PrettyGrammar.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/Reflection.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/ScopeWESL.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/TestLink.d.ts +21 -0
- package/dist/tools/packages/wesl/src/test/TestSetup.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/TestUtil.d.ts +40 -0
- package/dist/tools/packages/wesl/src/test/Tokenizer.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/TransformBindingStructs.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/Util.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/VirtualModules.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/WeslDevice.test.d.ts +1 -0
- package/dist/tools/packages/wesl/src/test/WgslTests.d.ts +0 -0
- package/dist/tools/packages/wesl/src/vlq/vlq.d.ts +11 -0
- package/package.json +46 -0
- package/src/AbstractElems.ts +446 -0
- package/src/Assertions.ts +51 -0
- package/src/BindIdents.ts +523 -0
- package/src/Conditions.ts +74 -0
- package/src/FlattenTreeImport.ts +55 -0
- package/src/LinkedWesl.ts +184 -0
- package/src/Linker.ts +284 -0
- package/src/LinkerUtil.ts +29 -0
- package/src/LiveDeclarations.ts +31 -0
- package/src/LowerAndEmit.ts +413 -0
- package/src/Mangler.ts +94 -0
- package/src/ParseWESL.ts +157 -0
- package/src/ParsedRegistry.ts +120 -0
- package/src/PathUtil.ts +31 -0
- package/src/RawEmit.ts +102 -0
- package/src/Reflection.ts +334 -0
- package/src/Scope.ts +162 -0
- package/src/StandardTypes.ts +97 -0
- package/src/TransformBindingStructs.ts +319 -0
- package/src/Util.ts +194 -0
- package/src/WESLCollect.ts +614 -0
- package/src/WeslBundle.ts +16 -0
- package/src/WeslDevice.ts +209 -0
- package/src/debug/ASTtoString.ts +290 -0
- package/src/debug/ImportToString.ts +29 -0
- package/src/debug/LineWrapper.ts +70 -0
- package/src/debug/ScopeToString.ts +79 -0
- package/src/index.ts +11 -0
- package/src/parse/ImportGrammar.ts +157 -0
- package/src/parse/Keywords.ts +26 -0
- package/src/parse/WeslBaseGrammar.ts +8 -0
- package/src/parse/WeslExpression.ts +207 -0
- package/src/parse/WeslGrammar.ts +856 -0
- package/src/parse/WeslStream.ts +279 -0
- package/src/test/BindWESL.test.ts +57 -0
- package/src/test/ConditionLinking.test.ts +91 -0
- package/src/test/ConditionalTranslationCases.test.ts +56 -0
- package/src/test/ErrorLogging.test.ts +30 -0
- package/src/test/Expression.test.ts +22 -0
- package/src/test/FlattenTreeImport.test.ts +74 -0
- package/src/test/ImportCases.test.ts +56 -0
- package/src/test/ImportSyntaxCases.test.ts +24 -0
- package/src/test/LinkGlob.test.ts +25 -0
- package/src/test/LinkPackage.test.ts +26 -0
- package/src/test/Linker.test.ts +125 -0
- package/src/test/Mangling.test.ts +45 -0
- package/src/test/ParseComments.test.ts +36 -0
- package/src/test/ParseConditions.test.ts +183 -0
- package/src/test/ParseError.test.ts +36 -0
- package/src/test/ParseWESL.test.ts +1572 -0
- package/src/test/PathUtil.test.ts +34 -0
- package/src/test/PrettyGrammar.test.ts +20 -0
- package/src/test/Reflection.test.ts +172 -0
- package/src/test/ScopeWESL.test.ts +462 -0
- package/src/test/TestLink.ts +82 -0
- package/src/test/TestSetup.ts +4 -0
- package/src/test/TestUtil.ts +126 -0
- package/src/test/Tokenizer.test.ts +135 -0
- package/src/test/TransformBindingStructs.test.ts +230 -0
- package/src/test/Util.test.ts +22 -0
- package/src/test/VirtualModules.test.ts +37 -0
- package/src/test/WeslDevice.test.ts +265 -0
- package/src/test/WgslTests.ts +0 -0
- package/src/test/__snapshots__/ParseDirectives.test.ts.snap +25 -0
- package/src/test/__snapshots__/ParseWESL.test.ts.snap +119 -0
- package/src/test/__snapshots__/RustDirective.test.ts.snap +359 -0
- package/src/test/wgsl_1/main.wgsl +3 -0
- package/src/test/wgsl_1/util.wgsl +1 -0
- package/src/test/wgsl_2/main2.wgsl +3 -0
- package/src/test/wgsl_2/util2.wgsl +1 -0
- package/src/vlq/vlq.ts +94 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4468 @@
|
|
|
1
|
+
var __typeError = (msg) => {
|
|
2
|
+
throw TypeError(msg);
|
|
3
|
+
};
|
|
4
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
5
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
|
+
var _fragments, _destLength, _entries, _fragments2, _column, _spc, _oneLine, _isHanging, _hangingSpc;
|
|
9
|
+
function assertThat(condition, msg) {
|
|
10
|
+
if (!condition) {
|
|
11
|
+
throw new Error(msg);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function assertUnreachable$1(value) {
|
|
15
|
+
throw new ErrorWithData$1("Unreachable value", { data: value });
|
|
16
|
+
}
|
|
17
|
+
let ErrorWithData$1 = class ErrorWithData extends Error {
|
|
18
|
+
constructor(message, options) {
|
|
19
|
+
super(message, options);
|
|
20
|
+
this.data = options == null ? void 0 : options.data;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
let log = console.log;
|
|
24
|
+
function srcLog(src, pos, ...msgs) {
|
|
25
|
+
logInternal(log, src, pos, ...msgs);
|
|
26
|
+
}
|
|
27
|
+
function quotedText(text2) {
|
|
28
|
+
return text2 ? `'${text2.replace(/\n/g, "\\n")}'` : "";
|
|
29
|
+
}
|
|
30
|
+
function logInternal(log2, srcOrSrcMap, destPos, ...msgs) {
|
|
31
|
+
if (typeof srcOrSrcMap === "string") {
|
|
32
|
+
logInternalSrc(log2, srcOrSrcMap, destPos, ...msgs);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const { src, positions } = mapSrcPositions(srcOrSrcMap, destPos);
|
|
36
|
+
logInternalSrc(log2, src.text, positions, ...msgs);
|
|
37
|
+
}
|
|
38
|
+
function mapSrcPositions(srcMap, destPos) {
|
|
39
|
+
var _a, _b, _c, _d;
|
|
40
|
+
const srcPos = srcMap.mapPositions(...[destPos].flat());
|
|
41
|
+
const { src } = srcPos[0];
|
|
42
|
+
let positions;
|
|
43
|
+
if (((_b = (_a = srcPos[1]) == null ? void 0 : _a.src) == null ? void 0 : _b.path) === src.path && ((_d = (_c = srcPos[1]) == null ? void 0 : _c.src) == null ? void 0 : _d.text) === src.text) {
|
|
44
|
+
positions = srcPos.map((p) => p.position);
|
|
45
|
+
} else {
|
|
46
|
+
positions = srcPos[0].position;
|
|
47
|
+
}
|
|
48
|
+
return { src, positions };
|
|
49
|
+
}
|
|
50
|
+
function logInternalSrc(log2, src, pos, ...msgs) {
|
|
51
|
+
log2(...msgs);
|
|
52
|
+
const { line, lineNum, linePos, linePos2 } = srcLine(src, pos);
|
|
53
|
+
{
|
|
54
|
+
log2(line, ` Ln ${lineNum}`);
|
|
55
|
+
}
|
|
56
|
+
const caret = carets(linePos, linePos2);
|
|
57
|
+
log2(caret);
|
|
58
|
+
}
|
|
59
|
+
function carets(linePos, linePos2) {
|
|
60
|
+
const firstCaret = " ".repeat(linePos) + "^";
|
|
61
|
+
let secondCaret = "";
|
|
62
|
+
if (linePos2 && linePos2 > linePos) {
|
|
63
|
+
secondCaret = " ".repeat(linePos2 - linePos - 1) + "^";
|
|
64
|
+
}
|
|
65
|
+
return firstCaret + secondCaret;
|
|
66
|
+
}
|
|
67
|
+
const startCache = /* @__PURE__ */ new Map();
|
|
68
|
+
function srcLine(src, position) {
|
|
69
|
+
let pos;
|
|
70
|
+
let pos2;
|
|
71
|
+
if (typeof position === "number") {
|
|
72
|
+
pos = position;
|
|
73
|
+
} else {
|
|
74
|
+
[pos, pos2] = position;
|
|
75
|
+
}
|
|
76
|
+
const starts = getStarts(src);
|
|
77
|
+
let start = 0;
|
|
78
|
+
let end = starts.length - 1;
|
|
79
|
+
if (pos >= starts[end]) {
|
|
80
|
+
start = end;
|
|
81
|
+
}
|
|
82
|
+
while (start + 1 < end) {
|
|
83
|
+
const mid = start + end >> 1;
|
|
84
|
+
if (pos >= starts[mid]) {
|
|
85
|
+
start = mid;
|
|
86
|
+
} else {
|
|
87
|
+
end = mid;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
let linePos2;
|
|
91
|
+
if (pos2 !== void 0 && pos2 >= starts[start] && pos2 < starts[end]) {
|
|
92
|
+
linePos2 = pos2 - starts[start];
|
|
93
|
+
}
|
|
94
|
+
const lineNl = src.slice(starts[start], starts[start + 1] || src.length);
|
|
95
|
+
const line = lineNl.slice(-1) === "\n" ? lineNl.slice(0, -1) : lineNl;
|
|
96
|
+
return { line, linePos: pos - starts[start], linePos2, lineNum: start + 1 };
|
|
97
|
+
}
|
|
98
|
+
function getStarts(src) {
|
|
99
|
+
const found = startCache.get(src);
|
|
100
|
+
if (found) return found;
|
|
101
|
+
const starts = [...src.matchAll(/\n/g)].map((m) => m.index + 1);
|
|
102
|
+
starts.unshift(0);
|
|
103
|
+
startCache.set(src, starts);
|
|
104
|
+
return starts;
|
|
105
|
+
}
|
|
106
|
+
function peekToken(stream) {
|
|
107
|
+
const start = stream.checkpoint();
|
|
108
|
+
const token2 = stream.nextToken();
|
|
109
|
+
stream.reset(start);
|
|
110
|
+
return token2;
|
|
111
|
+
}
|
|
112
|
+
function token(kindStr, value) {
|
|
113
|
+
return simpleParser(
|
|
114
|
+
`token '${kindStr}' ${quotedText(value)}`,
|
|
115
|
+
function _token(state) {
|
|
116
|
+
const start = state.stream.checkpoint();
|
|
117
|
+
const next = state.stream.nextToken();
|
|
118
|
+
if (next === null) return null;
|
|
119
|
+
if (next.kind !== kindStr || next.text !== value) {
|
|
120
|
+
state.stream.reset(start);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
return { value: next };
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
function tokenOf(kindStr, values) {
|
|
128
|
+
return simpleParser(
|
|
129
|
+
`tokenOf '${kindStr}'`,
|
|
130
|
+
function _tokenOf(state) {
|
|
131
|
+
const start = state.stream.checkpoint();
|
|
132
|
+
const next = state.stream.nextToken();
|
|
133
|
+
if (next === null) return null;
|
|
134
|
+
if (next.kind !== kindStr || !values.includes(next.text)) {
|
|
135
|
+
state.stream.reset(start);
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
return { value: next };
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
function tokenKind(kindStr) {
|
|
143
|
+
return simpleParser(
|
|
144
|
+
`tokenKind '${kindStr}'`,
|
|
145
|
+
function _tokenKind(state) {
|
|
146
|
+
const start = state.stream.checkpoint();
|
|
147
|
+
const next = state.stream.nextToken();
|
|
148
|
+
if (next === null) return null;
|
|
149
|
+
if (next.kind !== kindStr) {
|
|
150
|
+
state.stream.reset(start);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
return { value: next };
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
function kind(kindStr) {
|
|
158
|
+
return simpleParser(
|
|
159
|
+
`kind '${kindStr}'`,
|
|
160
|
+
function _kind(state) {
|
|
161
|
+
const start = state.stream.checkpoint();
|
|
162
|
+
const next = state.stream.nextToken();
|
|
163
|
+
if (next === null) return null;
|
|
164
|
+
if (next.kind !== kindStr) {
|
|
165
|
+
state.stream.reset(start);
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
return { value: next.text };
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
function text(value) {
|
|
173
|
+
return simpleParser(
|
|
174
|
+
`${quotedText(value)}`,
|
|
175
|
+
function _text(state) {
|
|
176
|
+
const start = state.stream.checkpoint();
|
|
177
|
+
const next = state.stream.nextToken();
|
|
178
|
+
if (next === null) return null;
|
|
179
|
+
if (next.text !== value) {
|
|
180
|
+
state.stream.reset(start);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
return { value: next.text };
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
function seq(...args) {
|
|
188
|
+
const parsers = args.map(parserArg);
|
|
189
|
+
const seqParser = parser("seq", function _seq(ctx) {
|
|
190
|
+
const values = [];
|
|
191
|
+
for (const p of parsers) {
|
|
192
|
+
const result = p._run(ctx);
|
|
193
|
+
if (result === null) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
values.push(result.value);
|
|
197
|
+
}
|
|
198
|
+
return { value: values };
|
|
199
|
+
});
|
|
200
|
+
trackChildren(seqParser, ...parsers);
|
|
201
|
+
return seqParser;
|
|
202
|
+
}
|
|
203
|
+
function seqObj(args) {
|
|
204
|
+
const parsers = Object.entries(args).map(
|
|
205
|
+
([name2, arg]) => [name2, parserArg(arg)]
|
|
206
|
+
);
|
|
207
|
+
const seqObjParser = parser("seqObj", function _seqObj(ctx) {
|
|
208
|
+
const values = {};
|
|
209
|
+
for (const [name2, p] of parsers) {
|
|
210
|
+
const result = p._run(ctx);
|
|
211
|
+
if (result === null) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
values[name2] = result.value;
|
|
215
|
+
}
|
|
216
|
+
return { value: values };
|
|
217
|
+
});
|
|
218
|
+
trackChildren(seqObjParser, ...parsers.map((v) => v[1]));
|
|
219
|
+
return seqObjParser;
|
|
220
|
+
}
|
|
221
|
+
function collectArray(p) {
|
|
222
|
+
return p.collect({ before: pushOpenArray, after: closeArray });
|
|
223
|
+
}
|
|
224
|
+
function preceded(ignoredArg, arg) {
|
|
225
|
+
const ignored = parserArg(ignoredArg);
|
|
226
|
+
const p = parserArg(arg);
|
|
227
|
+
const precededParser = parser(
|
|
228
|
+
"preceded",
|
|
229
|
+
function _preceded(ctx) {
|
|
230
|
+
const ignoredResult = ignored._run(ctx);
|
|
231
|
+
if (ignoredResult === null) return null;
|
|
232
|
+
const result = p._run(ctx);
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
return precededParser;
|
|
237
|
+
}
|
|
238
|
+
function terminated(arg, ignoredArg) {
|
|
239
|
+
const p = parserArg(arg);
|
|
240
|
+
const ignored = parserArg(ignoredArg);
|
|
241
|
+
const terminatedParser = parser(
|
|
242
|
+
"terminated",
|
|
243
|
+
function _terminated(ctx) {
|
|
244
|
+
const result = p._run(ctx);
|
|
245
|
+
if (result === null) return null;
|
|
246
|
+
const ignoredResult = ignored._run(ctx);
|
|
247
|
+
if (ignoredResult === null) return null;
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
return terminatedParser;
|
|
252
|
+
}
|
|
253
|
+
function delimited(ignoredArg1, arg, ignoredArg2) {
|
|
254
|
+
const ignored1 = parserArg(ignoredArg1);
|
|
255
|
+
const p = parserArg(arg);
|
|
256
|
+
const ignored2 = parserArg(ignoredArg2);
|
|
257
|
+
const delimitedParser = parser(
|
|
258
|
+
"delimited",
|
|
259
|
+
function _delimited(ctx) {
|
|
260
|
+
const ignoredResult1 = ignored1._run(ctx);
|
|
261
|
+
if (ignoredResult1 === null) return null;
|
|
262
|
+
const result = p._run(ctx);
|
|
263
|
+
if (result === null) return null;
|
|
264
|
+
const ignoredResult2 = ignored2._run(ctx);
|
|
265
|
+
if (ignoredResult2 === null) return null;
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
return delimitedParser;
|
|
270
|
+
}
|
|
271
|
+
function separated_pair(arg1, ignoredArg, arg2) {
|
|
272
|
+
const p1 = parserArg(arg1);
|
|
273
|
+
const ignored = parserArg(ignoredArg);
|
|
274
|
+
const p2 = parserArg(arg2);
|
|
275
|
+
const terminatedParser = parser(
|
|
276
|
+
"terminated",
|
|
277
|
+
function _terminated(ctx) {
|
|
278
|
+
const result1 = p1._run(ctx);
|
|
279
|
+
if (result1 === null) return null;
|
|
280
|
+
const ignoredResult = ignored._run(ctx);
|
|
281
|
+
if (ignoredResult === null) return null;
|
|
282
|
+
const result2 = p2._run(ctx);
|
|
283
|
+
if (result2 === null) return null;
|
|
284
|
+
return { value: [result1.value, result2.value] };
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
return terminatedParser;
|
|
288
|
+
}
|
|
289
|
+
function or(...args) {
|
|
290
|
+
const parsers = args.map(parserArg);
|
|
291
|
+
const orParser = parser("or", function _or(state) {
|
|
292
|
+
const start = state.stream.checkpoint();
|
|
293
|
+
for (const p of parsers) {
|
|
294
|
+
state.stream.reset(start);
|
|
295
|
+
const result = p._run(state);
|
|
296
|
+
if (result !== null) {
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
});
|
|
302
|
+
trackChildren(orParser, ...parsers);
|
|
303
|
+
return orParser;
|
|
304
|
+
}
|
|
305
|
+
function opt(arg) {
|
|
306
|
+
const p = parserArg(arg);
|
|
307
|
+
const optParser = parser(
|
|
308
|
+
"opt",
|
|
309
|
+
function _opt(state) {
|
|
310
|
+
const start = state.stream.checkpoint();
|
|
311
|
+
const result = p._run(state);
|
|
312
|
+
if (result === null) {
|
|
313
|
+
state.stream.reset(start);
|
|
314
|
+
return { value: null };
|
|
315
|
+
} else {
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
);
|
|
320
|
+
return optParser;
|
|
321
|
+
}
|
|
322
|
+
function repeat(arg) {
|
|
323
|
+
const p = parserArg(arg);
|
|
324
|
+
const repeatParser = parser("repeat", repeatWhileFilter(p));
|
|
325
|
+
return repeatParser;
|
|
326
|
+
}
|
|
327
|
+
function repeatPlus(arg) {
|
|
328
|
+
const p = parserArg(arg);
|
|
329
|
+
const repeatParser = seq(p, repeat(p)).map((r) => [r[0], ...r[1]]).setTraceName("repeatPlus");
|
|
330
|
+
return repeatParser;
|
|
331
|
+
}
|
|
332
|
+
function repeatWhileFilter(p, filterFn = () => true) {
|
|
333
|
+
return function _repeatWhileFilter(ctx) {
|
|
334
|
+
const values = [];
|
|
335
|
+
for (; ; ) {
|
|
336
|
+
const before = ctx.stream.checkpoint();
|
|
337
|
+
const result = runExtended(ctx, p);
|
|
338
|
+
if (result === null) {
|
|
339
|
+
ctx.stream.reset(before);
|
|
340
|
+
return { value: values };
|
|
341
|
+
}
|
|
342
|
+
if (!filterFn(result)) {
|
|
343
|
+
return { value: values };
|
|
344
|
+
}
|
|
345
|
+
values.push(result.value);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function span(arg) {
|
|
350
|
+
const p = parserArg(arg);
|
|
351
|
+
const result = parser("span", function _span(ctx) {
|
|
352
|
+
var _a, _b;
|
|
353
|
+
const start = ((_b = (_a = peekToken(ctx.stream)) == null ? void 0 : _a.span) == null ? void 0 : _b[0]) ?? null;
|
|
354
|
+
const result2 = p._run(ctx);
|
|
355
|
+
if (result2 === null) return null;
|
|
356
|
+
const end = ctx.stream.checkpoint();
|
|
357
|
+
return {
|
|
358
|
+
value: {
|
|
359
|
+
value: result2.value,
|
|
360
|
+
span: [start ?? end, end]
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
});
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
function eof() {
|
|
367
|
+
return simpleParser("eof", function _eof(state) {
|
|
368
|
+
const start = state.stream.checkpoint();
|
|
369
|
+
const result = state.stream.nextToken();
|
|
370
|
+
if (result !== null) {
|
|
371
|
+
state.stream.reset(start);
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
return { value: true };
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
function req(arg, msg) {
|
|
378
|
+
const p = parserArg(arg);
|
|
379
|
+
const reqParser = parser("req", function _req(ctx) {
|
|
380
|
+
const result = p._run(ctx);
|
|
381
|
+
if (result === null) {
|
|
382
|
+
throw new ParseError(msg, ctx.stream.checkpoint());
|
|
383
|
+
}
|
|
384
|
+
return result;
|
|
385
|
+
});
|
|
386
|
+
return reqParser;
|
|
387
|
+
}
|
|
388
|
+
function yes() {
|
|
389
|
+
return simpleParser("yes", function _yes() {
|
|
390
|
+
return { value: null };
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
function withSep(sep, p, opts = {}) {
|
|
394
|
+
const { trailing = true, requireOne = false } = opts;
|
|
395
|
+
const elementParser = parserArg(p);
|
|
396
|
+
const sepParser = parserArg(sep);
|
|
397
|
+
return parser("withSep", function _withSep(ctx) {
|
|
398
|
+
const results = [];
|
|
399
|
+
const startPosition = ctx.stream.checkpoint();
|
|
400
|
+
const result = elementParser._run(ctx);
|
|
401
|
+
if (result === null) {
|
|
402
|
+
ctx.stream.reset(startPosition);
|
|
403
|
+
if (requireOne) {
|
|
404
|
+
return null;
|
|
405
|
+
} else {
|
|
406
|
+
return {
|
|
407
|
+
value: results
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
results.push(result.value);
|
|
412
|
+
while (true) {
|
|
413
|
+
const beforeSeparator = ctx.stream.checkpoint();
|
|
414
|
+
const resultSeparator = sepParser._run(ctx);
|
|
415
|
+
if (resultSeparator === null) {
|
|
416
|
+
ctx.stream.reset(beforeSeparator);
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
const beforeElement = ctx.stream.checkpoint();
|
|
420
|
+
const resultElement = elementParser._run(ctx);
|
|
421
|
+
if (resultElement === null) {
|
|
422
|
+
if (trailing) {
|
|
423
|
+
ctx.stream.reset(beforeElement);
|
|
424
|
+
} else {
|
|
425
|
+
ctx.stream.reset(beforeSeparator);
|
|
426
|
+
}
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
results.push(resultElement.value);
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
value: results
|
|
433
|
+
};
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
function withSepPlus(sep, p) {
|
|
437
|
+
return withSep(sep, p, { requireOne: true }).setTraceName("withSepPlus");
|
|
438
|
+
}
|
|
439
|
+
function withStreamAction(action) {
|
|
440
|
+
return simpleParser(
|
|
441
|
+
`withStreamAction`,
|
|
442
|
+
function _withStreamAction(state) {
|
|
443
|
+
const result = action(state.stream);
|
|
444
|
+
if (result === null) return null;
|
|
445
|
+
return { value: result };
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
function parserArg(arg) {
|
|
450
|
+
if (typeof arg === "string") {
|
|
451
|
+
return text(arg);
|
|
452
|
+
} else if (arg instanceof Parser) {
|
|
453
|
+
return arg;
|
|
454
|
+
}
|
|
455
|
+
return fn(arg);
|
|
456
|
+
}
|
|
457
|
+
function fn(fn2) {
|
|
458
|
+
const fp = parser(
|
|
459
|
+
"fn()",
|
|
460
|
+
function _fn(state) {
|
|
461
|
+
if (!fn2) {
|
|
462
|
+
throw new ParseError(
|
|
463
|
+
`fn parser called before definition`,
|
|
464
|
+
state.stream.checkpoint()
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
const stage = fn2();
|
|
468
|
+
return stage._run(state);
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
return fp;
|
|
472
|
+
}
|
|
473
|
+
function collect(p, collectFn, ctag2) {
|
|
474
|
+
const origAfter = collectFn.after ?? collectFn;
|
|
475
|
+
const beforeFn = collectFn.before;
|
|
476
|
+
let afterFn = origAfter;
|
|
477
|
+
if (ctag2) {
|
|
478
|
+
afterFn = (cc) => {
|
|
479
|
+
const result = origAfter(cc);
|
|
480
|
+
if (result !== void 0 && result !== null) {
|
|
481
|
+
addTagValue(cc.tags, ctag2, result);
|
|
482
|
+
}
|
|
483
|
+
return result;
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
const debugName = ctag2 ? `${p.debugName}-${ctag2}` : `${p.debugName}`;
|
|
487
|
+
const collectParser = parser(
|
|
488
|
+
`collect`,
|
|
489
|
+
function _collect(ctx) {
|
|
490
|
+
const origStart = ctx.stream.checkpoint();
|
|
491
|
+
if (beforeFn) {
|
|
492
|
+
queueCollectFn(ctx, origStart, beforeFn, `${debugName}.before`);
|
|
493
|
+
}
|
|
494
|
+
return runAndCollectAfter(p, ctx, afterFn, debugName);
|
|
495
|
+
}
|
|
496
|
+
);
|
|
497
|
+
return collectParser;
|
|
498
|
+
}
|
|
499
|
+
function tagScope(arg) {
|
|
500
|
+
const p = parserArg(arg);
|
|
501
|
+
const sp = parser(
|
|
502
|
+
`tagScope`,
|
|
503
|
+
function _tagScope(ctx) {
|
|
504
|
+
const origStart = ctx.stream.checkpoint();
|
|
505
|
+
let origTags;
|
|
506
|
+
queueCollectFn(
|
|
507
|
+
ctx,
|
|
508
|
+
origStart,
|
|
509
|
+
(cc) => {
|
|
510
|
+
origTags = cloneTags(cc.tags);
|
|
511
|
+
cc.tags = {};
|
|
512
|
+
},
|
|
513
|
+
`scope.before ${p.debugName}`
|
|
514
|
+
);
|
|
515
|
+
return runAndCollectAfter(
|
|
516
|
+
p,
|
|
517
|
+
ctx,
|
|
518
|
+
(cc) => {
|
|
519
|
+
cc.tags = origTags;
|
|
520
|
+
},
|
|
521
|
+
`tagScope`
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
);
|
|
525
|
+
return sp;
|
|
526
|
+
}
|
|
527
|
+
function cloneTags(tags) {
|
|
528
|
+
const cloned = Object.entries(tags).map(([tag, values]) => {
|
|
529
|
+
return [tag, [...values]];
|
|
530
|
+
});
|
|
531
|
+
return Object.fromEntries(cloned);
|
|
532
|
+
}
|
|
533
|
+
function ctag(p, name2) {
|
|
534
|
+
const cp = parser(
|
|
535
|
+
`ctag`,
|
|
536
|
+
function _ctag(ctx) {
|
|
537
|
+
return runAndCollectAfter(
|
|
538
|
+
p,
|
|
539
|
+
ctx,
|
|
540
|
+
(cc) => {
|
|
541
|
+
const valueEntry = last$1(cc._values);
|
|
542
|
+
addTagValue(cc.tags, name2, valueEntry.value);
|
|
543
|
+
},
|
|
544
|
+
`ctag ${name2}`
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
);
|
|
548
|
+
return cp;
|
|
549
|
+
}
|
|
550
|
+
function runAndCollectAfter(p, ctx, collectFn, debugName = "") {
|
|
551
|
+
const origStart = ctx.stream.checkpoint();
|
|
552
|
+
const result = p._run(ctx);
|
|
553
|
+
if (result) {
|
|
554
|
+
queueCollectFn(ctx, origStart, collectFn, debugName);
|
|
555
|
+
}
|
|
556
|
+
return result;
|
|
557
|
+
}
|
|
558
|
+
function queueCollectFn(ctx, origStart, collectFn, debugName) {
|
|
559
|
+
const srcPosition = refinePosition(ctx.stream, origStart);
|
|
560
|
+
ctx._collect.push({
|
|
561
|
+
srcPosition,
|
|
562
|
+
collectFn,
|
|
563
|
+
debugName
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
function pushOpenArray(cc) {
|
|
567
|
+
cc._values.push({ value: null, openArray: [] });
|
|
568
|
+
}
|
|
569
|
+
function closeArray(cc) {
|
|
570
|
+
const lastValue = last$1(cc._values);
|
|
571
|
+
if (lastValue.openArray === void 0)
|
|
572
|
+
console.log("---closeArray: no open array");
|
|
573
|
+
cc._values.pop();
|
|
574
|
+
saveCollectValue(cc, lastValue.openArray);
|
|
575
|
+
}
|
|
576
|
+
function ptag(p, name2) {
|
|
577
|
+
const cp = parser(
|
|
578
|
+
`ptag`,
|
|
579
|
+
function _ptag(ctx) {
|
|
580
|
+
const origStart = ctx.stream.checkpoint();
|
|
581
|
+
const result = p._run(ctx);
|
|
582
|
+
if (result) {
|
|
583
|
+
const tagFn = (ctx2) => addTagValue(ctx2.tags, name2, result.value);
|
|
584
|
+
queueCollectFn(ctx, origStart, tagFn, `ptag ${name2}`);
|
|
585
|
+
}
|
|
586
|
+
return result;
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
return cp;
|
|
590
|
+
}
|
|
591
|
+
function addTagValue(tags, name2, value) {
|
|
592
|
+
if (tags[name2] === void 0) {
|
|
593
|
+
tags[name2] = [];
|
|
594
|
+
}
|
|
595
|
+
tags[name2].push(value);
|
|
596
|
+
}
|
|
597
|
+
function runCollection(_collect, app, stream) {
|
|
598
|
+
const tags = {};
|
|
599
|
+
const { src } = stream;
|
|
600
|
+
const _values = [{ value: null, openArray: void 0 }];
|
|
601
|
+
const collectContext = {
|
|
602
|
+
tags,
|
|
603
|
+
src,
|
|
604
|
+
start: -1,
|
|
605
|
+
end: -1,
|
|
606
|
+
app,
|
|
607
|
+
_values
|
|
608
|
+
};
|
|
609
|
+
_collect.forEach((entry) => {
|
|
610
|
+
const { collectFn, srcPosition } = entry;
|
|
611
|
+
collectContext.start = srcPosition.start;
|
|
612
|
+
collectContext.end = srcPosition.end;
|
|
613
|
+
const collectResult = collectFn(collectContext);
|
|
614
|
+
saveCollectValue(collectContext, collectResult);
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
function saveCollectValue(cc, value) {
|
|
618
|
+
if (value !== void 0) {
|
|
619
|
+
const valueEntry = last$1(cc._values);
|
|
620
|
+
if (!valueEntry) console.log("----saveCollectValue: no valueEntry");
|
|
621
|
+
if (valueEntry) valueEntry.value = value;
|
|
622
|
+
if ((valueEntry == null ? void 0 : valueEntry.openArray) !== void 0) {
|
|
623
|
+
valueEntry.openArray.push(value);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
function last$1(elems) {
|
|
628
|
+
return elems[elems.length - 1];
|
|
629
|
+
}
|
|
630
|
+
function refinePosition(stream, origStart) {
|
|
631
|
+
const end = stream.checkpoint();
|
|
632
|
+
stream.reset(origStart);
|
|
633
|
+
const start = skipIgnored(stream);
|
|
634
|
+
stream.reset(end);
|
|
635
|
+
return { start, end };
|
|
636
|
+
}
|
|
637
|
+
function skipIgnored(stream) {
|
|
638
|
+
const result = stream.nextToken();
|
|
639
|
+
if (result === null) {
|
|
640
|
+
return stream.checkpoint();
|
|
641
|
+
} else {
|
|
642
|
+
stream.reset(result.span[0]);
|
|
643
|
+
return stream.checkpoint();
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
class ParseError extends Error {
|
|
647
|
+
constructor(msg, position) {
|
|
648
|
+
super(msg);
|
|
649
|
+
this.position = position;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
class Parser {
|
|
653
|
+
constructor(args) {
|
|
654
|
+
this.fn = args.fn;
|
|
655
|
+
}
|
|
656
|
+
/** run the parser given an already created parsing context
|
|
657
|
+
*
|
|
658
|
+
* Execute a parser by running the core parsing fn given the parsing context
|
|
659
|
+
* also:
|
|
660
|
+
* . log if tracing is enabled
|
|
661
|
+
* . backtrack on failure
|
|
662
|
+
* . rollback context on failure
|
|
663
|
+
*/
|
|
664
|
+
_run(context) {
|
|
665
|
+
{
|
|
666
|
+
const origAppContext = context.app.context;
|
|
667
|
+
const origCollectLength = context._collect.length;
|
|
668
|
+
const result = this.fn(context);
|
|
669
|
+
if (result === null) {
|
|
670
|
+
context.app.context = origAppContext;
|
|
671
|
+
context._collect.length = origCollectLength;
|
|
672
|
+
}
|
|
673
|
+
return result;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/** tag parse results */
|
|
677
|
+
ptag(name2) {
|
|
678
|
+
return ptag(this, name2);
|
|
679
|
+
}
|
|
680
|
+
/** tag collect results */
|
|
681
|
+
ctag(name2) {
|
|
682
|
+
return ctag(this, name2);
|
|
683
|
+
}
|
|
684
|
+
/** record a name for debug tracing */
|
|
685
|
+
setTraceName(name2) {
|
|
686
|
+
return this;
|
|
687
|
+
}
|
|
688
|
+
/** trigger tracing for this parser (and by default also this parsers descendants) */
|
|
689
|
+
setTrace(opts = {}) {
|
|
690
|
+
return this;
|
|
691
|
+
}
|
|
692
|
+
/** map results to a new value, or add to app state as a side effect.
|
|
693
|
+
* Return null to cause the parser to fail.
|
|
694
|
+
* SAFETY: Side-effects should not be done if backtracking could occur!
|
|
695
|
+
*/
|
|
696
|
+
mapExtended(fn2) {
|
|
697
|
+
return mapExtended(this, fn2);
|
|
698
|
+
}
|
|
699
|
+
/** map results to a new value.
|
|
700
|
+
*/
|
|
701
|
+
map(fn2) {
|
|
702
|
+
return map(this, fn2);
|
|
703
|
+
}
|
|
704
|
+
/** Queue a function that runs later, typically to collect AST elements from the parse.
|
|
705
|
+
* when a commit() is parsed.
|
|
706
|
+
* Collection functions are dropped with parser backtracking, so
|
|
707
|
+
* only succsessful parses are collected. */
|
|
708
|
+
collect(fn2, ctag2) {
|
|
709
|
+
return collect(this, fn2, ctag2);
|
|
710
|
+
}
|
|
711
|
+
/** switch next parser based on results */
|
|
712
|
+
toParser(fn2) {
|
|
713
|
+
return toParser(this, fn2);
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* start parsing
|
|
717
|
+
*
|
|
718
|
+
* @throws {ParseError} when a combinator like `req` fails
|
|
719
|
+
*/
|
|
720
|
+
parse(init) {
|
|
721
|
+
const { stream, appState: app = { context: {}, stable: [] } } = init;
|
|
722
|
+
const _collect = [];
|
|
723
|
+
const result = this._run({
|
|
724
|
+
stream,
|
|
725
|
+
app,
|
|
726
|
+
_collect
|
|
727
|
+
});
|
|
728
|
+
if (result) runCollection(_collect, app, stream);
|
|
729
|
+
return result;
|
|
730
|
+
}
|
|
731
|
+
/** name of this parser for debugging/tracing */
|
|
732
|
+
get debugName() {
|
|
733
|
+
return "parser";
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
function parser(traceName, fn2, terminal) {
|
|
737
|
+
return new Parser({ fn: fn2, traceName, terminal });
|
|
738
|
+
}
|
|
739
|
+
function simpleParser(traceName, parserFn) {
|
|
740
|
+
return parser(traceName, parserFn, true);
|
|
741
|
+
}
|
|
742
|
+
function mapExtended(p, fn2) {
|
|
743
|
+
const mapParser = parser(
|
|
744
|
+
`mapExtended`,
|
|
745
|
+
function _mapExtended(ctx) {
|
|
746
|
+
const extended = runExtended(ctx, p);
|
|
747
|
+
if (!extended) return null;
|
|
748
|
+
const mappedValue = fn2(extended);
|
|
749
|
+
if (mappedValue === null) return null;
|
|
750
|
+
return { value: mappedValue };
|
|
751
|
+
}
|
|
752
|
+
);
|
|
753
|
+
return mapParser;
|
|
754
|
+
}
|
|
755
|
+
function map(p, fn2) {
|
|
756
|
+
const mapParser = parser(
|
|
757
|
+
`map`,
|
|
758
|
+
function _map(ctx) {
|
|
759
|
+
const result = p._run(ctx);
|
|
760
|
+
if (result === null) return null;
|
|
761
|
+
return { value: fn2(result.value) };
|
|
762
|
+
}
|
|
763
|
+
);
|
|
764
|
+
return mapParser;
|
|
765
|
+
}
|
|
766
|
+
function toParser(p, toParserFn) {
|
|
767
|
+
const newParser = parser(
|
|
768
|
+
"toParser",
|
|
769
|
+
function _toParser(ctx) {
|
|
770
|
+
const result = p._run(ctx);
|
|
771
|
+
if (result === null) return null;
|
|
772
|
+
const newParser2 = toParserFn(result);
|
|
773
|
+
if (newParser2 === null) {
|
|
774
|
+
return result;
|
|
775
|
+
}
|
|
776
|
+
const nextResult = newParser2._run(ctx);
|
|
777
|
+
return nextResult;
|
|
778
|
+
}
|
|
779
|
+
);
|
|
780
|
+
return newParser;
|
|
781
|
+
}
|
|
782
|
+
function runExtended(ctx, p) {
|
|
783
|
+
const origStart = ctx.stream.checkpoint();
|
|
784
|
+
const origResults = p._run(ctx);
|
|
785
|
+
if (origResults === null) {
|
|
786
|
+
ctx.stream.reset(origStart);
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
const { app } = ctx;
|
|
790
|
+
return { ...origResults, app };
|
|
791
|
+
}
|
|
792
|
+
function trackChildren(p, ...args) {
|
|
793
|
+
}
|
|
794
|
+
class SrcMap {
|
|
795
|
+
constructor(dest, entries = []) {
|
|
796
|
+
this.dest = dest;
|
|
797
|
+
this.entries = entries;
|
|
798
|
+
}
|
|
799
|
+
/** add a new mapping from src to dest ranges.
|
|
800
|
+
* entries must be non-overlapping in the destination
|
|
801
|
+
*/
|
|
802
|
+
addEntries(newEntries) {
|
|
803
|
+
this.entries.push(...newEntries);
|
|
804
|
+
}
|
|
805
|
+
/** given positions in the dest string,
|
|
806
|
+
* @return corresponding positions in the src strings */
|
|
807
|
+
mapPositions(...positions) {
|
|
808
|
+
return positions.map((p) => this.destToSrc(p));
|
|
809
|
+
}
|
|
810
|
+
/** internally compress adjacent entries where possible */
|
|
811
|
+
compact() {
|
|
812
|
+
if (!this.entries.length) return;
|
|
813
|
+
let prev = this.entries[0];
|
|
814
|
+
const newEntries = [prev];
|
|
815
|
+
for (let i = 1; i < this.entries.length; i++) {
|
|
816
|
+
const e = this.entries[i];
|
|
817
|
+
if (e.src.path === prev.src.path && e.src.text === prev.src.text && prev.destEnd === e.destStart && prev.srcEnd === e.srcStart) {
|
|
818
|
+
prev.destEnd = e.destEnd;
|
|
819
|
+
prev.srcEnd = e.srcEnd;
|
|
820
|
+
} else {
|
|
821
|
+
newEntries.push(e);
|
|
822
|
+
prev = e;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
this.entries = newEntries;
|
|
826
|
+
}
|
|
827
|
+
/** sort in destination order */
|
|
828
|
+
sort() {
|
|
829
|
+
this.entries.sort((a, b) => a.destStart - b.destStart);
|
|
830
|
+
}
|
|
831
|
+
/** This SrcMap's destination is a src for the other srcmap,
|
|
832
|
+
* so combine the two and return the result.
|
|
833
|
+
*/
|
|
834
|
+
merge(other) {
|
|
835
|
+
if (other === this) return this;
|
|
836
|
+
const mappedEntries = other.entries.filter(
|
|
837
|
+
(e) => e.src.path === this.dest.path && e.src.text === this.dest.text
|
|
838
|
+
);
|
|
839
|
+
if (mappedEntries.length === 0) {
|
|
840
|
+
console.log("other source map does not link to this one");
|
|
841
|
+
return other;
|
|
842
|
+
}
|
|
843
|
+
sortSrc(mappedEntries);
|
|
844
|
+
const newEntries = mappedEntries.map((e) => {
|
|
845
|
+
const { src, position: srcStart } = this.destToSrc(e.srcStart);
|
|
846
|
+
const { src: endSrc, position: srcEnd } = this.destToSrc(e.srcEnd);
|
|
847
|
+
if (endSrc !== src) throw new Error("NYI, need to split");
|
|
848
|
+
const newEntry = {
|
|
849
|
+
src,
|
|
850
|
+
srcStart,
|
|
851
|
+
srcEnd,
|
|
852
|
+
destStart: e.destStart,
|
|
853
|
+
destEnd: e.destEnd
|
|
854
|
+
};
|
|
855
|
+
return newEntry;
|
|
856
|
+
});
|
|
857
|
+
const otherSources = other.entries.filter(
|
|
858
|
+
(e) => e.src.path !== this.dest.path || e.src.text !== this.dest.text
|
|
859
|
+
);
|
|
860
|
+
const newMap = new SrcMap(other.dest, [...otherSources, ...newEntries]);
|
|
861
|
+
newMap.sort();
|
|
862
|
+
return newMap;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* @param entries should be sorted in destStart order
|
|
866
|
+
* @return the source position corresponding to a provided destination position
|
|
867
|
+
*
|
|
868
|
+
*/
|
|
869
|
+
destToSrc(destPos) {
|
|
870
|
+
const entry = this.entries.find(
|
|
871
|
+
(e) => e.destStart <= destPos && e.destEnd >= destPos
|
|
872
|
+
);
|
|
873
|
+
if (!entry) {
|
|
874
|
+
return {
|
|
875
|
+
src: this.dest,
|
|
876
|
+
position: destPos
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
return {
|
|
880
|
+
src: entry.src,
|
|
881
|
+
position: entry.srcStart + destPos - entry.destStart
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
function sortSrc(entries) {
|
|
886
|
+
entries.sort((a, b) => a.srcStart - b.srcStart);
|
|
887
|
+
}
|
|
888
|
+
class SrcMapBuilder {
|
|
889
|
+
constructor(source) {
|
|
890
|
+
__privateAdd(this, _fragments, []);
|
|
891
|
+
__privateAdd(this, _destLength, 0);
|
|
892
|
+
__privateAdd(this, _entries, []);
|
|
893
|
+
this.source = source;
|
|
894
|
+
}
|
|
895
|
+
/** append a string fragment to the destination string */
|
|
896
|
+
add(fragment, srcStart, srcEnd) {
|
|
897
|
+
const destStart = __privateGet(this, _destLength);
|
|
898
|
+
__privateSet(this, _destLength, __privateGet(this, _destLength) + fragment.length);
|
|
899
|
+
const destEnd = __privateGet(this, _destLength);
|
|
900
|
+
__privateGet(this, _fragments).push(fragment);
|
|
901
|
+
__privateGet(this, _entries).push({
|
|
902
|
+
src: this.source,
|
|
903
|
+
srcStart,
|
|
904
|
+
srcEnd,
|
|
905
|
+
destStart,
|
|
906
|
+
destEnd
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Append a fragment to the destination string,
|
|
911
|
+
* mapping source to the pervious,
|
|
912
|
+
* and guessing that the source fragment is just as long as the the dest fragment.
|
|
913
|
+
* (LATER we plan to drop or make optional src end positions)
|
|
914
|
+
*/
|
|
915
|
+
appendNext(fragment) {
|
|
916
|
+
var _a;
|
|
917
|
+
const lastEnd = ((_a = __privateGet(this, _entries).at(-1)) == null ? void 0 : _a.destEnd) ?? 0;
|
|
918
|
+
this.add(fragment, lastEnd, lastEnd + fragment.length);
|
|
919
|
+
}
|
|
920
|
+
addSynthetic(fragment, syntheticSource, srcStart, srcEnd) {
|
|
921
|
+
const destStart = __privateGet(this, _destLength);
|
|
922
|
+
__privateSet(this, _destLength, __privateGet(this, _destLength) + fragment.length);
|
|
923
|
+
const destEnd = __privateGet(this, _destLength);
|
|
924
|
+
__privateGet(this, _fragments).push(fragment);
|
|
925
|
+
__privateGet(this, _entries).push({
|
|
926
|
+
src: { text: syntheticSource },
|
|
927
|
+
srcStart,
|
|
928
|
+
srcEnd,
|
|
929
|
+
destStart,
|
|
930
|
+
destEnd
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
/** append a synthetic newline, mapped to previous source location */
|
|
934
|
+
addNl() {
|
|
935
|
+
const lastEntry = __privateGet(this, _entries).at(-1) ?? { srcStart: 0, srcEnd: 0 };
|
|
936
|
+
const { srcStart, srcEnd } = lastEntry;
|
|
937
|
+
this.add("\n", srcStart, srcEnd);
|
|
938
|
+
}
|
|
939
|
+
/** copy a string fragment from the src to the destination string */
|
|
940
|
+
addCopy(srcStart, srcEnd) {
|
|
941
|
+
const fragment = this.source.text.slice(srcStart, srcEnd);
|
|
942
|
+
this.add(fragment, srcStart, srcEnd);
|
|
943
|
+
}
|
|
944
|
+
/** return a SrcMap */
|
|
945
|
+
static build(builders) {
|
|
946
|
+
const map2 = new SrcMap(
|
|
947
|
+
{ text: builders.map((b) => __privateGet(b, _fragments).join("")).join("") },
|
|
948
|
+
builders.flatMap((b) => __privateGet(b, _entries))
|
|
949
|
+
);
|
|
950
|
+
map2.compact();
|
|
951
|
+
return map2;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
_fragments = new WeakMap();
|
|
955
|
+
_destLength = new WeakMap();
|
|
956
|
+
_entries = new WeakMap();
|
|
957
|
+
class CachingStream {
|
|
958
|
+
constructor(inner) {
|
|
959
|
+
this.inner = inner;
|
|
960
|
+
this.cache = new Cache(5);
|
|
961
|
+
}
|
|
962
|
+
checkpoint() {
|
|
963
|
+
return this.inner.checkpoint();
|
|
964
|
+
}
|
|
965
|
+
reset(position) {
|
|
966
|
+
this.inner.reset(position);
|
|
967
|
+
}
|
|
968
|
+
nextToken() {
|
|
969
|
+
const startPos = this.checkpoint();
|
|
970
|
+
const cachedValue = this.cache.get(startPos);
|
|
971
|
+
if (cachedValue !== void 0) {
|
|
972
|
+
this.reset(cachedValue.checkpoint);
|
|
973
|
+
return cachedValue.token;
|
|
974
|
+
} else {
|
|
975
|
+
const token2 = this.inner.nextToken();
|
|
976
|
+
const checkpoint = this.checkpoint();
|
|
977
|
+
this.cache.set(startPos, { token: token2, checkpoint });
|
|
978
|
+
return token2;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
get src() {
|
|
982
|
+
return this.inner.src;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
class Cache extends Map {
|
|
986
|
+
constructor(max) {
|
|
987
|
+
super();
|
|
988
|
+
this.max = max;
|
|
989
|
+
}
|
|
990
|
+
set(k, v) {
|
|
991
|
+
if (this.size > this.max) {
|
|
992
|
+
const first = this.keys().next().value;
|
|
993
|
+
if (first) this.delete(first);
|
|
994
|
+
}
|
|
995
|
+
return super.set(k, v);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
function toRegexSource(nameExp) {
|
|
999
|
+
const [name2, e] = nameExp;
|
|
1000
|
+
if (typeof e === "string") {
|
|
1001
|
+
const expSrc = `(${escapeRegex(e)})`;
|
|
1002
|
+
verifyNonCapturing(name2, new RegExp(expSrc));
|
|
1003
|
+
return expSrc;
|
|
1004
|
+
} else {
|
|
1005
|
+
verifyNonCapturing(name2, e);
|
|
1006
|
+
return `(${e.source})`;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
function verifyNonCapturing(name2, exp) {
|
|
1010
|
+
const willMatch = new RegExp("|" + exp.source);
|
|
1011
|
+
const result = willMatch.exec("");
|
|
1012
|
+
if (result.length > 1) {
|
|
1013
|
+
throw new Error(
|
|
1014
|
+
`match expression groups must be non-capturing: ${name2}: /${exp.source}/. Use (?:...) instead.`
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
const regexSpecials = /[$+*.?|(){}[\]\\/^]/g;
|
|
1019
|
+
function escapeRegex(s) {
|
|
1020
|
+
return s.replace(regexSpecials, "\\$&");
|
|
1021
|
+
}
|
|
1022
|
+
function matchOneOf(syms) {
|
|
1023
|
+
const symbolList = syms.split(/\s+/).sort((a, b) => b.length - a.length);
|
|
1024
|
+
const escaped = symbolList.filter((s) => s).map(escapeRegex);
|
|
1025
|
+
return new RegExp(escaped.join("|"));
|
|
1026
|
+
}
|
|
1027
|
+
class MatchersStream {
|
|
1028
|
+
constructor(text2, matchers) {
|
|
1029
|
+
this.text = text2;
|
|
1030
|
+
this.matchers = matchers;
|
|
1031
|
+
this.position = 0;
|
|
1032
|
+
}
|
|
1033
|
+
checkpoint() {
|
|
1034
|
+
return this.position;
|
|
1035
|
+
}
|
|
1036
|
+
reset(position) {
|
|
1037
|
+
this.position = position;
|
|
1038
|
+
}
|
|
1039
|
+
nextToken() {
|
|
1040
|
+
const result = this.matchers.execAt(this.text, this.position);
|
|
1041
|
+
if (result === null) return null;
|
|
1042
|
+
this.position = result.span[1];
|
|
1043
|
+
return result;
|
|
1044
|
+
}
|
|
1045
|
+
get src() {
|
|
1046
|
+
return this.text;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
class RegexMatchers {
|
|
1050
|
+
constructor(matchers) {
|
|
1051
|
+
this.groups = Object.keys(matchers);
|
|
1052
|
+
const expParts = Object.entries(matchers).map(toRegexSource).join("|");
|
|
1053
|
+
this.exp = new RegExp(expParts, "dyu");
|
|
1054
|
+
}
|
|
1055
|
+
execAt(text2, position) {
|
|
1056
|
+
this.exp.lastIndex = position;
|
|
1057
|
+
const matches = this.exp.exec(text2);
|
|
1058
|
+
const matchedIndex = findGroupDex(matches == null ? void 0 : matches.indices);
|
|
1059
|
+
if (matchedIndex) {
|
|
1060
|
+
const { span: span2, groupDex } = matchedIndex;
|
|
1061
|
+
const kind2 = this.groups[groupDex];
|
|
1062
|
+
return {
|
|
1063
|
+
kind: kind2,
|
|
1064
|
+
span: span2,
|
|
1065
|
+
text: text2.slice(span2[0], span2[1])
|
|
1066
|
+
};
|
|
1067
|
+
} else {
|
|
1068
|
+
return null;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
function findGroupDex(indices) {
|
|
1073
|
+
if (indices !== void 0) {
|
|
1074
|
+
for (let i = 1; i < indices.length; i++) {
|
|
1075
|
+
const span2 = indices[i];
|
|
1076
|
+
if (span2 !== void 0) {
|
|
1077
|
+
return { span: span2, groupDex: i - 1 };
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
function assertThatDebug(condition, msg) {
|
|
1083
|
+
}
|
|
1084
|
+
function assertUnreachable(value) {
|
|
1085
|
+
throw new ErrorWithData2("Unreachable value", { data: value });
|
|
1086
|
+
}
|
|
1087
|
+
class ErrorWithData2 extends Error {
|
|
1088
|
+
constructor(message, options) {
|
|
1089
|
+
super(message, options);
|
|
1090
|
+
this.data = options == null ? void 0 : options.data;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
function last(a) {
|
|
1094
|
+
return a[a.length - 1];
|
|
1095
|
+
}
|
|
1096
|
+
function filterMap(arr, fn2) {
|
|
1097
|
+
const out = [];
|
|
1098
|
+
for (const t of arr) {
|
|
1099
|
+
const u = fn2(t);
|
|
1100
|
+
if (u) out.push(u);
|
|
1101
|
+
}
|
|
1102
|
+
return out;
|
|
1103
|
+
}
|
|
1104
|
+
function findMap(arr, fn2) {
|
|
1105
|
+
for (const t of arr) {
|
|
1106
|
+
const u = fn2(t);
|
|
1107
|
+
if (u) return u;
|
|
1108
|
+
}
|
|
1109
|
+
return void 0;
|
|
1110
|
+
}
|
|
1111
|
+
function mapValues(obj, fn2) {
|
|
1112
|
+
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn2(v)]));
|
|
1113
|
+
}
|
|
1114
|
+
function offsetToLineNumber(offset, text2) {
|
|
1115
|
+
offset = Math.min(text2.length, Math.max(0, offset));
|
|
1116
|
+
let lineStartOffset = 0;
|
|
1117
|
+
let lineNum = 1;
|
|
1118
|
+
while (true) {
|
|
1119
|
+
const lineEnd = text2.indexOf("\n", lineStartOffset);
|
|
1120
|
+
if (lineEnd === -1 || offset <= lineEnd) {
|
|
1121
|
+
const linePos = 1 + (offset - lineStartOffset);
|
|
1122
|
+
return [lineNum, linePos];
|
|
1123
|
+
} else {
|
|
1124
|
+
lineStartOffset = lineEnd + 1;
|
|
1125
|
+
lineNum += 1;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
function errorHighlight(source, span2) {
|
|
1130
|
+
let lineStartOffset = source.lastIndexOf("\n", span2[0]);
|
|
1131
|
+
if (lineStartOffset === -1) {
|
|
1132
|
+
lineStartOffset = 0;
|
|
1133
|
+
}
|
|
1134
|
+
let lineEndOffset = source.indexOf("\n", span2[0]);
|
|
1135
|
+
if (lineEndOffset === -1) {
|
|
1136
|
+
lineEndOffset = source.length;
|
|
1137
|
+
}
|
|
1138
|
+
const errorLength = span2[1] - span2[0];
|
|
1139
|
+
const caretCount = Math.max(1, errorLength);
|
|
1140
|
+
const linePos = span2[0] - lineStartOffset;
|
|
1141
|
+
return [
|
|
1142
|
+
source.slice(lineStartOffset, lineEndOffset),
|
|
1143
|
+
" ".repeat(linePos) + "^".repeat(caretCount)
|
|
1144
|
+
];
|
|
1145
|
+
}
|
|
1146
|
+
function elementValid(elem, conditions) {
|
|
1147
|
+
const attributes = elem.attributes;
|
|
1148
|
+
if (!attributes) return true;
|
|
1149
|
+
const ifAttr = findMap(attributes, extractIfAttribute);
|
|
1150
|
+
return !ifAttr || evaluateIfAttribute(ifAttr);
|
|
1151
|
+
}
|
|
1152
|
+
function scopeValid(scope, conditions) {
|
|
1153
|
+
const { ifAttribute } = scope;
|
|
1154
|
+
if (!ifAttribute) return true;
|
|
1155
|
+
const result = evaluateIfAttribute(ifAttribute);
|
|
1156
|
+
return result;
|
|
1157
|
+
}
|
|
1158
|
+
function extractIfAttribute(elem) {
|
|
1159
|
+
const { attribute } = elem;
|
|
1160
|
+
return attribute.kind === "@if" ? attribute : void 0;
|
|
1161
|
+
}
|
|
1162
|
+
function evaluateIfAttribute(ifAttribute, conditions) {
|
|
1163
|
+
return evaluateIfExpression(ifAttribute.param.expression);
|
|
1164
|
+
}
|
|
1165
|
+
function evaluateIfExpression(expression2, conditions) {
|
|
1166
|
+
const { kind: kind2 } = expression2;
|
|
1167
|
+
if (kind2 == "unary-expression") {
|
|
1168
|
+
assertThatDebug(expression2.operator.value === "!");
|
|
1169
|
+
return !evaluateIfExpression(expression2.expression);
|
|
1170
|
+
} else if (kind2 == "binary-expression") {
|
|
1171
|
+
const op = expression2.operator.value;
|
|
1172
|
+
const leftResult = evaluateIfExpression(expression2.left);
|
|
1173
|
+
if (op === "||") {
|
|
1174
|
+
return leftResult || evaluateIfExpression(expression2.right);
|
|
1175
|
+
} else if (op === "&&") {
|
|
1176
|
+
return leftResult && evaluateIfExpression(expression2.right);
|
|
1177
|
+
} else {
|
|
1178
|
+
assertUnreachable(op);
|
|
1179
|
+
}
|
|
1180
|
+
} else if (kind2 == "literal") {
|
|
1181
|
+
const { value } = expression2;
|
|
1182
|
+
return value === "true";
|
|
1183
|
+
} else if (kind2 == "parenthesized-expression") {
|
|
1184
|
+
return evaluateIfExpression(expression2.expression);
|
|
1185
|
+
} else {
|
|
1186
|
+
throw new Error("unexpected @if expression ${expression}");
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
function mergeScope(a, b) {
|
|
1190
|
+
assertThatDebug(a.kind === b.kind);
|
|
1191
|
+
assertThatDebug(a.parent === b.parent);
|
|
1192
|
+
assertThatDebug(!b.ifAttribute);
|
|
1193
|
+
a.contents = a.contents.concat(b.contents);
|
|
1194
|
+
}
|
|
1195
|
+
function resetScopeIds() {
|
|
1196
|
+
scopeId = 0;
|
|
1197
|
+
identId = 0;
|
|
1198
|
+
}
|
|
1199
|
+
let scopeId = 0;
|
|
1200
|
+
let identId = 0;
|
|
1201
|
+
function nextIdentId() {
|
|
1202
|
+
return identId++;
|
|
1203
|
+
}
|
|
1204
|
+
function emptyScope(parent, kind2 = "scope") {
|
|
1205
|
+
const id = scopeId++;
|
|
1206
|
+
return { id, kind: kind2, parent, contents: [] };
|
|
1207
|
+
}
|
|
1208
|
+
function childScope(child) {
|
|
1209
|
+
const { kind: kind2 } = child;
|
|
1210
|
+
return kind2 === "partial" || kind2 === "scope";
|
|
1211
|
+
}
|
|
1212
|
+
function publicDecl(scope, name2, conditions) {
|
|
1213
|
+
for (const elem of scope.contents) {
|
|
1214
|
+
if (elem.kind === "decl" && elem.originalName === name2) {
|
|
1215
|
+
return elem;
|
|
1216
|
+
} else if (elem.kind === "partial" && scopeValid(elem)) {
|
|
1217
|
+
const found = publicDecl(elem, name2);
|
|
1218
|
+
if (found) return found;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
class LineWrapper {
|
|
1223
|
+
constructor(indent = 0, maxWidth = 60, hangingIndent = 2) {
|
|
1224
|
+
__privateAdd(this, _fragments2, []);
|
|
1225
|
+
__privateAdd(this, _column, 0);
|
|
1226
|
+
__privateAdd(this, _spc);
|
|
1227
|
+
__privateAdd(this, _oneLine, true);
|
|
1228
|
+
__privateAdd(this, _isHanging, false);
|
|
1229
|
+
__privateAdd(this, _hangingSpc);
|
|
1230
|
+
this.indent = indent;
|
|
1231
|
+
this.maxWidth = maxWidth;
|
|
1232
|
+
this.hangingIndent = hangingIndent;
|
|
1233
|
+
__privateSet(this, _spc, " ".repeat(indent));
|
|
1234
|
+
__privateSet(this, _hangingSpc, " ".repeat(hangingIndent));
|
|
1235
|
+
}
|
|
1236
|
+
/** add a new line to the constructed string */
|
|
1237
|
+
nl() {
|
|
1238
|
+
__privateGet(this, _fragments2).push("\n");
|
|
1239
|
+
__privateSet(this, _column, 0);
|
|
1240
|
+
__privateSet(this, _oneLine, false);
|
|
1241
|
+
__privateSet(this, _isHanging, false);
|
|
1242
|
+
}
|
|
1243
|
+
/** add a string, wrapping to the next line if necessary */
|
|
1244
|
+
add(s) {
|
|
1245
|
+
if (__privateGet(this, _column) + firstLineLength(s) > this.maxWidth) {
|
|
1246
|
+
this.hangingNl();
|
|
1247
|
+
}
|
|
1248
|
+
if (__privateGet(this, _column) === 0) {
|
|
1249
|
+
__privateGet(this, _fragments2).push(__privateGet(this, _spc));
|
|
1250
|
+
if (__privateGet(this, _isHanging)) {
|
|
1251
|
+
__privateGet(this, _fragments2).push(__privateGet(this, _hangingSpc));
|
|
1252
|
+
}
|
|
1253
|
+
__privateSet(this, _column, this.indent);
|
|
1254
|
+
}
|
|
1255
|
+
__privateGet(this, _fragments2).push(s);
|
|
1256
|
+
__privateSet(this, _column, __privateGet(this, _column) + s.length);
|
|
1257
|
+
}
|
|
1258
|
+
/** add a raw block of text with no wrapping */
|
|
1259
|
+
addBlock(s, andNewLine = true) {
|
|
1260
|
+
__privateGet(this, _fragments2).push(s);
|
|
1261
|
+
if (andNewLine) this.nl();
|
|
1262
|
+
}
|
|
1263
|
+
/** @return the constructed string */
|
|
1264
|
+
get result() {
|
|
1265
|
+
return __privateGet(this, _fragments2).join("");
|
|
1266
|
+
}
|
|
1267
|
+
/** true if the result contains no newlines */
|
|
1268
|
+
get oneLine() {
|
|
1269
|
+
return __privateGet(this, _oneLine);
|
|
1270
|
+
}
|
|
1271
|
+
hangingNl() {
|
|
1272
|
+
this.nl();
|
|
1273
|
+
__privateSet(this, _isHanging, true);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
_fragments2 = new WeakMap();
|
|
1277
|
+
_column = new WeakMap();
|
|
1278
|
+
_spc = new WeakMap();
|
|
1279
|
+
_oneLine = new WeakMap();
|
|
1280
|
+
_isHanging = new WeakMap();
|
|
1281
|
+
_hangingSpc = new WeakMap();
|
|
1282
|
+
function firstLineLength(s) {
|
|
1283
|
+
const i = s.indexOf("\n");
|
|
1284
|
+
return i === -1 ? s.length : i;
|
|
1285
|
+
}
|
|
1286
|
+
function scopeToString(scope, indent = 0, shortIdents = true) {
|
|
1287
|
+
const { contents, kind: kind2, ifAttribute } = scope;
|
|
1288
|
+
const str = new LineWrapper(indent);
|
|
1289
|
+
const attrStrings = ifAttribute && attributeToString$1(ifAttribute);
|
|
1290
|
+
if (attrStrings) str.add(attrStrings + " ");
|
|
1291
|
+
if (kind2 === "partial") str.add("-");
|
|
1292
|
+
str.add("{ ");
|
|
1293
|
+
const last2 = contents.length - 1;
|
|
1294
|
+
let lastWasScope = false;
|
|
1295
|
+
let hasBlock = false;
|
|
1296
|
+
contents.forEach((elem, i) => {
|
|
1297
|
+
if (childScope(elem)) {
|
|
1298
|
+
const childScope2 = elem;
|
|
1299
|
+
const childBlock = scopeToString(childScope2, indent + 2, shortIdents);
|
|
1300
|
+
!lastWasScope && str.nl();
|
|
1301
|
+
str.addBlock(childBlock);
|
|
1302
|
+
lastWasScope = true;
|
|
1303
|
+
hasBlock = true;
|
|
1304
|
+
} else {
|
|
1305
|
+
lastWasScope && str.add(" ");
|
|
1306
|
+
lastWasScope = false;
|
|
1307
|
+
const ident2 = elem;
|
|
1308
|
+
if (shortIdents) {
|
|
1309
|
+
str.add(identShortString(ident2));
|
|
1310
|
+
} else {
|
|
1311
|
+
str.add(identToString(ident2));
|
|
1312
|
+
}
|
|
1313
|
+
if (i < last2) str.add(" ");
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
if (!hasBlock && str.oneLine) {
|
|
1317
|
+
str.add(" }");
|
|
1318
|
+
} else {
|
|
1319
|
+
if (hasBlock && !lastWasScope) str.nl();
|
|
1320
|
+
str.add("}");
|
|
1321
|
+
}
|
|
1322
|
+
str.add(` #${scope.id}`);
|
|
1323
|
+
return str.result;
|
|
1324
|
+
}
|
|
1325
|
+
function scopeToStringLong(scope) {
|
|
1326
|
+
return scopeToString(scope, 0, false);
|
|
1327
|
+
}
|
|
1328
|
+
function identShortString(ident2) {
|
|
1329
|
+
const { kind: kind2, originalName } = ident2;
|
|
1330
|
+
const prefix = kind2 === "decl" ? "%" : "";
|
|
1331
|
+
return `${prefix}${originalName}`;
|
|
1332
|
+
}
|
|
1333
|
+
function identToString(ident2) {
|
|
1334
|
+
if (!ident2) return JSON.stringify(ident2);
|
|
1335
|
+
const { kind: kind2, originalName } = ident2;
|
|
1336
|
+
const idStr = ident2.id ? `#${ident2.id}` : "";
|
|
1337
|
+
if (kind2 === "ref") {
|
|
1338
|
+
const ref = identToString(ident2.refersTo);
|
|
1339
|
+
return `${originalName} ${idStr} -> ${ref}`;
|
|
1340
|
+
} else {
|
|
1341
|
+
const { mangledName } = ident2;
|
|
1342
|
+
const mangled = mangledName ? `(${mangledName})` : "";
|
|
1343
|
+
return `%${originalName}${mangled} ${idStr} `;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
function makeLiveDecls(parent = null) {
|
|
1347
|
+
return { decls: /* @__PURE__ */ new Map(), parent };
|
|
1348
|
+
}
|
|
1349
|
+
function minimalMangle(_d, _s, proposedName, globalNames) {
|
|
1350
|
+
return minimallyMangledName(proposedName, globalNames);
|
|
1351
|
+
}
|
|
1352
|
+
function minimallyMangledName(proposedName, globalNames) {
|
|
1353
|
+
let renamed = proposedName;
|
|
1354
|
+
let conflicts = 0;
|
|
1355
|
+
while (globalNames.has(renamed)) {
|
|
1356
|
+
renamed = proposedName + conflicts++;
|
|
1357
|
+
}
|
|
1358
|
+
return renamed;
|
|
1359
|
+
}
|
|
1360
|
+
function flattenTreeImport(imp) {
|
|
1361
|
+
return recursiveResolve([], [], imp.segments, imp.finalSegment);
|
|
1362
|
+
function recursiveResolve(resolvedImportPath, resolvedExportPath, remainingPath, finalSegment) {
|
|
1363
|
+
if (remainingPath.length > 0) {
|
|
1364
|
+
const [segment, ...rest] = remainingPath;
|
|
1365
|
+
const importPath = [...resolvedImportPath, segment.name];
|
|
1366
|
+
const modulePath = [...resolvedExportPath, segment.name];
|
|
1367
|
+
return recursiveResolve(importPath, modulePath, rest, finalSegment);
|
|
1368
|
+
} else if (finalSegment.kind === "import-collection") {
|
|
1369
|
+
return finalSegment.subtrees.flatMap((elem) => {
|
|
1370
|
+
return recursiveResolve(
|
|
1371
|
+
resolvedImportPath,
|
|
1372
|
+
resolvedExportPath,
|
|
1373
|
+
elem.segments,
|
|
1374
|
+
elem.finalSegment
|
|
1375
|
+
);
|
|
1376
|
+
});
|
|
1377
|
+
} else if (finalSegment.kind === "import-item") {
|
|
1378
|
+
const importPath = [
|
|
1379
|
+
...resolvedImportPath,
|
|
1380
|
+
finalSegment.as ?? finalSegment.name
|
|
1381
|
+
];
|
|
1382
|
+
const modulePath = [...resolvedExportPath, finalSegment.name];
|
|
1383
|
+
return [{ importPath, modulePath }];
|
|
1384
|
+
} else {
|
|
1385
|
+
assertUnreachable(finalSegment);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
var spaces = memoize((nesting) => {
|
|
1390
|
+
return " ".repeat(nesting);
|
|
1391
|
+
});
|
|
1392
|
+
var defaultCallerSize = 20;
|
|
1393
|
+
"\n" + spaces(defaultCallerSize + 3);
|
|
1394
|
+
function memoize(fn2) {
|
|
1395
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1396
|
+
return function(...args) {
|
|
1397
|
+
const key = JSON.stringify(args);
|
|
1398
|
+
if (cache.has(key)) {
|
|
1399
|
+
return cache.get(key);
|
|
1400
|
+
} else {
|
|
1401
|
+
const value = fn2(...args);
|
|
1402
|
+
cache.set(key, value);
|
|
1403
|
+
return value;
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
if (typeof DOMRect === "undefined") {
|
|
1408
|
+
globalThis.DOMRect = function() {
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
function importElem(cc) {
|
|
1412
|
+
var _a;
|
|
1413
|
+
const importElems = (_a = cc.tags.owo) == null ? void 0 : _a[0];
|
|
1414
|
+
for (const importElem2 of importElems) {
|
|
1415
|
+
cc.app.stable.imports.push(importElem2.imports);
|
|
1416
|
+
addToOpenElem(cc, importElem2);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
function addToOpenElem(cc, elem) {
|
|
1420
|
+
const weslContext = cc.app.context;
|
|
1421
|
+
const { openElems } = weslContext;
|
|
1422
|
+
if (openElems && openElems.length) {
|
|
1423
|
+
const open = openElems[openElems.length - 1];
|
|
1424
|
+
open.contents.push(elem);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
function refIdent(cc) {
|
|
1428
|
+
const { src, start, end } = cc;
|
|
1429
|
+
const app = cc.app;
|
|
1430
|
+
const { srcModule } = app.stable;
|
|
1431
|
+
const originalName = src.slice(start, end);
|
|
1432
|
+
const kind2 = "ref";
|
|
1433
|
+
const ident2 = {
|
|
1434
|
+
kind: kind2,
|
|
1435
|
+
originalName,
|
|
1436
|
+
ast: cc.app.stable,
|
|
1437
|
+
id: nextIdentId(),
|
|
1438
|
+
refIdentElem: null
|
|
1439
|
+
// set below
|
|
1440
|
+
};
|
|
1441
|
+
const identElem = { kind: kind2, start, end, srcModule, ident: ident2 };
|
|
1442
|
+
ident2.refIdentElem = identElem;
|
|
1443
|
+
saveIdent(cc, identElem);
|
|
1444
|
+
addToOpenElem(cc, identElem);
|
|
1445
|
+
return identElem;
|
|
1446
|
+
}
|
|
1447
|
+
function declCollect(cc) {
|
|
1448
|
+
return declCollectInternal(cc, false);
|
|
1449
|
+
}
|
|
1450
|
+
function globalDeclCollect(cc) {
|
|
1451
|
+
return declCollectInternal(cc, true);
|
|
1452
|
+
}
|
|
1453
|
+
function declCollectInternal(cc, isGlobal2) {
|
|
1454
|
+
const { src, start, end } = cc;
|
|
1455
|
+
const app = cc.app;
|
|
1456
|
+
const { scope } = app.context;
|
|
1457
|
+
const { srcModule } = app.stable;
|
|
1458
|
+
const originalName = src.slice(start, end);
|
|
1459
|
+
const kind2 = "decl";
|
|
1460
|
+
const declElem = null;
|
|
1461
|
+
const ident2 = {
|
|
1462
|
+
declElem,
|
|
1463
|
+
kind: kind2,
|
|
1464
|
+
originalName,
|
|
1465
|
+
scope,
|
|
1466
|
+
isGlobal: isGlobal2,
|
|
1467
|
+
id: nextIdentId(),
|
|
1468
|
+
srcModule
|
|
1469
|
+
};
|
|
1470
|
+
const identElem = { kind: kind2, start, end, srcModule, ident: ident2 };
|
|
1471
|
+
saveIdent(cc, identElem);
|
|
1472
|
+
addToOpenElem(cc, identElem);
|
|
1473
|
+
return identElem;
|
|
1474
|
+
}
|
|
1475
|
+
const typedDecl = collectElem(
|
|
1476
|
+
"typeDecl",
|
|
1477
|
+
(cc, openElem) => {
|
|
1478
|
+
var _a, _b;
|
|
1479
|
+
const decl = (_a = cc.tags.decl_elem) == null ? void 0 : _a[0];
|
|
1480
|
+
const typeRef = (_b = cc.tags.typeRefElem) == null ? void 0 : _b[0];
|
|
1481
|
+
const partial = { ...openElem, decl, typeRef };
|
|
1482
|
+
const elem = withTextCover(partial, cc);
|
|
1483
|
+
return elem;
|
|
1484
|
+
}
|
|
1485
|
+
);
|
|
1486
|
+
function saveIdent(cc, identElem) {
|
|
1487
|
+
const { ident: ident2 } = identElem;
|
|
1488
|
+
ident2.id = nextIdentId();
|
|
1489
|
+
const weslContext = cc.app.context;
|
|
1490
|
+
weslContext.scope.contents.push(ident2);
|
|
1491
|
+
}
|
|
1492
|
+
function startScope(cc) {
|
|
1493
|
+
startSomeScope("scope", cc);
|
|
1494
|
+
}
|
|
1495
|
+
function startPartialScope(cc) {
|
|
1496
|
+
startSomeScope("partial", cc);
|
|
1497
|
+
}
|
|
1498
|
+
function startSomeScope(kind2, cc) {
|
|
1499
|
+
const { scope } = cc.app.context;
|
|
1500
|
+
const newScope = emptyScope(scope, kind2);
|
|
1501
|
+
scope.contents.push(newScope);
|
|
1502
|
+
cc.app.context.scope = newScope;
|
|
1503
|
+
}
|
|
1504
|
+
function completeScope(cc) {
|
|
1505
|
+
const weslContext = cc.app.context;
|
|
1506
|
+
const completedScope = weslContext.scope;
|
|
1507
|
+
const ifAttributes = collectIfAttributes(cc);
|
|
1508
|
+
const { parent } = completedScope;
|
|
1509
|
+
if (parent) {
|
|
1510
|
+
weslContext.scope = parent;
|
|
1511
|
+
}
|
|
1512
|
+
completedScope.ifAttribute = ifAttributes == null ? void 0 : ifAttributes[0];
|
|
1513
|
+
return completedScope;
|
|
1514
|
+
}
|
|
1515
|
+
function collectIfAttributes(cc) {
|
|
1516
|
+
const attributes = cc.tags.attribute;
|
|
1517
|
+
return filterIfAttributes(attributes);
|
|
1518
|
+
}
|
|
1519
|
+
function filterIfAttributes(attributes) {
|
|
1520
|
+
if (!attributes) return;
|
|
1521
|
+
return filterMap(
|
|
1522
|
+
attributes,
|
|
1523
|
+
(a) => a.attribute.kind === "@if" ? a.attribute : void 0
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
function collectVarLike(kind2) {
|
|
1527
|
+
return collectElem(kind2, (cc, openElem) => {
|
|
1528
|
+
var _a, _b;
|
|
1529
|
+
const name2 = (_a = cc.tags.var_name) == null ? void 0 : _a[0];
|
|
1530
|
+
const decl_scope = (_b = cc.tags.decl_scope) == null ? void 0 : _b[0];
|
|
1531
|
+
const attributes = cc.tags.attribute;
|
|
1532
|
+
const partElem = { ...openElem, name: name2, attributes };
|
|
1533
|
+
const varElem = withTextCover(partElem, cc);
|
|
1534
|
+
name2.decl.ident.declElem = varElem;
|
|
1535
|
+
name2.decl.ident.scope = decl_scope;
|
|
1536
|
+
return varElem;
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
const aliasCollect = collectElem(
|
|
1540
|
+
"alias",
|
|
1541
|
+
(cc, openElem) => {
|
|
1542
|
+
var _a, _b, _c, _d;
|
|
1543
|
+
const name2 = (_a = cc.tags.alias_name) == null ? void 0 : _a[0];
|
|
1544
|
+
const alias_scope = (_b = cc.tags.alias_scope) == null ? void 0 : _b[0];
|
|
1545
|
+
const typeRef = (_c = cc.tags.typeRefElem) == null ? void 0 : _c[0];
|
|
1546
|
+
const attributes = ((_d = cc.tags.attributes) == null ? void 0 : _d.flat()) ?? [];
|
|
1547
|
+
const partElem = { ...openElem, name: name2, attributes, typeRef };
|
|
1548
|
+
const aliasElem = withTextCover(partElem, cc);
|
|
1549
|
+
name2.ident.scope = alias_scope;
|
|
1550
|
+
name2.ident.declElem = aliasElem;
|
|
1551
|
+
return aliasElem;
|
|
1552
|
+
}
|
|
1553
|
+
);
|
|
1554
|
+
const fnCollect = collectElem(
|
|
1555
|
+
"fn",
|
|
1556
|
+
(cc, openElem) => {
|
|
1557
|
+
var _a;
|
|
1558
|
+
const ourTags = fnTags(cc);
|
|
1559
|
+
const { name: name2, headerScope, returnScope, bodyScope, body, params } = ourTags;
|
|
1560
|
+
const { attributes, returnAttributes, returnType, fnScope } = ourTags;
|
|
1561
|
+
const fnElem = {
|
|
1562
|
+
...openElem,
|
|
1563
|
+
...{ name: name2, attributes, params, returnAttributes, body, returnType }
|
|
1564
|
+
};
|
|
1565
|
+
fnScope.ifAttribute = (_a = filterIfAttributes(attributes)) == null ? void 0 : _a[0];
|
|
1566
|
+
const mergedScope = headerScope;
|
|
1567
|
+
returnScope && mergeScope(mergedScope, returnScope);
|
|
1568
|
+
mergeScope(mergedScope, bodyScope);
|
|
1569
|
+
const filtered = [];
|
|
1570
|
+
for (const e of fnScope.contents) {
|
|
1571
|
+
if (e === headerScope || e == returnScope) {
|
|
1572
|
+
continue;
|
|
1573
|
+
} else if (e === bodyScope) {
|
|
1574
|
+
filtered.push(mergedScope);
|
|
1575
|
+
} else {
|
|
1576
|
+
filtered.push(e);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
fnScope.contents = filtered;
|
|
1580
|
+
name2.ident.declElem = fnElem;
|
|
1581
|
+
name2.ident.scope = mergedScope;
|
|
1582
|
+
return fnElem;
|
|
1583
|
+
}
|
|
1584
|
+
);
|
|
1585
|
+
function fnTags(cc) {
|
|
1586
|
+
const { fn_attributes, fn_name, fn_param, return_attributes } = cc.tags;
|
|
1587
|
+
const { return_type } = cc.tags;
|
|
1588
|
+
const { header_scope, return_scope, body_scope, body_statement } = cc.tags;
|
|
1589
|
+
const { fn_partial_scope } = cc.tags;
|
|
1590
|
+
const name2 = fn_name == null ? void 0 : fn_name[0];
|
|
1591
|
+
const headerScope = header_scope == null ? void 0 : header_scope[0];
|
|
1592
|
+
const returnScope = return_scope == null ? void 0 : return_scope[0];
|
|
1593
|
+
const bodyScope = body_scope == null ? void 0 : body_scope[0];
|
|
1594
|
+
const body = body_statement == null ? void 0 : body_statement[0];
|
|
1595
|
+
const params = (fn_param == null ? void 0 : fn_param.flat(3)) ?? [];
|
|
1596
|
+
const attributes = fn_attributes == null ? void 0 : fn_attributes.flat();
|
|
1597
|
+
const returnAttributes = return_attributes == null ? void 0 : return_attributes.flat();
|
|
1598
|
+
const returnType = return_type == null ? void 0 : return_type.flat(3)[0];
|
|
1599
|
+
const fnScope = fn_partial_scope == null ? void 0 : fn_partial_scope[0];
|
|
1600
|
+
return {
|
|
1601
|
+
...{ name: name2, headerScope, returnScope, bodyScope, body, params },
|
|
1602
|
+
...{ attributes, returnAttributes, returnType, fnScope }
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
const collectFnParam = collectElem(
|
|
1606
|
+
"param",
|
|
1607
|
+
(cc, openElem) => {
|
|
1608
|
+
var _a, _b;
|
|
1609
|
+
const name2 = (_a = cc.tags.param_name) == null ? void 0 : _a[0];
|
|
1610
|
+
const attributes = ((_b = cc.tags.attributes) == null ? void 0 : _b.flat()) ?? [];
|
|
1611
|
+
const elem = { ...openElem, name: name2, attributes };
|
|
1612
|
+
const paramElem = withTextCover(elem, cc);
|
|
1613
|
+
name2.decl.ident.declElem = paramElem;
|
|
1614
|
+
return paramElem;
|
|
1615
|
+
}
|
|
1616
|
+
);
|
|
1617
|
+
const collectStruct = collectElem(
|
|
1618
|
+
"struct",
|
|
1619
|
+
(cc, openElem) => {
|
|
1620
|
+
var _a, _b, _c;
|
|
1621
|
+
const name2 = (_a = cc.tags.type_name) == null ? void 0 : _a[0];
|
|
1622
|
+
const members = cc.tags.members;
|
|
1623
|
+
const attributes = ((_b = cc.tags.attributes) == null ? void 0 : _b.flat()) ?? [];
|
|
1624
|
+
name2.ident.scope = (_c = cc.tags.struct_scope) == null ? void 0 : _c[0];
|
|
1625
|
+
const structElem = { ...openElem, name: name2, attributes, members };
|
|
1626
|
+
const elem = withTextCover(structElem, cc);
|
|
1627
|
+
name2.ident.declElem = elem;
|
|
1628
|
+
return elem;
|
|
1629
|
+
}
|
|
1630
|
+
);
|
|
1631
|
+
const collectStructMember = collectElem(
|
|
1632
|
+
"member",
|
|
1633
|
+
(cc, openElem) => {
|
|
1634
|
+
var _a, _b, _c;
|
|
1635
|
+
const name2 = (_a = cc.tags.nameElem) == null ? void 0 : _a[0];
|
|
1636
|
+
const typeRef = (_b = cc.tags.typeRefElem) == null ? void 0 : _b[0];
|
|
1637
|
+
const attributes = (_c = cc.tags.attribute) == null ? void 0 : _c.flat(3);
|
|
1638
|
+
const partElem = { ...openElem, name: name2, attributes, typeRef };
|
|
1639
|
+
return withTextCover(partElem, cc);
|
|
1640
|
+
}
|
|
1641
|
+
);
|
|
1642
|
+
const specialAttribute = collectElem(
|
|
1643
|
+
"attribute",
|
|
1644
|
+
(cc, openElem) => {
|
|
1645
|
+
var _a;
|
|
1646
|
+
const attribute = (_a = cc.tags.attr_variant) == null ? void 0 : _a[0];
|
|
1647
|
+
const attrElem = { ...openElem, attribute };
|
|
1648
|
+
return attrElem;
|
|
1649
|
+
}
|
|
1650
|
+
);
|
|
1651
|
+
const assertCollect = attrElemCollect("assert");
|
|
1652
|
+
const statementCollect = attrElemCollect("statement");
|
|
1653
|
+
const switchClauseCollect = attrElemCollect("switch-clause");
|
|
1654
|
+
function attrElemCollect(kind2) {
|
|
1655
|
+
return collectElem(kind2, (cc, openElem) => {
|
|
1656
|
+
var _a;
|
|
1657
|
+
const attributes = (_a = cc.tags.attribute) == null ? void 0 : _a.flat(3);
|
|
1658
|
+
const partElem = { ...openElem, attributes };
|
|
1659
|
+
return withTextCover(partElem, cc);
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
const collectAttribute = collectElem(
|
|
1663
|
+
"attribute",
|
|
1664
|
+
(cc, openElem) => {
|
|
1665
|
+
var _a;
|
|
1666
|
+
const params = cc.tags.attrParam;
|
|
1667
|
+
const name2 = (_a = cc.tags.name) == null ? void 0 : _a[0];
|
|
1668
|
+
const kind2 = "@attribute";
|
|
1669
|
+
const stdAttribute = { kind: kind2, name: name2, params };
|
|
1670
|
+
const attrElem = { ...openElem, attribute: stdAttribute };
|
|
1671
|
+
return attrElem;
|
|
1672
|
+
}
|
|
1673
|
+
);
|
|
1674
|
+
const typeRefCollect = collectElem(
|
|
1675
|
+
"type",
|
|
1676
|
+
// @ts-ignore
|
|
1677
|
+
(cc, openElem) => {
|
|
1678
|
+
var _a, _b;
|
|
1679
|
+
let templateParamsTemp = (_a = cc.tags.templateParam) == null ? void 0 : _a.flat(3);
|
|
1680
|
+
const typeRef = (_b = cc.tags.typeRefName) == null ? void 0 : _b[0];
|
|
1681
|
+
const name2 = typeof typeRef === "string" ? typeRef : typeRef.ident;
|
|
1682
|
+
const partElem = {
|
|
1683
|
+
...openElem,
|
|
1684
|
+
name: name2,
|
|
1685
|
+
templateParams: templateParamsTemp
|
|
1686
|
+
};
|
|
1687
|
+
return withTextCover(partElem, cc);
|
|
1688
|
+
}
|
|
1689
|
+
);
|
|
1690
|
+
const expressionCollect = collectElem(
|
|
1691
|
+
"expression",
|
|
1692
|
+
(cc, openElem) => {
|
|
1693
|
+
const partElem = { ...openElem };
|
|
1694
|
+
return withTextCover(partElem, cc);
|
|
1695
|
+
}
|
|
1696
|
+
);
|
|
1697
|
+
function globalAssertCollect(cc) {
|
|
1698
|
+
var _a;
|
|
1699
|
+
const globalAssert = (_a = cc.tags.const_assert) == null ? void 0 : _a.flat()[0];
|
|
1700
|
+
const ast = cc.app.stable;
|
|
1701
|
+
if (!ast.moduleAsserts) ast.moduleAsserts = [];
|
|
1702
|
+
ast.moduleAsserts.push(globalAssert);
|
|
1703
|
+
}
|
|
1704
|
+
const stuffCollect = collectElem(
|
|
1705
|
+
"stuff",
|
|
1706
|
+
(cc, openElem) => {
|
|
1707
|
+
const partElem = { ...openElem };
|
|
1708
|
+
return withTextCover(partElem, cc);
|
|
1709
|
+
}
|
|
1710
|
+
);
|
|
1711
|
+
const memberRefCollect = collectElem(
|
|
1712
|
+
"memberRef",
|
|
1713
|
+
(cc, openElem) => {
|
|
1714
|
+
const { component, structRef, extra_components } = cc.tags;
|
|
1715
|
+
const member = component[0];
|
|
1716
|
+
const name2 = structRef == null ? void 0 : structRef.flat()[0];
|
|
1717
|
+
const extraComponents = extra_components == null ? void 0 : extra_components.flat()[0];
|
|
1718
|
+
const partElem = {
|
|
1719
|
+
...openElem,
|
|
1720
|
+
name: name2,
|
|
1721
|
+
member,
|
|
1722
|
+
extraComponents
|
|
1723
|
+
};
|
|
1724
|
+
return withTextCover(partElem, cc);
|
|
1725
|
+
}
|
|
1726
|
+
);
|
|
1727
|
+
function nameCollect(cc) {
|
|
1728
|
+
const { start, end, src, app } = cc;
|
|
1729
|
+
const name2 = src.slice(start, end);
|
|
1730
|
+
const elem = { kind: "name", start, end, name: name2 };
|
|
1731
|
+
addToOpenElem(cc, elem);
|
|
1732
|
+
return elem;
|
|
1733
|
+
}
|
|
1734
|
+
const collectModule = collectElem(
|
|
1735
|
+
"module",
|
|
1736
|
+
(cc, openElem) => {
|
|
1737
|
+
const ccComplete = { ...cc, start: 0, end: cc.src.length };
|
|
1738
|
+
const moduleElem = withTextCover(openElem, ccComplete);
|
|
1739
|
+
const weslState = cc.app.stable;
|
|
1740
|
+
weslState.moduleElem = moduleElem;
|
|
1741
|
+
return moduleElem;
|
|
1742
|
+
}
|
|
1743
|
+
);
|
|
1744
|
+
function directiveCollect(cc) {
|
|
1745
|
+
var _a, _b;
|
|
1746
|
+
const { start, end } = cc;
|
|
1747
|
+
const directive = (_a = cc.tags.directive) == null ? void 0 : _a.flat()[0];
|
|
1748
|
+
const attributes = (_b = cc.tags.attribute) == null ? void 0 : _b.flat();
|
|
1749
|
+
const kind2 = "directive";
|
|
1750
|
+
const elem = { kind: kind2, attributes, start, end, directive };
|
|
1751
|
+
addToOpenElem(cc, elem);
|
|
1752
|
+
return elem;
|
|
1753
|
+
}
|
|
1754
|
+
const scopeCollect = {
|
|
1755
|
+
before: startScope,
|
|
1756
|
+
after: completeScope
|
|
1757
|
+
};
|
|
1758
|
+
const partialScopeCollect = {
|
|
1759
|
+
before: startPartialScope,
|
|
1760
|
+
after: completeScope
|
|
1761
|
+
};
|
|
1762
|
+
function collectElem(kind2, fn2) {
|
|
1763
|
+
return {
|
|
1764
|
+
before: (cc) => {
|
|
1765
|
+
const partialElem = { kind: kind2, contents: [] };
|
|
1766
|
+
const weslContext = cc.app.context;
|
|
1767
|
+
weslContext.openElems.push(partialElem);
|
|
1768
|
+
},
|
|
1769
|
+
after: (cc) => {
|
|
1770
|
+
const weslContext = cc.app.context;
|
|
1771
|
+
const partialElem = weslContext.openElems.pop();
|
|
1772
|
+
console.assert(partialElem && partialElem.kind === kind2);
|
|
1773
|
+
const elem = fn2(cc, { ...partialElem, start: cc.start, end: cc.end });
|
|
1774
|
+
if (elem) addToOpenElem(cc, elem);
|
|
1775
|
+
return elem;
|
|
1776
|
+
}
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
function withTextCover(elem, cc) {
|
|
1780
|
+
const contents = coverWithText(cc, elem);
|
|
1781
|
+
return { ...elem, contents };
|
|
1782
|
+
}
|
|
1783
|
+
function coverWithText(cc, elem) {
|
|
1784
|
+
let { start: pos } = cc;
|
|
1785
|
+
const ast = cc.app.stable;
|
|
1786
|
+
const { contents, end } = elem;
|
|
1787
|
+
const sorted = contents.sort((a, b) => a.start - b.start);
|
|
1788
|
+
const elems = [];
|
|
1789
|
+
for (const elem2 of sorted) {
|
|
1790
|
+
if (pos < elem2.start) {
|
|
1791
|
+
elems.push(makeTextElem(elem2.start));
|
|
1792
|
+
}
|
|
1793
|
+
elems.push(elem2);
|
|
1794
|
+
pos = elem2.end;
|
|
1795
|
+
}
|
|
1796
|
+
if (pos < end) {
|
|
1797
|
+
elems.push(makeTextElem(end));
|
|
1798
|
+
}
|
|
1799
|
+
return elems;
|
|
1800
|
+
function makeTextElem(end2) {
|
|
1801
|
+
return { kind: "text", start: pos, end: end2, srcModule: ast.srcModule };
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
const word = kind("word");
|
|
1805
|
+
kind("keyword");
|
|
1806
|
+
const qualified_ident = withSepPlus("::", or(word, "package", "super"));
|
|
1807
|
+
const number = kind("number");
|
|
1808
|
+
function makeStatement(segments, finalSegment) {
|
|
1809
|
+
return { kind: "import-statement", segments, finalSegment };
|
|
1810
|
+
}
|
|
1811
|
+
function makeSegment(name2) {
|
|
1812
|
+
return { kind: "import-segment", name: name2 };
|
|
1813
|
+
}
|
|
1814
|
+
function makeCollection(subtrees) {
|
|
1815
|
+
return {
|
|
1816
|
+
kind: "import-collection",
|
|
1817
|
+
subtrees
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
function makeItem(name2, as) {
|
|
1821
|
+
return { kind: "import-item", name: name2, as };
|
|
1822
|
+
}
|
|
1823
|
+
function prependSegments(segments, statement2) {
|
|
1824
|
+
statement2.segments = segments.concat(statement2.segments);
|
|
1825
|
+
return statement2;
|
|
1826
|
+
}
|
|
1827
|
+
let import_collection = null;
|
|
1828
|
+
const import_path_or_item = seq(
|
|
1829
|
+
word,
|
|
1830
|
+
or(
|
|
1831
|
+
preceded(
|
|
1832
|
+
"::",
|
|
1833
|
+
req(
|
|
1834
|
+
or(
|
|
1835
|
+
fn(() => import_collection),
|
|
1836
|
+
fn(() => import_path_or_item)
|
|
1837
|
+
),
|
|
1838
|
+
"invalid import, expected '{' or name"
|
|
1839
|
+
)
|
|
1840
|
+
),
|
|
1841
|
+
preceded("as", req(word, "invalid alias, expected name")).map(
|
|
1842
|
+
(v) => makeItem("", v)
|
|
1843
|
+
),
|
|
1844
|
+
yes().map(() => makeItem(""))
|
|
1845
|
+
// Optional
|
|
1846
|
+
)
|
|
1847
|
+
).map(([name2, next]) => {
|
|
1848
|
+
if (next.kind === "import-collection") {
|
|
1849
|
+
return makeStatement([makeSegment(name2)], next);
|
|
1850
|
+
} else if (next.kind === "import-statement") {
|
|
1851
|
+
return prependSegments([makeSegment(name2)], next);
|
|
1852
|
+
} else if (next.kind === "import-item") {
|
|
1853
|
+
next.name = name2;
|
|
1854
|
+
return makeStatement([], next);
|
|
1855
|
+
} else {
|
|
1856
|
+
assertUnreachable(next);
|
|
1857
|
+
}
|
|
1858
|
+
});
|
|
1859
|
+
import_collection = delimited(
|
|
1860
|
+
"{",
|
|
1861
|
+
withSepPlus(",", () => import_path_or_item).map(makeCollection),
|
|
1862
|
+
req("}", "invalid import collection, expected }")
|
|
1863
|
+
);
|
|
1864
|
+
const import_relative = or(
|
|
1865
|
+
terminated("package", req("::", "invalid import, expected '::'")).map((v) => [
|
|
1866
|
+
makeSegment(v)
|
|
1867
|
+
]),
|
|
1868
|
+
repeatPlus(
|
|
1869
|
+
terminated("super", req("::", "invalid import, expected '::'")).map(
|
|
1870
|
+
makeSegment
|
|
1871
|
+
)
|
|
1872
|
+
)
|
|
1873
|
+
);
|
|
1874
|
+
const import_statement = span(
|
|
1875
|
+
delimited(
|
|
1876
|
+
"import",
|
|
1877
|
+
seqObj({
|
|
1878
|
+
relative: opt(import_relative),
|
|
1879
|
+
collection_or_statement: req(
|
|
1880
|
+
or(import_collection, import_path_or_item),
|
|
1881
|
+
"invalid import, expected { or name"
|
|
1882
|
+
)
|
|
1883
|
+
}).map(({ relative, collection_or_statement }) => {
|
|
1884
|
+
if (collection_or_statement.kind === "import-statement") {
|
|
1885
|
+
return prependSegments(relative ?? [], collection_or_statement);
|
|
1886
|
+
} else {
|
|
1887
|
+
return makeStatement(relative ?? [], collection_or_statement);
|
|
1888
|
+
}
|
|
1889
|
+
}),
|
|
1890
|
+
req(";", "invalid import, expected ';'")
|
|
1891
|
+
)
|
|
1892
|
+
).map(
|
|
1893
|
+
(v) => ({
|
|
1894
|
+
kind: "import",
|
|
1895
|
+
imports: v.value,
|
|
1896
|
+
start: v.span[0],
|
|
1897
|
+
end: v.span[1]
|
|
1898
|
+
})
|
|
1899
|
+
);
|
|
1900
|
+
const weslImports = tagScope(
|
|
1901
|
+
repeat(import_statement).ptag("owo").collect(importElem)
|
|
1902
|
+
);
|
|
1903
|
+
const keywords = `alias break case const const_assert continue continuing
|
|
1904
|
+
default diagnostic discard else enable false fn for if
|
|
1905
|
+
let loop override requires return struct switch true var while`.split(/\s+/);
|
|
1906
|
+
const reservedWords = `NULL Self abstract active alignas alignof as asm asm_fragment async attribute auto await
|
|
1907
|
+
become binding_array cast catch class co_await co_return co_yield coherent column_major
|
|
1908
|
+
common compile compile_fragment concept const_cast consteval constexpr constinit crate
|
|
1909
|
+
debugger decltype delete demote demote_to_helper do dynamic_cast
|
|
1910
|
+
enum explicit export extends extern external fallthrough filter final finally friend from fxgroup
|
|
1911
|
+
get goto groupshared highp impl implements import inline instanceof interface layout lowp
|
|
1912
|
+
macro macro_rules match mediump meta mod module move mut mutable
|
|
1913
|
+
namespace new nil noexcept noinline nointerpolation non_coherent noncoherent noperspective null nullptr
|
|
1914
|
+
of operator package packoffset partition pass patch pixelfragment precise precision premerge
|
|
1915
|
+
priv protected pub public readonly ref regardless register reinterpret_cast require resource restrict
|
|
1916
|
+
self set shared sizeof smooth snorm static static_assert static_cast std subroutine super
|
|
1917
|
+
target template this thread_local throw trait try type typedef typeid typename typeof
|
|
1918
|
+
union unless unorm unsafe unsized use using varying virtual volatile wgsl where with writeonly yield`.split(
|
|
1919
|
+
/\s+/
|
|
1920
|
+
);
|
|
1921
|
+
const blankspaces = /[ \t\n\v\f\r\u{0085}\u{200E}\u{200F}\u{2028}\u{2029}]+/u;
|
|
1922
|
+
const symbolSet = "& && -> @ / ! [ ] { } :: : , == = != >>= >> >= > <<= << <= < % - -- . + ++ | || ( ) ; * ~ ^ // /* */ += -= *= /= %= &= |= ^= _";
|
|
1923
|
+
const ident = /(?:(?:[_\p{XID_Start}][\p{XID_Continue}]+)|(?:[\p{XID_Start}]))/u;
|
|
1924
|
+
const keywordOrReserved = new Set(keywords.concat(reservedWords));
|
|
1925
|
+
const digits = new RegExp(
|
|
1926
|
+
// decimal_float_literal
|
|
1927
|
+
/(?:0[fh])|(?:[1-9][0-9]*[fh])/.source + /|(?:[0-9]*\.[0-9]+(?:[eE][+-]?[0-9]+)?[fh]?)/.source + /|(?:[0-9]+\.[0-9]*(?:[eE][+-]?[0-9]+)?[fh]?)/.source + /|(?:[0-9]+[eE][+-]?[0-9]+[fh]?)/.source + // hex_float_literal
|
|
1928
|
+
/|(?:0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+(?:[pP][+-]?[0-9]+[fh]?)?)/.source + /|(?:0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*(?:[pP][+-]?[0-9]+[fh]?)?)/.source + /|(?:0[xX][0-9a-fA-F]+[pP][+-]?[0-9]+[fh]?)/.source + // hex_int_literal
|
|
1929
|
+
/|(?:0[xX][0-9a-fA-F]+[iu]?)/.source + // decimal_int_literal
|
|
1930
|
+
/|(?:0[iu]?)|(?:[1-9][0-9]*[iu]?)/.source
|
|
1931
|
+
);
|
|
1932
|
+
const commentStart = /\/\/|\/\*/;
|
|
1933
|
+
const weslMatcher = new RegexMatchers({
|
|
1934
|
+
word: ident,
|
|
1935
|
+
number: digits,
|
|
1936
|
+
blankspaces,
|
|
1937
|
+
commentStart,
|
|
1938
|
+
symbol: matchOneOf(symbolSet),
|
|
1939
|
+
invalid: /[^]/
|
|
1940
|
+
});
|
|
1941
|
+
function weslExtension(combinator) {
|
|
1942
|
+
return combinator;
|
|
1943
|
+
}
|
|
1944
|
+
class WeslStream {
|
|
1945
|
+
constructor(src) {
|
|
1946
|
+
this.src = src;
|
|
1947
|
+
this.eolPattern = /[\n\v\f\u{0085}\u{2028}\u{2029}]|\r\n?/gu;
|
|
1948
|
+
this.blockCommentPattern = /\/\*|\*\//g;
|
|
1949
|
+
this.stream = new CachingStream(new MatchersStream(src, weslMatcher));
|
|
1950
|
+
}
|
|
1951
|
+
checkpoint() {
|
|
1952
|
+
return this.stream.checkpoint();
|
|
1953
|
+
}
|
|
1954
|
+
reset(position) {
|
|
1955
|
+
this.stream.reset(position);
|
|
1956
|
+
}
|
|
1957
|
+
nextToken() {
|
|
1958
|
+
while (true) {
|
|
1959
|
+
const token2 = this.stream.nextToken();
|
|
1960
|
+
if (token2 === null) return null;
|
|
1961
|
+
const kind2 = token2.kind;
|
|
1962
|
+
if (kind2 === "blankspaces") {
|
|
1963
|
+
continue;
|
|
1964
|
+
} else if (kind2 === "commentStart") {
|
|
1965
|
+
if (token2.text === "//") {
|
|
1966
|
+
this.stream.reset(this.skipToEol(token2.span[1]));
|
|
1967
|
+
} else {
|
|
1968
|
+
this.stream.reset(this.skipBlockComment(token2.span[1]));
|
|
1969
|
+
}
|
|
1970
|
+
} else if (kind2 === "word") {
|
|
1971
|
+
let returnToken = token2;
|
|
1972
|
+
if (keywordOrReserved.has(token2.text)) {
|
|
1973
|
+
returnToken.kind = "keyword";
|
|
1974
|
+
}
|
|
1975
|
+
return returnToken;
|
|
1976
|
+
} else if (kind2 === "invalid") {
|
|
1977
|
+
throw new ParseError(
|
|
1978
|
+
"Invalid token " + token2.text,
|
|
1979
|
+
this.stream.checkpoint()
|
|
1980
|
+
);
|
|
1981
|
+
} else {
|
|
1982
|
+
return token2;
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
skipToEol(position) {
|
|
1987
|
+
this.eolPattern.lastIndex = position;
|
|
1988
|
+
const result = this.eolPattern.exec(this.src);
|
|
1989
|
+
if (result === null) {
|
|
1990
|
+
return this.src.length;
|
|
1991
|
+
} else {
|
|
1992
|
+
return this.eolPattern.lastIndex;
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
skipBlockComment(position) {
|
|
1996
|
+
while (true) {
|
|
1997
|
+
this.blockCommentPattern.lastIndex = position;
|
|
1998
|
+
const result = this.blockCommentPattern.exec(this.src);
|
|
1999
|
+
if (result === null) {
|
|
2000
|
+
throw new ParseError("Unclosed block comment!", position);
|
|
2001
|
+
} else if (result[0] === "*/") {
|
|
2002
|
+
return this.blockCommentPattern.lastIndex;
|
|
2003
|
+
} else if (result[0] === "/*") {
|
|
2004
|
+
position = this.skipBlockComment(this.blockCommentPattern.lastIndex);
|
|
2005
|
+
} else {
|
|
2006
|
+
throw new Error("Unreachable, invalid block comment pattern");
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
/**
|
|
2011
|
+
* Only matches the `<` token if it is a template
|
|
2012
|
+
* Precondition: An ident was parsed right before this.
|
|
2013
|
+
* Runs the [template list discovery algorithm](https://www.w3.org/TR/WGSL/#template-list-discovery).
|
|
2014
|
+
*/
|
|
2015
|
+
nextTemplateStartToken() {
|
|
2016
|
+
const startPosition = this.stream.checkpoint();
|
|
2017
|
+
const token2 = this.nextToken();
|
|
2018
|
+
this.stream.reset(startPosition);
|
|
2019
|
+
if (token2 === null) return null;
|
|
2020
|
+
if (token2.kind !== "symbol") {
|
|
2021
|
+
return null;
|
|
2022
|
+
}
|
|
2023
|
+
if (token2.text === "<") {
|
|
2024
|
+
if (this.isTemplateStart(token2.span[1])) {
|
|
2025
|
+
this.stream.reset(token2.span[1]);
|
|
2026
|
+
return token2;
|
|
2027
|
+
} else {
|
|
2028
|
+
this.stream.reset(startPosition);
|
|
2029
|
+
return null;
|
|
2030
|
+
}
|
|
2031
|
+
} else {
|
|
2032
|
+
return null;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
nextTemplateEndToken() {
|
|
2036
|
+
const startPosition = this.stream.checkpoint();
|
|
2037
|
+
const token2 = this.nextToken();
|
|
2038
|
+
this.stream.reset(startPosition);
|
|
2039
|
+
if (token2 === null) return null;
|
|
2040
|
+
if (token2.kind === "symbol" && token2.text[0] === ">") {
|
|
2041
|
+
const tokenPosition = token2.span[0];
|
|
2042
|
+
this.stream.reset(tokenPosition + 1);
|
|
2043
|
+
return {
|
|
2044
|
+
kind: "symbol",
|
|
2045
|
+
span: [tokenPosition, tokenPosition + 1],
|
|
2046
|
+
text: ">"
|
|
2047
|
+
};
|
|
2048
|
+
} else {
|
|
2049
|
+
return null;
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
isTemplateStart(afterToken) {
|
|
2053
|
+
this.stream.reset(afterToken);
|
|
2054
|
+
let pendingCounter = 1;
|
|
2055
|
+
while (true) {
|
|
2056
|
+
const nextToken = this.stream.nextToken();
|
|
2057
|
+
if (nextToken === null) return false;
|
|
2058
|
+
if (nextToken.kind !== "symbol") continue;
|
|
2059
|
+
if (nextToken.text === "<") {
|
|
2060
|
+
pendingCounter += 1;
|
|
2061
|
+
} else if (nextToken.text[0] === ">") {
|
|
2062
|
+
if (nextToken.text === ">" || nextToken.text == ">=") {
|
|
2063
|
+
pendingCounter -= 1;
|
|
2064
|
+
} else if (nextToken.text === ">>=" || nextToken.text === ">>") {
|
|
2065
|
+
pendingCounter -= 2;
|
|
2066
|
+
} else {
|
|
2067
|
+
throw new Error(
|
|
2068
|
+
"This case should never be reached, looks like we forgot one of the tokens that start with >"
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
if (pendingCounter <= 0) {
|
|
2072
|
+
return true;
|
|
2073
|
+
}
|
|
2074
|
+
} else if (nextToken.text === "(") {
|
|
2075
|
+
this.skipBracketsTo(")");
|
|
2076
|
+
} else if (nextToken.text === "[") {
|
|
2077
|
+
this.skipBracketsTo("]");
|
|
2078
|
+
} else if (nextToken.text === "==" || nextToken.text === "!=" || nextToken.text === ";" || nextToken.text === "{" || nextToken.text === ":" || nextToken.text === "&&" || nextToken.text === "||") {
|
|
2079
|
+
return false;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
/**
|
|
2084
|
+
* Call this after consuming an opening bracket.
|
|
2085
|
+
* Skips until a closing bracket. This also consumes the closing bracket.
|
|
2086
|
+
*/
|
|
2087
|
+
skipBracketsTo(closingBracket) {
|
|
2088
|
+
while (true) {
|
|
2089
|
+
const nextToken = this.stream.nextToken();
|
|
2090
|
+
if (nextToken === null)
|
|
2091
|
+
throw new ParseError("Unclosed bracket!", this.stream.checkpoint());
|
|
2092
|
+
if (nextToken.kind !== "symbol") continue;
|
|
2093
|
+
if (nextToken.text === "(") {
|
|
2094
|
+
this.skipBracketsTo(")");
|
|
2095
|
+
} else if (nextToken.text === "[") {
|
|
2096
|
+
this.skipBracketsTo("]");
|
|
2097
|
+
} else if (nextToken.text === closingBracket) {
|
|
2098
|
+
return;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
const templateOpen = withStreamAction((stream) => {
|
|
2104
|
+
return stream.nextTemplateStartToken();
|
|
2105
|
+
});
|
|
2106
|
+
const templateClose = withStreamAction((stream) => {
|
|
2107
|
+
return stream.nextTemplateEndToken();
|
|
2108
|
+
});
|
|
2109
|
+
const opt_template_list = opt(
|
|
2110
|
+
seq(
|
|
2111
|
+
templateOpen,
|
|
2112
|
+
withSepPlus(",", () => template_parameter),
|
|
2113
|
+
req(templateClose, "invalid template, expected '>'")
|
|
2114
|
+
)
|
|
2115
|
+
);
|
|
2116
|
+
const template_elaborated_ident = seq(
|
|
2117
|
+
qualified_ident.collect(refIdent),
|
|
2118
|
+
opt_template_list
|
|
2119
|
+
);
|
|
2120
|
+
const literal = or("true", "false", number);
|
|
2121
|
+
const paren_expression = seq(
|
|
2122
|
+
"(",
|
|
2123
|
+
() => expression,
|
|
2124
|
+
req(")", "invalid expression, expected ')'")
|
|
2125
|
+
);
|
|
2126
|
+
const primary_expression = or(
|
|
2127
|
+
literal,
|
|
2128
|
+
paren_expression,
|
|
2129
|
+
seq(template_elaborated_ident, opt(fn(() => argument_expression_list)))
|
|
2130
|
+
);
|
|
2131
|
+
const component_or_swizzle = repeatPlus(
|
|
2132
|
+
or(
|
|
2133
|
+
preceded(".", word),
|
|
2134
|
+
collectArray(
|
|
2135
|
+
delimited(
|
|
2136
|
+
"[",
|
|
2137
|
+
() => expression,
|
|
2138
|
+
req("]", "invalid expression, expected ']'")
|
|
2139
|
+
)
|
|
2140
|
+
)
|
|
2141
|
+
)
|
|
2142
|
+
);
|
|
2143
|
+
const simple_component_reference = tagScope(
|
|
2144
|
+
seq(
|
|
2145
|
+
qualified_ident.collect(refIdent, "structRef"),
|
|
2146
|
+
seq(".", word.collect(nameCollect, "component")),
|
|
2147
|
+
opt(component_or_swizzle.collect(stuffCollect, "extra_components"))
|
|
2148
|
+
).collect(memberRefCollect)
|
|
2149
|
+
);
|
|
2150
|
+
const unary_expression = or(
|
|
2151
|
+
seq(tokenOf("symbol", ["!", "&", "*", "-", "~"]), () => unary_expression),
|
|
2152
|
+
or(
|
|
2153
|
+
simple_component_reference,
|
|
2154
|
+
seq(primary_expression, opt(component_or_swizzle))
|
|
2155
|
+
)
|
|
2156
|
+
);
|
|
2157
|
+
const bitwise_post_unary = or(
|
|
2158
|
+
// LATER I can skip template list discovery in these cases, because a&b<c cannot be a comparison. Must be a template
|
|
2159
|
+
repeatPlus(seq("&", unary_expression)),
|
|
2160
|
+
repeatPlus(seq("^", unary_expression)),
|
|
2161
|
+
repeatPlus(seq("|", unary_expression))
|
|
2162
|
+
);
|
|
2163
|
+
const multiplicative_operator = or("%", "*", "/");
|
|
2164
|
+
const additive_operator = or("+", "-");
|
|
2165
|
+
const shift_post_unary = (inTemplate) => {
|
|
2166
|
+
const shift_left = seq("<<", unary_expression);
|
|
2167
|
+
const shift_right = seq(">>", unary_expression);
|
|
2168
|
+
const mul_add = seq(
|
|
2169
|
+
repeat(seq(multiplicative_operator, unary_expression)),
|
|
2170
|
+
repeat(
|
|
2171
|
+
seq(
|
|
2172
|
+
additive_operator,
|
|
2173
|
+
unary_expression,
|
|
2174
|
+
repeat(seq(multiplicative_operator, unary_expression))
|
|
2175
|
+
)
|
|
2176
|
+
)
|
|
2177
|
+
);
|
|
2178
|
+
return inTemplate ? or(shift_left, mul_add) : or(shift_left, shift_right, mul_add);
|
|
2179
|
+
};
|
|
2180
|
+
const relational_post_unary = (inTemplate) => {
|
|
2181
|
+
return seq(
|
|
2182
|
+
shift_post_unary(inTemplate),
|
|
2183
|
+
opt(
|
|
2184
|
+
seq(
|
|
2185
|
+
// '<' is unambiguous, since templates were already caught by the primary expression inside of the previous unary_expression!
|
|
2186
|
+
inTemplate ? tokenOf("symbol", ["<", "<=", "!=", "=="]) : tokenOf("symbol", [">", ">=", "<", "<=", "!=", "=="]),
|
|
2187
|
+
// LATER I can skip template list discovery in this cases, because a>=b<c cannot be a comparison. Must be a template
|
|
2188
|
+
unary_expression,
|
|
2189
|
+
shift_post_unary(inTemplate)
|
|
2190
|
+
)
|
|
2191
|
+
)
|
|
2192
|
+
);
|
|
2193
|
+
};
|
|
2194
|
+
const expressionParser = (inTemplate) => {
|
|
2195
|
+
return seq(
|
|
2196
|
+
unary_expression,
|
|
2197
|
+
or(
|
|
2198
|
+
bitwise_post_unary,
|
|
2199
|
+
seq(
|
|
2200
|
+
relational_post_unary(inTemplate),
|
|
2201
|
+
inTemplate ? (
|
|
2202
|
+
// Don't accept || or && in template mode
|
|
2203
|
+
yes()
|
|
2204
|
+
) : or(
|
|
2205
|
+
repeatPlus(
|
|
2206
|
+
seq("||", seq(unary_expression, relational_post_unary(false)))
|
|
2207
|
+
),
|
|
2208
|
+
repeatPlus(
|
|
2209
|
+
seq("&&", seq(unary_expression, relational_post_unary(false)))
|
|
2210
|
+
),
|
|
2211
|
+
yes().map(() => [])
|
|
2212
|
+
)
|
|
2213
|
+
)
|
|
2214
|
+
)
|
|
2215
|
+
);
|
|
2216
|
+
};
|
|
2217
|
+
let maybe_template = false;
|
|
2218
|
+
const expression = expressionParser(maybe_template);
|
|
2219
|
+
let is_template = true;
|
|
2220
|
+
const template_arg_expression = expressionParser(is_template);
|
|
2221
|
+
const std_type_specifier = seq(
|
|
2222
|
+
qualified_ident.collect(refIdent, "typeRefName"),
|
|
2223
|
+
() => opt_template_list
|
|
2224
|
+
).collect(typeRefCollect);
|
|
2225
|
+
const type_specifier = tagScope(
|
|
2226
|
+
std_type_specifier
|
|
2227
|
+
).ctag("typeRefElem");
|
|
2228
|
+
const template_parameter = or(
|
|
2229
|
+
// LATER Remove this, it's wrong. This should instead be done by inspecting the syntax tree.
|
|
2230
|
+
type_specifier.ctag("templateParam"),
|
|
2231
|
+
template_arg_expression.collect(expressionCollect, "templateParam")
|
|
2232
|
+
);
|
|
2233
|
+
const argument_expression_list = seq(
|
|
2234
|
+
"(",
|
|
2235
|
+
withSep(",", expression),
|
|
2236
|
+
req(")", "invalid fn arguments, expected ')'")
|
|
2237
|
+
);
|
|
2238
|
+
const name = tokenKind("word").map(makeName);
|
|
2239
|
+
const diagnostic_rule_name = seq(
|
|
2240
|
+
name,
|
|
2241
|
+
opt(preceded(".", req(name, "invalid diagnostic rule name, expected name")))
|
|
2242
|
+
);
|
|
2243
|
+
const diagnostic_control = delimited(
|
|
2244
|
+
"(",
|
|
2245
|
+
req(
|
|
2246
|
+
separated_pair(name, ",", diagnostic_rule_name),
|
|
2247
|
+
"invalid diagnostic control, expected rule name"
|
|
2248
|
+
),
|
|
2249
|
+
seq(opt(","), req(")", "invalid diagnostic control, expected ')'"))
|
|
2250
|
+
);
|
|
2251
|
+
const name_list = withSep(",", name, { requireOne: true });
|
|
2252
|
+
const special_attribute = tagScope(
|
|
2253
|
+
preceded(
|
|
2254
|
+
"@",
|
|
2255
|
+
or(
|
|
2256
|
+
// These attributes have no arguments
|
|
2257
|
+
or("compute", "const", "fragment", "invariant", "must_use", "vertex").map((name2) => makeStandardAttribute([name2, []])),
|
|
2258
|
+
// These attributes have arguments, but the argument doesn't have any identifiers
|
|
2259
|
+
preceded("interpolate", req(delimited("(", name_list, ")"), "invalid @interpolate, expected '('")).map(makeInterpolateAttribute),
|
|
2260
|
+
preceded("builtin", req(delimited("(", name, ")"), "invalid @builtin, expected '('")).map(makeBuiltinAttribute),
|
|
2261
|
+
preceded("diagnostic", req(diagnostic_control, "invalid @diagnostic, expected '('")).map(makeDiagnosticAttribute)
|
|
2262
|
+
).ptag("attr_variant")
|
|
2263
|
+
).collect(specialAttribute)
|
|
2264
|
+
);
|
|
2265
|
+
const if_attribute = tagScope(
|
|
2266
|
+
preceded(
|
|
2267
|
+
seq("@", weslExtension("if")),
|
|
2268
|
+
span(
|
|
2269
|
+
delimited(
|
|
2270
|
+
"(",
|
|
2271
|
+
fn(() => attribute_if_expression),
|
|
2272
|
+
seq(opt(","), ")")
|
|
2273
|
+
)
|
|
2274
|
+
).map(makeTranslateTimeExpressionElem)
|
|
2275
|
+
).map(makeIfAttribute).ptag("attr_variant").collect(specialAttribute)
|
|
2276
|
+
);
|
|
2277
|
+
const normal_attribute = tagScope(
|
|
2278
|
+
preceded(
|
|
2279
|
+
"@",
|
|
2280
|
+
or(
|
|
2281
|
+
// These are normal attributes, with required arguments
|
|
2282
|
+
seq(
|
|
2283
|
+
or(
|
|
2284
|
+
"workgroup_size",
|
|
2285
|
+
"align",
|
|
2286
|
+
"binding",
|
|
2287
|
+
"blend_src",
|
|
2288
|
+
"group",
|
|
2289
|
+
"id",
|
|
2290
|
+
"location",
|
|
2291
|
+
"size"
|
|
2292
|
+
).ptag("name"),
|
|
2293
|
+
req(() => attribute_argument_list, "invalid attribute, expected '('")
|
|
2294
|
+
),
|
|
2295
|
+
// Everything else is also a normal attribute, optional expression list
|
|
2296
|
+
seq(
|
|
2297
|
+
// we don't want this to interfere with if_attribute,
|
|
2298
|
+
// but not("if") isn't necessary for now, since 'if' is a keyword, not a word
|
|
2299
|
+
word.ptag("name"),
|
|
2300
|
+
opt(() => attribute_argument_list)
|
|
2301
|
+
)
|
|
2302
|
+
)
|
|
2303
|
+
).collect(collectAttribute)
|
|
2304
|
+
);
|
|
2305
|
+
const attribute_argument_list = delimited(
|
|
2306
|
+
"(",
|
|
2307
|
+
withSep(
|
|
2308
|
+
",",
|
|
2309
|
+
span(fn(() => expression)).collect(expressionCollect, "attrParam")
|
|
2310
|
+
// LATER These unknown expressions have decls inside of them, that's why they're tough to replace!
|
|
2311
|
+
),
|
|
2312
|
+
req(")", "invalid attribute arguments, expected ')'")
|
|
2313
|
+
);
|
|
2314
|
+
const attribute_no_if = or(
|
|
2315
|
+
special_attribute,
|
|
2316
|
+
normal_attribute
|
|
2317
|
+
).ctag("attribute");
|
|
2318
|
+
const attribute_incl_if = or(
|
|
2319
|
+
if_attribute,
|
|
2320
|
+
special_attribute,
|
|
2321
|
+
normal_attribute
|
|
2322
|
+
).ctag("attribute");
|
|
2323
|
+
const opt_attributes = repeat(attribute_incl_if);
|
|
2324
|
+
const opt_attributes_no_if = repeat(attribute_no_if);
|
|
2325
|
+
const globalTypeNameDecl = req(
|
|
2326
|
+
word.collect(globalDeclCollect, "type_name"),
|
|
2327
|
+
"invalid type name, expected a name"
|
|
2328
|
+
);
|
|
2329
|
+
const fnNameDecl = req(
|
|
2330
|
+
word.collect(globalDeclCollect, "fn_name"),
|
|
2331
|
+
"missing fn name"
|
|
2332
|
+
);
|
|
2333
|
+
const optionally_typed_ident = tagScope(
|
|
2334
|
+
seq(
|
|
2335
|
+
word.collect(declCollect, "decl_elem"),
|
|
2336
|
+
opt(seq(":", type_specifier))
|
|
2337
|
+
).collect(typedDecl)
|
|
2338
|
+
).ctag("var_name");
|
|
2339
|
+
const req_optionally_typed_ident = req(optionally_typed_ident, "invalid ident");
|
|
2340
|
+
const global_ident = tagScope(
|
|
2341
|
+
req(
|
|
2342
|
+
seq(
|
|
2343
|
+
word.collect(globalDeclCollect, "decl_elem"),
|
|
2344
|
+
opt(seq(":", type_specifier))
|
|
2345
|
+
).collect(typedDecl),
|
|
2346
|
+
"expected identifier"
|
|
2347
|
+
)
|
|
2348
|
+
).ctag("var_name");
|
|
2349
|
+
const struct_member = tagScope(
|
|
2350
|
+
seq(
|
|
2351
|
+
opt_attributes,
|
|
2352
|
+
word.collect(nameCollect, "nameElem"),
|
|
2353
|
+
req(":", "invalid struct member, expected ':'"),
|
|
2354
|
+
req(type_specifier, "invalid struct member, expected type specifier")
|
|
2355
|
+
).collect(collectStructMember)
|
|
2356
|
+
).ctag("members");
|
|
2357
|
+
const struct_decl = seq(
|
|
2358
|
+
weslExtension(opt_attributes).collect((cc) => cc.tags.attribute, "attributes"),
|
|
2359
|
+
"struct",
|
|
2360
|
+
req(globalTypeNameDecl, "invalid struct, expected name"),
|
|
2361
|
+
seq(
|
|
2362
|
+
req("{", "invalid struct, expected '{'"),
|
|
2363
|
+
withSepPlus(",", struct_member),
|
|
2364
|
+
req("}", "invalid struct, expected '}'")
|
|
2365
|
+
).collect(scopeCollect, "struct_scope")
|
|
2366
|
+
).collect(collectStruct);
|
|
2367
|
+
const fn_call = seq(
|
|
2368
|
+
qualified_ident.collect(refIdent),
|
|
2369
|
+
() => opt_template_list,
|
|
2370
|
+
argument_expression_list
|
|
2371
|
+
);
|
|
2372
|
+
const fnParam = tagScope(
|
|
2373
|
+
seq(
|
|
2374
|
+
opt_attributes.collect((cc) => cc.tags.attribute, "attributes"),
|
|
2375
|
+
word.collect(declCollect, "decl_elem"),
|
|
2376
|
+
opt(seq(":", req(type_specifier, "invalid fn parameter, expected type specifier"))).collect(typedDecl, "param_name")
|
|
2377
|
+
).collect(collectFnParam)
|
|
2378
|
+
).ctag("fn_param");
|
|
2379
|
+
const fnParamList = seq("(", withSep(",", fnParam), ")");
|
|
2380
|
+
const local_variable_decl = seq(
|
|
2381
|
+
"var",
|
|
2382
|
+
() => opt_template_list,
|
|
2383
|
+
req_optionally_typed_ident,
|
|
2384
|
+
opt(seq("=", () => expression))
|
|
2385
|
+
// no decl_scope, but I think that's ok
|
|
2386
|
+
).collect(collectVarLike("var"));
|
|
2387
|
+
const global_variable_decl = seq(
|
|
2388
|
+
"var",
|
|
2389
|
+
() => opt_template_list,
|
|
2390
|
+
global_ident,
|
|
2391
|
+
// TODO shouldn't decl_scope include the ident type?
|
|
2392
|
+
opt(seq("=", () => expression.collect(scopeCollect, "decl_scope")))
|
|
2393
|
+
);
|
|
2394
|
+
const attribute_if_primary_expression = or(
|
|
2395
|
+
tokenOf("keyword", ["true", "false"]).map(makeLiteral),
|
|
2396
|
+
delimited(
|
|
2397
|
+
token("symbol", "("),
|
|
2398
|
+
fn(() => attribute_if_expression),
|
|
2399
|
+
token("symbol", ")")
|
|
2400
|
+
).map(makeParenthesizedExpression),
|
|
2401
|
+
tokenKind("word").map(makeTranslateTimeFeature)
|
|
2402
|
+
);
|
|
2403
|
+
const attribute_if_unary_expression = or(
|
|
2404
|
+
seq(
|
|
2405
|
+
token("symbol", "!").map(makeUnaryOperator),
|
|
2406
|
+
fn(() => attribute_if_unary_expression)
|
|
2407
|
+
).map(makeUnaryExpression),
|
|
2408
|
+
attribute_if_primary_expression
|
|
2409
|
+
);
|
|
2410
|
+
const attribute_if_expression = weslExtension(
|
|
2411
|
+
seq(
|
|
2412
|
+
attribute_if_unary_expression,
|
|
2413
|
+
or(
|
|
2414
|
+
repeatPlus(
|
|
2415
|
+
seq(
|
|
2416
|
+
token("symbol", "||").map(makeBinaryOperator),
|
|
2417
|
+
req(
|
|
2418
|
+
attribute_if_unary_expression,
|
|
2419
|
+
"invalid expression, expected expression"
|
|
2420
|
+
)
|
|
2421
|
+
)
|
|
2422
|
+
),
|
|
2423
|
+
repeatPlus(
|
|
2424
|
+
seq(
|
|
2425
|
+
token("symbol", "&&").map(makeBinaryOperator),
|
|
2426
|
+
req(
|
|
2427
|
+
attribute_if_unary_expression,
|
|
2428
|
+
"invalid expression, expected expression"
|
|
2429
|
+
)
|
|
2430
|
+
)
|
|
2431
|
+
),
|
|
2432
|
+
yes().map(() => [])
|
|
2433
|
+
)
|
|
2434
|
+
).map(makeRepeatingBinaryExpression)
|
|
2435
|
+
);
|
|
2436
|
+
const unscoped_compound_statement = seq(
|
|
2437
|
+
opt_attributes,
|
|
2438
|
+
text("{"),
|
|
2439
|
+
repeat(() => statement),
|
|
2440
|
+
req("}", "invalid block, expected }")
|
|
2441
|
+
).collect(statementCollect);
|
|
2442
|
+
const compound_statement = tagScope(
|
|
2443
|
+
seq(
|
|
2444
|
+
opt_attributes,
|
|
2445
|
+
seq(
|
|
2446
|
+
text("{"),
|
|
2447
|
+
repeat(() => statement),
|
|
2448
|
+
req("}", "invalid block, expected '}'")
|
|
2449
|
+
).collect(scopeCollect)
|
|
2450
|
+
).collect(statementCollect)
|
|
2451
|
+
);
|
|
2452
|
+
const for_init = seq(
|
|
2453
|
+
opt_attributes,
|
|
2454
|
+
or(
|
|
2455
|
+
fn_call,
|
|
2456
|
+
() => variable_or_value_statement,
|
|
2457
|
+
() => variable_updating_statement
|
|
2458
|
+
)
|
|
2459
|
+
);
|
|
2460
|
+
const for_update = seq(
|
|
2461
|
+
opt_attributes,
|
|
2462
|
+
or(fn_call, () => variable_updating_statement)
|
|
2463
|
+
);
|
|
2464
|
+
const for_statement = seq(
|
|
2465
|
+
// LATER consider allowing @if on for_init, expression and for_update
|
|
2466
|
+
"for",
|
|
2467
|
+
seq(
|
|
2468
|
+
req("(", "invalid for loop, expected '('"),
|
|
2469
|
+
opt(for_init),
|
|
2470
|
+
req(";", "invalid for loop, expected ';'"),
|
|
2471
|
+
opt(expression),
|
|
2472
|
+
req(";", "invalid for loop, expected ';'"),
|
|
2473
|
+
opt(for_update),
|
|
2474
|
+
req(")", "invalid for loop, expected ')'"),
|
|
2475
|
+
unscoped_compound_statement
|
|
2476
|
+
).collect(scopeCollect)
|
|
2477
|
+
);
|
|
2478
|
+
const if_statement = seq(
|
|
2479
|
+
"if",
|
|
2480
|
+
req(seq(expression, compound_statement), "invalid if statement"),
|
|
2481
|
+
repeat(
|
|
2482
|
+
seq(
|
|
2483
|
+
"else",
|
|
2484
|
+
"if",
|
|
2485
|
+
req(seq(expression, compound_statement), "invalid else if branch")
|
|
2486
|
+
)
|
|
2487
|
+
),
|
|
2488
|
+
opt(
|
|
2489
|
+
seq("else", req(compound_statement, "invalid else branch, expected '{'"))
|
|
2490
|
+
)
|
|
2491
|
+
);
|
|
2492
|
+
const loop_statement = seq(
|
|
2493
|
+
"loop",
|
|
2494
|
+
opt_attributes_no_if,
|
|
2495
|
+
req(
|
|
2496
|
+
seq(
|
|
2497
|
+
"{",
|
|
2498
|
+
repeat(() => statement),
|
|
2499
|
+
opt(
|
|
2500
|
+
tagScope(
|
|
2501
|
+
seq(
|
|
2502
|
+
opt_attributes,
|
|
2503
|
+
"continuing",
|
|
2504
|
+
opt_attributes_no_if,
|
|
2505
|
+
"{",
|
|
2506
|
+
repeat(() => statement),
|
|
2507
|
+
tagScope(
|
|
2508
|
+
opt(
|
|
2509
|
+
seq(
|
|
2510
|
+
opt_attributes,
|
|
2511
|
+
seq("break", "if", expression, ";")
|
|
2512
|
+
).collect(statementCollect)
|
|
2513
|
+
)
|
|
2514
|
+
),
|
|
2515
|
+
"}"
|
|
2516
|
+
).collect(statementCollect).collect(scopeCollect)
|
|
2517
|
+
)
|
|
2518
|
+
),
|
|
2519
|
+
"}"
|
|
2520
|
+
),
|
|
2521
|
+
"invalid loop statement"
|
|
2522
|
+
)
|
|
2523
|
+
).collect(scopeCollect);
|
|
2524
|
+
const case_selector = or("default", expression);
|
|
2525
|
+
const switch_clause = tagScope(
|
|
2526
|
+
seq(
|
|
2527
|
+
opt_attributes,
|
|
2528
|
+
or(
|
|
2529
|
+
seq(
|
|
2530
|
+
"case",
|
|
2531
|
+
withSep(",", case_selector, { requireOne: true }),
|
|
2532
|
+
opt(":"),
|
|
2533
|
+
compound_statement
|
|
2534
|
+
),
|
|
2535
|
+
seq("default", opt(":"), compound_statement)
|
|
2536
|
+
).collect(switchClauseCollect)
|
|
2537
|
+
)
|
|
2538
|
+
);
|
|
2539
|
+
const switch_body = seq(opt_attributes, "{", repeatPlus(switch_clause), "}");
|
|
2540
|
+
const switch_statement = seq("switch", expression, switch_body);
|
|
2541
|
+
const while_statement = seq("while", expression, compound_statement);
|
|
2542
|
+
const regular_statement = or(
|
|
2543
|
+
for_statement,
|
|
2544
|
+
if_statement,
|
|
2545
|
+
loop_statement,
|
|
2546
|
+
switch_statement,
|
|
2547
|
+
while_statement,
|
|
2548
|
+
seq("break", ";"),
|
|
2549
|
+
// ambiguous with break if
|
|
2550
|
+
seq("continue", req(";", "invalid statement, expected ';'")),
|
|
2551
|
+
seq(";"),
|
|
2552
|
+
// LATER this one cannot have attributes in front of it
|
|
2553
|
+
() => const_assert,
|
|
2554
|
+
seq("discard", req(";", "invalid statement, expected ';'")),
|
|
2555
|
+
seq("return", opt(expression), req(";", "invalid statement, expected ';'")),
|
|
2556
|
+
seq(fn_call, req(";", "invalid statement, expected ';'")),
|
|
2557
|
+
seq(
|
|
2558
|
+
() => variable_or_value_statement,
|
|
2559
|
+
req(";", "invalid statement, expected ';'")
|
|
2560
|
+
),
|
|
2561
|
+
seq(
|
|
2562
|
+
() => variable_updating_statement,
|
|
2563
|
+
req(";", "invalid statement, expected ';'")
|
|
2564
|
+
)
|
|
2565
|
+
);
|
|
2566
|
+
const conditional_statement = tagScope(
|
|
2567
|
+
seq(
|
|
2568
|
+
opt_attributes,
|
|
2569
|
+
regular_statement
|
|
2570
|
+
).collect(statementCollect).collect(partialScopeCollect)
|
|
2571
|
+
);
|
|
2572
|
+
const unconditional_statement = tagScope(
|
|
2573
|
+
seq(
|
|
2574
|
+
opt_attributes_no_if,
|
|
2575
|
+
regular_statement
|
|
2576
|
+
)
|
|
2577
|
+
);
|
|
2578
|
+
const statement = or(
|
|
2579
|
+
compound_statement,
|
|
2580
|
+
unconditional_statement,
|
|
2581
|
+
conditional_statement
|
|
2582
|
+
);
|
|
2583
|
+
const lhs_expression = or(
|
|
2584
|
+
simple_component_reference,
|
|
2585
|
+
seq(
|
|
2586
|
+
qualified_ident.collect(refIdent),
|
|
2587
|
+
opt(component_or_swizzle)
|
|
2588
|
+
),
|
|
2589
|
+
seq(
|
|
2590
|
+
"(",
|
|
2591
|
+
() => lhs_expression,
|
|
2592
|
+
")",
|
|
2593
|
+
opt(component_or_swizzle)
|
|
2594
|
+
// LATER this doesn't find member references.
|
|
2595
|
+
),
|
|
2596
|
+
seq("&", () => lhs_expression),
|
|
2597
|
+
seq("*", () => lhs_expression)
|
|
2598
|
+
);
|
|
2599
|
+
const variable_or_value_statement = tagScope(
|
|
2600
|
+
// LATER consider collecting these as var elems and scopes
|
|
2601
|
+
or(
|
|
2602
|
+
// Also covers the = expression case
|
|
2603
|
+
local_variable_decl,
|
|
2604
|
+
seq("const", req_optionally_typed_ident, req("=", "invalid const declaration, expected '='"), expression),
|
|
2605
|
+
seq(
|
|
2606
|
+
"let",
|
|
2607
|
+
req_optionally_typed_ident,
|
|
2608
|
+
req("=", "invalid let declaration, expected '='"),
|
|
2609
|
+
expression
|
|
2610
|
+
)
|
|
2611
|
+
)
|
|
2612
|
+
);
|
|
2613
|
+
const variable_updating_statement = or(
|
|
2614
|
+
seq(
|
|
2615
|
+
lhs_expression,
|
|
2616
|
+
or("=", "<<=", ">>=", "%=", "&=", "*=", "+=", "-=", "/=", "^=", "|="),
|
|
2617
|
+
expression
|
|
2618
|
+
),
|
|
2619
|
+
seq(lhs_expression, or("++", "--")),
|
|
2620
|
+
seq("_", "=", expression)
|
|
2621
|
+
);
|
|
2622
|
+
const fn_decl = seq(
|
|
2623
|
+
tagScope(
|
|
2624
|
+
opt_attributes.collect((cc) => cc.tags.attribute || [])
|
|
2625
|
+
).ctag("fn_attributes"),
|
|
2626
|
+
text("fn"),
|
|
2627
|
+
req(fnNameDecl, "invalid fn, expected function name"),
|
|
2628
|
+
seq(
|
|
2629
|
+
req(fnParamList, "invalid fn, expected function parameters").collect(scopeCollect, "header_scope"),
|
|
2630
|
+
opt(seq(
|
|
2631
|
+
"->",
|
|
2632
|
+
opt_attributes.collect((cc) => cc.tags.attribute, "return_attributes"),
|
|
2633
|
+
type_specifier.ctag("return_type").collect(scopeCollect, "return_scope")
|
|
2634
|
+
)),
|
|
2635
|
+
req(
|
|
2636
|
+
unscoped_compound_statement,
|
|
2637
|
+
"invalid fn, expected function body"
|
|
2638
|
+
).ctag("body_statement").collect(scopeCollect, "body_scope")
|
|
2639
|
+
)
|
|
2640
|
+
).collect(partialScopeCollect, "fn_partial_scope").collect(fnCollect);
|
|
2641
|
+
const global_value_decl = or(
|
|
2642
|
+
seq(
|
|
2643
|
+
opt_attributes,
|
|
2644
|
+
"override",
|
|
2645
|
+
global_ident,
|
|
2646
|
+
seq(opt(seq("=", expression.collect(scopeCollect, "decl_scope")))),
|
|
2647
|
+
// TODO partial scopes for decl_scopes?
|
|
2648
|
+
";"
|
|
2649
|
+
).collect(collectVarLike("override")),
|
|
2650
|
+
seq(
|
|
2651
|
+
opt_attributes,
|
|
2652
|
+
"const",
|
|
2653
|
+
global_ident,
|
|
2654
|
+
"=",
|
|
2655
|
+
seq(expression).collect(scopeCollect, "decl_scope"),
|
|
2656
|
+
";"
|
|
2657
|
+
).collect(collectVarLike("const"))
|
|
2658
|
+
);
|
|
2659
|
+
const global_alias = seq(
|
|
2660
|
+
weslExtension(opt_attributes).collect((cc) => cc.tags.attribute, "attributes"),
|
|
2661
|
+
"alias",
|
|
2662
|
+
req(word, "invalid alias, expected name").collect(globalDeclCollect, "alias_name"),
|
|
2663
|
+
req("=", "invalid alias, expected '='"),
|
|
2664
|
+
req(type_specifier, "invalid alias, expected type").collect(scopeCollect, "alias_scope"),
|
|
2665
|
+
req(";", "invalid alias, expected ';'")
|
|
2666
|
+
).collect(aliasCollect);
|
|
2667
|
+
const const_assert = tagScope(
|
|
2668
|
+
seq(
|
|
2669
|
+
opt_attributes,
|
|
2670
|
+
"const_assert",
|
|
2671
|
+
req(expression, "invalid const_assert, expected expression"),
|
|
2672
|
+
req(";", "invalid statement, expected ';'")
|
|
2673
|
+
).collect(assertCollect)
|
|
2674
|
+
).ctag("const_assert");
|
|
2675
|
+
const global_directive = tagScope(
|
|
2676
|
+
seq(
|
|
2677
|
+
opt_attributes,
|
|
2678
|
+
terminated(
|
|
2679
|
+
or(
|
|
2680
|
+
preceded("diagnostic", diagnostic_control).map(makeDiagnosticDirective),
|
|
2681
|
+
preceded("enable", name_list).map(makeEnableDirective),
|
|
2682
|
+
preceded("requires", name_list).map(makeRequiresDirective)
|
|
2683
|
+
).ptag("directive"),
|
|
2684
|
+
";"
|
|
2685
|
+
)
|
|
2686
|
+
).collect(directiveCollect)
|
|
2687
|
+
);
|
|
2688
|
+
const global_decl = tagScope(
|
|
2689
|
+
or(
|
|
2690
|
+
fn_decl,
|
|
2691
|
+
seq(
|
|
2692
|
+
opt_attributes,
|
|
2693
|
+
global_variable_decl,
|
|
2694
|
+
";"
|
|
2695
|
+
).collect(collectVarLike("gvar")),
|
|
2696
|
+
global_value_decl,
|
|
2697
|
+
";",
|
|
2698
|
+
global_alias,
|
|
2699
|
+
const_assert.collect(globalAssertCollect),
|
|
2700
|
+
struct_decl
|
|
2701
|
+
)
|
|
2702
|
+
);
|
|
2703
|
+
const weslRoot = seq(
|
|
2704
|
+
weslExtension(weslImports),
|
|
2705
|
+
repeat(global_directive),
|
|
2706
|
+
repeat(global_decl),
|
|
2707
|
+
req(eof(), "invalid WESL, expected EOF")
|
|
2708
|
+
).collect(collectModule, "collectModule");
|
|
2709
|
+
function makeDiagnosticDirective([severity, rule]) {
|
|
2710
|
+
return { kind: "diagnostic", severity, rule };
|
|
2711
|
+
}
|
|
2712
|
+
function makeEnableDirective(extensions) {
|
|
2713
|
+
return { kind: "enable", extensions };
|
|
2714
|
+
}
|
|
2715
|
+
function makeRequiresDirective(extensions) {
|
|
2716
|
+
return { kind: "requires", extensions };
|
|
2717
|
+
}
|
|
2718
|
+
function makeStandardAttribute([name2, params]) {
|
|
2719
|
+
return {
|
|
2720
|
+
kind: "@attribute",
|
|
2721
|
+
name: name2,
|
|
2722
|
+
params
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
function makeInterpolateAttribute(params) {
|
|
2726
|
+
return {
|
|
2727
|
+
kind: "@interpolate",
|
|
2728
|
+
params
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
function makeBuiltinAttribute(param) {
|
|
2732
|
+
return {
|
|
2733
|
+
kind: "@builtin",
|
|
2734
|
+
param
|
|
2735
|
+
};
|
|
2736
|
+
}
|
|
2737
|
+
function makeDiagnosticAttribute([severity, rule]) {
|
|
2738
|
+
return {
|
|
2739
|
+
kind: "@diagnostic",
|
|
2740
|
+
severity,
|
|
2741
|
+
rule
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2744
|
+
function makeIfAttribute(param) {
|
|
2745
|
+
return {
|
|
2746
|
+
kind: "@if",
|
|
2747
|
+
param
|
|
2748
|
+
};
|
|
2749
|
+
}
|
|
2750
|
+
function makeTranslateTimeExpressionElem(args) {
|
|
2751
|
+
return {
|
|
2752
|
+
kind: "translate-time-expression",
|
|
2753
|
+
expression: args.value,
|
|
2754
|
+
span: args.span
|
|
2755
|
+
};
|
|
2756
|
+
}
|
|
2757
|
+
function makeName(token2) {
|
|
2758
|
+
return {
|
|
2759
|
+
kind: "name",
|
|
2760
|
+
name: token2.text,
|
|
2761
|
+
start: token2.span[0],
|
|
2762
|
+
end: token2.span[1]
|
|
2763
|
+
};
|
|
2764
|
+
}
|
|
2765
|
+
function makeLiteral(token2) {
|
|
2766
|
+
return {
|
|
2767
|
+
kind: "literal",
|
|
2768
|
+
value: token2.text,
|
|
2769
|
+
span: token2.span
|
|
2770
|
+
};
|
|
2771
|
+
}
|
|
2772
|
+
function makeTranslateTimeFeature(token2) {
|
|
2773
|
+
return {
|
|
2774
|
+
kind: "translate-time-feature",
|
|
2775
|
+
name: token2.text,
|
|
2776
|
+
span: token2.span
|
|
2777
|
+
};
|
|
2778
|
+
}
|
|
2779
|
+
function makeParenthesizedExpression(expression2) {
|
|
2780
|
+
return {
|
|
2781
|
+
kind: "parenthesized-expression",
|
|
2782
|
+
expression: expression2
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2785
|
+
function makeUnaryOperator(token2) {
|
|
2786
|
+
return {
|
|
2787
|
+
value: token2.text,
|
|
2788
|
+
span: token2.span
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
function makeBinaryOperator(token2) {
|
|
2792
|
+
return {
|
|
2793
|
+
value: token2.text,
|
|
2794
|
+
span: token2.span
|
|
2795
|
+
};
|
|
2796
|
+
}
|
|
2797
|
+
function makeUnaryExpression([operator, expression2]) {
|
|
2798
|
+
return {
|
|
2799
|
+
kind: "unary-expression",
|
|
2800
|
+
operator,
|
|
2801
|
+
expression: expression2
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
function makeRepeatingBinaryExpression([start, repeating]) {
|
|
2805
|
+
let result = start;
|
|
2806
|
+
for (const [op, left] of repeating) {
|
|
2807
|
+
result = makeBinaryExpression([result, op, left]);
|
|
2808
|
+
}
|
|
2809
|
+
return result;
|
|
2810
|
+
}
|
|
2811
|
+
function makeBinaryExpression([left, operator, right]) {
|
|
2812
|
+
return {
|
|
2813
|
+
kind: "binary-expression",
|
|
2814
|
+
operator,
|
|
2815
|
+
left,
|
|
2816
|
+
right
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
2819
|
+
/*!
|
|
2820
|
+
Copyright (c) 2017-2021 [these people](https://github.com/Rich-Harris/vlq/graphs/contributors)
|
|
2821
|
+
|
|
2822
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
2823
|
+
|
|
2824
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
2825
|
+
|
|
2826
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
2827
|
+
*/
|
|
2828
|
+
let integer_to_char = {};
|
|
2829
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".split("").forEach(function(char, i) {
|
|
2830
|
+
integer_to_char[i] = char;
|
|
2831
|
+
});
|
|
2832
|
+
function encodeVlq(value) {
|
|
2833
|
+
if (typeof value === "number") {
|
|
2834
|
+
return encode_integer(value);
|
|
2835
|
+
}
|
|
2836
|
+
let result = "";
|
|
2837
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
2838
|
+
result += encode_integer(value[i]);
|
|
2839
|
+
}
|
|
2840
|
+
return result;
|
|
2841
|
+
}
|
|
2842
|
+
function encode_integer(num) {
|
|
2843
|
+
let result = "";
|
|
2844
|
+
if (num < 0) {
|
|
2845
|
+
num = -num << 1 | 1;
|
|
2846
|
+
} else {
|
|
2847
|
+
num <<= 1;
|
|
2848
|
+
}
|
|
2849
|
+
do {
|
|
2850
|
+
let clamped = num & 31;
|
|
2851
|
+
num >>>= 5;
|
|
2852
|
+
if (num > 0) {
|
|
2853
|
+
clamped |= 32;
|
|
2854
|
+
}
|
|
2855
|
+
result += integer_to_char[clamped];
|
|
2856
|
+
} while (num > 0);
|
|
2857
|
+
return result;
|
|
2858
|
+
}
|
|
2859
|
+
function makeWeslDevice(device) {
|
|
2860
|
+
const errorScopeStack = [];
|
|
2861
|
+
device.injectError = (type, error) => {
|
|
2862
|
+
const errorScope = errorScopeStack.findLast((v) => v.filter === type);
|
|
2863
|
+
if (errorScope !== void 0) {
|
|
2864
|
+
errorScope.errors.push(error);
|
|
2865
|
+
} else {
|
|
2866
|
+
error.then((e) => {
|
|
2867
|
+
if (e !== null) {
|
|
2868
|
+
dispatchError(e);
|
|
2869
|
+
}
|
|
2870
|
+
});
|
|
2871
|
+
}
|
|
2872
|
+
};
|
|
2873
|
+
function dispatchError(e) {
|
|
2874
|
+
device.addEventListener(
|
|
2875
|
+
"uncapturederror",
|
|
2876
|
+
(ev) => {
|
|
2877
|
+
if (!ev.defaultPrevented) {
|
|
2878
|
+
if ("compilationInfo" in ev.error) {
|
|
2879
|
+
const error = ev.error;
|
|
2880
|
+
if (error.compilationInfo) {
|
|
2881
|
+
for (const message of error.compilationInfo.messages) {
|
|
2882
|
+
throwClickableError({
|
|
2883
|
+
url: message.module.url,
|
|
2884
|
+
text: message.module.text ?? null,
|
|
2885
|
+
lineNumber: message.lineNum,
|
|
2886
|
+
lineColumn: message.linePos,
|
|
2887
|
+
length: message.length,
|
|
2888
|
+
error: new Error(message.type + ": " + message.message)
|
|
2889
|
+
});
|
|
2890
|
+
}
|
|
2891
|
+
} else {
|
|
2892
|
+
console.error(ev.error.message);
|
|
2893
|
+
}
|
|
2894
|
+
} else {
|
|
2895
|
+
console.error(ev.error.message);
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
},
|
|
2899
|
+
{
|
|
2900
|
+
// This event listener should only happen for this event!
|
|
2901
|
+
once: true
|
|
2902
|
+
}
|
|
2903
|
+
);
|
|
2904
|
+
device.dispatchEvent(
|
|
2905
|
+
new GPUUncapturedErrorEvent("uncapturederror", { error: e })
|
|
2906
|
+
);
|
|
2907
|
+
}
|
|
2908
|
+
device.pushErrorScope = /* @__PURE__ */ ((baseFn) => {
|
|
2909
|
+
return function(filter) {
|
|
2910
|
+
errorScopeStack.push({
|
|
2911
|
+
filter,
|
|
2912
|
+
errors: []
|
|
2913
|
+
});
|
|
2914
|
+
return baseFn.call(this, filter);
|
|
2915
|
+
};
|
|
2916
|
+
})(device.pushErrorScope);
|
|
2917
|
+
device.popErrorScope = /* @__PURE__ */ ((baseFn) => {
|
|
2918
|
+
return function() {
|
|
2919
|
+
const errorScope = errorScopeStack.pop();
|
|
2920
|
+
if (errorScope === void 0) {
|
|
2921
|
+
throw new DOMException(
|
|
2922
|
+
"popErrorScope called on empty error scope stack",
|
|
2923
|
+
"OperationError"
|
|
2924
|
+
);
|
|
2925
|
+
}
|
|
2926
|
+
errorScope.errors.push(baseFn.call(this));
|
|
2927
|
+
const errorPromise = Promise.all(errorScope.errors).then(
|
|
2928
|
+
(values) => values.find((v) => v !== null) ?? null
|
|
2929
|
+
);
|
|
2930
|
+
return errorPromise;
|
|
2931
|
+
};
|
|
2932
|
+
})(device.popErrorScope);
|
|
2933
|
+
return device;
|
|
2934
|
+
}
|
|
2935
|
+
function throwClickableError({
|
|
2936
|
+
url,
|
|
2937
|
+
text: text2,
|
|
2938
|
+
lineNumber,
|
|
2939
|
+
lineColumn,
|
|
2940
|
+
length,
|
|
2941
|
+
error
|
|
2942
|
+
}) {
|
|
2943
|
+
let mappings = encodeVlq([
|
|
2944
|
+
0,
|
|
2945
|
+
0,
|
|
2946
|
+
Math.max(0, lineNumber - 1),
|
|
2947
|
+
Math.max(0, lineColumn - 1)
|
|
2948
|
+
]) + "," + // Sadly no browser makes use of this info to map the error properly
|
|
2949
|
+
encodeVlq([
|
|
2950
|
+
18,
|
|
2951
|
+
// Arbitrary number that is high enough
|
|
2952
|
+
0,
|
|
2953
|
+
Math.max(0, lineNumber - 1),
|
|
2954
|
+
Math.max(0, lineColumn - 1) + length
|
|
2955
|
+
]);
|
|
2956
|
+
const sourceMap = {
|
|
2957
|
+
version: 3,
|
|
2958
|
+
file: null,
|
|
2959
|
+
sources: [url],
|
|
2960
|
+
sourcesContent: [text2 ?? null],
|
|
2961
|
+
names: [],
|
|
2962
|
+
mappings
|
|
2963
|
+
};
|
|
2964
|
+
let generatedCode = `throw new Error(${JSON.stringify(error.message + "")})`;
|
|
2965
|
+
generatedCode += "\n//# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));
|
|
2966
|
+
generatedCode += "\n//# sourceURL=" + sourceMap.sources[0];
|
|
2967
|
+
let oldLimit = 0;
|
|
2968
|
+
if ("stackTraceLimit" in Error) {
|
|
2969
|
+
oldLimit = Error.stackTraceLimit;
|
|
2970
|
+
Error.stackTraceLimit = 1;
|
|
2971
|
+
}
|
|
2972
|
+
try {
|
|
2973
|
+
(0, eval)(generatedCode);
|
|
2974
|
+
} catch (e) {
|
|
2975
|
+
if ("stackTraceLimit" in Error) {
|
|
2976
|
+
Error.stackTraceLimit = oldLimit;
|
|
2977
|
+
}
|
|
2978
|
+
error.message = "";
|
|
2979
|
+
e.cause = error;
|
|
2980
|
+
throw e;
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
class WeslParseError extends Error {
|
|
2984
|
+
constructor(opts) {
|
|
2985
|
+
const source = opts.src.src;
|
|
2986
|
+
const [lineNum, linePos] = offsetToLineNumber(opts.cause.position, source);
|
|
2987
|
+
let message = `${opts.src.debugFilePath}:${lineNum}:${linePos}`;
|
|
2988
|
+
message += ` error: ${opts.cause.message}
|
|
2989
|
+
`;
|
|
2990
|
+
message += errorHighlight(source, [
|
|
2991
|
+
opts.cause.position,
|
|
2992
|
+
opts.cause.position + 1
|
|
2993
|
+
]).join("\n");
|
|
2994
|
+
super(message, {
|
|
2995
|
+
cause: opts.cause
|
|
2996
|
+
});
|
|
2997
|
+
this.position = opts.cause.position;
|
|
2998
|
+
this.src = opts.src;
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
function parseSrcModule(srcModule, srcMap) {
|
|
3002
|
+
const stream = new WeslStream(srcModule.src);
|
|
3003
|
+
const appState = blankWeslParseState(srcModule);
|
|
3004
|
+
const init = { stream, appState };
|
|
3005
|
+
try {
|
|
3006
|
+
const parseResult = weslRoot.parse(init);
|
|
3007
|
+
if (parseResult === null) {
|
|
3008
|
+
throw new Error("parseWESL failed");
|
|
3009
|
+
}
|
|
3010
|
+
} catch (e) {
|
|
3011
|
+
if (e instanceof ParseError) {
|
|
3012
|
+
const [lineNumber, lineColumn] = offsetToLineNumber(
|
|
3013
|
+
e.position,
|
|
3014
|
+
srcModule.src
|
|
3015
|
+
);
|
|
3016
|
+
const error = new WeslParseError({ cause: e, src: srcModule });
|
|
3017
|
+
throwClickableError({
|
|
3018
|
+
url: srcModule.debugFilePath,
|
|
3019
|
+
text: srcModule.src,
|
|
3020
|
+
error,
|
|
3021
|
+
lineNumber,
|
|
3022
|
+
lineColumn,
|
|
3023
|
+
length: 1
|
|
3024
|
+
});
|
|
3025
|
+
} else {
|
|
3026
|
+
throw e;
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
return appState.stable;
|
|
3030
|
+
}
|
|
3031
|
+
function parseWESL(src, srcMap) {
|
|
3032
|
+
const srcModule = {
|
|
3033
|
+
modulePath: "package::test",
|
|
3034
|
+
// TODO this ought not be used outside of tests
|
|
3035
|
+
debugFilePath: "./test.wesl",
|
|
3036
|
+
src
|
|
3037
|
+
};
|
|
3038
|
+
return parseSrcModule(srcModule);
|
|
3039
|
+
}
|
|
3040
|
+
function blankWeslParseState(srcModule) {
|
|
3041
|
+
const rootScope = emptyScope(null);
|
|
3042
|
+
const moduleElem = null;
|
|
3043
|
+
return {
|
|
3044
|
+
context: { scope: rootScope, openElems: [] },
|
|
3045
|
+
stable: { srcModule, imports: [], rootScope, moduleElem }
|
|
3046
|
+
};
|
|
3047
|
+
}
|
|
3048
|
+
function syntheticWeslParseState() {
|
|
3049
|
+
const srcModule = {
|
|
3050
|
+
modulePath: "package::test",
|
|
3051
|
+
debugFilePath: "./test.wesl",
|
|
3052
|
+
src: ""
|
|
3053
|
+
};
|
|
3054
|
+
return blankWeslParseState(srcModule);
|
|
3055
|
+
}
|
|
3056
|
+
function flatImports(ast) {
|
|
3057
|
+
if (ast._flatImports) return ast._flatImports;
|
|
3058
|
+
const flat = ast.imports.flatMap(flattenTreeImport);
|
|
3059
|
+
ast._flatImports = flat;
|
|
3060
|
+
return flat;
|
|
3061
|
+
}
|
|
3062
|
+
const stdFns = `bitcast all any select arrayLength
|
|
3063
|
+
abs acos acosh asin asinh atan atanh atan2 ceil clamp cos cosh
|
|
3064
|
+
countLeadingZeros countOneBits countTrailingZeros cross
|
|
3065
|
+
degrees determinant distance dot dot4U8Packed dot4I8Packed
|
|
3066
|
+
exp exp2 extractBits faceForward firstLeadingBit firstTrailingBit
|
|
3067
|
+
floor fma fract frexp insertBits inverseSqrt ldexp length log log2
|
|
3068
|
+
max min mix modf normalize pow quantizeToF16 radians reflect refract
|
|
3069
|
+
reverseBits round saturate sign sin sinh smoothstep sqrt step tan tanh
|
|
3070
|
+
transpose trunc
|
|
3071
|
+
dpdx dpdxCoarse dpdxFine dpdy dpdyCoarse dpdyFine fwidth
|
|
3072
|
+
fwidthCoarse fwidthFine
|
|
3073
|
+
textureDimensions textureGather textureGatherCompare textureLoad
|
|
3074
|
+
textureNumLayers textureNumLevels textureNumSamples
|
|
3075
|
+
textureSample textureSampleBias textureSampleCompare textureSampleCompareLevel
|
|
3076
|
+
textureSampleGrad textureSampleLevel textureSampleBaseClampToEdge
|
|
3077
|
+
textureStore
|
|
3078
|
+
atomicLoad atomicStore atomicAdd atomicSub atomicMax atomicMin
|
|
3079
|
+
atomicAnd atomicOr atomicXor atomicExchange atomicCompareExchangeWeak
|
|
3080
|
+
pack4x8snorm pack4x8unorm pack4xI8 pack4xU8 pack4xI8Clamp pack4xU8Clamp
|
|
3081
|
+
pack2x16snorm pack2x16unorm pack2x16float
|
|
3082
|
+
unpack4x8snorm unpack4x8unorm unpack4xI8 unpack4xU8
|
|
3083
|
+
unpack2x16snorm unpack2x16unorm unpack2x16float
|
|
3084
|
+
storageBarrier textureBarrier workgroupBarrier workgroupUniformLoad
|
|
3085
|
+
subgroupAdd subgroupAll subgroupAnd subgroupAny subgroupBallot
|
|
3086
|
+
subgroupBroadcast subgroupBroadcastFirst subgroupElect
|
|
3087
|
+
subgroupExclusiveAdd subgroupExclusiveMul subgroupInclusiveAdd
|
|
3088
|
+
subgroupInclusiveMul subgroupMax subgroupMin subgroupMul subgroupOr
|
|
3089
|
+
subgroupShuffle subgroupShuffleUp subgroupShuffleXor subgroupXor
|
|
3090
|
+
quadBroadcast quadSwapDiagonal quadSwapX quadSwapY`.split(/\s+/);
|
|
3091
|
+
const sampledTextureTypes = `
|
|
3092
|
+
texture_1d texture_2d texture_2d_array texture_3d
|
|
3093
|
+
texture_cube texture_cube_array
|
|
3094
|
+
`;
|
|
3095
|
+
const multisampledTextureTypes = `
|
|
3096
|
+
texture_multisampled_2d texture_depth_multisampled_2d
|
|
3097
|
+
`;
|
|
3098
|
+
const textureStorageTypes = `
|
|
3099
|
+
texture_storage_1d texture_storage_2d texture_storage_2d_array
|
|
3100
|
+
texture_storage_3d
|
|
3101
|
+
`;
|
|
3102
|
+
const stdTypes = `array atomic bool f16 f32 i32
|
|
3103
|
+
mat2x2 mat2x3 mat2x4 mat3x2 mat3x3 mat3x4 mat4x2 mat4x3 mat4x4
|
|
3104
|
+
mat2x2f mat2x3f mat2x4f mat3x2f mat3x3f mat3x4f
|
|
3105
|
+
mat4x2f mat4x3f mat4x4f
|
|
3106
|
+
mat2x2h mat2x3h mat2x4h mat3x2h mat3x3h mat3x4h
|
|
3107
|
+
mat4x2h mat4x3h mat4x4h
|
|
3108
|
+
u32 vec2 vec3 vec4 ptr
|
|
3109
|
+
vec2i vec3i vec4i vec2u vec3u vec4u
|
|
3110
|
+
vec2f vec3f vec4f vec2h vec3h vec4h
|
|
3111
|
+
${sampledTextureTypes}
|
|
3112
|
+
${multisampledTextureTypes}
|
|
3113
|
+
texture_external
|
|
3114
|
+
${textureStorageTypes}
|
|
3115
|
+
texture_depth_2d texture_depth_2d_array texture_depth_cube
|
|
3116
|
+
texture_depth_cube_array
|
|
3117
|
+
sampler sampler_comparison
|
|
3118
|
+
rgba8unorm rgba8snorm rgba8uint rgba8sint
|
|
3119
|
+
rgba16uint rgba16sint rgba16float
|
|
3120
|
+
r32uint r32sint r32float rg32uint rg32sint rg32float
|
|
3121
|
+
rgba32uint rgba32sint rgba32float
|
|
3122
|
+
bgra8unorm`.split(/\s+/);
|
|
3123
|
+
const stdEnumerants = `read write read_write
|
|
3124
|
+
function private workgroup uniform storage
|
|
3125
|
+
rgba8unorm rgba8snorm rgba8uint rgba8sint
|
|
3126
|
+
rgba16uint rgba16sint rgba16float
|
|
3127
|
+
r32uint r32sint r32float rg32uint rg32sint rg32float
|
|
3128
|
+
rgba32uint rgba32sint rgba32float bgra8unorm`.split(/\s+/);
|
|
3129
|
+
function stdType(name2) {
|
|
3130
|
+
return stdTypes.includes(name2);
|
|
3131
|
+
}
|
|
3132
|
+
function stdFn(name2) {
|
|
3133
|
+
return stdFns.includes(name2) || stdType(name2);
|
|
3134
|
+
}
|
|
3135
|
+
function stdEnumerant(name2) {
|
|
3136
|
+
return stdEnumerants.includes(name2);
|
|
3137
|
+
}
|
|
3138
|
+
function bindIdents(params) {
|
|
3139
|
+
const { rootAst, registry, virtuals } = params;
|
|
3140
|
+
const { conditions = {}, mangler = minimalMangle } = params;
|
|
3141
|
+
const { rootScope } = rootAst;
|
|
3142
|
+
const globalNames = /* @__PURE__ */ new Set();
|
|
3143
|
+
const knownDecls = /* @__PURE__ */ new Set();
|
|
3144
|
+
const validRootDecls = findValidRootDecls(rootScope);
|
|
3145
|
+
validRootDecls.forEach((decl) => {
|
|
3146
|
+
decl.mangledName = decl.originalName;
|
|
3147
|
+
globalNames.add(decl.originalName);
|
|
3148
|
+
knownDecls.add(decl);
|
|
3149
|
+
});
|
|
3150
|
+
const globalStatements = /* @__PURE__ */ new Map();
|
|
3151
|
+
const bindContext = {
|
|
3152
|
+
registry,
|
|
3153
|
+
conditions,
|
|
3154
|
+
knownDecls,
|
|
3155
|
+
foundScopes: /* @__PURE__ */ new Set(),
|
|
3156
|
+
globalNames,
|
|
3157
|
+
globalStatements,
|
|
3158
|
+
virtuals,
|
|
3159
|
+
mangler
|
|
3160
|
+
};
|
|
3161
|
+
const declEntries = validRootDecls.map((d) => [d.originalName, d]);
|
|
3162
|
+
const liveDecls = { decls: new Map(declEntries), parent: null };
|
|
3163
|
+
const decls = bindIdentsRecursive(rootScope, bindContext, liveDecls, true);
|
|
3164
|
+
const filteredDecls = decls.filter(isGlobal);
|
|
3165
|
+
const newStatements = [...globalStatements.values()];
|
|
3166
|
+
return { decls: filteredDecls, globalNames, newStatements };
|
|
3167
|
+
}
|
|
3168
|
+
function findValidRootDecls(rootScope, conditions) {
|
|
3169
|
+
const found = [];
|
|
3170
|
+
for (const e of rootScope.contents) {
|
|
3171
|
+
if (e.kind === "decl") {
|
|
3172
|
+
assertThatDebug(e.declElem);
|
|
3173
|
+
if (elementValid(e.declElem)) {
|
|
3174
|
+
found.push(e);
|
|
3175
|
+
}
|
|
3176
|
+
} else if (e.kind === "partial") {
|
|
3177
|
+
found.push(...findValidRootDecls(e));
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
return found;
|
|
3181
|
+
}
|
|
3182
|
+
function bindIdentsRecursive(scope, bindContext, liveDecls, isRoot = false) {
|
|
3183
|
+
const { conditions, foundScopes } = bindContext;
|
|
3184
|
+
if (foundScopes.has(scope)) return [];
|
|
3185
|
+
foundScopes.add(scope);
|
|
3186
|
+
const newGlobals = [];
|
|
3187
|
+
const newFromChildren = [];
|
|
3188
|
+
scope.contents.forEach((child) => {
|
|
3189
|
+
const { kind: kind2 } = child;
|
|
3190
|
+
if (kind2 === "decl") {
|
|
3191
|
+
const ident2 = child;
|
|
3192
|
+
if (!isRoot) liveDecls.decls.set(ident2.originalName, ident2);
|
|
3193
|
+
} else if (kind2 === "ref") {
|
|
3194
|
+
const newDecl = handleRef(child, liveDecls, bindContext);
|
|
3195
|
+
newDecl && newGlobals.push(newDecl);
|
|
3196
|
+
} else {
|
|
3197
|
+
const fromScope = handleScope(child, liveDecls, bindContext);
|
|
3198
|
+
if (fromScope) {
|
|
3199
|
+
newFromChildren.push(...fromScope);
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
});
|
|
3203
|
+
const newFromRefs = newGlobals.flatMap((decl) => {
|
|
3204
|
+
const foundsScope = decl.scope;
|
|
3205
|
+
const rootDecls = globalDeclToRootLiveDecls(decl);
|
|
3206
|
+
{
|
|
3207
|
+
const rootLive = makeLiveDecls(rootDecls);
|
|
3208
|
+
return bindIdentsRecursive(foundsScope, bindContext, rootLive);
|
|
3209
|
+
}
|
|
3210
|
+
});
|
|
3211
|
+
return [newGlobals, newFromChildren, newFromRefs].flat();
|
|
3212
|
+
}
|
|
3213
|
+
function handleRef(ident2, liveDecls, bindContext) {
|
|
3214
|
+
const { registry, conditions } = bindContext;
|
|
3215
|
+
const { virtuals } = bindContext;
|
|
3216
|
+
if (!ident2.refersTo && !ident2.std) {
|
|
3217
|
+
const foundDecl = findDeclInModule(ident2, liveDecls) ?? findQualifiedImport(ident2, registry, conditions, virtuals);
|
|
3218
|
+
if (foundDecl) {
|
|
3219
|
+
ident2.refersTo = foundDecl.decl;
|
|
3220
|
+
return handleNewDecl(ident2, foundDecl, bindContext);
|
|
3221
|
+
} else if (stdWgsl(ident2.originalName)) {
|
|
3222
|
+
ident2.std = true;
|
|
3223
|
+
} else {
|
|
3224
|
+
failMissingIdent(ident2);
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
function handleScope(childScope2, liveDecls, bindContext) {
|
|
3229
|
+
if (!scopeValid(childScope2)) return;
|
|
3230
|
+
const { kind: kind2 } = childScope2;
|
|
3231
|
+
if (kind2 === "scope") {
|
|
3232
|
+
const newLive = makeLiveDecls(liveDecls);
|
|
3233
|
+
return bindIdentsRecursive(childScope2, bindContext, newLive);
|
|
3234
|
+
} else if (kind2 === "partial") {
|
|
3235
|
+
return bindIdentsRecursive(childScope2, bindContext, liveDecls);
|
|
3236
|
+
} else ;
|
|
3237
|
+
}
|
|
3238
|
+
function handleNewDecl(refIdent2, foundDecl, bindContext) {
|
|
3239
|
+
const { decl, moduleAst } = foundDecl;
|
|
3240
|
+
const { knownDecls, globalNames, mangler, globalStatements } = bindContext;
|
|
3241
|
+
if (!knownDecls.has(decl)) {
|
|
3242
|
+
knownDecls.add(decl);
|
|
3243
|
+
const { srcModule } = decl;
|
|
3244
|
+
const proposed = refIdent2.originalName;
|
|
3245
|
+
setMangledName(proposed, decl, globalNames, srcModule, mangler);
|
|
3246
|
+
if (isGlobal(decl)) {
|
|
3247
|
+
const { moduleAsserts } = moduleAst;
|
|
3248
|
+
const moduleEmit = moduleAsserts == null ? void 0 : moduleAsserts.map((elem) => ({ srcModule, elem }));
|
|
3249
|
+
moduleEmit == null ? void 0 : moduleEmit.forEach((e) => globalStatements.set(e.elem, e));
|
|
3250
|
+
return decl;
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
function globalDeclToRootLiveDecls(decl, conditions) {
|
|
3255
|
+
assertThatDebug(decl.isGlobal, identToString(decl));
|
|
3256
|
+
let rootScope = decl.scope;
|
|
3257
|
+
while (rootScope.parent) {
|
|
3258
|
+
rootScope = rootScope.parent;
|
|
3259
|
+
}
|
|
3260
|
+
const rootDecls = findValidRootDecls(rootScope);
|
|
3261
|
+
const entires = rootDecls.map((d) => [d.originalName, d]);
|
|
3262
|
+
const decls = new Map(entires);
|
|
3263
|
+
return { decls };
|
|
3264
|
+
}
|
|
3265
|
+
function failMissingIdent(ident2) {
|
|
3266
|
+
const { refIdentElem } = ident2;
|
|
3267
|
+
if (refIdentElem) {
|
|
3268
|
+
const { srcModule, start, end } = refIdentElem;
|
|
3269
|
+
const { debugFilePath: filePath } = srcModule;
|
|
3270
|
+
const msg = `unresolved identifier '${ident2.originalName}' in file: ${filePath}`;
|
|
3271
|
+
srcLog(srcModule.src, [start, end], msg);
|
|
3272
|
+
throw new Error(msg);
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
function setMangledName(proposedName, decl, globalNames, srcModule, mangler) {
|
|
3276
|
+
if (!decl.mangledName) {
|
|
3277
|
+
let mangledName;
|
|
3278
|
+
if (isGlobal(decl)) {
|
|
3279
|
+
const sep = proposedName.lastIndexOf("::");
|
|
3280
|
+
const name2 = sep === -1 ? proposedName : proposedName.slice(sep + 2);
|
|
3281
|
+
mangledName = mangler(decl, srcModule, name2, globalNames);
|
|
3282
|
+
} else {
|
|
3283
|
+
mangledName = decl.originalName;
|
|
3284
|
+
}
|
|
3285
|
+
decl.mangledName = mangledName;
|
|
3286
|
+
globalNames.add(mangledName);
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
function stdWgsl(name2) {
|
|
3290
|
+
return stdType(name2) || stdFn(name2) || stdEnumerant(name2);
|
|
3291
|
+
}
|
|
3292
|
+
function findDeclInModule(ident2, liveDecls) {
|
|
3293
|
+
const { originalName } = ident2;
|
|
3294
|
+
const found = liveDecls.decls.get(originalName);
|
|
3295
|
+
if (found) {
|
|
3296
|
+
return { decl: found, moduleAst: ident2.ast };
|
|
3297
|
+
}
|
|
3298
|
+
const { parent } = liveDecls;
|
|
3299
|
+
if (parent) {
|
|
3300
|
+
return findDeclInModule(ident2, parent);
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
function findQualifiedImport(refIdent2, parsed, conditions, virtuals) {
|
|
3304
|
+
const flatImps = flatImports(refIdent2.ast);
|
|
3305
|
+
const identParts = refIdent2.originalName.split("::");
|
|
3306
|
+
const modulePathParts = matchingImport(identParts, flatImps) ?? qualifiedImport(identParts);
|
|
3307
|
+
if (modulePathParts) {
|
|
3308
|
+
const { srcModule } = refIdent2.ast;
|
|
3309
|
+
return findExport(modulePathParts, srcModule, parsed, conditions, virtuals);
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
function qualifiedImport(identParts) {
|
|
3313
|
+
if (identParts.length > 1) return identParts;
|
|
3314
|
+
}
|
|
3315
|
+
function matchingImport(identParts, flatImports2) {
|
|
3316
|
+
for (const flat of flatImports2) {
|
|
3317
|
+
if (flat.importPath.at(-1) === identParts.at(0)) {
|
|
3318
|
+
return [...flat.modulePath, ...identParts.slice(1)];
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
function findExport(modulePathParts, srcModule, parsed, conditions = {}, virtuals) {
|
|
3323
|
+
const fqPathParts = absoluteModulePath(modulePathParts, srcModule);
|
|
3324
|
+
const modulePath = fqPathParts.slice(0, -1).join("::");
|
|
3325
|
+
const moduleAst = parsed.modules[modulePath] ?? virtualModule(modulePathParts[0], conditions, virtuals);
|
|
3326
|
+
if (!moduleAst) {
|
|
3327
|
+
console.log(`ident ${modulePathParts.join("::")}, but module not found`);
|
|
3328
|
+
return void 0;
|
|
3329
|
+
}
|
|
3330
|
+
const name2 = last(modulePathParts);
|
|
3331
|
+
const decl = publicDecl(moduleAst.rootScope, name2);
|
|
3332
|
+
if (decl) {
|
|
3333
|
+
return { decl, moduleAst };
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
function absoluteModulePath(modulePathParts, srcModule) {
|
|
3337
|
+
const lastSuper = modulePathParts.findLastIndex((p) => p === "super");
|
|
3338
|
+
if (lastSuper > -1) {
|
|
3339
|
+
const srcModuleParts = srcModule.modulePath.split("::");
|
|
3340
|
+
const base = srcModuleParts.slice(0, -(lastSuper + 1));
|
|
3341
|
+
const noSupers = modulePathParts.slice(lastSuper + 1);
|
|
3342
|
+
return [...base, ...noSupers];
|
|
3343
|
+
}
|
|
3344
|
+
return modulePathParts;
|
|
3345
|
+
}
|
|
3346
|
+
function virtualModule(moduleName, conditions = {}, virtuals) {
|
|
3347
|
+
if (!virtuals) return void 0;
|
|
3348
|
+
const found = virtuals[moduleName];
|
|
3349
|
+
if (found) {
|
|
3350
|
+
const { ast, fn: fn2 } = found;
|
|
3351
|
+
if (ast) return ast;
|
|
3352
|
+
const src = fn2(conditions);
|
|
3353
|
+
const srcModule = {
|
|
3354
|
+
modulePath: moduleName,
|
|
3355
|
+
debugFilePath: moduleName,
|
|
3356
|
+
src
|
|
3357
|
+
};
|
|
3358
|
+
found.ast = parseSrcModule(srcModule);
|
|
3359
|
+
return found.ast;
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
function isGlobal(declIdent) {
|
|
3363
|
+
const { declElem } = declIdent;
|
|
3364
|
+
if (!declElem) return false;
|
|
3365
|
+
return ["alias", "const", "override", "fn", "struct", "gvar"].includes(
|
|
3366
|
+
declElem.kind
|
|
3367
|
+
);
|
|
3368
|
+
}
|
|
3369
|
+
function lowerAndEmit(srcBuilder, rootElems, conditions, extracting = true) {
|
|
3370
|
+
const emitContext = { conditions, srcBuilder, extracting };
|
|
3371
|
+
rootElems.forEach((e) => lowerAndEmitElem(e, emitContext));
|
|
3372
|
+
}
|
|
3373
|
+
function lowerAndEmitElem(e, ctx) {
|
|
3374
|
+
if (!conditionsValid(e, ctx.conditions)) return;
|
|
3375
|
+
switch (e.kind) {
|
|
3376
|
+
// import statements are dropped from from emitted text
|
|
3377
|
+
case "import":
|
|
3378
|
+
return;
|
|
3379
|
+
// terminal elements copy strings to the output
|
|
3380
|
+
case "text":
|
|
3381
|
+
return emitText(e, ctx);
|
|
3382
|
+
case "name":
|
|
3383
|
+
return emitName(e, ctx);
|
|
3384
|
+
case "synthetic":
|
|
3385
|
+
return emitSynthetic(e, ctx);
|
|
3386
|
+
// identifiers are copied to the output, but with potentially mangled names
|
|
3387
|
+
case "ref":
|
|
3388
|
+
return emitRefIdent(e, ctx);
|
|
3389
|
+
case "decl":
|
|
3390
|
+
return emitDeclIdent(e, ctx);
|
|
3391
|
+
// container elements just emit their child elements
|
|
3392
|
+
case "param":
|
|
3393
|
+
case "var":
|
|
3394
|
+
case "typeDecl":
|
|
3395
|
+
case "let":
|
|
3396
|
+
case "module":
|
|
3397
|
+
case "member":
|
|
3398
|
+
case "memberRef":
|
|
3399
|
+
case "expression":
|
|
3400
|
+
case "type":
|
|
3401
|
+
case "statement":
|
|
3402
|
+
case "stuff":
|
|
3403
|
+
case "switch-clause":
|
|
3404
|
+
return emitContents(e, ctx);
|
|
3405
|
+
// root level container elements get some extra newlines to make the output prettier
|
|
3406
|
+
case "override":
|
|
3407
|
+
case "const":
|
|
3408
|
+
case "assert":
|
|
3409
|
+
case "alias":
|
|
3410
|
+
case "gvar":
|
|
3411
|
+
emitRootElemNl(ctx);
|
|
3412
|
+
return emitContents(e, ctx);
|
|
3413
|
+
case "fn":
|
|
3414
|
+
emitRootElemNl(ctx);
|
|
3415
|
+
return emitFn(e, ctx);
|
|
3416
|
+
case "struct":
|
|
3417
|
+
emitRootElemNl(ctx);
|
|
3418
|
+
return emitStruct(e, ctx);
|
|
3419
|
+
case "attribute":
|
|
3420
|
+
return emitAttribute(e, ctx);
|
|
3421
|
+
case "directive":
|
|
3422
|
+
return emitDirective(e, ctx);
|
|
3423
|
+
default:
|
|
3424
|
+
assertUnreachable(e);
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
function emitRootElemNl(ctx) {
|
|
3428
|
+
if (ctx.extracting) {
|
|
3429
|
+
ctx.srcBuilder.addNl();
|
|
3430
|
+
ctx.srcBuilder.addNl();
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
function emitText(e, ctx) {
|
|
3434
|
+
ctx.srcBuilder.addCopy(e.start, e.end);
|
|
3435
|
+
}
|
|
3436
|
+
function emitName(e, ctx) {
|
|
3437
|
+
ctx.srcBuilder.add(e.name, e.start, e.end);
|
|
3438
|
+
}
|
|
3439
|
+
function emitFn(e, ctx) {
|
|
3440
|
+
const { attributes, name: name2, params, returnAttributes, returnType, body } = e;
|
|
3441
|
+
const { conditions, srcBuilder: builder } = ctx;
|
|
3442
|
+
emitAttributes(attributes, ctx);
|
|
3443
|
+
builder.add("fn ", name2.start - 3, name2.start);
|
|
3444
|
+
emitDeclIdent(name2, ctx);
|
|
3445
|
+
builder.appendNext("(");
|
|
3446
|
+
const validParams = params.filter((p) => conditionsValid(p));
|
|
3447
|
+
validParams.forEach((p, i) => {
|
|
3448
|
+
emitContentsNoWs(p, ctx);
|
|
3449
|
+
if (i < validParams.length - 1) {
|
|
3450
|
+
builder.appendNext(", ");
|
|
3451
|
+
}
|
|
3452
|
+
});
|
|
3453
|
+
builder.appendNext(") ");
|
|
3454
|
+
if (returnType) {
|
|
3455
|
+
builder.appendNext("-> ");
|
|
3456
|
+
emitAttributes(returnAttributes, ctx);
|
|
3457
|
+
emitContents(returnType, ctx);
|
|
3458
|
+
builder.appendNext(" ");
|
|
3459
|
+
}
|
|
3460
|
+
emitContents(body, ctx);
|
|
3461
|
+
}
|
|
3462
|
+
function emitAttributes(attributes, ctx) {
|
|
3463
|
+
attributes == null ? void 0 : attributes.forEach((a) => {
|
|
3464
|
+
emitAttribute(a, ctx);
|
|
3465
|
+
ctx.srcBuilder.add(" ", a.start, a.end);
|
|
3466
|
+
});
|
|
3467
|
+
}
|
|
3468
|
+
function emitStruct(e, ctx) {
|
|
3469
|
+
const { name: name2, members, start, end } = e;
|
|
3470
|
+
const { srcBuilder } = ctx;
|
|
3471
|
+
const validMembers = members.filter((m) => conditionsValid(m, ctx.conditions));
|
|
3472
|
+
const validLength = validMembers.length;
|
|
3473
|
+
if (validLength === 0) {
|
|
3474
|
+
warnEmptyStruct(e);
|
|
3475
|
+
return;
|
|
3476
|
+
}
|
|
3477
|
+
srcBuilder.add("struct ", start, name2.start);
|
|
3478
|
+
emitDeclIdent(name2, ctx);
|
|
3479
|
+
if (validLength === 1) {
|
|
3480
|
+
srcBuilder.add(" { ", name2.end, members[0].start);
|
|
3481
|
+
emitContentsNoWs(validMembers[0], ctx);
|
|
3482
|
+
srcBuilder.add(" }\n", end - 1, end);
|
|
3483
|
+
} else {
|
|
3484
|
+
srcBuilder.add(" {\n", name2.end, members[0].start);
|
|
3485
|
+
validMembers.forEach((m) => {
|
|
3486
|
+
srcBuilder.add(" ", m.start - 1, m.start);
|
|
3487
|
+
emitContentsNoWs(m, ctx);
|
|
3488
|
+
srcBuilder.add(",", m.end, m.end + 1);
|
|
3489
|
+
srcBuilder.addNl();
|
|
3490
|
+
});
|
|
3491
|
+
srcBuilder.add("}\n", end - 1, end);
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
function warnEmptyStruct(e) {
|
|
3495
|
+
const { name: name2, members } = e;
|
|
3496
|
+
const condStr = members.length ? "(with current conditions)" : "";
|
|
3497
|
+
const { debugFilePath: filePath } = name2.srcModule;
|
|
3498
|
+
srcLog(
|
|
3499
|
+
name2.srcModule.src,
|
|
3500
|
+
e.start,
|
|
3501
|
+
`struct ${name2.ident.originalName} in ${filePath} has no members ${condStr}`
|
|
3502
|
+
);
|
|
3503
|
+
}
|
|
3504
|
+
function emitSynthetic(e, ctx) {
|
|
3505
|
+
const { text: text2 } = e;
|
|
3506
|
+
ctx.srcBuilder.addSynthetic(text2, text2, 0, text2.length);
|
|
3507
|
+
}
|
|
3508
|
+
function emitContents(elem, ctx) {
|
|
3509
|
+
elem.contents.forEach((e) => lowerAndEmitElem(e, ctx));
|
|
3510
|
+
}
|
|
3511
|
+
function emitContentsNoWs(elem, ctx) {
|
|
3512
|
+
elem.contents.forEach((e) => {
|
|
3513
|
+
if (e.kind === "text") {
|
|
3514
|
+
const { srcModule, start, end } = e;
|
|
3515
|
+
const text2 = srcModule.src.slice(start, end);
|
|
3516
|
+
if (text2.trim() === "") {
|
|
3517
|
+
return;
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
lowerAndEmitElem(e, ctx);
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
function emitRefIdent(e, ctx) {
|
|
3524
|
+
if (e.ident.std) {
|
|
3525
|
+
ctx.srcBuilder.add(e.ident.originalName, e.start, e.end);
|
|
3526
|
+
} else {
|
|
3527
|
+
const declIdent = findDecl(e.ident);
|
|
3528
|
+
const mangledName = displayName(declIdent);
|
|
3529
|
+
ctx.srcBuilder.add(mangledName, e.start, e.end);
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
function emitDeclIdent(e, ctx) {
|
|
3533
|
+
const mangledName = displayName(e.ident);
|
|
3534
|
+
ctx.srcBuilder.add(mangledName, e.start, e.end);
|
|
3535
|
+
}
|
|
3536
|
+
function emitAttribute(e, ctx) {
|
|
3537
|
+
const { kind: kind2 } = e.attribute;
|
|
3538
|
+
if (kind2 === "@attribute") {
|
|
3539
|
+
const { params } = e.attribute;
|
|
3540
|
+
if (!params || params.length === 0) {
|
|
3541
|
+
ctx.srcBuilder.add("@" + e.attribute.name, e.start, e.end);
|
|
3542
|
+
} else {
|
|
3543
|
+
ctx.srcBuilder.add(
|
|
3544
|
+
"@" + e.attribute.name + "(",
|
|
3545
|
+
e.start,
|
|
3546
|
+
params[0].start
|
|
3547
|
+
);
|
|
3548
|
+
for (let i = 0; i < params.length; i++) {
|
|
3549
|
+
emitContents(params[i], ctx);
|
|
3550
|
+
if (i < params.length - 1) {
|
|
3551
|
+
ctx.srcBuilder.add(",", params[i].end, params[i + 1].start);
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3554
|
+
ctx.srcBuilder.add(")", params[params.length - 1].end, e.end);
|
|
3555
|
+
}
|
|
3556
|
+
} else if (kind2 === "@builtin") {
|
|
3557
|
+
ctx.srcBuilder.add(
|
|
3558
|
+
"@builtin(" + e.attribute.param.name + ")",
|
|
3559
|
+
e.start,
|
|
3560
|
+
e.end
|
|
3561
|
+
);
|
|
3562
|
+
} else if (kind2 === "@diagnostic") {
|
|
3563
|
+
ctx.srcBuilder.add(
|
|
3564
|
+
"@diagnostic" + diagnosticControlToString(e.attribute.severity, e.attribute.rule),
|
|
3565
|
+
e.start,
|
|
3566
|
+
e.end
|
|
3567
|
+
);
|
|
3568
|
+
} else if (kind2 === "@if") ;
|
|
3569
|
+
else if (kind2 === "@interpolate") {
|
|
3570
|
+
ctx.srcBuilder.add(
|
|
3571
|
+
`@interpolate(${e.attribute.params.map((v) => v.name).join(", ")})`,
|
|
3572
|
+
e.start,
|
|
3573
|
+
e.end
|
|
3574
|
+
);
|
|
3575
|
+
} else {
|
|
3576
|
+
assertUnreachable(kind2);
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
function diagnosticControlToString(severity, rule) {
|
|
3580
|
+
const ruleStr = rule[0].name + (rule[1] !== null ? "." + rule[1].name : "");
|
|
3581
|
+
return `(${severity.name}, ${ruleStr})`;
|
|
3582
|
+
}
|
|
3583
|
+
function expressionToString(elem) {
|
|
3584
|
+
const { kind: kind2 } = elem;
|
|
3585
|
+
if (kind2 === "binary-expression") {
|
|
3586
|
+
return `${expressionToString(elem.left)} ${elem.operator.value} ${expressionToString(elem.right)}`;
|
|
3587
|
+
} else if (kind2 === "unary-expression") {
|
|
3588
|
+
return `${elem.operator.value}${expressionToString(elem.expression)}`;
|
|
3589
|
+
} else if (kind2 === "ref") {
|
|
3590
|
+
return elem.ident.originalName;
|
|
3591
|
+
} else if (kind2 === "literal") {
|
|
3592
|
+
return elem.value;
|
|
3593
|
+
} else if (kind2 === "translate-time-feature") {
|
|
3594
|
+
return elem.name;
|
|
3595
|
+
} else if (kind2 === "parenthesized-expression") {
|
|
3596
|
+
return `(${expressionToString(elem.expression)})`;
|
|
3597
|
+
} else if (kind2 === "component-expression") {
|
|
3598
|
+
return `${expressionToString(elem.base)}[${elem.access}]`;
|
|
3599
|
+
} else if (kind2 === "component-member-expression") {
|
|
3600
|
+
return `${expressionToString(elem.base)}.${elem.access}`;
|
|
3601
|
+
} else if (kind2 === "call-expression") {
|
|
3602
|
+
return `${elem.function.ident.originalName}(${elem.arguments.map(expressionToString).join(", ")})`;
|
|
3603
|
+
} else {
|
|
3604
|
+
assertUnreachable(kind2);
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
function emitDirective(e, ctx) {
|
|
3608
|
+
const { directive } = e;
|
|
3609
|
+
const { kind: kind2 } = directive;
|
|
3610
|
+
if (kind2 === "diagnostic") {
|
|
3611
|
+
ctx.srcBuilder.add(
|
|
3612
|
+
`diagnostic${diagnosticControlToString(directive.severity, directive.rule)};`,
|
|
3613
|
+
e.start,
|
|
3614
|
+
e.end
|
|
3615
|
+
);
|
|
3616
|
+
} else if (kind2 === "enable") {
|
|
3617
|
+
ctx.srcBuilder.add(
|
|
3618
|
+
`enable ${directive.extensions.map((v) => v.name).join(", ")};`,
|
|
3619
|
+
e.start,
|
|
3620
|
+
e.end
|
|
3621
|
+
);
|
|
3622
|
+
} else if (kind2 === "requires") {
|
|
3623
|
+
ctx.srcBuilder.add(
|
|
3624
|
+
`requires ${directive.extensions.map((v) => v.name).join(", ")};`,
|
|
3625
|
+
e.start,
|
|
3626
|
+
e.end
|
|
3627
|
+
);
|
|
3628
|
+
} else {
|
|
3629
|
+
assertUnreachable(kind2);
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
function displayName(declIdent) {
|
|
3633
|
+
if (isGlobal(declIdent)) {
|
|
3634
|
+
assertThatDebug(
|
|
3635
|
+
declIdent.mangledName,
|
|
3636
|
+
`ERR: mangled name not found for decl ident ${identToString(declIdent)}`
|
|
3637
|
+
);
|
|
3638
|
+
return declIdent.mangledName;
|
|
3639
|
+
}
|
|
3640
|
+
return declIdent.mangledName || declIdent.originalName;
|
|
3641
|
+
}
|
|
3642
|
+
function findDecl(ident2) {
|
|
3643
|
+
let i = ident2;
|
|
3644
|
+
do {
|
|
3645
|
+
if (i.kind === "decl") {
|
|
3646
|
+
return i;
|
|
3647
|
+
}
|
|
3648
|
+
i = i.refersTo;
|
|
3649
|
+
} while (i);
|
|
3650
|
+
throw new Error(`unresolved identifer: ${ident2.originalName}`);
|
|
3651
|
+
}
|
|
3652
|
+
function conditionsValid(elem, conditions) {
|
|
3653
|
+
const attrElem = elem;
|
|
3654
|
+
const { kind: kind2 } = attrElem;
|
|
3655
|
+
switch (kind2) {
|
|
3656
|
+
case "alias":
|
|
3657
|
+
case "assert":
|
|
3658
|
+
case "const":
|
|
3659
|
+
case "directive":
|
|
3660
|
+
case "member":
|
|
3661
|
+
case "var":
|
|
3662
|
+
case "let":
|
|
3663
|
+
case "statement":
|
|
3664
|
+
case "switch-clause":
|
|
3665
|
+
case "override":
|
|
3666
|
+
case "gvar":
|
|
3667
|
+
case "fn":
|
|
3668
|
+
case "struct":
|
|
3669
|
+
case "param":
|
|
3670
|
+
return elementValid(attrElem);
|
|
3671
|
+
}
|
|
3672
|
+
return true;
|
|
3673
|
+
}
|
|
3674
|
+
function importToString(tree) {
|
|
3675
|
+
return importToStringImpl(tree) + ";";
|
|
3676
|
+
}
|
|
3677
|
+
function importToStringImpl(tree) {
|
|
3678
|
+
return [
|
|
3679
|
+
...tree.segments.map((s) => s.name),
|
|
3680
|
+
segmentToString(tree.finalSegment)
|
|
3681
|
+
].join("::");
|
|
3682
|
+
}
|
|
3683
|
+
function segmentToString(segment) {
|
|
3684
|
+
if (segment.kind === "import-item") {
|
|
3685
|
+
const { name: name2, as } = segment;
|
|
3686
|
+
const asMsg = as ? ` as ${as}` : "";
|
|
3687
|
+
return `${name2}${asMsg}`;
|
|
3688
|
+
} else if (segment.kind === "import-collection") {
|
|
3689
|
+
return `{${segment.subtrees.map((s) => importToStringImpl(s)).join(", ")}}`;
|
|
3690
|
+
} else {
|
|
3691
|
+
assertUnreachable$1(segment);
|
|
3692
|
+
}
|
|
3693
|
+
}
|
|
3694
|
+
const maxLineLength = 150;
|
|
3695
|
+
function astToString(elem, indent = 0) {
|
|
3696
|
+
const { kind: kind2 } = elem;
|
|
3697
|
+
const str = new LineWrapper(indent, maxLineLength);
|
|
3698
|
+
str.add(kind2);
|
|
3699
|
+
addElemFields(elem, str);
|
|
3700
|
+
let childStrings = [];
|
|
3701
|
+
if ("contents" in elem) {
|
|
3702
|
+
childStrings = elem.contents.map((e) => astToString(e, indent + 2));
|
|
3703
|
+
}
|
|
3704
|
+
if (childStrings.length) {
|
|
3705
|
+
str.nl();
|
|
3706
|
+
str.addBlock(childStrings.join("\n"), false);
|
|
3707
|
+
}
|
|
3708
|
+
return str.result;
|
|
3709
|
+
}
|
|
3710
|
+
function addElemFields(elem, str) {
|
|
3711
|
+
const { kind: kind2 } = elem;
|
|
3712
|
+
if (kind2 === "text") {
|
|
3713
|
+
const { srcModule, start, end } = elem;
|
|
3714
|
+
str.add(` '${srcModule.src.slice(start, end)}'`);
|
|
3715
|
+
} else if (kind2 === "var" || kind2 === "let" || kind2 === "gvar" || kind2 === "const" || kind2 === "override") {
|
|
3716
|
+
addTypedDeclIdent(elem.name, str);
|
|
3717
|
+
listAttributeElems(elem.attributes, str);
|
|
3718
|
+
} else if (kind2 === "struct") {
|
|
3719
|
+
str.add(" " + elem.name.ident.originalName);
|
|
3720
|
+
} else if (kind2 === "member") {
|
|
3721
|
+
const { name: name2, typeRef, attributes } = elem;
|
|
3722
|
+
listAttributeElems(attributes, str);
|
|
3723
|
+
str.add(" " + name2.name);
|
|
3724
|
+
str.add(": " + typeRefElemToString(typeRef));
|
|
3725
|
+
} else if (kind2 === "name") {
|
|
3726
|
+
str.add(" " + elem.name);
|
|
3727
|
+
} else if (kind2 === "memberRef") {
|
|
3728
|
+
const { extraComponents } = elem;
|
|
3729
|
+
const extraText = extraComponents ? debugContentsToString(extraComponents) : "";
|
|
3730
|
+
str.add(` ${elem.name.ident.originalName}.${elem.member.name}${extraText}`);
|
|
3731
|
+
} else if (kind2 === "fn") {
|
|
3732
|
+
addFnFields(elem, str);
|
|
3733
|
+
} else if (kind2 === "alias") {
|
|
3734
|
+
const { name: name2, typeRef } = elem;
|
|
3735
|
+
const prefix = name2.ident.kind === "decl" ? "%" : "";
|
|
3736
|
+
str.add(" " + prefix + name2.ident.originalName);
|
|
3737
|
+
str.add("=" + typeRefElemToString(typeRef));
|
|
3738
|
+
} else if (kind2 === "attribute") {
|
|
3739
|
+
addAttributeFields(elem.attribute, str);
|
|
3740
|
+
} else if (kind2 === "expression") {
|
|
3741
|
+
const contents = elem.contents.map((e) => {
|
|
3742
|
+
if (e.kind === "text") {
|
|
3743
|
+
return "'" + e.srcModule.src.slice(e.start, e.end) + "'";
|
|
3744
|
+
} else {
|
|
3745
|
+
return astToString(e);
|
|
3746
|
+
}
|
|
3747
|
+
}).join(" ");
|
|
3748
|
+
str.add(" " + contents);
|
|
3749
|
+
} else if (kind2 === "type") {
|
|
3750
|
+
const { name: name2 } = elem;
|
|
3751
|
+
const nameStr = typeof name2 === "string" ? name2 : name2.originalName;
|
|
3752
|
+
str.add(" " + nameStr);
|
|
3753
|
+
if (elem.templateParams !== void 0) {
|
|
3754
|
+
const paramStrs = elem.templateParams.map(templateParamToString).join(", ");
|
|
3755
|
+
str.add("<" + paramStrs + ">");
|
|
3756
|
+
}
|
|
3757
|
+
} else if (kind2 === "synthetic") {
|
|
3758
|
+
str.add(` '${elem.text}'`);
|
|
3759
|
+
} else if (kind2 === "import") {
|
|
3760
|
+
str.add(" " + importToString(elem.imports));
|
|
3761
|
+
} else if (kind2 === "ref") {
|
|
3762
|
+
str.add(" " + elem.ident.originalName);
|
|
3763
|
+
} else if (kind2 === "typeDecl") {
|
|
3764
|
+
addTypedDeclIdent(elem, str);
|
|
3765
|
+
} else if (kind2 === "decl") {
|
|
3766
|
+
const { ident: ident2 } = elem;
|
|
3767
|
+
str.add(" %" + ident2.originalName);
|
|
3768
|
+
} else if (kind2 === "assert") ;
|
|
3769
|
+
else if (kind2 === "module") ;
|
|
3770
|
+
else if (kind2 === "param") ;
|
|
3771
|
+
else if (kind2 === "stuff") ;
|
|
3772
|
+
else if (kind2 === "directive") {
|
|
3773
|
+
addDirective(elem, str);
|
|
3774
|
+
} else if (kind2 === "statement") {
|
|
3775
|
+
listAttributeElems(elem.attributes, str);
|
|
3776
|
+
} else if (kind2 === "switch-clause") ;
|
|
3777
|
+
else {
|
|
3778
|
+
assertUnreachable$1(kind2);
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
function addAttributeFields(attr, str) {
|
|
3782
|
+
const { kind: kind2 } = attr;
|
|
3783
|
+
if (kind2 === "@attribute") {
|
|
3784
|
+
const { name: name2, params } = attr;
|
|
3785
|
+
str.add(" @" + name2);
|
|
3786
|
+
if (params && params.length > 0) {
|
|
3787
|
+
str.add("(");
|
|
3788
|
+
str.add(params.map(unknownExpressionToString).join(", "));
|
|
3789
|
+
str.add(")");
|
|
3790
|
+
}
|
|
3791
|
+
} else if (kind2 === "@builtin") {
|
|
3792
|
+
str.add(` @builtin(${attr.param.name})`);
|
|
3793
|
+
} else if (kind2 === "@diagnostic") {
|
|
3794
|
+
str.add(
|
|
3795
|
+
` @diagnostic${diagnosticControlToString(attr.severity, attr.rule)}`
|
|
3796
|
+
);
|
|
3797
|
+
} else if (kind2 === "@if") {
|
|
3798
|
+
str.add(" @if");
|
|
3799
|
+
str.add("(");
|
|
3800
|
+
str.add(expressionToString(attr.param.expression));
|
|
3801
|
+
str.add(")");
|
|
3802
|
+
} else if (kind2 === "@interpolate") {
|
|
3803
|
+
str.add(` @interpolate(${attr.params.map((v) => v.name).join(", ")})`);
|
|
3804
|
+
} else {
|
|
3805
|
+
assertUnreachable$1(kind2);
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
function attributeToString$1(attr) {
|
|
3809
|
+
const str = new LineWrapper(0, maxLineLength);
|
|
3810
|
+
addAttributeFields(attr, str);
|
|
3811
|
+
return str.result;
|
|
3812
|
+
}
|
|
3813
|
+
function addTypedDeclIdent(elem, str) {
|
|
3814
|
+
const { decl, typeRef } = elem;
|
|
3815
|
+
str.add(" %" + decl.ident.originalName);
|
|
3816
|
+
if (typeRef) {
|
|
3817
|
+
str.add(" : " + typeRefElemToString(typeRef));
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
function addFnFields(elem, str) {
|
|
3821
|
+
const { name: name2, params, returnType, attributes } = elem;
|
|
3822
|
+
str.add(" " + name2.ident.originalName);
|
|
3823
|
+
str.add("(");
|
|
3824
|
+
const paramStrs = params.map(
|
|
3825
|
+
(p) => {
|
|
3826
|
+
const { name: name22 } = p;
|
|
3827
|
+
const { originalName } = name22.decl.ident;
|
|
3828
|
+
const typeRef = typeRefElemToString(name22.typeRef);
|
|
3829
|
+
return originalName + ": " + typeRef;
|
|
3830
|
+
}
|
|
3831
|
+
).join(", ");
|
|
3832
|
+
str.add(paramStrs);
|
|
3833
|
+
str.add(")");
|
|
3834
|
+
listAttributeElems(attributes, str);
|
|
3835
|
+
if (returnType) {
|
|
3836
|
+
str.add(" -> " + typeRefElemToString(returnType));
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
function listAttributeElems(attributes, str) {
|
|
3840
|
+
attributes == null ? void 0 : attributes.forEach((a) => str.add(" " + attributeName(a.attribute)));
|
|
3841
|
+
}
|
|
3842
|
+
function attributeName(attr) {
|
|
3843
|
+
const { kind: kind2 } = attr;
|
|
3844
|
+
if (kind2 === "@attribute") {
|
|
3845
|
+
return "@" + attr.name;
|
|
3846
|
+
} else {
|
|
3847
|
+
return kind2;
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
function addDirective(elem, str) {
|
|
3851
|
+
const { directive, attributes } = elem;
|
|
3852
|
+
const { kind: kind2 } = directive;
|
|
3853
|
+
if (kind2 === "diagnostic") {
|
|
3854
|
+
const { severity, rule } = directive;
|
|
3855
|
+
const control = diagnosticControlToString(severity, rule);
|
|
3856
|
+
str.add(` diagnostic${control}`);
|
|
3857
|
+
} else if (kind2 === "enable" || kind2 === "requires") {
|
|
3858
|
+
str.add(` ${kind2} ${directive.extensions.map((v) => v.name).join(", ")}`);
|
|
3859
|
+
} else {
|
|
3860
|
+
assertUnreachable$1(kind2);
|
|
3861
|
+
}
|
|
3862
|
+
listAttributeElems(attributes, str);
|
|
3863
|
+
}
|
|
3864
|
+
function unknownExpressionToString(elem) {
|
|
3865
|
+
if ("contents" in elem) {
|
|
3866
|
+
const contents = elem.contents.map((e) => {
|
|
3867
|
+
if (e.kind === "text") {
|
|
3868
|
+
return "'" + e.srcModule.src.slice(e.start, e.end) + "'";
|
|
3869
|
+
} else {
|
|
3870
|
+
return astToString(e);
|
|
3871
|
+
}
|
|
3872
|
+
}).join(" ");
|
|
3873
|
+
return contents;
|
|
3874
|
+
}
|
|
3875
|
+
return astToString(elem);
|
|
3876
|
+
}
|
|
3877
|
+
function templateParamToString(p) {
|
|
3878
|
+
if (typeof p === "string") {
|
|
3879
|
+
return p;
|
|
3880
|
+
} else if (p.kind === "type") {
|
|
3881
|
+
return typeRefElemToString(p);
|
|
3882
|
+
} else if (p.kind === "expression") {
|
|
3883
|
+
return unknownExpressionToString(p);
|
|
3884
|
+
} else {
|
|
3885
|
+
console.log("unknown template parameter type", p);
|
|
3886
|
+
return "??";
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
function typeRefElemToString(elem) {
|
|
3890
|
+
if (!elem) return "?type?";
|
|
3891
|
+
const { name: name2 } = elem;
|
|
3892
|
+
const nameStr = typeof name2 === "string" ? name2 : name2.originalName;
|
|
3893
|
+
let params = "";
|
|
3894
|
+
if (elem.templateParams !== void 0) {
|
|
3895
|
+
const paramStrs = elem.templateParams.map(templateParamToString).join(", ");
|
|
3896
|
+
params = "<" + paramStrs + ">";
|
|
3897
|
+
}
|
|
3898
|
+
return nameStr + params;
|
|
3899
|
+
}
|
|
3900
|
+
function debugContentsToString(elem) {
|
|
3901
|
+
const parts = elem.contents.map((c) => {
|
|
3902
|
+
const { kind: kind2 } = c;
|
|
3903
|
+
if (kind2 === "text") {
|
|
3904
|
+
return c.srcModule.src.slice(c.start, c.end);
|
|
3905
|
+
} else if (kind2 === "ref") {
|
|
3906
|
+
return c.ident.originalName;
|
|
3907
|
+
} else {
|
|
3908
|
+
return `?${c.kind}?`;
|
|
3909
|
+
}
|
|
3910
|
+
});
|
|
3911
|
+
return parts.join(" ");
|
|
3912
|
+
}
|
|
3913
|
+
class LinkedWesl {
|
|
3914
|
+
constructor(sourceMap) {
|
|
3915
|
+
this.sourceMap = sourceMap;
|
|
3916
|
+
}
|
|
3917
|
+
/**
|
|
3918
|
+
* Creates a {@link GPUShaderModule}.
|
|
3919
|
+
* When errors occur, they will point at the original WESL source code.
|
|
3920
|
+
*
|
|
3921
|
+
* The compilation info {@link GPUShaderModule.getCompilationInfo}
|
|
3922
|
+
* can be remapped with {@link mapGPUCompilationInfo}
|
|
3923
|
+
* @param device GPUDevice. Preferably a {@link WeslDevice} for better error reporting.
|
|
3924
|
+
* @param descriptor - Description of the {@link GPUShaderModule} to create.
|
|
3925
|
+
*/
|
|
3926
|
+
createShaderModule(device, descriptor) {
|
|
3927
|
+
if (!("injectError" in device)) {
|
|
3928
|
+
return device.createShaderModule({
|
|
3929
|
+
...descriptor,
|
|
3930
|
+
code: this.dest
|
|
3931
|
+
});
|
|
3932
|
+
}
|
|
3933
|
+
device.pushErrorScope("validation");
|
|
3934
|
+
const module = device.createShaderModule({
|
|
3935
|
+
...descriptor,
|
|
3936
|
+
code: this.dest
|
|
3937
|
+
});
|
|
3938
|
+
device.popErrorScope();
|
|
3939
|
+
let { promise, resolve } = Promise.withResolvers();
|
|
3940
|
+
device.injectError("validation", promise);
|
|
3941
|
+
module.getCompilationInfo().then((compilationInfo) => {
|
|
3942
|
+
if (compilationInfo.messages.length === 0) {
|
|
3943
|
+
resolve(null);
|
|
3944
|
+
return;
|
|
3945
|
+
}
|
|
3946
|
+
const mappedCompilationInfo = this.mapGPUCompilationInfo(compilationInfo);
|
|
3947
|
+
const errorMessage = compilationInfoToErrorMessage(
|
|
3948
|
+
mappedCompilationInfo,
|
|
3949
|
+
module
|
|
3950
|
+
);
|
|
3951
|
+
assertThat(errorMessage !== null);
|
|
3952
|
+
const error = new GPUValidationError(
|
|
3953
|
+
errorMessage
|
|
3954
|
+
);
|
|
3955
|
+
error.cause = new Error("createShaderModule failed");
|
|
3956
|
+
error.compilationInfo = mappedCompilationInfo;
|
|
3957
|
+
resolve(error);
|
|
3958
|
+
});
|
|
3959
|
+
return module;
|
|
3960
|
+
}
|
|
3961
|
+
/**
|
|
3962
|
+
* Use {@link LinkedWesl.createShaderModule} for a
|
|
3963
|
+
* better error reporting experience.
|
|
3964
|
+
*/
|
|
3965
|
+
get dest() {
|
|
3966
|
+
return this.sourceMap.dest.text;
|
|
3967
|
+
}
|
|
3968
|
+
/** Turns raw compilation info into compilation info
|
|
3969
|
+
* that points at the WESL sources. */
|
|
3970
|
+
mapGPUCompilationInfo(compilationInfo) {
|
|
3971
|
+
return {
|
|
3972
|
+
__brand: compilationInfo.__brand,
|
|
3973
|
+
messages: compilationInfo.messages.map(
|
|
3974
|
+
(v) => this.mapGPUCompilationMessage(v)
|
|
3975
|
+
)
|
|
3976
|
+
};
|
|
3977
|
+
}
|
|
3978
|
+
mapGPUCompilationMessage(message) {
|
|
3979
|
+
const srcMap = this.sourceMap;
|
|
3980
|
+
const srcPosition = srcMap.destToSrc(message.offset);
|
|
3981
|
+
const srcEndPosition = message.length > 0 ? srcMap.destToSrc(message.offset + message.length) : srcPosition;
|
|
3982
|
+
const length = srcEndPosition.position - srcPosition.position;
|
|
3983
|
+
let [lineNum, linePos] = offsetToLineNumber(
|
|
3984
|
+
srcPosition.position,
|
|
3985
|
+
srcPosition.src.text
|
|
3986
|
+
);
|
|
3987
|
+
return {
|
|
3988
|
+
__brand: message.__brand,
|
|
3989
|
+
type: message.type,
|
|
3990
|
+
message: message.message,
|
|
3991
|
+
offset: srcPosition.position,
|
|
3992
|
+
length,
|
|
3993
|
+
lineNum,
|
|
3994
|
+
linePos,
|
|
3995
|
+
module: {
|
|
3996
|
+
url: srcPosition.src.path ?? "",
|
|
3997
|
+
text: srcPosition.src.text
|
|
3998
|
+
}
|
|
3999
|
+
};
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
4002
|
+
function compilationInfoToErrorMessage(compilationInfo, shaderModule) {
|
|
4003
|
+
if (compilationInfo.messages.length === 0) return null;
|
|
4004
|
+
let result = `Compilation log for [Invalid ShaderModule (${shaderModule.label || "unlabled"})]:
|
|
4005
|
+
`;
|
|
4006
|
+
let errorCount = compilationInfo.messages.filter(
|
|
4007
|
+
(v) => v.type === "error"
|
|
4008
|
+
).length;
|
|
4009
|
+
if (errorCount > 0) {
|
|
4010
|
+
result += `${errorCount} error(s) generated while compiling the shader:
|
|
4011
|
+
`;
|
|
4012
|
+
}
|
|
4013
|
+
for (const message of compilationInfo.messages) {
|
|
4014
|
+
const { lineNum, linePos } = message;
|
|
4015
|
+
result += `${message.module.url}:${lineNum}:${linePos}`;
|
|
4016
|
+
result += ` ${message.type}: ${message.message}
|
|
4017
|
+
`;
|
|
4018
|
+
const source = message.module.text;
|
|
4019
|
+
if (source) {
|
|
4020
|
+
result += errorHighlight(source, [
|
|
4021
|
+
message.offset,
|
|
4022
|
+
message.offset + message.length
|
|
4023
|
+
]).join("\n");
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
return result;
|
|
4027
|
+
}
|
|
4028
|
+
function normalize(path) {
|
|
4029
|
+
const segments = path.split("/");
|
|
4030
|
+
const noDots = segments.filter((s) => s !== ".");
|
|
4031
|
+
const noDbl = [];
|
|
4032
|
+
noDots.forEach((s) => {
|
|
4033
|
+
if (s !== "") {
|
|
4034
|
+
if (s === ".." && noDbl.length && noDbl[noDbl.length - 1] !== "..") {
|
|
4035
|
+
noDbl.pop();
|
|
4036
|
+
} else {
|
|
4037
|
+
noDbl.push(s);
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4040
|
+
});
|
|
4041
|
+
return noDbl.join("/");
|
|
4042
|
+
}
|
|
4043
|
+
function noSuffix(path) {
|
|
4044
|
+
const lastSlash = path.lastIndexOf("/");
|
|
4045
|
+
const lastStart = lastSlash === -1 ? 0 : lastSlash + 1;
|
|
4046
|
+
const suffix = path.indexOf(".", lastStart);
|
|
4047
|
+
const suffixStart = suffix === -1 ? path.length : suffix;
|
|
4048
|
+
return path.slice(0, suffixStart);
|
|
4049
|
+
}
|
|
4050
|
+
function parsedRegistry() {
|
|
4051
|
+
resetScopeIds();
|
|
4052
|
+
return { modules: {} };
|
|
4053
|
+
}
|
|
4054
|
+
function registryToString(registry) {
|
|
4055
|
+
return `modules: ${[...Object.keys(registry.modules)]}`;
|
|
4056
|
+
}
|
|
4057
|
+
function parseWeslSrc(src) {
|
|
4058
|
+
const parsedEntries = Object.entries(src).map(([path, src2]) => {
|
|
4059
|
+
const weslAST = parseWESL(src2);
|
|
4060
|
+
return [path, weslAST];
|
|
4061
|
+
});
|
|
4062
|
+
return { modules: Object.fromEntries(parsedEntries) };
|
|
4063
|
+
}
|
|
4064
|
+
function selectModule(parsed, selectPath, packageName = "package") {
|
|
4065
|
+
let modulePath;
|
|
4066
|
+
if (selectPath.includes("::")) {
|
|
4067
|
+
modulePath = selectPath;
|
|
4068
|
+
} else if (selectPath.includes("/") || selectPath.endsWith(".wesl") || selectPath.endsWith(".wgsl")) {
|
|
4069
|
+
modulePath = fileToModulePath(selectPath, packageName);
|
|
4070
|
+
} else {
|
|
4071
|
+
modulePath = packageName + "::" + selectPath;
|
|
4072
|
+
}
|
|
4073
|
+
return parsed.modules[modulePath];
|
|
4074
|
+
}
|
|
4075
|
+
function parseIntoRegistry(srcFiles, registry, packageName = "package", debugWeslRoot) {
|
|
4076
|
+
if (debugWeslRoot === void 0) {
|
|
4077
|
+
debugWeslRoot = "";
|
|
4078
|
+
} else if (!debugWeslRoot.endsWith("/")) {
|
|
4079
|
+
debugWeslRoot += "/";
|
|
4080
|
+
}
|
|
4081
|
+
const srcModules = Object.entries(srcFiles).map(
|
|
4082
|
+
([filePath, src]) => {
|
|
4083
|
+
const modulePath = fileToModulePath(filePath, packageName);
|
|
4084
|
+
return { modulePath, debugFilePath: debugWeslRoot + filePath, src };
|
|
4085
|
+
}
|
|
4086
|
+
);
|
|
4087
|
+
srcModules.forEach((mod) => {
|
|
4088
|
+
const parsed = parseSrcModule(mod);
|
|
4089
|
+
if (registry.modules[mod.modulePath]) {
|
|
4090
|
+
throw new Error(`duplicate module path: '${mod.modulePath}'`);
|
|
4091
|
+
}
|
|
4092
|
+
registry.modules[mod.modulePath] = parsed;
|
|
4093
|
+
});
|
|
4094
|
+
}
|
|
4095
|
+
function parseLibsIntoRegistry(libs, registry) {
|
|
4096
|
+
libs.forEach(
|
|
4097
|
+
({ modules, name: name2 }) => parseIntoRegistry(modules, registry, name2)
|
|
4098
|
+
);
|
|
4099
|
+
}
|
|
4100
|
+
const libRegex = /^lib\.w[eg]sl$/i;
|
|
4101
|
+
function fileToModulePath(filePath, packageName) {
|
|
4102
|
+
if (filePath.includes("::")) {
|
|
4103
|
+
return filePath;
|
|
4104
|
+
}
|
|
4105
|
+
if (packageName !== "package" && libRegex.test(filePath)) {
|
|
4106
|
+
return packageName;
|
|
4107
|
+
}
|
|
4108
|
+
const strippedPath = noSuffix(normalize(filePath));
|
|
4109
|
+
const moduleSuffix = strippedPath.replaceAll("/", "::");
|
|
4110
|
+
const modulePath = packageName + "::" + moduleSuffix;
|
|
4111
|
+
return modulePath;
|
|
4112
|
+
}
|
|
4113
|
+
async function link(params) {
|
|
4114
|
+
const { weslSrc, debugWeslRoot, libs = [] } = params;
|
|
4115
|
+
const registry = parsedRegistry();
|
|
4116
|
+
parseIntoRegistry(weslSrc, registry, "package", debugWeslRoot);
|
|
4117
|
+
parseLibsIntoRegistry(libs, registry);
|
|
4118
|
+
return new LinkedWesl(linkRegistry({ registry, ...params }));
|
|
4119
|
+
}
|
|
4120
|
+
function linkRegistry(params) {
|
|
4121
|
+
const bound = bindAndTransform(params);
|
|
4122
|
+
const { transformedAst, newDecls, newStatements } = bound;
|
|
4123
|
+
return SrcMapBuilder.build(
|
|
4124
|
+
emitWgsl(
|
|
4125
|
+
transformedAst.moduleElem,
|
|
4126
|
+
transformedAst.srcModule,
|
|
4127
|
+
newDecls,
|
|
4128
|
+
newStatements,
|
|
4129
|
+
params.conditions
|
|
4130
|
+
)
|
|
4131
|
+
);
|
|
4132
|
+
}
|
|
4133
|
+
function bindAndTransform(params) {
|
|
4134
|
+
const { registry, mangler } = params;
|
|
4135
|
+
const { rootModuleName = "main", conditions = {} } = params;
|
|
4136
|
+
const rootAst = getRootModule(registry, rootModuleName);
|
|
4137
|
+
const { constants, config } = params;
|
|
4138
|
+
let { virtualLibs } = params;
|
|
4139
|
+
if (constants) {
|
|
4140
|
+
virtualLibs = { ...virtualLibs, constants: constantsGenerator(constants) };
|
|
4141
|
+
}
|
|
4142
|
+
let virtuals = virtualLibs && mapValues(virtualLibs, (fn2) => ({ fn: fn2 }));
|
|
4143
|
+
const bindParams = { rootAst, registry, conditions, virtuals, mangler };
|
|
4144
|
+
const bindResults = bindIdents(bindParams);
|
|
4145
|
+
const { globalNames, decls: newDecls, newStatements } = bindResults;
|
|
4146
|
+
const transformedAst = applyTransformPlugins(rootAst, globalNames, config);
|
|
4147
|
+
return { transformedAst, newDecls, newStatements };
|
|
4148
|
+
}
|
|
4149
|
+
function constantsGenerator(constants) {
|
|
4150
|
+
return () => Object.entries(constants).map(([name2, value]) => `const ${name2} = ${value};`).join("\n");
|
|
4151
|
+
}
|
|
4152
|
+
function getRootModule(parsed, rootModuleName) {
|
|
4153
|
+
const rootModule = selectModule(parsed, rootModuleName);
|
|
4154
|
+
if (!rootModule) {
|
|
4155
|
+
throw new Error(`Root module not found: ${rootModuleName}`);
|
|
4156
|
+
}
|
|
4157
|
+
return rootModule;
|
|
4158
|
+
}
|
|
4159
|
+
function applyTransformPlugins(rootModule, globalNames, config) {
|
|
4160
|
+
const { moduleElem, srcModule } = rootModule;
|
|
4161
|
+
const startAst = { moduleElem, srcModule, globalNames, notableElems: {} };
|
|
4162
|
+
const plugins = (config == null ? void 0 : config.plugins) ?? [];
|
|
4163
|
+
const transforms = filterMap(plugins, (plugin) => plugin.transform);
|
|
4164
|
+
const transformedAst = transforms.reduce(
|
|
4165
|
+
(ast, transform) => transform(ast),
|
|
4166
|
+
startAst
|
|
4167
|
+
);
|
|
4168
|
+
return transformedAst;
|
|
4169
|
+
}
|
|
4170
|
+
function emitWgsl(rootModuleElem, srcModule, newDecls, newStatements, conditions = {}) {
|
|
4171
|
+
const prologueBuilders = newStatements.map((s) => {
|
|
4172
|
+
const { elem, srcModule: srcModule2 } = s;
|
|
4173
|
+
const { src: text2, debugFilePath: path } = srcModule2;
|
|
4174
|
+
const builder = new SrcMapBuilder({ text: text2, path });
|
|
4175
|
+
lowerAndEmit(builder, [elem], conditions);
|
|
4176
|
+
builder.addNl();
|
|
4177
|
+
return builder;
|
|
4178
|
+
});
|
|
4179
|
+
const rootBuilder = new SrcMapBuilder({
|
|
4180
|
+
text: srcModule.src,
|
|
4181
|
+
path: srcModule.debugFilePath
|
|
4182
|
+
});
|
|
4183
|
+
lowerAndEmit(rootBuilder, [rootModuleElem], conditions, false);
|
|
4184
|
+
const declBuilders = newDecls.map((decl) => {
|
|
4185
|
+
const builder = new SrcMapBuilder({
|
|
4186
|
+
text: decl.srcModule.src,
|
|
4187
|
+
path: decl.srcModule.debugFilePath
|
|
4188
|
+
});
|
|
4189
|
+
lowerAndEmit(builder, [decl.declElem], conditions);
|
|
4190
|
+
return builder;
|
|
4191
|
+
});
|
|
4192
|
+
return [...prologueBuilders, rootBuilder, ...declBuilders];
|
|
4193
|
+
}
|
|
4194
|
+
function visitAst(elem, visitor) {
|
|
4195
|
+
visitor(elem);
|
|
4196
|
+
if (elem.contents) {
|
|
4197
|
+
const container = elem;
|
|
4198
|
+
container.contents.forEach((child) => visitAst(child, visitor));
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
function attributeToString(e) {
|
|
4202
|
+
const { kind: kind2 } = e.attribute;
|
|
4203
|
+
if (kind2 === "@attribute") {
|
|
4204
|
+
const { params } = e.attribute;
|
|
4205
|
+
if (params === void 0 || params.length === 0) {
|
|
4206
|
+
return "@" + e.attribute.name;
|
|
4207
|
+
} else {
|
|
4208
|
+
return `@${e.attribute.name}(${params.map((param) => contentsToString(param)).join(", ")})`;
|
|
4209
|
+
}
|
|
4210
|
+
} else if (kind2 === "@builtin") {
|
|
4211
|
+
return "@builtin(" + e.attribute.param.name + ")";
|
|
4212
|
+
} else if (kind2 === "@diagnostic") {
|
|
4213
|
+
return "@diagnostic" + diagnosticControlToString(e.attribute.severity, e.attribute.rule);
|
|
4214
|
+
} else if (kind2 === "@if") {
|
|
4215
|
+
return `@if(${expressionToString(e.attribute.param.expression)})`;
|
|
4216
|
+
} else if (kind2 === "@interpolate") {
|
|
4217
|
+
return `@interpolate(${e.attribute.params.map((v) => v.name).join(", ")})`;
|
|
4218
|
+
} else {
|
|
4219
|
+
assertUnreachable(kind2);
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
function typeListToString(params) {
|
|
4223
|
+
return `<${params.map(typeParamToString).join(", ")}>`;
|
|
4224
|
+
}
|
|
4225
|
+
function typeParamToString(param) {
|
|
4226
|
+
if (param === void 0) return "?";
|
|
4227
|
+
if (typeof param === "string") return param;
|
|
4228
|
+
if (param.kind === "expression") return contentsToString(param);
|
|
4229
|
+
if (param.kind === "type") return typeRefToString(param);
|
|
4230
|
+
assertUnreachable(param);
|
|
4231
|
+
}
|
|
4232
|
+
function typeRefToString(t) {
|
|
4233
|
+
if (!t) return "?";
|
|
4234
|
+
const { name: name2, templateParams } = t;
|
|
4235
|
+
const params = templateParams ? typeListToString(templateParams) : "";
|
|
4236
|
+
return `${refToString(name2)}${params}`;
|
|
4237
|
+
}
|
|
4238
|
+
function refToString(ref) {
|
|
4239
|
+
if (typeof ref === "string") return ref;
|
|
4240
|
+
if (ref.std) return ref.originalName;
|
|
4241
|
+
const decl = findDecl(ref);
|
|
4242
|
+
return decl.mangledName || decl.originalName;
|
|
4243
|
+
}
|
|
4244
|
+
function contentsToString(elem) {
|
|
4245
|
+
if (elem.kind === "translate-time-expression") {
|
|
4246
|
+
throw new Error("Not supported");
|
|
4247
|
+
} else if (elem.kind === "expression" || elem.kind === "stuff") {
|
|
4248
|
+
const parts = elem.contents.map((c) => {
|
|
4249
|
+
const { kind: kind2 } = c;
|
|
4250
|
+
if (kind2 === "text") {
|
|
4251
|
+
return c.srcModule.src.slice(c.start, c.end);
|
|
4252
|
+
} else if (kind2 === "ref") {
|
|
4253
|
+
return refToString(c.ident);
|
|
4254
|
+
} else {
|
|
4255
|
+
return `?${c.kind}?`;
|
|
4256
|
+
}
|
|
4257
|
+
});
|
|
4258
|
+
return parts.join(" ");
|
|
4259
|
+
} else if (elem.kind === "name") {
|
|
4260
|
+
return elem.name;
|
|
4261
|
+
} else {
|
|
4262
|
+
assertUnreachable(elem);
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
const textureStorage = matchOneOf(textureStorageTypes);
|
|
4266
|
+
matchOneOf(sampledTextureTypes);
|
|
4267
|
+
matchOneOf(multisampledTextureTypes);
|
|
4268
|
+
function bindingStructsPlugin() {
|
|
4269
|
+
return {
|
|
4270
|
+
transform: lowerBindingStructs
|
|
4271
|
+
};
|
|
4272
|
+
}
|
|
4273
|
+
function lowerBindingStructs(ast) {
|
|
4274
|
+
const clonedAst = structuredClone(ast);
|
|
4275
|
+
const { moduleElem, globalNames, notableElems } = clonedAst;
|
|
4276
|
+
const bindingStructs = markBindingStructs(moduleElem);
|
|
4277
|
+
markEntryTypes(moduleElem, bindingStructs);
|
|
4278
|
+
const newVars = bindingStructs.flatMap(
|
|
4279
|
+
(s) => transformBindingStruct(s, globalNames)
|
|
4280
|
+
);
|
|
4281
|
+
const bindingRefs = findRefsToBindingStructs(moduleElem);
|
|
4282
|
+
bindingRefs.forEach(
|
|
4283
|
+
({ memberRef, struct }) => transformBindingReference(memberRef, struct)
|
|
4284
|
+
);
|
|
4285
|
+
bindingRefs.forEach(
|
|
4286
|
+
({ intermediates }) => intermediates.forEach((e) => e.contents = [])
|
|
4287
|
+
);
|
|
4288
|
+
const contents = removeBindingStructs(moduleElem);
|
|
4289
|
+
moduleElem.contents = [...newVars, ...contents];
|
|
4290
|
+
notableElems.bindingStructs = bindingStructs;
|
|
4291
|
+
return { ...clonedAst, moduleElem };
|
|
4292
|
+
}
|
|
4293
|
+
function markEntryTypes(moduleElem, bindingStructs) {
|
|
4294
|
+
const fns = moduleElem.contents.filter((e) => e.kind === "fn");
|
|
4295
|
+
const fnFound = fnReferencesBindingStruct(fns, bindingStructs);
|
|
4296
|
+
if (fnFound) {
|
|
4297
|
+
const { fn: fn2, struct } = fnFound;
|
|
4298
|
+
struct.entryFn = fn2;
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
4301
|
+
function fnReferencesBindingStruct(fns, bindingStructs) {
|
|
4302
|
+
var _a, _b, _c;
|
|
4303
|
+
for (const fn2 of fns) {
|
|
4304
|
+
const { params } = fn2;
|
|
4305
|
+
for (const p of params) {
|
|
4306
|
+
const ref = (_b = (_a = p.name) == null ? void 0 : _a.typeRef) == null ? void 0 : _b.name;
|
|
4307
|
+
const referencedElem = (_c = ref == null ? void 0 : ref.refersTo) == null ? void 0 : _c.declElem;
|
|
4308
|
+
const struct = bindingStructs.find((s) => s === referencedElem);
|
|
4309
|
+
if (struct) {
|
|
4310
|
+
return { fn: fn2, struct };
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
function removeBindingStructs(moduleElem) {
|
|
4316
|
+
return moduleElem.contents.filter(
|
|
4317
|
+
(elem) => elem.kind !== "struct" || !elem.bindingStruct
|
|
4318
|
+
);
|
|
4319
|
+
}
|
|
4320
|
+
function markBindingStructs(moduleElem) {
|
|
4321
|
+
const structs = moduleElem.contents.filter((elem) => elem.kind === "struct");
|
|
4322
|
+
const bindingStructs = structs.filter(containsBinding);
|
|
4323
|
+
bindingStructs.forEach((struct) => struct.bindingStruct = true);
|
|
4324
|
+
return bindingStructs;
|
|
4325
|
+
}
|
|
4326
|
+
function containsBinding(struct) {
|
|
4327
|
+
return struct.members.some(({ attributes }) => bindingAttribute(attributes));
|
|
4328
|
+
}
|
|
4329
|
+
function bindingAttribute(attributes) {
|
|
4330
|
+
if (!attributes) return false;
|
|
4331
|
+
return attributes.some(
|
|
4332
|
+
({ attribute }) => attribute.kind === "@attribute" && (attribute.name === "binding" || attribute.name === "group")
|
|
4333
|
+
);
|
|
4334
|
+
}
|
|
4335
|
+
function transformBindingStruct(s, globalNames) {
|
|
4336
|
+
return s.members.map((member) => {
|
|
4337
|
+
var _a;
|
|
4338
|
+
const { typeRef, name: memberName } = member;
|
|
4339
|
+
const { name: typeName } = typeRef;
|
|
4340
|
+
const typeParameters = typeRef == null ? void 0 : typeRef.templateParams;
|
|
4341
|
+
const varName = minimallyMangledName(memberName.name, globalNames);
|
|
4342
|
+
member.mangledVarName = varName;
|
|
4343
|
+
globalNames.add(varName);
|
|
4344
|
+
const attributes = ((_a = member.attributes) == null ? void 0 : _a.map(attributeToString).join(" ")) ?? "";
|
|
4345
|
+
const varTypes = lowerPtrMember(member, typeName, typeParameters) ?? lowerStdTypeMember(typeName, typeParameters) ?? lowerStorageTextureMember(typeName, typeParameters);
|
|
4346
|
+
if (!varTypes) {
|
|
4347
|
+
console.log("unhandled case transforming member", typeName);
|
|
4348
|
+
return syntheticVar(attributes, varName, "", "??");
|
|
4349
|
+
}
|
|
4350
|
+
const { storage: storageType, varType } = varTypes;
|
|
4351
|
+
return syntheticVar(attributes, varName, storageType, varType);
|
|
4352
|
+
});
|
|
4353
|
+
}
|
|
4354
|
+
function lowerPtrMember(member, typeName, typeParameters, varName) {
|
|
4355
|
+
if (typeName.originalName === "ptr") {
|
|
4356
|
+
const origParams = typeParameters ?? [];
|
|
4357
|
+
const newParams = [origParams[0]];
|
|
4358
|
+
if (origParams[2]) newParams.push(origParams[2]);
|
|
4359
|
+
const storage = typeListToString(newParams);
|
|
4360
|
+
const varType = typeParamToString(origParams == null ? void 0 : origParams[1]);
|
|
4361
|
+
return { storage, varType };
|
|
4362
|
+
}
|
|
4363
|
+
}
|
|
4364
|
+
function lowerStdTypeMember(typeName, typeParameters) {
|
|
4365
|
+
if (typeof typeName !== "string") {
|
|
4366
|
+
const varBaseType = typeName.std ? typeName.originalName : "??";
|
|
4367
|
+
const params = typeParameters ? typeListToString(typeParameters) : "";
|
|
4368
|
+
const varType = varBaseType + params;
|
|
4369
|
+
return { varType, storage: "" };
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
function lowerStorageTextureMember(typeName, typeParameters) {
|
|
4373
|
+
if (textureStorage.test(typeName.originalName)) {
|
|
4374
|
+
const params = typeParameters ? typeListToString(typeParameters) : "";
|
|
4375
|
+
const varType = typeName + params;
|
|
4376
|
+
return { varType, storage: "" };
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
function syntheticVar(attributes, varName, storageTemplate, varType) {
|
|
4380
|
+
const varText = `${attributes} var${storageTemplate} ${varName} : ${varType};
|
|
4381
|
+
`;
|
|
4382
|
+
const elem = {
|
|
4383
|
+
kind: "synthetic",
|
|
4384
|
+
text: varText
|
|
4385
|
+
};
|
|
4386
|
+
return elem;
|
|
4387
|
+
}
|
|
4388
|
+
function findRefsToBindingStructs(moduleElem) {
|
|
4389
|
+
const members = [];
|
|
4390
|
+
visitAst(moduleElem, (elem) => {
|
|
4391
|
+
if (elem.kind === "memberRef") members.push(elem);
|
|
4392
|
+
});
|
|
4393
|
+
return filterMap(members, refersToBindingStruct);
|
|
4394
|
+
}
|
|
4395
|
+
function refersToBindingStruct(memberRef) {
|
|
4396
|
+
const found = traceToStruct(memberRef.name.ident);
|
|
4397
|
+
if (found && found.struct.bindingStruct) {
|
|
4398
|
+
return { memberRef, ...found };
|
|
4399
|
+
}
|
|
4400
|
+
}
|
|
4401
|
+
function traceToStruct(ident2) {
|
|
4402
|
+
const decl = findDecl(ident2);
|
|
4403
|
+
const declElem = decl.declElem;
|
|
4404
|
+
if (declElem && declElem.kind === "param") {
|
|
4405
|
+
const name2 = declElem.name.typeRef.name;
|
|
4406
|
+
if (typeof name2 !== "string") {
|
|
4407
|
+
if (name2.std) {
|
|
4408
|
+
return void 0;
|
|
4409
|
+
}
|
|
4410
|
+
const paramDecl = findDecl(name2);
|
|
4411
|
+
const structElem = paramDecl.declElem;
|
|
4412
|
+
if ((structElem == null ? void 0 : structElem.kind) === "struct") {
|
|
4413
|
+
return { struct: structElem, intermediates: [declElem] };
|
|
4414
|
+
}
|
|
4415
|
+
return void 0;
|
|
4416
|
+
}
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
4419
|
+
function transformBindingReference(memberRef, struct) {
|
|
4420
|
+
const refName = memberRef.member.name;
|
|
4421
|
+
const structMember = struct.members.find((m) => m.name.name === refName);
|
|
4422
|
+
if (!structMember || !structMember.mangledVarName) {
|
|
4423
|
+
return { kind: "synthetic", text: refName };
|
|
4424
|
+
}
|
|
4425
|
+
const { extraComponents } = memberRef;
|
|
4426
|
+
const extraText = extraComponents ? contentsToString(extraComponents) : "";
|
|
4427
|
+
const text2 = structMember.mangledVarName + extraText;
|
|
4428
|
+
const synthElem = { kind: "synthetic", text: text2 };
|
|
4429
|
+
memberRef.contents = [synthElem];
|
|
4430
|
+
return synthElem;
|
|
4431
|
+
}
|
|
4432
|
+
export {
|
|
4433
|
+
LinkedWesl,
|
|
4434
|
+
WeslParseError,
|
|
4435
|
+
WeslStream,
|
|
4436
|
+
astToString,
|
|
4437
|
+
attributeToString$1 as attributeToString,
|
|
4438
|
+
bindAndTransform,
|
|
4439
|
+
bindingStructsPlugin,
|
|
4440
|
+
blankWeslParseState,
|
|
4441
|
+
debugContentsToString,
|
|
4442
|
+
findRefsToBindingStructs,
|
|
4443
|
+
flatImports,
|
|
4444
|
+
identToString,
|
|
4445
|
+
link,
|
|
4446
|
+
linkRegistry,
|
|
4447
|
+
lowerBindingStructs,
|
|
4448
|
+
makeWeslDevice,
|
|
4449
|
+
markBindingStructs,
|
|
4450
|
+
markEntryTypes,
|
|
4451
|
+
noSuffix,
|
|
4452
|
+
normalize,
|
|
4453
|
+
parseIntoRegistry,
|
|
4454
|
+
parseLibsIntoRegistry,
|
|
4455
|
+
parseSrcModule,
|
|
4456
|
+
parseWESL,
|
|
4457
|
+
parseWeslSrc,
|
|
4458
|
+
parsedRegistry,
|
|
4459
|
+
registryToString,
|
|
4460
|
+
scopeToString,
|
|
4461
|
+
scopeToStringLong,
|
|
4462
|
+
selectModule,
|
|
4463
|
+
syntheticWeslParseState,
|
|
4464
|
+
throwClickableError,
|
|
4465
|
+
transformBindingReference,
|
|
4466
|
+
transformBindingStruct
|
|
4467
|
+
};
|
|
4468
|
+
//# sourceMappingURL=index.js.map
|