wesl 0.7.24 → 0.7.26
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 +1 -1
- package/dist/index.d.ts +19 -24
- package/dist/index.js +23 -21
- package/package.json +3 -4
- package/src/BindIdents.ts +31 -51
- package/src/Linker.ts +38 -25
- package/src/discovery/FindUnboundIdents.ts +1 -0
package/README.md
CHANGED
|
@@ -41,5 +41,5 @@ fn random_color(uv: vec2u) -> vec3f {
|
|
|
41
41
|
</pre>
|
|
42
42
|
|
|
43
43
|
[wesl plugin]: https://www.npmjs.com/package/wesl-plugin
|
|
44
|
-
[examples]: https://github.com/wgsl-tooling-wg/wesl-js/tree/main/
|
|
44
|
+
[examples]: https://github.com/wgsl-tooling-wg/wesl-js/tree/main/examples
|
|
45
45
|
[wesl]: https://www.npmjs.com/package/wesl
|
package/dist/index.d.ts
CHANGED
|
@@ -887,8 +887,16 @@ interface LinkParams {
|
|
|
887
887
|
/** function to construct globally unique wgsl identifiers */
|
|
888
888
|
mangler?: ManglerFn;
|
|
889
889
|
}
|
|
890
|
-
/**
|
|
891
|
-
type
|
|
890
|
+
/** Project config for web components and tools. */
|
|
891
|
+
type WeslProject = Pick<LinkParams, "weslSrc" | "rootModuleName" | "conditions" | "constants" | "libs" | "packageName">;
|
|
892
|
+
/** Context passed to virtual library generators. */
|
|
893
|
+
interface VirtualLibContext {
|
|
894
|
+
conditions: Conditions;
|
|
895
|
+
rootModulePath: string;
|
|
896
|
+
packageName: string;
|
|
897
|
+
}
|
|
898
|
+
/** Generate a virtual WESL module. */
|
|
899
|
+
type VirtualLibraryFn = (ctx: VirtualLibContext) => string;
|
|
892
900
|
/**
|
|
893
901
|
* Link a set of WESL source modules (typically the text from .wesl files) into a single WGSL string.
|
|
894
902
|
* Linking starts with a specified 'root' source module, and recursively incorporates code
|
|
@@ -925,23 +933,12 @@ declare function normalizeModuleName(name: string): string;
|
|
|
925
933
|
//#endregion
|
|
926
934
|
//#region src/BindIdents.d.ts
|
|
927
935
|
/**
|
|
928
|
-
* BindIdents pass:
|
|
929
|
-
*
|
|
930
|
-
* Goals:
|
|
931
|
-
* - Link reference idents to declaration idents
|
|
932
|
-
* - Collect used declarations (to emit in link)
|
|
933
|
-
* - Create mangled names for globals to avoid conflicts
|
|
936
|
+
* BindIdents pass: depth-first walk of the scope tree (not syntax tree),
|
|
937
|
+
* linking ref idents to declarations and mangling global names.
|
|
934
938
|
*
|
|
935
|
-
*
|
|
936
|
-
*
|
|
937
|
-
*
|
|
938
|
-
* - If no local match: check import statements for external matches
|
|
939
|
-
* - For found global decls: mangle name to be unique, collect for emission
|
|
940
|
-
*
|
|
941
|
-
* LiveDecls: tracks visible declarations at the current position, with parent links.
|
|
942
|
-
*
|
|
943
|
-
* @if/@else: respects conditional compilation by tracking @else validity state,
|
|
944
|
-
* mirroring the emission phase's filterValidElements but on scopes.
|
|
939
|
+
* For each ref: search current scope upward, then check imports for external matches.
|
|
940
|
+
* LiveDecls tracks visible declarations with parent links.
|
|
941
|
+
* @if/@else: mirrors filterValidElements but on scopes.
|
|
945
942
|
*/
|
|
946
943
|
/** Results returned from binding pass. */
|
|
947
944
|
interface BindResults {
|
|
@@ -1012,6 +1009,8 @@ interface BindContext {
|
|
|
1012
1009
|
virtuals?: VirtualLibrarySet;
|
|
1013
1010
|
/** Host package name for resolving package:: in virtual modules. */
|
|
1014
1011
|
packageName: string;
|
|
1012
|
+
/** Root module path (e.g., "package::main"). */
|
|
1013
|
+
rootModulePath: string;
|
|
1015
1014
|
/** Unbound identifiers if accumulateUnbound is true. */
|
|
1016
1015
|
unbound?: UnboundRef[];
|
|
1017
1016
|
/** Don't follow references from declarations (for library dependency detection). */
|
|
@@ -1019,11 +1018,7 @@ interface BindContext {
|
|
|
1019
1018
|
/** Visit all conditional branches (for dependency discovery). */
|
|
1020
1019
|
discoveryMode?: boolean;
|
|
1021
1020
|
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Recursively bind references to declarations in this scope and child scopes.
|
|
1024
|
-
* Tracks @else state to ensure filtered @else blocks don't pull in unused declarations.
|
|
1025
|
-
* @return new declarations found
|
|
1026
|
-
*/
|
|
1021
|
+
/** Recursively bind refs to decls in this scope and children. @return new declarations found */
|
|
1027
1022
|
declare function bindIdentsRecursive(scope: Scope, bindContext: BindContext, liveDecls: LiveDecls): DeclIdent[];
|
|
1028
1023
|
//#endregion
|
|
1029
1024
|
//#region src/Conditions.d.ts
|
|
@@ -1282,4 +1277,4 @@ declare function offsetToLineNumber(offset: number, text: string): [lineNum: num
|
|
|
1282
1277
|
*/
|
|
1283
1278
|
declare function errorHighlight(source: string, span: Span): [string, string];
|
|
1284
1279
|
//#endregion
|
|
1285
|
-
export { AbstractElem, AbstractElemBase, AliasElem, Attribute, AttributeElem, BatchModuleResolver, BinaryExpression, BinaryOperator, BindIdentsParams, BindResults, BindingAST, BindingStructElem, BlockStatement, BoundAndTransformed, BuiltinAttribute, BundleResolver, ComponentExpression, ComponentMemberExpression, CompositeResolver, ConditionalAttribute, Conditions, ConstAssertElem, ConstElem, ContainerElem, ContinuingElem, DeclIdent, DeclIdentElem, DeclarationElem, DiagnosticAttribute, DiagnosticDirective, DiagnosticRule, DirectiveElem, DirectiveVariant, ElemKindMap, ElemWithAttributes, ElemWithContentsBase, ElifAttribute, ElseAttribute, EmittableElem, EnableDirective, ExpressionElem, ExtendedGPUValidationError, FnElem, FnParamElem, FunctionCallExpression, GlobalDeclarationElem, GlobalVarElem, GrammarElem, HasAttributes, Ident, IfAttribute, ImportCollection, ImportElem, ImportItem, ImportSegment, ImportStatement, InterpolateAttribute, LetElem, LexicalScope, LinkConfig, LinkParams, LinkRegistryParams, LinkedWesl, LinkerTransform, Literal, LiveDecls, ManglerFn, ModuleElem, ModuleResolver, NameElem, OpenElem, OverrideElem, ParenthesizedExpression, ParseError, type ParseOptions, PartialScope, RecordResolver, RecordResolverOptions, RefIdent, RefIdentElem, RequiresDirective, Scope, ScopeItem, SimpleMemberRef, Span, SrcMap, SrcMapBuilder, SrcMapEntry, SrcModule, SrcPosition, SrcWithPath, StableState, StandardAttribute, StatementElem, StructElem, StructMemberElem, StuffElem, SwitchClauseElem, SyntheticElem, TerminalElem, TextElem, TrackingResolver, TransformedAST, TranslateTimeExpressionElem, TypeRefElem, TypeTemplateParameter, TypedDeclElem, UnaryExpression, UnaryOperator, UnboundRef, UnknownExpressionElem, VarElem, VirtualLibrary, VirtualLibraryFn, VirtualLibrarySet, WeslAST, WeslBundle, WeslDevice, WeslGPUCompilationInfo, WeslGPUCompilationMessage, WeslJsPlugin, WeslParseContext, WeslParseError, WeslParseState, WeslStream, _linkSync, astToString, attributeToString, bindAndTransform, bindIdents, bindIdentsRecursive, bindingStructsPlugin, childIdent, childScope, containsScope, debug, debugContentsToString, discoverModules, emptyScope, errorHighlight, fileToModulePath, filterMap, filterValidElements, findAllRootDecls, findMap, findRefsToBindingStructs, findUnboundIdents, findUnboundRefs, findValidRootDecls, flatImports, freshResolver, groupBy, grouped, identToString, last, lengthPrefixMangle, link, linkRegistry, liveDeclsToString, log, lowerBindingStructs, makeLiveDecls, makeWeslDevice, mapForward, mapValues, markBindingStructs, markEntryTypes, mergeScope, minimalMangle, minimallyMangledName, modulePartsToRelativePath, moduleToRelativePath, multiKeySet, multisampledTextureTypes, nextIdentId, noSuffix, normalize, normalizeDebugRoot, normalizeModuleName, npmNameVariations, offsetToLineNumber, overlapTail, parseSrcModule, partition, publicDecl, replaceWords, requestWeslDevice, resetScopeIds, resolveModulePath, sampledTextureTypes, sanitizePackageName, scan, scopeToString, scopeToStringLong, srcLog, stdEnumerant, stdEnumerants, stdFn, stdFns, stdType, stdTypes, textureStorageTypes, transformBindingReference, transformBindingStruct, underscoreMangle, validation, wgslStandardAttributes, withLoggerAsync };
|
|
1280
|
+
export { AbstractElem, AbstractElemBase, AliasElem, Attribute, AttributeElem, BatchModuleResolver, BinaryExpression, BinaryOperator, BindIdentsParams, BindResults, BindingAST, BindingStructElem, BlockStatement, BoundAndTransformed, BuiltinAttribute, BundleResolver, ComponentExpression, ComponentMemberExpression, CompositeResolver, ConditionalAttribute, Conditions, ConstAssertElem, ConstElem, ContainerElem, ContinuingElem, DeclIdent, DeclIdentElem, DeclarationElem, DiagnosticAttribute, DiagnosticDirective, DiagnosticRule, DirectiveElem, DirectiveVariant, ElemKindMap, ElemWithAttributes, ElemWithContentsBase, ElifAttribute, ElseAttribute, EmittableElem, EnableDirective, ExpressionElem, ExtendedGPUValidationError, FnElem, FnParamElem, FunctionCallExpression, GlobalDeclarationElem, GlobalVarElem, GrammarElem, HasAttributes, Ident, IfAttribute, ImportCollection, ImportElem, ImportItem, ImportSegment, ImportStatement, InterpolateAttribute, LetElem, LexicalScope, LinkConfig, LinkParams, LinkRegistryParams, LinkedWesl, LinkerTransform, Literal, LiveDecls, ManglerFn, ModuleElem, ModuleResolver, NameElem, OpenElem, OverrideElem, ParenthesizedExpression, ParseError, type ParseOptions, PartialScope, RecordResolver, RecordResolverOptions, RefIdent, RefIdentElem, RequiresDirective, Scope, ScopeItem, SimpleMemberRef, Span, SrcMap, SrcMapBuilder, SrcMapEntry, SrcModule, SrcPosition, SrcWithPath, StableState, StandardAttribute, StatementElem, StructElem, StructMemberElem, StuffElem, SwitchClauseElem, SyntheticElem, TerminalElem, TextElem, TrackingResolver, TransformedAST, TranslateTimeExpressionElem, TypeRefElem, TypeTemplateParameter, TypedDeclElem, UnaryExpression, UnaryOperator, UnboundRef, UnknownExpressionElem, VarElem, VirtualLibContext, VirtualLibrary, VirtualLibraryFn, VirtualLibrarySet, WeslAST, WeslBundle, WeslDevice, WeslGPUCompilationInfo, WeslGPUCompilationMessage, WeslJsPlugin, WeslParseContext, WeslParseError, WeslParseState, WeslProject, WeslStream, _linkSync, astToString, attributeToString, bindAndTransform, bindIdents, bindIdentsRecursive, bindingStructsPlugin, childIdent, childScope, containsScope, debug, debugContentsToString, discoverModules, emptyScope, errorHighlight, fileToModulePath, filterMap, filterValidElements, findAllRootDecls, findMap, findRefsToBindingStructs, findUnboundIdents, findUnboundRefs, findValidRootDecls, flatImports, freshResolver, groupBy, grouped, identToString, last, lengthPrefixMangle, link, linkRegistry, liveDeclsToString, log, lowerBindingStructs, makeLiveDecls, makeWeslDevice, mapForward, mapValues, markBindingStructs, markEntryTypes, mergeScope, minimalMangle, minimallyMangledName, modulePartsToRelativePath, moduleToRelativePath, multiKeySet, multisampledTextureTypes, nextIdentId, noSuffix, normalize, normalizeDebugRoot, normalizeModuleName, npmNameVariations, offsetToLineNumber, overlapTail, parseSrcModule, partition, publicDecl, replaceWords, requestWeslDevice, resetScopeIds, resolveModulePath, sampledTextureTypes, sanitizePackageName, scan, scopeToString, scopeToStringLong, srcLog, stdEnumerant, stdEnumerants, stdFn, stdFns, stdType, stdTypes, textureStorageTypes, transformBindingReference, transformBindingStruct, underscoreMangle, validation, wgslStandardAttributes, withLoggerAsync };
|
package/dist/index.js
CHANGED
|
@@ -3633,9 +3633,8 @@ function flatImports(ast, conditions) {
|
|
|
3633
3633
|
//#region src/BindIdents.ts
|
|
3634
3634
|
/** Bind ref idents to declarations and mangle global declaration names. */
|
|
3635
3635
|
function bindIdents(params) {
|
|
3636
|
-
const { rootAst, resolver, virtuals, accumulateUnbound } = params;
|
|
3636
|
+
const { rootAst, resolver, virtuals, accumulateUnbound, discoveryMode } = params;
|
|
3637
3637
|
const { conditions = {}, mangler = minimalMangle } = params;
|
|
3638
|
-
const { discoveryMode } = params;
|
|
3639
3638
|
const packageName = rootAst.srcModule.modulePath.split("::")[0];
|
|
3640
3639
|
const rootDecls = discoveryMode ? findAllRootDecls(rootAst.rootScope) : findValidRootDecls(rootAst.rootScope, conditions);
|
|
3641
3640
|
const { globalNames, knownDecls } = initRootDecls(rootDecls);
|
|
@@ -3646,6 +3645,7 @@ function bindIdents(params) {
|
|
|
3646
3645
|
virtuals,
|
|
3647
3646
|
mangler,
|
|
3648
3647
|
packageName,
|
|
3648
|
+
rootModulePath: rootAst.srcModule.modulePath,
|
|
3649
3649
|
foundScopes: /* @__PURE__ */ new Set(),
|
|
3650
3650
|
globalNames,
|
|
3651
3651
|
globalStatements: /* @__PURE__ */ new Map(),
|
|
@@ -3656,8 +3656,9 @@ function bindIdents(params) {
|
|
|
3656
3656
|
decls: new Map(rootDecls.map((d) => [d.originalName, d])),
|
|
3657
3657
|
parent: null
|
|
3658
3658
|
};
|
|
3659
|
-
const fromRootDecls = rootDecls.flatMap((
|
|
3660
|
-
const
|
|
3659
|
+
const fromRootDecls = rootDecls.flatMap((d) => processDependentScope(d, bindContext));
|
|
3660
|
+
const { rootScope } = rootAst;
|
|
3661
|
+
const fromRefs = bindIdentsRecursive(rootScope, bindContext, liveDecls);
|
|
3661
3662
|
const newStatements = [...bindContext.globalStatements.values()];
|
|
3662
3663
|
return {
|
|
3663
3664
|
decls: [...fromRootDecls, ...fromRefs],
|
|
@@ -3702,11 +3703,7 @@ function findAllRootDecls(rootScope) {
|
|
|
3702
3703
|
function publicDecl(scope, name, conditions) {
|
|
3703
3704
|
return getValidRootDecls(scope, conditions).find((d) => d.originalName === name);
|
|
3704
3705
|
}
|
|
3705
|
-
/**
|
|
3706
|
-
* Recursively bind references to declarations in this scope and child scopes.
|
|
3707
|
-
* Tracks @else state to ensure filtered @else blocks don't pull in unused declarations.
|
|
3708
|
-
* @return new declarations found
|
|
3709
|
-
*/
|
|
3706
|
+
/** Recursively bind refs to decls in this scope and children. @return new declarations found */
|
|
3710
3707
|
function bindIdentsRecursive(scope, bindContext, liveDecls) {
|
|
3711
3708
|
const { dontFollowDecls, foundScopes } = bindContext;
|
|
3712
3709
|
if (foundScopes.has(scope)) return [];
|
|
@@ -3744,11 +3741,7 @@ function processDependentScope(decl, ctx) {
|
|
|
3744
3741
|
if (!rootDecls) return [];
|
|
3745
3742
|
return bindIdentsRecursive(dependentScope, ctx, makeLiveDecls(rootDecls));
|
|
3746
3743
|
}
|
|
3747
|
-
/**
|
|
3748
|
-
* Trace references to their declarations.
|
|
3749
|
-
* Mutates to mangle declarations and mark std references.
|
|
3750
|
-
* @return found declaration, or undefined if already processed
|
|
3751
|
-
*/
|
|
3744
|
+
/** Resolve a ref to its declaration, mangling globals and marking std refs. */
|
|
3752
3745
|
function handleRef(ident, liveDecls, bindContext) {
|
|
3753
3746
|
if (ident.refersTo || ident.std) return;
|
|
3754
3747
|
if (ident.conditionRef) return;
|
|
@@ -3828,7 +3821,8 @@ function findExport(pathParts, srcModule, ctx) {
|
|
|
3828
3821
|
const modulePath = resolveModulePath(pathParts, srcModule.modulePath.split("::")).slice(0, -1).join("::");
|
|
3829
3822
|
const moduleAst = ctx.resolver.resolveModule(modulePath) ?? virtualModule(pathParts[0], ctx);
|
|
3830
3823
|
if (!moduleAst) return void 0;
|
|
3831
|
-
const
|
|
3824
|
+
const name = last(pathParts);
|
|
3825
|
+
const decl = publicDecl(moduleAst.rootScope, name, ctx.conditions);
|
|
3832
3826
|
if (decl) return {
|
|
3833
3827
|
decl,
|
|
3834
3828
|
moduleAst
|
|
@@ -3839,9 +3833,14 @@ function virtualModule(moduleName, ctx) {
|
|
|
3839
3833
|
const found = ctx.virtuals?.[moduleName];
|
|
3840
3834
|
if (!found) return void 0;
|
|
3841
3835
|
if (found.ast) return found.ast;
|
|
3842
|
-
const
|
|
3836
|
+
const { conditions, rootModulePath, packageName } = ctx;
|
|
3837
|
+
const src = found.fn({
|
|
3838
|
+
conditions,
|
|
3839
|
+
rootModulePath,
|
|
3840
|
+
packageName
|
|
3841
|
+
});
|
|
3843
3842
|
found.ast = parseSrcModule({
|
|
3844
|
-
modulePath:
|
|
3843
|
+
modulePath: packageName + "::" + moduleName,
|
|
3845
3844
|
debugFilePath: moduleName,
|
|
3846
3845
|
src
|
|
3847
3846
|
});
|
|
@@ -3861,8 +3860,8 @@ function rootLiveDecls(decl, conditions) {
|
|
|
3861
3860
|
assertThatDebug(scope.kind === "scope");
|
|
3862
3861
|
const root = scope;
|
|
3863
3862
|
if (!root._scopeDecls) {
|
|
3864
|
-
const
|
|
3865
|
-
root._scopeDecls = { decls: new Map(
|
|
3863
|
+
const decls = findValidRootDecls(scope, conditions);
|
|
3864
|
+
root._scopeDecls = { decls: new Map(decls.map((d) => [d.originalName, d])) };
|
|
3866
3865
|
}
|
|
3867
3866
|
return root._scopeDecls;
|
|
3868
3867
|
}
|
|
@@ -4083,6 +4082,7 @@ function findUnboundRefs(resolver) {
|
|
|
4083
4082
|
globalStatements: /* @__PURE__ */ new Map(),
|
|
4084
4083
|
mangler: minimalMangle,
|
|
4085
4084
|
packageName: "package",
|
|
4085
|
+
rootModulePath: "package::main",
|
|
4086
4086
|
unbound: [],
|
|
4087
4087
|
dontFollowDecls: true,
|
|
4088
4088
|
discoveryMode: true
|
|
@@ -4515,8 +4515,9 @@ function flattenLibraryTree(libs) {
|
|
|
4515
4515
|
* that share some sources.)
|
|
4516
4516
|
*/
|
|
4517
4517
|
function linkRegistry(params) {
|
|
4518
|
-
const { transformedAst, newDecls, newStatements } = bindAndTransform(params);
|
|
4519
|
-
|
|
4518
|
+
const { transformedAst: ast, newDecls, newStatements } = bindAndTransform(params);
|
|
4519
|
+
const builders = emitWgsl(ast.moduleElem, ast.srcModule, newDecls, newStatements, params.conditions);
|
|
4520
|
+
return SrcMapBuilder.build(builders);
|
|
4520
4521
|
}
|
|
4521
4522
|
/** Bind identifiers and apply transform plugins */
|
|
4522
4523
|
function bindAndTransform(params) {
|
|
@@ -4574,6 +4575,7 @@ function applyTransformPlugins(rootModule, globalNames, config) {
|
|
|
4574
4575
|
};
|
|
4575
4576
|
return filterMap(config?.plugins ?? [], (plugin) => plugin.transform).reduce((ast, transform) => transform(ast), startAst);
|
|
4576
4577
|
}
|
|
4578
|
+
/** Assemble WGSL output from prologue statements, root module, and imported declarations. */
|
|
4577
4579
|
function emitWgsl(rootModuleElem, srcModule, newDecls, newStatements, conditions = {}) {
|
|
4578
4580
|
const prologueBuilders = newStatements.map((s) => emitStatement(s, conditions));
|
|
4579
4581
|
const rootBuilder = new SrcMapBuilder({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wesl",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.26",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
"multi_pkg": "x",
|
|
24
24
|
"terser": "^5.43.1",
|
|
25
25
|
"typedoc": "^0.28.7",
|
|
26
|
-
"typedoc-theme-hierarchy": "^6.0.0"
|
|
27
|
-
"wrangler": "^4.22.0"
|
|
26
|
+
"typedoc-theme-hierarchy": "^6.0.0"
|
|
28
27
|
},
|
|
29
28
|
"license": "MIT",
|
|
30
29
|
"keywords": [
|
|
@@ -38,7 +37,7 @@
|
|
|
38
37
|
"build:nodebug": "vite build --config vite.nodebug.config.ts",
|
|
39
38
|
"build:size": "./scripts/size-check.ts",
|
|
40
39
|
"deploy:docsite": "run-s build:docs pages:deploy",
|
|
41
|
-
"pages:deploy": "wrangler pages deploy --project-name wesl-js docs",
|
|
40
|
+
"pages:deploy": "pnpx wrangler pages deploy --project-name wesl-js docs",
|
|
42
41
|
"test": "vitest --hideSkippedTests",
|
|
43
42
|
"test:cts": "./scripts/test-cts.ts",
|
|
44
43
|
"test:nodebug": "vitest run --config vitest.nodebug.config.ts",
|
package/src/BindIdents.ts
CHANGED
|
@@ -28,23 +28,12 @@ import {
|
|
|
28
28
|
import { last } from "./Util.ts";
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* BindIdents pass:
|
|
31
|
+
* BindIdents pass: depth-first walk of the scope tree (not syntax tree),
|
|
32
|
+
* linking ref idents to declarations and mangling global names.
|
|
32
33
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* - Create mangled names for globals to avoid conflicts
|
|
37
|
-
*
|
|
38
|
-
* Algorithm:
|
|
39
|
-
* - Recursive depth-first walk of scope tree (not syntax tree)
|
|
40
|
-
* - For each ref: search current scope, then up to parent scopes
|
|
41
|
-
* - If no local match: check import statements for external matches
|
|
42
|
-
* - For found global decls: mangle name to be unique, collect for emission
|
|
43
|
-
*
|
|
44
|
-
* LiveDecls: tracks visible declarations at the current position, with parent links.
|
|
45
|
-
*
|
|
46
|
-
* @if/@else: respects conditional compilation by tracking @else validity state,
|
|
47
|
-
* mirroring the emission phase's filterValidElements but on scopes.
|
|
34
|
+
* For each ref: search current scope upward, then check imports for external matches.
|
|
35
|
+
* LiveDecls tracks visible declarations with parent links.
|
|
36
|
+
* @if/@else: mirrors filterValidElements but on scopes.
|
|
48
37
|
*/
|
|
49
38
|
|
|
50
39
|
/** Results returned from binding pass. */
|
|
@@ -107,9 +96,9 @@ export interface BindIdentsParams
|
|
|
107
96
|
|
|
108
97
|
/** Bind ref idents to declarations and mangle global declaration names. */
|
|
109
98
|
export function bindIdents(params: BindIdentsParams): BindResults {
|
|
110
|
-
const { rootAst, resolver, virtuals, accumulateUnbound } =
|
|
99
|
+
const { rootAst, resolver, virtuals, accumulateUnbound, discoveryMode } =
|
|
100
|
+
params;
|
|
111
101
|
const { conditions = {}, mangler = minimalMangle } = params;
|
|
112
|
-
const { discoveryMode } = params;
|
|
113
102
|
const packageName = rootAst.srcModule.modulePath.split("::")[0];
|
|
114
103
|
|
|
115
104
|
const rootDecls = discoveryMode
|
|
@@ -117,6 +106,7 @@ export function bindIdents(params: BindIdentsParams): BindResults {
|
|
|
117
106
|
: findValidRootDecls(rootAst.rootScope, conditions);
|
|
118
107
|
const { globalNames, knownDecls } = initRootDecls(rootDecls);
|
|
119
108
|
|
|
109
|
+
const rootModulePath = rootAst.srcModule.modulePath;
|
|
120
110
|
const bindContext = {
|
|
121
111
|
resolver,
|
|
122
112
|
conditions,
|
|
@@ -124,6 +114,7 @@ export function bindIdents(params: BindIdentsParams): BindResults {
|
|
|
124
114
|
virtuals,
|
|
125
115
|
mangler,
|
|
126
116
|
packageName,
|
|
117
|
+
rootModulePath,
|
|
127
118
|
foundScopes: new Set<Scope>(),
|
|
128
119
|
globalNames,
|
|
129
120
|
globalStatements: new Map<AbstractElem, EmittableElem>(),
|
|
@@ -134,15 +125,11 @@ export function bindIdents(params: BindIdentsParams): BindResults {
|
|
|
134
125
|
const decls = new Map(rootDecls.map(d => [d.originalName, d] as const));
|
|
135
126
|
const liveDecls: LiveDecls = { decls, parent: null };
|
|
136
127
|
|
|
137
|
-
const fromRootDecls = rootDecls.flatMap(
|
|
138
|
-
processDependentScope(
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
const fromRefs = bindIdentsRecursive(
|
|
142
|
-
rootAst.rootScope,
|
|
143
|
-
bindContext,
|
|
144
|
-
liveDecls,
|
|
128
|
+
const fromRootDecls = rootDecls.flatMap(d =>
|
|
129
|
+
processDependentScope(d, bindContext),
|
|
145
130
|
);
|
|
131
|
+
const { rootScope } = rootAst;
|
|
132
|
+
const fromRefs = bindIdentsRecursive(rootScope, bindContext, liveDecls);
|
|
146
133
|
const newStatements = [...bindContext.globalStatements.values()];
|
|
147
134
|
return {
|
|
148
135
|
decls: [...fromRootDecls, ...fromRefs],
|
|
@@ -233,6 +220,9 @@ interface BindContext {
|
|
|
233
220
|
/** Host package name for resolving package:: in virtual modules. */
|
|
234
221
|
packageName: string;
|
|
235
222
|
|
|
223
|
+
/** Root module path (e.g., "package::main"). */
|
|
224
|
+
rootModulePath: string;
|
|
225
|
+
|
|
236
226
|
/** Unbound identifiers if accumulateUnbound is true. */
|
|
237
227
|
unbound?: UnboundRef[];
|
|
238
228
|
|
|
@@ -243,11 +233,7 @@ interface BindContext {
|
|
|
243
233
|
discoveryMode?: boolean;
|
|
244
234
|
}
|
|
245
235
|
|
|
246
|
-
/**
|
|
247
|
-
* Recursively bind references to declarations in this scope and child scopes.
|
|
248
|
-
* Tracks @else state to ensure filtered @else blocks don't pull in unused declarations.
|
|
249
|
-
* @return new declarations found
|
|
250
|
-
*/
|
|
236
|
+
/** Recursively bind refs to decls in this scope and children. @return new declarations found */
|
|
251
237
|
export function bindIdentsRecursive(
|
|
252
238
|
scope: Scope,
|
|
253
239
|
bindContext: BindContext,
|
|
@@ -257,8 +243,11 @@ export function bindIdentsRecursive(
|
|
|
257
243
|
if (foundScopes.has(scope)) return [];
|
|
258
244
|
foundScopes.add(scope);
|
|
259
245
|
|
|
260
|
-
const
|
|
261
|
-
|
|
246
|
+
const { newGlobals, newFromChildren } = processScope(
|
|
247
|
+
scope,
|
|
248
|
+
bindContext,
|
|
249
|
+
liveDecls,
|
|
250
|
+
);
|
|
262
251
|
const newFromRefs = dontFollowDecls
|
|
263
252
|
? []
|
|
264
253
|
: handleDecls(newGlobals, bindContext);
|
|
@@ -301,11 +290,7 @@ function processDependentScope(decl: DeclIdent, ctx: BindContext): DeclIdent[] {
|
|
|
301
290
|
return bindIdentsRecursive(dependentScope, ctx, makeLiveDecls(rootDecls));
|
|
302
291
|
}
|
|
303
292
|
|
|
304
|
-
/**
|
|
305
|
-
* Trace references to their declarations.
|
|
306
|
-
* Mutates to mangle declarations and mark std references.
|
|
307
|
-
* @return found declaration, or undefined if already processed
|
|
308
|
-
*/
|
|
293
|
+
/** Resolve a ref to its declaration, mangling globals and marking std refs. */
|
|
309
294
|
function handleRef(
|
|
310
295
|
ident: RefIdent,
|
|
311
296
|
liveDecls: LiveDecls,
|
|
@@ -443,11 +428,8 @@ function findExport(
|
|
|
443
428
|
ctx.resolver.resolveModule(modulePath) ?? virtualModule(pathParts[0], ctx);
|
|
444
429
|
if (!moduleAst) return undefined;
|
|
445
430
|
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
last(pathParts)!,
|
|
449
|
-
ctx.conditions,
|
|
450
|
-
);
|
|
431
|
+
const name = last(pathParts)!;
|
|
432
|
+
const decl = publicDecl(moduleAst.rootScope, name, ctx.conditions);
|
|
451
433
|
if (decl) return { decl, moduleAst };
|
|
452
434
|
}
|
|
453
435
|
|
|
@@ -460,10 +442,10 @@ function virtualModule(
|
|
|
460
442
|
if (!found) return undefined;
|
|
461
443
|
if (found.ast) return found.ast;
|
|
462
444
|
|
|
463
|
-
const
|
|
464
|
-
const
|
|
465
|
-
const
|
|
466
|
-
found.ast = parseSrcModule({ modulePath, debugFilePath, src });
|
|
445
|
+
const { conditions, rootModulePath, packageName } = ctx;
|
|
446
|
+
const src = found.fn({ conditions, rootModulePath, packageName });
|
|
447
|
+
const modulePath = packageName + "::" + moduleName;
|
|
448
|
+
found.ast = parseSrcModule({ modulePath, debugFilePath: moduleName, src });
|
|
467
449
|
return found.ast;
|
|
468
450
|
}
|
|
469
451
|
|
|
@@ -490,10 +472,8 @@ function rootLiveDecls(
|
|
|
490
472
|
|
|
491
473
|
const root = scope as LexicalScope;
|
|
492
474
|
if (!root._scopeDecls) {
|
|
493
|
-
const
|
|
494
|
-
root._scopeDecls = {
|
|
495
|
-
decls: new Map(rootDecls.map(d => [d.originalName, d])),
|
|
496
|
-
};
|
|
475
|
+
const decls = findValidRootDecls(scope, conditions);
|
|
476
|
+
root._scopeDecls = { decls: new Map(decls.map(d => [d.originalName, d])) };
|
|
497
477
|
}
|
|
498
478
|
return root._scopeDecls;
|
|
499
479
|
}
|
package/src/Linker.ts
CHANGED
|
@@ -91,8 +91,26 @@ export interface LinkParams {
|
|
|
91
91
|
mangler?: ManglerFn;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
/**
|
|
95
|
-
export type
|
|
94
|
+
/** Project config for web components and tools. */
|
|
95
|
+
export type WeslProject = Pick<
|
|
96
|
+
LinkParams,
|
|
97
|
+
| "weslSrc"
|
|
98
|
+
| "rootModuleName"
|
|
99
|
+
| "conditions"
|
|
100
|
+
| "constants"
|
|
101
|
+
| "libs"
|
|
102
|
+
| "packageName"
|
|
103
|
+
>;
|
|
104
|
+
|
|
105
|
+
/** Context passed to virtual library generators. */
|
|
106
|
+
export interface VirtualLibContext {
|
|
107
|
+
conditions: Conditions;
|
|
108
|
+
rootModulePath: string;
|
|
109
|
+
packageName: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Generate a virtual WESL module. */
|
|
113
|
+
export type VirtualLibraryFn = (ctx: VirtualLibContext) => string;
|
|
96
114
|
|
|
97
115
|
/**
|
|
98
116
|
* Link a set of WESL source modules (typically the text from .wesl files) into a single WGSL string.
|
|
@@ -182,18 +200,19 @@ export interface LinkRegistryParams
|
|
|
182
200
|
* that share some sources.)
|
|
183
201
|
*/
|
|
184
202
|
export function linkRegistry(params: LinkRegistryParams): SrcMap {
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
203
|
+
const {
|
|
204
|
+
transformedAst: ast,
|
|
205
|
+
newDecls,
|
|
206
|
+
newStatements,
|
|
207
|
+
} = bindAndTransform(params);
|
|
208
|
+
const builders = emitWgsl(
|
|
209
|
+
ast.moduleElem,
|
|
210
|
+
ast.srcModule,
|
|
211
|
+
newDecls,
|
|
212
|
+
newStatements,
|
|
213
|
+
params.conditions,
|
|
196
214
|
);
|
|
215
|
+
return SrcMapBuilder.build(builders);
|
|
197
216
|
}
|
|
198
217
|
|
|
199
218
|
export interface BoundAndTransformed {
|
|
@@ -214,15 +233,14 @@ export function bindAndTransform(
|
|
|
214
233
|
|
|
215
234
|
const virtuals = setupVirtualLibs(params.virtualLibs, constants);
|
|
216
235
|
|
|
217
|
-
const
|
|
236
|
+
const bound = bindIdents({
|
|
218
237
|
rootAst,
|
|
219
238
|
resolver,
|
|
220
239
|
conditions,
|
|
221
240
|
virtuals,
|
|
222
241
|
mangler,
|
|
223
|
-
};
|
|
224
|
-
const
|
|
225
|
-
const { globalNames, decls: newDecls, newStatements } = bindResults;
|
|
242
|
+
});
|
|
243
|
+
const { globalNames, decls: newDecls, newStatements } = bound;
|
|
226
244
|
|
|
227
245
|
const transformedAst = applyTransformPlugins(rootAst, globalNames, config);
|
|
228
246
|
return { transformedAst, newDecls, newStatements };
|
|
@@ -264,7 +282,7 @@ function setupVirtualLibs(
|
|
|
264
282
|
): VirtualLibrarySet | undefined {
|
|
265
283
|
let libs = virtualLibs;
|
|
266
284
|
if (constants) {
|
|
267
|
-
const constantsGen = () =>
|
|
285
|
+
const constantsGen: VirtualLibraryFn = () =>
|
|
268
286
|
Object.entries(constants)
|
|
269
287
|
.map(([name, value]) => `const ${name} = ${value};`)
|
|
270
288
|
.join("\n");
|
|
@@ -284,14 +302,10 @@ function applyTransformPlugins(
|
|
|
284
302
|
const startAst = { moduleElem, srcModule, globalNames, notableElems: {} };
|
|
285
303
|
const plugins = config?.plugins ?? [];
|
|
286
304
|
const transforms = filterMap(plugins, plugin => plugin.transform);
|
|
287
|
-
|
|
288
|
-
(ast, transform) => transform(ast),
|
|
289
|
-
startAst,
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
return transformedAst;
|
|
305
|
+
return transforms.reduce((ast, transform) => transform(ast), startAst);
|
|
293
306
|
}
|
|
294
307
|
|
|
308
|
+
/** Assemble WGSL output from prologue statements, root module, and imported declarations. */
|
|
295
309
|
function emitWgsl(
|
|
296
310
|
rootModuleElem: ModuleElem,
|
|
297
311
|
srcModule: SrcModule,
|
|
@@ -342,7 +356,6 @@ function emitDecl(decl: DeclIdent, conditions: Conditions): SrcMapBuilder {
|
|
|
342
356
|
return builder;
|
|
343
357
|
}
|
|
344
358
|
|
|
345
|
-
/* ---- Commentary on present and future features ---- */
|
|
346
359
|
/*
|
|
347
360
|
|
|
348
361
|
LATER
|
|
@@ -42,6 +42,7 @@ export function findUnboundRefs(resolver: BatchModuleResolver): UnboundRef[] {
|
|
|
42
42
|
globalStatements: new Map<AbstractElem, EmittableElem>(),
|
|
43
43
|
mangler: minimalMangle,
|
|
44
44
|
packageName: "package",
|
|
45
|
+
rootModulePath: "package::main",
|
|
45
46
|
unbound: [] as UnboundRef[],
|
|
46
47
|
dontFollowDecls: true,
|
|
47
48
|
discoveryMode: true,
|