wesl 0.6.49 → 0.7.1
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/dist/index.d.ts +269 -215
- package/dist/index.js +2911 -1539
- package/package.json +6 -8
- package/src/AbstractElems.ts +81 -81
- package/src/Assertions.ts +5 -5
- package/src/BindIdents.ts +192 -306
- package/src/ClickableError.ts +3 -2
- package/src/Conditions.ts +2 -2
- package/src/LinkedWesl.ts +1 -1
- package/src/Linker.ts +4 -3
- package/src/LinkerUtil.ts +1 -1
- package/src/Logging.ts +165 -0
- package/src/LowerAndEmit.ts +278 -110
- package/src/ModuleResolver.ts +15 -25
- package/src/ParseError.ts +9 -0
- package/src/ParseWESL.ts +30 -94
- package/src/RawEmit.ts +1 -4
- package/src/Reflection.ts +1 -1
- package/src/Scope.ts +3 -0
- package/src/Span.ts +2 -0
- package/src/SrcMap.ts +208 -0
- package/src/Stream.ts +30 -0
- package/src/TransformBindingStructs.ts +2 -2
- package/src/Util.ts +1 -1
- package/src/debug/ASTtoString.ts +84 -135
- package/src/discovery/FindUnboundIdents.ts +14 -5
- package/src/index.ts +4 -0
- package/src/parse/ContentsHelpers.ts +70 -0
- package/src/parse/ExpressionUtil.ts +121 -0
- package/src/parse/Keywords.ts +12 -12
- package/src/parse/OperatorBinding.ts +146 -0
- package/src/parse/ParseAttribute.ts +272 -0
- package/src/parse/ParseCall.ts +77 -0
- package/src/parse/ParseControlFlow.ts +129 -0
- package/src/parse/ParseDirective.ts +105 -0
- package/src/parse/ParseExpression.ts +288 -0
- package/src/parse/ParseFn.ts +151 -0
- package/src/parse/ParseGlobalVar.ts +131 -0
- package/src/parse/ParseIdent.ts +77 -0
- package/src/parse/ParseImport.ts +160 -0
- package/src/parse/ParseLocalVar.ts +69 -0
- package/src/parse/ParseLoop.ts +112 -0
- package/src/parse/ParseModule.ts +116 -0
- package/src/parse/ParseSimpleStatement.ts +162 -0
- package/src/parse/ParseStatement.ts +215 -0
- package/src/parse/ParseStruct.ts +89 -0
- package/src/parse/ParseType.ts +71 -0
- package/src/parse/ParseUtil.ts +174 -0
- package/src/parse/ParseValueDeclaration.ts +130 -0
- package/src/parse/ParseWesl.ts +51 -0
- package/src/parse/ParsingContext.ts +93 -0
- package/src/parse/WeslStream.ts +63 -20
- package/src/parse/stream/CachingStream.ts +48 -0
- package/src/parse/stream/MatchersStream.ts +85 -0
- package/src/parse/stream/RegexHelpers.ts +38 -0
- package/src/test/BevyLink.test.ts +100 -0
- package/src/test/BindStdTypes.test.ts +110 -0
- package/src/test/{BindWESL.test.ts → BindWESLV2.test.ts} +21 -22
- package/src/test/BulkTests.test.ts +11 -12
- package/src/test/ConditionLinking.test.ts +107 -0
- package/src/test/ConditionalElif.test.ts +1 -13
- package/src/test/ConditionalTranslationCases.test.ts +5 -0
- package/src/test/ErrorLogging.test.ts +2 -2
- package/src/test/ImportCasesV2.test.ts +63 -0
- package/src/test/LinkFails.test.ts +69 -0
- package/src/test/LinkPackage.test.ts +1 -1
- package/src/test/Linker.test.ts +75 -2
- package/src/test/LogCatcher.ts +53 -0
- package/src/test/Mangling.test.ts +1 -1
- package/src/test/ParseComments.test.ts +1 -2
- package/src/test/{ParseConditions.test.ts → ParseConditionsV2.test.ts} +57 -49
- package/src/test/ParseErrorV2.test.ts +73 -0
- package/src/test/{ParseWESL.test.ts → ParseWeslV2.test.ts} +288 -370
- package/src/test/{ScopeWESL.test.ts → ScopeWESLV2.test.ts} +205 -176
- package/src/test/TestLink.ts +51 -51
- package/src/test/TestSetup.ts +9 -3
- package/src/test/TestUtil.ts +47 -77
- package/src/test/TrimmedMatch.ts +40 -0
- package/src/test/VirtualModules.test.ts +33 -2
- package/src/test/WeslDevice.test.ts +9 -2
- package/src/test/__snapshots__/ParseWeslV2.test.ts.snap +67 -0
- package/src/test-util.ts +7 -0
- package/src/WESLCollect.ts +0 -656
- package/src/parse/AttributeGrammar.ts +0 -232
- package/src/parse/ImportGrammar.ts +0 -195
- package/src/parse/WeslBaseGrammar.ts +0 -11
- package/src/parse/WeslExpression.ts +0 -231
- package/src/parse/WeslGrammar.ts +0 -739
- package/src/test/Expression.test.ts +0 -22
- package/src/test/ImportSyntaxCases.test.ts +0 -24
- package/src/test/ParseError.test.ts +0 -45
- package/src/test/Reflection.test.ts +0 -176
- package/src/test/TransformBindingStructs.test.ts +0 -238
- /package/src/test/{ParseElif.test.ts → ParseElifV2.test.ts} +0 -0
package/src/WESLCollect.ts
DELETED
|
@@ -1,656 +0,0 @@
|
|
|
1
|
-
import { dlog } from "berry-pretty";
|
|
2
|
-
import {
|
|
3
|
-
type CollectContext,
|
|
4
|
-
type CollectPair,
|
|
5
|
-
srcLog,
|
|
6
|
-
tracing,
|
|
7
|
-
} from "mini-parse";
|
|
8
|
-
import type {
|
|
9
|
-
AbstractElem,
|
|
10
|
-
AliasElem,
|
|
11
|
-
Attribute,
|
|
12
|
-
AttributeElem,
|
|
13
|
-
ConstAssertElem,
|
|
14
|
-
ConstElem,
|
|
15
|
-
ContainerElem,
|
|
16
|
-
DeclarationElem,
|
|
17
|
-
DeclIdentElem,
|
|
18
|
-
DirectiveElem,
|
|
19
|
-
DirectiveVariant,
|
|
20
|
-
ElifAttribute,
|
|
21
|
-
ElseAttribute,
|
|
22
|
-
FnElem,
|
|
23
|
-
FnParamElem,
|
|
24
|
-
GlobalVarElem,
|
|
25
|
-
GrammarElem,
|
|
26
|
-
HasAttributes,
|
|
27
|
-
IfAttribute,
|
|
28
|
-
ImportElem,
|
|
29
|
-
LetElem,
|
|
30
|
-
ModuleElem,
|
|
31
|
-
NameElem,
|
|
32
|
-
OverrideElem,
|
|
33
|
-
RefIdentElem,
|
|
34
|
-
SimpleMemberRef,
|
|
35
|
-
StandardAttribute,
|
|
36
|
-
StatementElem,
|
|
37
|
-
StructElem,
|
|
38
|
-
StructMemberElem,
|
|
39
|
-
StuffElem,
|
|
40
|
-
SwitchClauseElem,
|
|
41
|
-
TextElem,
|
|
42
|
-
TypedDeclElem,
|
|
43
|
-
TypeRefElem,
|
|
44
|
-
UnknownExpressionElem,
|
|
45
|
-
VarElem,
|
|
46
|
-
} from "./AbstractElems.ts";
|
|
47
|
-
import { findConditional } from "./Conditions.ts";
|
|
48
|
-
import type {
|
|
49
|
-
StableState,
|
|
50
|
-
WeslAST,
|
|
51
|
-
WeslParseContext,
|
|
52
|
-
WeslParseState,
|
|
53
|
-
} from "./ParseWESL.ts";
|
|
54
|
-
import {
|
|
55
|
-
type DeclIdent,
|
|
56
|
-
emptyScope,
|
|
57
|
-
type Ident,
|
|
58
|
-
mergeScope,
|
|
59
|
-
nextIdentId,
|
|
60
|
-
type PartialScope,
|
|
61
|
-
type RefIdent,
|
|
62
|
-
type Scope,
|
|
63
|
-
} from "./Scope.ts";
|
|
64
|
-
|
|
65
|
-
export function importElem(cc: CollectContext) {
|
|
66
|
-
const importElems = cc.tags.owo?.[0] as ImportElem[]; // LATER ts typing
|
|
67
|
-
for (const importElem of importElems) {
|
|
68
|
-
(cc.app.stable as StableState).imports.push(importElem.imports);
|
|
69
|
-
addToOpenElem(cc, importElem as AbstractElem);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** add an elem to the .contents array of the currently containing element */
|
|
74
|
-
function addToOpenElem(cc: CollectContext, elem: AbstractElem): void {
|
|
75
|
-
const weslContext: WeslParseContext = cc.app.context;
|
|
76
|
-
const { openElems } = weslContext;
|
|
77
|
-
if (openElems?.length) {
|
|
78
|
-
const open = openElems[openElems.length - 1];
|
|
79
|
-
open.contents.push(elem);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** create reference Ident and add to context */
|
|
84
|
-
export function refIdent(cc: CollectContext): RefIdentElem {
|
|
85
|
-
const { src, start, end } = cc;
|
|
86
|
-
const app = cc.app as WeslParseState;
|
|
87
|
-
const { srcModule } = app.stable;
|
|
88
|
-
const originalName = src.slice(start, end);
|
|
89
|
-
|
|
90
|
-
const kind = "ref";
|
|
91
|
-
const ident: RefIdent = {
|
|
92
|
-
kind,
|
|
93
|
-
originalName,
|
|
94
|
-
ast: cc.app.stable,
|
|
95
|
-
id: nextIdentId(),
|
|
96
|
-
refIdentElem: null as any, // set below
|
|
97
|
-
};
|
|
98
|
-
const identElem: RefIdentElem = { kind, start, end, srcModule, ident };
|
|
99
|
-
ident.refIdentElem = identElem;
|
|
100
|
-
|
|
101
|
-
saveIdent(cc, identElem);
|
|
102
|
-
addToOpenElem(cc, identElem);
|
|
103
|
-
return identElem;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** create declaration Ident and add to context */
|
|
107
|
-
export function declCollect(cc: CollectContext): DeclIdentElem {
|
|
108
|
-
return declCollectInternal(cc, false);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** create global declaration Ident and add to context */
|
|
112
|
-
export function globalDeclCollect(cc: CollectContext): DeclIdentElem {
|
|
113
|
-
return declCollectInternal(cc, true);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function declCollectInternal(
|
|
117
|
-
cc: CollectContext,
|
|
118
|
-
isGlobal: boolean,
|
|
119
|
-
): DeclIdentElem {
|
|
120
|
-
const { src, start, end } = cc;
|
|
121
|
-
const app = cc.app as WeslParseState;
|
|
122
|
-
const { scope: containingScope } = app.context;
|
|
123
|
-
const { srcModule } = app.stable;
|
|
124
|
-
const originalName = src.slice(start, end);
|
|
125
|
-
|
|
126
|
-
const kind = "decl";
|
|
127
|
-
const declElem = null as any; // we'll set declElem later
|
|
128
|
-
const ident: DeclIdent = {
|
|
129
|
-
declElem,
|
|
130
|
-
kind,
|
|
131
|
-
originalName,
|
|
132
|
-
containingScope,
|
|
133
|
-
isGlobal,
|
|
134
|
-
id: nextIdentId(),
|
|
135
|
-
srcModule,
|
|
136
|
-
};
|
|
137
|
-
const identElem: DeclIdentElem = { kind, start, end, srcModule, ident };
|
|
138
|
-
|
|
139
|
-
saveIdent(cc, identElem);
|
|
140
|
-
addToOpenElem(cc, identElem);
|
|
141
|
-
return identElem;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export const typedDecl = collectElem(
|
|
145
|
-
"typeDecl",
|
|
146
|
-
(cc: CollectContext, openElem: PartElem<TypedDeclElem>) => {
|
|
147
|
-
const decl = cc.tags.decl_elem?.[0] as DeclIdentElem;
|
|
148
|
-
const typeRef = cc.tags.typeRefElem?.[0] as TypeRefElem | undefined;
|
|
149
|
-
const typeScope = cc.tags.decl_type?.[0] as PartialScope | undefined;
|
|
150
|
-
|
|
151
|
-
const partial: TypedDeclElem = { ...openElem, decl, typeScope, typeRef };
|
|
152
|
-
const elem = withTextCover(partial, cc);
|
|
153
|
-
|
|
154
|
-
return elem;
|
|
155
|
-
},
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
/** add Ident to current open scope, add IdentElem to current open element */
|
|
159
|
-
function saveIdent(
|
|
160
|
-
cc: CollectContext,
|
|
161
|
-
identElem: RefIdentElem | DeclIdentElem,
|
|
162
|
-
) {
|
|
163
|
-
const { ident } = identElem;
|
|
164
|
-
ident.id = nextIdentId();
|
|
165
|
-
const weslContext: WeslParseContext = cc.app.context;
|
|
166
|
-
weslContext.scope.contents.push(ident);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/** start a new child lexical Scope */
|
|
170
|
-
function startScope(cc: CollectContext) {
|
|
171
|
-
startSomeScope("scope", cc);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/** start a new child partial Scope */
|
|
175
|
-
function startPartialScope(cc: CollectContext) {
|
|
176
|
-
startSomeScope("partial", cc);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/** start a new lexical or partial scope */
|
|
180
|
-
function startSomeScope(kind: Scope["kind"], cc: CollectContext): void {
|
|
181
|
-
const { scope } = cc.app.context as WeslParseContext;
|
|
182
|
-
const newScope = emptyScope(scope, kind);
|
|
183
|
-
|
|
184
|
-
scope.contents.push(newScope);
|
|
185
|
-
cc.app.context.scope = newScope;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/* close current Scope and set current scope to parent */
|
|
189
|
-
function completeScope(cc: CollectContext): Scope {
|
|
190
|
-
return completeScopeInternal(cc, true);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function completeScopeNoIf(cc: CollectContext): Scope {
|
|
194
|
-
return completeScopeInternal(cc, false);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function completeScopeInternal(cc: CollectContext, attachIfs: boolean): Scope {
|
|
198
|
-
const weslContext = cc.app.context as WeslParseContext;
|
|
199
|
-
const completedScope = weslContext.scope;
|
|
200
|
-
|
|
201
|
-
const { parent } = completedScope;
|
|
202
|
-
if (parent) {
|
|
203
|
-
weslContext.scope = parent;
|
|
204
|
-
} else if (tracing) {
|
|
205
|
-
console.log("ERR: completeScope, no parent scope", completedScope.contents);
|
|
206
|
-
}
|
|
207
|
-
if (attachIfs) {
|
|
208
|
-
const condAttribute = collectConditionalAttribute(cc, completedScope);
|
|
209
|
-
completedScope.condAttribute = condAttribute;
|
|
210
|
-
}
|
|
211
|
-
return completedScope;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/** return @if, @elif, or @else attribute from the 'attribute' or 'fn_attributes' tag */
|
|
215
|
-
function collectConditionalAttribute(
|
|
216
|
-
cc: CollectContext,
|
|
217
|
-
completedScope: Scope,
|
|
218
|
-
): IfAttribute | ElifAttribute | ElseAttribute | undefined {
|
|
219
|
-
// For fn_partial_scope, use fn_attributes
|
|
220
|
-
if (completedScope.kind === "partial" && cc.tags.fn_name !== undefined) {
|
|
221
|
-
const attributes = cc.tags.fn_attributes as AttributeElem[] | undefined;
|
|
222
|
-
const flatAttrs = attributes?.flat?.();
|
|
223
|
-
return findConditional(flatAttrs);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// For other partial scopes, use attribute
|
|
227
|
-
const attributes = cc.tags.attribute as AttributeElem[] | undefined;
|
|
228
|
-
return findConditional(attributes);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// prettier-ignore
|
|
232
|
-
export type OpenElem<T extends ContainerElem = ContainerElem> = Pick<
|
|
233
|
-
T,
|
|
234
|
-
"kind" | "contents"
|
|
235
|
-
>;
|
|
236
|
-
|
|
237
|
-
// prettier-ignore
|
|
238
|
-
export type PartElem<T extends ContainerElem = ContainerElem> = Pick<
|
|
239
|
-
T,
|
|
240
|
-
"kind" | "start" | "end" | "contents"
|
|
241
|
-
>;
|
|
242
|
-
|
|
243
|
-
// prettier-ignore
|
|
244
|
-
type VarLikeElem = GlobalVarElem | VarElem | LetElem | ConstElem | OverrideElem;
|
|
245
|
-
|
|
246
|
-
export function collectVarLike<E extends VarLikeElem>(
|
|
247
|
-
kind: E["kind"],
|
|
248
|
-
): CollectPair<E> {
|
|
249
|
-
return collectElem(kind, (cc: CollectContext, openElem: PartElem<E>) => {
|
|
250
|
-
const name = cc.tags.var_name?.[0] as TypedDeclElem;
|
|
251
|
-
const decl_scope = cc.tags.decl_scope?.[0] as Scope;
|
|
252
|
-
const attributes = cc.tags.attribute as AttributeElem[] | undefined;
|
|
253
|
-
const partElem = { ...openElem, name, attributes } as E;
|
|
254
|
-
const varElem = withTextCover(partElem, cc);
|
|
255
|
-
const declIdent = name.decl.ident;
|
|
256
|
-
declIdent.declElem = varElem as DeclarationElem;
|
|
257
|
-
|
|
258
|
-
if (name.typeScope) {
|
|
259
|
-
mergeScope(name.typeScope, decl_scope);
|
|
260
|
-
declIdent.dependentScope = name.typeScope;
|
|
261
|
-
} else {
|
|
262
|
-
declIdent.dependentScope = decl_scope;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return varElem;
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export const aliasCollect = collectElem(
|
|
270
|
-
"alias",
|
|
271
|
-
(cc: CollectContext, openElem: PartElem<AliasElem>) => {
|
|
272
|
-
const name = cc.tags.alias_name?.[0] as DeclIdentElem;
|
|
273
|
-
const alias_scope = cc.tags.alias_scope?.[0] as Scope;
|
|
274
|
-
const typeRef = cc.tags.typeRefElem?.[0] as TypeRefElem;
|
|
275
|
-
const attributes: AttributeElem[] = cc.tags.attributes?.flat() ?? [];
|
|
276
|
-
const partElem: AliasElem = { ...openElem, name, attributes, typeRef };
|
|
277
|
-
const aliasElem = withTextCover(partElem, cc);
|
|
278
|
-
name.ident.dependentScope = alias_scope;
|
|
279
|
-
name.ident.declElem = aliasElem;
|
|
280
|
-
return aliasElem;
|
|
281
|
-
},
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Collect a FnElem and associated scopes.
|
|
286
|
-
*
|
|
287
|
-
* Scope definition is a bit complicated in wgsl and wesl for fns.
|
|
288
|
-
* Here's what we collect for scopes for this example function:
|
|
289
|
-
* @if(true) fn foo(a: u32) -> @location(x) R { let y = a; }
|
|
290
|
-
*
|
|
291
|
-
* -{ // partial scope in case the whole shebang is prefixed by an `@if`
|
|
292
|
-
* %foo
|
|
293
|
-
*
|
|
294
|
-
* {<=%foo // foo decl references this header+returnType+body scope (for tracing dependencies from decls)
|
|
295
|
-
* x // for @location(x) (contains no decls, so ok to merge for tracing)
|
|
296
|
-
* %a u32 // merged from header scope
|
|
297
|
-
* R // merged from return type (contains no decls, so ok to merge for tracing)
|
|
298
|
-
* %y a // merged body scope
|
|
299
|
-
* }
|
|
300
|
-
* }
|
|
301
|
-
*/
|
|
302
|
-
export const fnCollect = collectElem(
|
|
303
|
-
"fn",
|
|
304
|
-
(cc: CollectContext, openElem: PartElem<FnElem>) => {
|
|
305
|
-
// extract tags we care about
|
|
306
|
-
const ourTags = fnTags(cc);
|
|
307
|
-
const { name, headerScope, returnScope, bodyScope, body, params } = ourTags;
|
|
308
|
-
const { attributes, returnAttributes, returnType, fnScope } = ourTags;
|
|
309
|
-
|
|
310
|
-
// create the fn element (keep all attributes including conditional ones)
|
|
311
|
-
const fnElem: FnElem = {
|
|
312
|
-
...openElem,
|
|
313
|
-
...{ name, attributes, params, returnAttributes, body, returnType },
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
// --- setup the various scopes --
|
|
317
|
-
|
|
318
|
-
// merge the header, return and body scopes into the one scope
|
|
319
|
-
const mergedScope = headerScope;
|
|
320
|
-
if (returnScope) mergeScope(mergedScope, returnScope);
|
|
321
|
-
mergeScope(mergedScope, bodyScope);
|
|
322
|
-
|
|
323
|
-
// rewrite scope contents to remove old scopes and add merged scope
|
|
324
|
-
const filtered: (Ident | Scope)[] = [];
|
|
325
|
-
for (const e of fnScope.contents) {
|
|
326
|
-
if (e === headerScope || e === returnScope) {
|
|
327
|
-
continue;
|
|
328
|
-
} else if (e === bodyScope) {
|
|
329
|
-
filtered.push(mergedScope);
|
|
330
|
-
} else {
|
|
331
|
-
filtered.push(e);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
fnScope.contents = filtered;
|
|
335
|
-
|
|
336
|
-
name.ident.declElem = fnElem;
|
|
337
|
-
name.ident.dependentScope = mergedScope;
|
|
338
|
-
|
|
339
|
-
return fnElem;
|
|
340
|
-
},
|
|
341
|
-
);
|
|
342
|
-
|
|
343
|
-
/** Fetch and cast the collection tags for fnCollect
|
|
344
|
-
* LATER typechecking for collect! */
|
|
345
|
-
function fnTags(cc: CollectContext) {
|
|
346
|
-
const { fn_attributes, fn_name, fn_param, return_attributes } = cc.tags;
|
|
347
|
-
const { return_type } = cc.tags;
|
|
348
|
-
const { header_scope, return_scope, body_scope, body_statement } = cc.tags;
|
|
349
|
-
const { fn_partial_scope } = cc.tags;
|
|
350
|
-
|
|
351
|
-
const name = fn_name?.[0] as DeclIdentElem;
|
|
352
|
-
const headerScope = header_scope?.[0] as Scope;
|
|
353
|
-
const returnScope = return_scope?.[0] as Scope | undefined;
|
|
354
|
-
const bodyScope = body_scope?.[0] as Scope;
|
|
355
|
-
const body = body_statement?.[0] as StatementElem;
|
|
356
|
-
const params: FnParamElem[] = fn_param?.flat(3) ?? [];
|
|
357
|
-
const attributes: AttributeElem[] | undefined = fn_attributes?.flat();
|
|
358
|
-
const returnAttributes: AttributeElem[] | undefined =
|
|
359
|
-
return_attributes?.flat();
|
|
360
|
-
const returnType: TypeRefElem | undefined = return_type?.flat(3)[0];
|
|
361
|
-
const fnScope = fn_partial_scope?.[0] as PartialScope;
|
|
362
|
-
|
|
363
|
-
return {
|
|
364
|
-
...{ name, headerScope, returnScope, bodyScope, body, params },
|
|
365
|
-
...{ attributes, returnAttributes, returnType, fnScope },
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
export const collectFnParam = collectElem(
|
|
370
|
-
"param",
|
|
371
|
-
(cc: CollectContext, openElem: PartElem<FnParamElem>) => {
|
|
372
|
-
const name = cc.tags.param_name?.[0] as TypedDeclElem;
|
|
373
|
-
const attributes: AttributeElem[] = cc.tags.attributes?.flat() ?? [];
|
|
374
|
-
const elem: FnParamElem = { ...openElem, name, attributes };
|
|
375
|
-
const paramElem = withTextCover(elem, cc);
|
|
376
|
-
name.decl.ident.declElem = paramElem;
|
|
377
|
-
|
|
378
|
-
return paramElem;
|
|
379
|
-
},
|
|
380
|
-
);
|
|
381
|
-
|
|
382
|
-
export const collectStruct = collectElem(
|
|
383
|
-
"struct",
|
|
384
|
-
(cc: CollectContext, openElem: PartElem<StructElem>) => {
|
|
385
|
-
const name = cc.tags.type_name?.[0] as DeclIdentElem;
|
|
386
|
-
const members = cc.tags.members as StructMemberElem[];
|
|
387
|
-
const attributes: AttributeElem[] = cc.tags.attributes?.flat() ?? [];
|
|
388
|
-
name.ident.dependentScope = cc.tags.struct_scope?.[0] as Scope;
|
|
389
|
-
const structElem = { ...openElem, name, attributes, members };
|
|
390
|
-
const elem = withTextCover(structElem, cc);
|
|
391
|
-
name.ident.declElem = elem as DeclarationElem;
|
|
392
|
-
|
|
393
|
-
return elem;
|
|
394
|
-
},
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
export const collectStructMember = collectElem(
|
|
398
|
-
"member",
|
|
399
|
-
(cc: CollectContext, openElem: PartElem<StructMemberElem>) => {
|
|
400
|
-
const name = cc.tags.nameElem?.[0] as NameElem;
|
|
401
|
-
const typeRef = cc.tags.typeRefElem?.[0];
|
|
402
|
-
const attributes = cc.tags.attribute?.flat(3) as AttributeElem[];
|
|
403
|
-
const partElem = { ...openElem, name, attributes, typeRef };
|
|
404
|
-
return withTextCover(partElem, cc);
|
|
405
|
-
},
|
|
406
|
-
);
|
|
407
|
-
|
|
408
|
-
export const specialAttribute = collectElem(
|
|
409
|
-
"attribute",
|
|
410
|
-
(cc: CollectContext, openElem: PartElem<AttributeElem>) => {
|
|
411
|
-
const attribute = cc.tags.attr_variant?.[0] as Attribute;
|
|
412
|
-
const attrElem: AttributeElem = { ...openElem, attribute };
|
|
413
|
-
return attrElem;
|
|
414
|
-
},
|
|
415
|
-
);
|
|
416
|
-
|
|
417
|
-
/** debug routine to log tags at collect() */
|
|
418
|
-
export function logCollect(msg?: string): (cc: CollectContext) => void {
|
|
419
|
-
return function _log(cc: CollectContext) {
|
|
420
|
-
dlog(msg ?? "log", { tags: [...Object.keys(cc.tags)] });
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
export const assertCollect = attrElemCollect<ConstAssertElem>("assert");
|
|
425
|
-
export const statementCollect = attrElemCollect<StatementElem>("statement");
|
|
426
|
-
export const switchClauseCollect =
|
|
427
|
-
attrElemCollect<SwitchClauseElem>("switch-clause");
|
|
428
|
-
|
|
429
|
-
/** @return a collector for container elem types that have only an attributes field */
|
|
430
|
-
function attrElemCollect<T extends ContainerElem & HasAttributes>(
|
|
431
|
-
kind: T["kind"],
|
|
432
|
-
): CollectPair<T> {
|
|
433
|
-
return collectElem(kind, (cc: CollectContext, openElem: PartElem<T>) => {
|
|
434
|
-
const attributes = cc.tags.attribute?.flat(3) as AttributeElem[];
|
|
435
|
-
const partElem = { ...openElem, attributes };
|
|
436
|
-
return withTextCover(partElem as T, cc);
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
export const collectAttribute = collectElem(
|
|
441
|
-
"attribute",
|
|
442
|
-
(cc: CollectContext, openElem: PartElem<AttributeElem>) => {
|
|
443
|
-
const params = cc.tags.attrParam as UnknownExpressionElem[] | undefined;
|
|
444
|
-
const name = cc.tags.name?.[0] as string;
|
|
445
|
-
const kind = "@attribute";
|
|
446
|
-
const stdAttribute: StandardAttribute = { kind, name, params };
|
|
447
|
-
const attrElem: AttributeElem = { ...openElem, attribute: stdAttribute };
|
|
448
|
-
return attrElem;
|
|
449
|
-
},
|
|
450
|
-
);
|
|
451
|
-
|
|
452
|
-
export const typeRefCollect = collectElem(
|
|
453
|
-
"type",
|
|
454
|
-
// @ts-expect-error type mismatch
|
|
455
|
-
(cc: CollectContext, openElem: PartElem<TypeRefElem>) => {
|
|
456
|
-
const templateParamsTemp: any[] | undefined =
|
|
457
|
-
cc.tags.templateParam?.flat(3);
|
|
458
|
-
|
|
459
|
-
const typeRef = cc.tags.typeRefName?.[0] as string | RefIdentElem;
|
|
460
|
-
const name = typeof typeRef === "string" ? typeRef : typeRef.ident;
|
|
461
|
-
const partElem = {
|
|
462
|
-
...openElem,
|
|
463
|
-
name,
|
|
464
|
-
templateParams: templateParamsTemp as any[],
|
|
465
|
-
};
|
|
466
|
-
// @ts-expect-error type mismatch
|
|
467
|
-
return withTextCover(partElem, cc);
|
|
468
|
-
},
|
|
469
|
-
);
|
|
470
|
-
|
|
471
|
-
// LATER This creates useless unknown-expression elements
|
|
472
|
-
export const expressionCollect = collectElem(
|
|
473
|
-
"expression",
|
|
474
|
-
(cc: CollectContext, openElem: PartElem<UnknownExpressionElem>) => {
|
|
475
|
-
const partElem = { ...openElem };
|
|
476
|
-
return withTextCover(partElem, cc);
|
|
477
|
-
},
|
|
478
|
-
);
|
|
479
|
-
|
|
480
|
-
export function globalAssertCollect(cc: CollectContext): void {
|
|
481
|
-
const globalAssert = cc.tags.const_assert?.flat()[0];
|
|
482
|
-
const ast = cc.app.stable as WeslAST;
|
|
483
|
-
if (!ast.moduleAsserts) ast.moduleAsserts = [];
|
|
484
|
-
ast.moduleAsserts.push(globalAssert);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
export const stuffCollect = collectElem(
|
|
488
|
-
"stuff",
|
|
489
|
-
(cc: CollectContext, openElem: PartElem<StuffElem>) => {
|
|
490
|
-
const partElem = { ...openElem };
|
|
491
|
-
return withTextCover(partElem, cc);
|
|
492
|
-
},
|
|
493
|
-
);
|
|
494
|
-
|
|
495
|
-
export const memberRefCollect = collectElem(
|
|
496
|
-
"memberRef",
|
|
497
|
-
(cc: CollectContext, openElem: PartElem<SimpleMemberRef>) => {
|
|
498
|
-
const { component, structRef, extra_components } = cc.tags;
|
|
499
|
-
const member = component?.[0] as NameElem;
|
|
500
|
-
const name = structRef?.flat()[0] as RefIdentElem;
|
|
501
|
-
const extraComponents = extra_components?.flat()[0] as StuffElem;
|
|
502
|
-
|
|
503
|
-
const partElem: SimpleMemberRef = {
|
|
504
|
-
...openElem,
|
|
505
|
-
name,
|
|
506
|
-
member,
|
|
507
|
-
extraComponents,
|
|
508
|
-
};
|
|
509
|
-
return withTextCover(partElem, cc) as any;
|
|
510
|
-
},
|
|
511
|
-
);
|
|
512
|
-
|
|
513
|
-
export function nameCollect(cc: CollectContext): NameElem {
|
|
514
|
-
const { start, end, src } = cc;
|
|
515
|
-
const name = src.slice(start, end);
|
|
516
|
-
const elem: NameElem = { kind: "name", start, end, name };
|
|
517
|
-
addToOpenElem(cc, elem);
|
|
518
|
-
return elem;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
export const collectModule = collectElem(
|
|
522
|
-
"module",
|
|
523
|
-
(cc: CollectContext, openElem: PartElem<ModuleElem>) => {
|
|
524
|
-
const ccComplete = { ...cc, start: 0, end: cc.src.length }; // force module to cover entire source despite ws skipping
|
|
525
|
-
const moduleElem: ModuleElem = withTextCover(openElem, ccComplete);
|
|
526
|
-
const weslState: StableState = cc.app.stable;
|
|
527
|
-
weslState.moduleElem = moduleElem;
|
|
528
|
-
return moduleElem;
|
|
529
|
-
},
|
|
530
|
-
);
|
|
531
|
-
|
|
532
|
-
export function directiveCollect(cc: CollectContext): DirectiveElem {
|
|
533
|
-
const { start, end } = cc;
|
|
534
|
-
const directive: DirectiveVariant = cc.tags.directive?.flat()[0];
|
|
535
|
-
const attributes: AttributeElem[] | undefined = cc.tags.attribute?.flat();
|
|
536
|
-
|
|
537
|
-
const kind = "directive";
|
|
538
|
-
const elem: DirectiveElem = { kind, attributes, start, end, directive };
|
|
539
|
-
addToOpenElem(cc, elem);
|
|
540
|
-
return elem;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
/**
|
|
544
|
-
* Collect a LexicalScope.
|
|
545
|
-
*
|
|
546
|
-
* The scope starts encloses all idents and subscopes inside the parser to which
|
|
547
|
-
* .collect is attached
|
|
548
|
-
*/
|
|
549
|
-
export const scopeCollect: CollectPair<Scope> = {
|
|
550
|
-
before: startScope,
|
|
551
|
-
after: completeScope,
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
/**
|
|
555
|
-
* Collect a LexicalScope.
|
|
556
|
-
*
|
|
557
|
-
* The scope starts encloses all idents and subscopes inside the parser to which
|
|
558
|
-
* .collect is attached
|
|
559
|
-
*
|
|
560
|
-
* '@if' attributes are not attached to the scope.
|
|
561
|
-
*/
|
|
562
|
-
export const scopeCollectNoIf: CollectPair<Scope> = {
|
|
563
|
-
before: startScope,
|
|
564
|
-
after: completeScopeNoIf,
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* Collect a PartialScope.
|
|
569
|
-
*
|
|
570
|
-
* The scope starts encloses all idents and subscopes inside the parser to which
|
|
571
|
-
* .collect is attached
|
|
572
|
-
*/
|
|
573
|
-
export const partialScopeCollect: CollectPair<Scope> = {
|
|
574
|
-
before: startPartialScope,
|
|
575
|
-
after: completeScope,
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
/** utility to collect an ElemWithContents
|
|
579
|
-
* starts the new element as the collection point corresponding
|
|
580
|
-
* to the start of the attached grammar and completes
|
|
581
|
-
* the element in the at the end of the grammar.
|
|
582
|
-
*
|
|
583
|
-
* In between the start and the end, the new element is available
|
|
584
|
-
* as an 'open' element in the collection context. While this element
|
|
585
|
-
* is 'open', other collected are added to the 'contents' field of this
|
|
586
|
-
* open element.
|
|
587
|
-
*/
|
|
588
|
-
function collectElem<V extends ContainerElem>(
|
|
589
|
-
kind: V["kind"],
|
|
590
|
-
fn: (cc: CollectContext, partialElem: PartElem<V>) => V,
|
|
591
|
-
): CollectPair<V> {
|
|
592
|
-
return {
|
|
593
|
-
before: (cc: CollectContext) => {
|
|
594
|
-
const partialElem = { kind, contents: [] };
|
|
595
|
-
const weslContext: WeslParseContext = cc.app.context;
|
|
596
|
-
weslContext.openElems.push(partialElem);
|
|
597
|
-
},
|
|
598
|
-
after: (cc: CollectContext) => {
|
|
599
|
-
// LATER refine start?
|
|
600
|
-
const weslContext: WeslParseContext = cc.app.context;
|
|
601
|
-
const partialElem = weslContext.openElems.pop() as PartElem<V>;
|
|
602
|
-
console.assert(partialElem && partialElem.kind === kind);
|
|
603
|
-
const elem = fn(cc, { ...partialElem, start: cc.start, end: cc.end });
|
|
604
|
-
if (elem) addToOpenElem(cc, elem as AbstractElem);
|
|
605
|
-
return elem;
|
|
606
|
-
},
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
/**
|
|
611
|
-
* @return a copy of the element with contents extended
|
|
612
|
-
* to include TextElems to cover the entire range.
|
|
613
|
-
*/
|
|
614
|
-
function withTextCover<T extends ContainerElem>(
|
|
615
|
-
elem: T,
|
|
616
|
-
cc: CollectContext,
|
|
617
|
-
): T {
|
|
618
|
-
const contents = coverWithText(cc, elem);
|
|
619
|
-
return { ...elem, contents };
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
/** cover the entire source range with Elems by creating TextElems to
|
|
623
|
-
* cover any parts of the source that are not covered by other elems
|
|
624
|
-
* @returns the existing elems combined with any new TextElems, in src order */
|
|
625
|
-
function coverWithText(cc: CollectContext, elem: ContainerElem): GrammarElem[] {
|
|
626
|
-
let { start: pos } = cc;
|
|
627
|
-
const ast: WeslAST = cc.app.stable;
|
|
628
|
-
const { contents, end } = elem;
|
|
629
|
-
const sorted = (contents as GrammarElem[]).sort((a, b) => a.start - b.start);
|
|
630
|
-
|
|
631
|
-
const elems: GrammarElem[] = [];
|
|
632
|
-
for (const elem of sorted) {
|
|
633
|
-
if (pos < elem.start) {
|
|
634
|
-
elems.push(makeTextElem(elem.start));
|
|
635
|
-
}
|
|
636
|
-
elems.push(elem);
|
|
637
|
-
pos = elem.end;
|
|
638
|
-
}
|
|
639
|
-
if (pos < end) {
|
|
640
|
-
elems.push(makeTextElem(end));
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
return elems;
|
|
644
|
-
|
|
645
|
-
function makeTextElem(end: number): TextElem {
|
|
646
|
-
return { kind: "text", start: pos, end, srcModule: ast.srcModule };
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/** for debugging */
|
|
651
|
-
// oxlint-disable-next-line eslint(no-unused-vars)
|
|
652
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
653
|
-
function _collectLog(cc: CollectContext, ...messages: any[]): void {
|
|
654
|
-
const { src, start, end } = cc;
|
|
655
|
-
srcLog(src, [start, end], ...messages);
|
|
656
|
-
}
|