typegpu 0.10.1 → 0.11.0-rc.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/_virtual/_rolldown/runtime.js +13 -0
- package/builtin.d.ts +50 -0
- package/builtin.js +35 -0
- package/common/fullScreenTriangle.d.ts +22 -0
- package/common/fullScreenTriangle.js +34 -0
- package/common/index.d.ts +4 -4
- package/common/index.js +8 -7
- package/common/writeSoA.d.ts +16 -0
- package/common/writeSoA.js +90 -0
- package/core/buffer/buffer.d.ts +79 -0
- package/core/buffer/buffer.js +246 -0
- package/core/buffer/bufferShorthand.d.ts +48 -0
- package/core/buffer/bufferShorthand.js +53 -0
- package/core/buffer/bufferUsage.d.ts +43 -0
- package/core/buffer/bufferUsage.js +165 -0
- package/core/constant/tgpuConstant.d.ts +29 -0
- package/core/constant/tgpuConstant.js +68 -0
- package/core/declare/tgpuDeclare.d.ts +18 -0
- package/core/declare/tgpuDeclare.js +39 -0
- package/core/function/autoIO.d.ts +38 -0
- package/core/function/autoIO.js +85 -0
- package/core/function/comptime.d.ts +39 -0
- package/core/function/comptime.js +49 -0
- package/core/function/createCallableSchema.js +40 -0
- package/core/function/dualImpl.js +52 -0
- package/core/function/entryInputRouter.js +39 -0
- package/core/function/extractArgs.js +204 -0
- package/core/function/fnCore.js +90 -0
- package/core/function/fnTypes.d.ts +40 -0
- package/core/function/ioSchema.d.ts +10 -0
- package/core/function/ioSchema.js +51 -0
- package/core/function/shelllessImpl.d.ts +28 -0
- package/core/function/shelllessImpl.js +21 -0
- package/core/function/templateUtils.js +12 -0
- package/core/function/tgpuComputeFn.d.ts +48 -0
- package/core/function/tgpuComputeFn.js +55 -0
- package/core/function/tgpuFn.d.ts +52 -0
- package/core/function/tgpuFn.js +168 -0
- package/core/function/tgpuFragmentFn.d.ts +72 -0
- package/core/function/tgpuFragmentFn.js +63 -0
- package/core/function/tgpuVertexFn.d.ts +59 -0
- package/core/function/tgpuVertexFn.js +59 -0
- package/core/pipeline/applyPipelineState.js +35 -0
- package/core/pipeline/computePipeline.d.ts +54 -0
- package/core/pipeline/computePipeline.js +227 -0
- package/core/pipeline/connectAttachmentToShader.js +24 -0
- package/core/pipeline/connectTargetsToShader.js +27 -0
- package/core/pipeline/limitsOverflow.js +12 -0
- package/core/pipeline/pipelineUtils.js +29 -0
- package/core/pipeline/renderPipeline.d.ts +284 -0
- package/core/pipeline/renderPipeline.js +489 -0
- package/core/pipeline/timeable.d.ts +20 -0
- package/core/pipeline/timeable.js +55 -0
- package/core/pipeline/typeGuards.js +27 -0
- package/core/querySet/querySet.d.ts +20 -0
- package/core/querySet/querySet.js +104 -0
- package/core/rawCodeSnippet/tgpuRawCodeSnippet.d.ts +59 -0
- package/core/rawCodeSnippet/tgpuRawCodeSnippet.js +94 -0
- package/core/resolve/externals.d.ts +8 -0
- package/core/resolve/externals.js +56 -0
- package/core/resolve/namespace.d.ts +38 -0
- package/core/resolve/namespace.js +39 -0
- package/core/resolve/resolveData.js +144 -0
- package/core/resolve/stitch.js +23 -0
- package/core/resolve/tgpuResolve.d.ts +153 -0
- package/core/resolve/tgpuResolve.js +66 -0
- package/core/root/configurableImpl.js +17 -0
- package/core/root/init.d.ts +64 -0
- package/core/root/init.js +464 -0
- package/core/root/rootTypes.d.ts +642 -0
- package/core/sampler/sampler.d.ts +31 -0
- package/core/sampler/sampler.js +116 -0
- package/core/simulate/tgpuSimulate.d.ts +36 -0
- package/core/simulate/tgpuSimulate.js +74 -0
- package/core/slot/accessor.d.ts +9 -0
- package/core/slot/accessor.js +95 -0
- package/core/slot/internalSlots.js +5 -0
- package/core/slot/lazy.d.ts +6 -0
- package/core/slot/lazy.js +40 -0
- package/core/slot/slot.d.ts +6 -0
- package/core/slot/slot.js +39 -0
- package/core/slot/slotTypes.d.ts +92 -0
- package/core/slot/slotTypes.js +19 -0
- package/core/texture/externalTexture.d.ts +6 -0
- package/core/texture/externalTexture.js +47 -0
- package/core/texture/texture.d.ts +114 -0
- package/core/texture/texture.js +314 -0
- package/core/texture/textureFormats.d.ts +29 -0
- package/core/texture/textureFormats.js +97 -0
- package/core/texture/textureProps.d.ts +11 -0
- package/core/texture/textureUtils.js +222 -0
- package/core/texture/usageExtension.d.ts +21 -0
- package/core/texture/usageExtension.js +19 -0
- package/core/unroll/tgpuUnroll.d.ts +68 -0
- package/core/unroll/tgpuUnroll.js +94 -0
- package/core/valueProxyUtils.js +42 -0
- package/core/variable/tgpuVariable.d.ts +38 -0
- package/core/variable/tgpuVariable.js +99 -0
- package/core/vertexLayout/connectAttributesToShader.js +57 -0
- package/core/vertexLayout/vertexAttribute.d.ts +29 -0
- package/core/vertexLayout/vertexLayout.d.ts +19 -0
- package/core/vertexLayout/vertexLayout.js +103 -0
- package/data/alignIO.js +14 -0
- package/data/alignmentOf.d.ts +9 -0
- package/data/alignmentOf.js +86 -0
- package/data/array.d.ts +26 -0
- package/data/array.js +46 -0
- package/data/atomic.d.ts +15 -0
- package/data/atomic.js +24 -0
- package/data/attributes.d.ts +121 -0
- package/data/attributes.js +145 -0
- package/data/autoStruct.d.ts +1 -0
- package/data/autoStruct.js +81 -0
- package/data/compiledIO.js +228 -0
- package/data/dataIO.js +556 -0
- package/data/dataTypes.d.ts +115 -0
- package/data/dataTypes.js +100 -0
- package/data/deepEqual.d.ts +25 -0
- package/data/deepEqual.js +56 -0
- package/data/disarray.d.ts +32 -0
- package/data/disarray.js +50 -0
- package/data/getLongestContiguousPrefix.d.ts +9 -0
- package/data/getLongestContiguousPrefix.js +13 -0
- package/data/index.d.ts +26 -4
- package/data/index.js +36 -9
- package/data/instanceToSchema.d.ts +33 -0
- package/data/isContiguous.d.ts +9 -0
- package/data/isContiguous.js +13 -0
- package/data/matrix.d.ts +124 -0
- package/data/matrix.js +531 -0
- package/data/numberOps.js +23 -0
- package/data/numeric.d.ts +81 -0
- package/data/numeric.js +221 -0
- package/data/offsetUtils.d.ts +33 -0
- package/data/offsetUtils.js +165 -0
- package/data/offsets.js +34 -0
- package/data/partialIO.js +113 -0
- package/data/ptr.d.ts +11 -0
- package/data/ptr.js +44 -0
- package/data/ref.d.ts +34 -0
- package/data/ref.js +94 -0
- package/data/sampler.d.ts +107 -0
- package/data/sampler.js +24 -0
- package/data/schemaCallWrapper.js +30 -0
- package/data/schemaMemoryLayout.js +198 -0
- package/data/sizeOf.d.ts +9 -0
- package/data/sizeOf.js +13 -0
- package/data/snippet.d.ts +26 -0
- package/data/snippet.js +70 -0
- package/data/struct.d.ts +17 -0
- package/data/struct.js +44 -0
- package/data/texture.d.ts +292 -0
- package/{texture-BagDrrks.js → data/texture.js} +6 -5
- package/data/unstruct.d.ts +24 -0
- package/data/unstruct.js +41 -0
- package/data/vector.d.ts +191 -0
- package/data/vector.js +239 -0
- package/data/vectorImpl.js +515 -0
- package/data/vectorOps.js +681 -0
- package/data/vertexFormatData.d.ts +190 -0
- package/data/vertexFormatData.js +109 -0
- package/data/wgslTypes.d.ts +924 -0
- package/data/wgslTypes.js +222 -0
- package/errors.d.ts +44 -0
- package/errors.js +131 -0
- package/execMode.js +49 -0
- package/extension.d.ts +11 -0
- package/extension.js +16 -0
- package/getGPUValue.js +7 -0
- package/index.d.ts +42 -243
- package/index.js +21 -6320
- package/indexNamedExports.d.ts +40 -0
- package/mathUtils.js +12 -0
- package/memo.js +22 -0
- package/nameRegistry.d.ts +30 -0
- package/nameRegistry.js +447 -0
- package/package.js +4 -0
- package/package.json +26 -26
- package/resolutionCtx.d.ts +19 -0
- package/resolutionCtx.js +612 -0
- package/shared/env.js +12 -0
- package/shared/generators.js +13 -0
- package/shared/meta.d.ts +39 -0
- package/shared/meta.js +61 -0
- package/shared/repr.d.ts +138 -0
- package/shared/stringify.js +20 -0
- package/shared/symbols.d.ts +70 -0
- package/shared/symbols.js +48 -0
- package/shared/utilityTypes.d.ts +33 -0
- package/shared/utilityTypes.js +6 -0
- package/shared/vertexFormat.d.ts +70 -0
- package/shared/vertexFormat.js +63 -0
- package/std/array.d.ts +7 -0
- package/std/array.js +25 -0
- package/std/atomic.d.ts +19 -0
- package/std/atomic.js +111 -0
- package/std/bitcast.d.ts +10 -0
- package/std/bitcast.js +41 -0
- package/std/boolean.d.ts +141 -0
- package/std/boolean.js +299 -0
- package/std/derivative.d.ts +16 -0
- package/std/derivative.js +87 -0
- package/std/discard.d.ts +6 -0
- package/std/discard.js +14 -0
- package/std/extensions.d.ts +6 -0
- package/std/extensions.js +12 -0
- package/std/index.d.ts +17 -4
- package/std/index.js +21 -7
- package/std/matrix.d.ts +41 -0
- package/std/matrix.js +85 -0
- package/std/numeric.d.ts +200 -0
- package/std/numeric.js +845 -0
- package/std/operators.d.ts +56 -0
- package/std/operators.js +227 -0
- package/std/packing.d.ts +26 -0
- package/std/packing.js +84 -0
- package/std/range.d.ts +24 -0
- package/std/range.js +38 -0
- package/std/subgroup.d.ts +47 -0
- package/std/subgroup.js +218 -0
- package/std/texture.d.ts +117 -0
- package/std/texture.js +207 -0
- package/tgpu.js +42 -0
- package/tgpuBindGroupLayout.d.ts +161 -0
- package/tgpuBindGroupLayout.js +272 -0
- package/tgpuUnstable.d.ts +48 -0
- package/tgpuUnstable.js +64 -0
- package/tgsl/accessIndex.js +43 -0
- package/tgsl/accessProp.js +115 -0
- package/tgsl/consoleLog/deserializers.js +115 -0
- package/tgsl/consoleLog/logGenerator.js +84 -0
- package/tgsl/consoleLog/serializers.js +223 -0
- package/tgsl/consoleLog/types.d.ts +52 -0
- package/tgsl/consoleLog/types.js +11 -0
- package/tgsl/conversion.js +198 -0
- package/tgsl/forOfUtils.js +71 -0
- package/tgsl/generationHelpers.d.ts +37 -0
- package/tgsl/generationHelpers.js +67 -0
- package/tgsl/math.js +43 -0
- package/tgsl/shaderGenerator.d.ts +20 -0
- package/tgsl/shaderGenerator_members.d.ts +2 -0
- package/tgsl/shaderGenerator_members.js +6 -0
- package/tgsl/shellless.d.ts +11 -0
- package/tgsl/shellless.js +46 -0
- package/tgsl/wgslGenerator.d.ts +36 -0
- package/tgsl/wgslGenerator.js +639 -0
- package/types.d.ts +265 -0
- package/types.js +43 -0
- package/unwrapper.d.ts +27 -0
- package/wgslExtensions.d.ts +5 -0
- package/wgslExtensions.js +17 -0
- package/builtin-DdtWpk2t.js +0 -818
- package/builtin-DdtWpk2t.js.map +0 -1
- package/chunk-BYypO7fO.js +0 -18
- package/common/index.d.ts.map +0 -1
- package/common/index.js.map +0 -1
- package/data/index.d.ts.map +0 -1
- package/data/index.js.map +0 -1
- package/deepEqual-DQxK4vdp.js +0 -413
- package/deepEqual-DQxK4vdp.js.map +0 -1
- package/extensions-DIVuAfBM.js +0 -2032
- package/extensions-DIVuAfBM.js.map +0 -1
- package/fullScreenTriangle-CfFyQd_0.js +0 -543
- package/fullScreenTriangle-CfFyQd_0.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/indexNamedExports-oL6tyaJ9.d.ts +0 -5697
- package/indexNamedExports-oL6tyaJ9.d.ts.map +0 -1
- package/operators-d-PMVTo7.js +0 -4158
- package/operators-d-PMVTo7.js.map +0 -1
- package/std/index.d.ts.map +0 -1
- package/std/index.js.map +0 -1
- package/texture-BagDrrks.js.map +0 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { $getNameForward, $gpuCallable, $internal } from "../../shared/symbols.js";
|
|
2
|
+
import { setName } from "../../shared/meta.js";
|
|
3
|
+
import { WgslTypeError } from "../../errors.js";
|
|
4
|
+
import { isKnownAtComptime } from "../../types.js";
|
|
5
|
+
import { coerceToSnippet } from "../../tgsl/generationHelpers.js";
|
|
6
|
+
//#region src/core/function/comptime.ts
|
|
7
|
+
/**
|
|
8
|
+
* Creates a version of `func` that can called safely in a TypeGPU function to
|
|
9
|
+
* precompute and inject a value into the final shader code.
|
|
10
|
+
*
|
|
11
|
+
* Note how the function passed into `comptime` doesn't have to be marked with
|
|
12
|
+
* 'use gpu'. That's because the function doesn't execute on the GPU, it gets
|
|
13
|
+
* executed before the shader code gets sent to the GPU.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const color = tgpu.comptime((int: number) => {
|
|
18
|
+
* const r = (int >> 16) & 0xff;
|
|
19
|
+
* const g = (int >> 8) & 0xff;
|
|
20
|
+
* const b = int & 0xff;
|
|
21
|
+
* return d.vec3f(r / 255, g / 255, b / 255);
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* const material = (diffuse: d.v3f): d.v3f => {
|
|
25
|
+
* 'use gpu';
|
|
26
|
+
* const albedo = color(0xff00ff);
|
|
27
|
+
* return albedo.mul(diffuse);
|
|
28
|
+
* };
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
function comptime(func) {
|
|
32
|
+
const impl = ((...args) => {
|
|
33
|
+
return func(...args);
|
|
34
|
+
});
|
|
35
|
+
impl.toString = () => "comptime";
|
|
36
|
+
impl[$getNameForward] = func;
|
|
37
|
+
impl[$gpuCallable] = { call(_ctx, args) {
|
|
38
|
+
if (!args.every((s) => isKnownAtComptime(s))) throw new WgslTypeError(`Called comptime function with runtime-known values: ${args.filter((s) => !isKnownAtComptime(s)).map((s) => `'${s.value}'`).join(", ")}`);
|
|
39
|
+
return coerceToSnippet(func(...args.map((s) => s.value)));
|
|
40
|
+
} };
|
|
41
|
+
impl.$name = (label) => {
|
|
42
|
+
setName(func, label);
|
|
43
|
+
return impl;
|
|
44
|
+
};
|
|
45
|
+
Object.defineProperty(impl, $internal, { value: { isComptime: true } });
|
|
46
|
+
return impl;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { comptime };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { $gpuCallable } from "../../shared/symbols.js";
|
|
2
|
+
import { setName } from "../../shared/meta.js";
|
|
3
|
+
import { isPtr } from "../../data/wgslTypes.js";
|
|
4
|
+
import { snip } from "../../data/snippet.js";
|
|
5
|
+
import { NormalState, isKnownAtComptime } from "../../types.js";
|
|
6
|
+
import { tryConvertSnippet } from "../../tgsl/conversion.js";
|
|
7
|
+
//#region src/core/function/createCallableSchema.ts
|
|
8
|
+
function callableSchema(options) {
|
|
9
|
+
const impl = ((...args) => {
|
|
10
|
+
return options.normalImpl(...args);
|
|
11
|
+
});
|
|
12
|
+
setName(impl, options.name);
|
|
13
|
+
impl.toString = () => options.name;
|
|
14
|
+
impl[$gpuCallable] = {
|
|
15
|
+
get strictSignature() {},
|
|
16
|
+
call(ctx, args) {
|
|
17
|
+
const argTypes = options.argTypes(...args.map((s) => {
|
|
18
|
+
if (isPtr(s.dataType) && s.dataType.implicit) return s.dataType.inner;
|
|
19
|
+
return s.dataType;
|
|
20
|
+
}));
|
|
21
|
+
const converted = args.map((s, idx) => {
|
|
22
|
+
const argType = argTypes[idx];
|
|
23
|
+
if (!argType) throw new Error("Function called with invalid arguments");
|
|
24
|
+
return tryConvertSnippet(ctx, s, argType, false);
|
|
25
|
+
});
|
|
26
|
+
if (converted.every((s) => isKnownAtComptime(s))) {
|
|
27
|
+
ctx.pushMode(new NormalState());
|
|
28
|
+
try {
|
|
29
|
+
return snip(options.normalImpl(...converted.map((s) => s.value)), options.schema(), "constant");
|
|
30
|
+
} finally {
|
|
31
|
+
ctx.popMode("normal");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return options.codegenImpl(ctx, converted);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return impl;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { callableSchema };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { $gpuCallable } from "../../shared/symbols.js";
|
|
2
|
+
import { setName } from "../../shared/meta.js";
|
|
3
|
+
import { isPtr } from "../../data/wgslTypes.js";
|
|
4
|
+
import { snip } from "../../data/snippet.js";
|
|
5
|
+
import { NormalState, isKnownAtComptime } from "../../types.js";
|
|
6
|
+
import { tryConvertSnippet } from "../../tgsl/conversion.js";
|
|
7
|
+
import { concretize } from "../../tgsl/generationHelpers.js";
|
|
8
|
+
//#region src/core/function/dualImpl.ts
|
|
9
|
+
var MissingCpuImplError = class extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = this.constructor.name;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function dualImpl(options) {
|
|
16
|
+
const impl = ((...args) => {
|
|
17
|
+
if (typeof options.normalImpl === "string") throw new MissingCpuImplError(options.normalImpl);
|
|
18
|
+
return options.normalImpl(...args);
|
|
19
|
+
});
|
|
20
|
+
setName(impl, options.name);
|
|
21
|
+
impl.toString = () => options.name ?? "<unknown>";
|
|
22
|
+
impl[$gpuCallable] = {
|
|
23
|
+
get strictSignature() {
|
|
24
|
+
return typeof options.signature !== "function" ? options.signature : void 0;
|
|
25
|
+
},
|
|
26
|
+
call(ctx, args) {
|
|
27
|
+
const { argTypes, returnType } = typeof options.signature === "function" ? options.signature(...args.map((s) => {
|
|
28
|
+
if (isPtr(s.dataType) && s.dataType.implicit) return s.dataType.inner;
|
|
29
|
+
return s.dataType;
|
|
30
|
+
})) : options.signature;
|
|
31
|
+
const converted = args.map((s, idx) => {
|
|
32
|
+
const argType = argTypes[idx];
|
|
33
|
+
if (!argType) throw new Error("Function called with invalid arguments");
|
|
34
|
+
return tryConvertSnippet(ctx, s, argType, !options.ignoreImplicitCastWarning);
|
|
35
|
+
});
|
|
36
|
+
if (!options.noComptime && converted.every((s) => isKnownAtComptime(s)) && typeof options.normalImpl === "function") {
|
|
37
|
+
ctx.pushMode(new NormalState());
|
|
38
|
+
try {
|
|
39
|
+
return snip(options.normalImpl(...converted.map((s) => s.value)), returnType, "constant");
|
|
40
|
+
} catch (e) {
|
|
41
|
+
if (!(e instanceof MissingCpuImplError)) throw e;
|
|
42
|
+
} finally {
|
|
43
|
+
ctx.popMode("normal");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return snip(options.codegenImpl(ctx, converted), concretize(returnType), "runtime");
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
return impl;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { MissingCpuImplError, dualImpl };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { $internal } from "../../shared/symbols.js";
|
|
2
|
+
import { isWgslStruct } from "../../data/wgslTypes.js";
|
|
3
|
+
import { undecorate } from "../../data/dataTypes.js";
|
|
4
|
+
import { snip } from "../../data/snippet.js";
|
|
5
|
+
//#region src/core/function/entryInputRouter.ts
|
|
6
|
+
/**
|
|
7
|
+
* Routes `(input) => { input.x }` style property access to the correct WGSL
|
|
8
|
+
* expression: positional args get a direct snippet, struct fields get
|
|
9
|
+
* `structArgName.fieldName`.
|
|
10
|
+
*/
|
|
11
|
+
var EntryInputRouter = class {
|
|
12
|
+
[$internal] = {};
|
|
13
|
+
type = "entry-input-router";
|
|
14
|
+
structArgName;
|
|
15
|
+
dataSchema;
|
|
16
|
+
/** Maps schemaKey → { WGSL arg name, type } */
|
|
17
|
+
positionalArgsMap;
|
|
18
|
+
constructor(structArgName, dataSchema, positionalArgs) {
|
|
19
|
+
this.structArgName = structArgName;
|
|
20
|
+
this.dataSchema = dataSchema;
|
|
21
|
+
this.positionalArgsMap = new Map(positionalArgs.map((a) => [a.schemaKey, {
|
|
22
|
+
argName: a.argName,
|
|
23
|
+
type: a.type
|
|
24
|
+
}]));
|
|
25
|
+
}
|
|
26
|
+
toString() {
|
|
27
|
+
return "entry-input-router";
|
|
28
|
+
}
|
|
29
|
+
accessProp(propName) {
|
|
30
|
+
const positionalEntry = this.positionalArgsMap.get(propName);
|
|
31
|
+
if (positionalEntry) return snip(positionalEntry.argName, positionalEntry.type, "argument");
|
|
32
|
+
if (this.dataSchema && isWgslStruct(this.dataSchema)) {
|
|
33
|
+
const propType = this.dataSchema.propTypes[propName];
|
|
34
|
+
if (propType) return snip(`${this.structArgName}.${propName}`, undecorate(propType), "argument");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { EntryInputRouter };
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
//#region src/core/function/extractArgs.ts
|
|
2
|
+
/**
|
|
3
|
+
* Extracts info about arguments of a given WGSL function string.
|
|
4
|
+
* @example
|
|
5
|
+
* const code = `
|
|
6
|
+
* fn add(a: i32, @location(0) b: i32, c) -> i32 {
|
|
7
|
+
* return a + b + c;
|
|
8
|
+
* }`;
|
|
9
|
+
*
|
|
10
|
+
* extractArgs(code);
|
|
11
|
+
* // {
|
|
12
|
+
* // args: [
|
|
13
|
+
* // { identifier: 'a', attributes: [], type: 'i32' },
|
|
14
|
+
* // { identifier: 'b', attributes: ['@location(0)'], type: 'i32' },
|
|
15
|
+
* // { identifier: 'c', attributes: [], type: undefined }
|
|
16
|
+
* // ],
|
|
17
|
+
* // ret: { type: 'i32', attributes: [] },
|
|
18
|
+
* // range: { begin: 11, end: 51 }
|
|
19
|
+
* // }
|
|
20
|
+
*/
|
|
21
|
+
function extractArgs(rawCode) {
|
|
22
|
+
const { strippedCode, argRange: range } = strip(rawCode);
|
|
23
|
+
const code = new ParsableString(strippedCode);
|
|
24
|
+
code.consume("(");
|
|
25
|
+
const args = [];
|
|
26
|
+
while (!code.isAt(")")) {
|
|
27
|
+
const attributes = [];
|
|
28
|
+
while (code.isAt("@")) {
|
|
29
|
+
code.parseUntil(closingParenthesis, parentheses);
|
|
30
|
+
code.consume(")");
|
|
31
|
+
attributes.push(code.lastParsed);
|
|
32
|
+
}
|
|
33
|
+
code.parseUntil(identifierEndSymbols);
|
|
34
|
+
const identifier = code.lastParsed;
|
|
35
|
+
let maybeType;
|
|
36
|
+
if (code.isAt(":")) {
|
|
37
|
+
code.consume(":");
|
|
38
|
+
code.parseUntil(typeEndSymbols, angleBrackets);
|
|
39
|
+
maybeType = code.lastParsed;
|
|
40
|
+
}
|
|
41
|
+
args.push({
|
|
42
|
+
identifier,
|
|
43
|
+
attributes,
|
|
44
|
+
type: maybeType
|
|
45
|
+
});
|
|
46
|
+
if (code.isAt(",")) code.consume(",");
|
|
47
|
+
}
|
|
48
|
+
code.consume(")");
|
|
49
|
+
let maybeRet;
|
|
50
|
+
if (code.isAt("->")) {
|
|
51
|
+
code.consume("->");
|
|
52
|
+
const attributes = [];
|
|
53
|
+
while (code.isAt("@")) {
|
|
54
|
+
code.parseUntil(closingParenthesis, parentheses);
|
|
55
|
+
code.consume(")");
|
|
56
|
+
attributes.push(code.lastParsed);
|
|
57
|
+
}
|
|
58
|
+
maybeRet = {
|
|
59
|
+
type: code.str.slice(code.pos),
|
|
60
|
+
attributes
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
args,
|
|
65
|
+
ret: maybeRet,
|
|
66
|
+
range: {
|
|
67
|
+
begin: range[0],
|
|
68
|
+
end: range[1]
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Strips comments, whitespaces, the name and the body of the function.
|
|
74
|
+
* @example
|
|
75
|
+
* const code = `
|
|
76
|
+
* fn add( a, // first argument
|
|
77
|
+
* @location(0) b : i32 ) -> i32 {
|
|
78
|
+
* return a + b; // returns the sum
|
|
79
|
+
* }`;
|
|
80
|
+
*
|
|
81
|
+
* strip(code); // "(a,@location(0)b:i32)->i32"
|
|
82
|
+
*/
|
|
83
|
+
function strip(rawCode) {
|
|
84
|
+
const code = new ParsableString(rawCode);
|
|
85
|
+
let strippedCode = "";
|
|
86
|
+
let argsStart;
|
|
87
|
+
while (!code.isFinished()) {
|
|
88
|
+
if (code.isAt(blankSpaces)) {
|
|
89
|
+
code.advanceBy(1);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (code.isAt("//")) {
|
|
93
|
+
code.consume("//");
|
|
94
|
+
code.parseUntil(lineBreaks);
|
|
95
|
+
code.advanceBy(1);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (code.isAt("/*")) {
|
|
99
|
+
code.parseUntil(openingCommentBlock, commentBlocks);
|
|
100
|
+
code.consume("*/");
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (code.isAt("{")) return {
|
|
104
|
+
strippedCode,
|
|
105
|
+
argRange: [argsStart, code.pos]
|
|
106
|
+
};
|
|
107
|
+
if (code.isAt("(") && argsStart === void 0) argsStart = code.pos;
|
|
108
|
+
if (argsStart !== void 0) strippedCode += code.str[code.pos];
|
|
109
|
+
code.advanceBy(1);
|
|
110
|
+
}
|
|
111
|
+
throw new Error("Invalid wgsl code!");
|
|
112
|
+
}
|
|
113
|
+
var ParsableString = class {
|
|
114
|
+
str;
|
|
115
|
+
#parseStartPos;
|
|
116
|
+
#pos;
|
|
117
|
+
constructor(str) {
|
|
118
|
+
this.str = str;
|
|
119
|
+
this.#pos = 0;
|
|
120
|
+
}
|
|
121
|
+
get pos() {
|
|
122
|
+
return this.#pos;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* This property is equivalent to the substring of `this.str`
|
|
126
|
+
* from the position of the last `parseUntil` call, to the current position.
|
|
127
|
+
*/
|
|
128
|
+
get lastParsed() {
|
|
129
|
+
if (this.#parseStartPos === void 0) throw new Error("Parse was not called yet!");
|
|
130
|
+
return this.str.slice(this.#parseStartPos, this.pos);
|
|
131
|
+
}
|
|
132
|
+
isFinished() {
|
|
133
|
+
return this.#pos >= this.str.length;
|
|
134
|
+
}
|
|
135
|
+
isAt(substr) {
|
|
136
|
+
if (typeof substr === "string") {
|
|
137
|
+
for (let i = 0; i < substr.length; i++) if (this.str[this.#pos + i] !== substr[i]) return false;
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
for (const elem of substr) if (this.isAt(elem)) return true;
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* @param toFind a set of strings either of which satisfy the search.
|
|
145
|
+
* @param brackets a pair of brackets that has to be closed for result to be valid. This includes the found character(s).
|
|
146
|
+
* @example
|
|
147
|
+
* // internal state:
|
|
148
|
+
* // '(@attribute(0) identifier: type)'
|
|
149
|
+
* // ^
|
|
150
|
+
* this.parse(new Set(')'), ['(', ')']);
|
|
151
|
+
* // internal state:
|
|
152
|
+
* // '(@attribute(0) identifier: type)'
|
|
153
|
+
* // ^
|
|
154
|
+
*/
|
|
155
|
+
parseUntil(toFind, brackets) {
|
|
156
|
+
this.#parseStartPos = this.#pos;
|
|
157
|
+
let openedBrackets = 0;
|
|
158
|
+
while (this.#pos < this.str.length) {
|
|
159
|
+
if (brackets && this.isAt(brackets[0])) openedBrackets += 1;
|
|
160
|
+
if (brackets && this.isAt(brackets[1])) openedBrackets -= 1;
|
|
161
|
+
if (openedBrackets === 0) {
|
|
162
|
+
if (this.isAt(toFind)) return this.#pos;
|
|
163
|
+
}
|
|
164
|
+
this.#pos += 1;
|
|
165
|
+
}
|
|
166
|
+
throw new Error("Reached the end of the string without finding a match!");
|
|
167
|
+
}
|
|
168
|
+
advanceBy(steps) {
|
|
169
|
+
this.#pos += steps;
|
|
170
|
+
}
|
|
171
|
+
consume(str) {
|
|
172
|
+
if (!this.isAt(str)) throw new Error(`Expected '${str}' at position ${this.#pos}, but found '${this.str.slice(this.#pos, this.#pos + str.length)}'`);
|
|
173
|
+
this.advanceBy(str.length);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const lineBreaks = new Set([
|
|
177
|
+
"\n",
|
|
178
|
+
"\v",
|
|
179
|
+
"\f",
|
|
180
|
+
"\r",
|
|
181
|
+
"
",
|
|
182
|
+
"\u2028",
|
|
183
|
+
"\u2029"
|
|
184
|
+
]);
|
|
185
|
+
const blankSpaces = new Set([
|
|
186
|
+
...lineBreaks,
|
|
187
|
+
" ",
|
|
188
|
+
" ",
|
|
189
|
+
"",
|
|
190
|
+
""
|
|
191
|
+
]);
|
|
192
|
+
const closingParenthesis = new Set([")"]);
|
|
193
|
+
const identifierEndSymbols = new Set([
|
|
194
|
+
":",
|
|
195
|
+
",",
|
|
196
|
+
")"
|
|
197
|
+
]);
|
|
198
|
+
const typeEndSymbols = new Set([",", ")"]);
|
|
199
|
+
const openingCommentBlock = new Set(["*/"]);
|
|
200
|
+
const parentheses = ["(", ")"];
|
|
201
|
+
const angleBrackets = ["<", ">"];
|
|
202
|
+
const commentBlocks = ["/*", "*/"];
|
|
203
|
+
//#endregion
|
|
204
|
+
export { extractArgs };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { $getNameForward } from "../../shared/symbols.js";
|
|
2
|
+
import { getMetaData, getName } from "../../shared/meta.js";
|
|
3
|
+
import { Void, isWgslData, isWgslStruct } from "../../data/wgslTypes.js";
|
|
4
|
+
import { undecorate } from "../../data/dataTypes.js";
|
|
5
|
+
import { snip } from "../../data/snippet.js";
|
|
6
|
+
import { MissingLinksError } from "../../errors.js";
|
|
7
|
+
import { getAttributesString } from "../../data/attributes.js";
|
|
8
|
+
import { applyExternals, replaceExternalsInWgsl } from "../resolve/externals.js";
|
|
9
|
+
import { extractArgs } from "./extractArgs.js";
|
|
10
|
+
//#region src/core/function/fnCore.ts
|
|
11
|
+
function createFnCore(implementation, fnAttribute = "") {
|
|
12
|
+
/**
|
|
13
|
+
* External application has to be deferred until resolution because
|
|
14
|
+
* some externals can reference the owner function which has not been
|
|
15
|
+
* initialized yet (like when accessing the Output struct of a vertex
|
|
16
|
+
* entry fn).
|
|
17
|
+
*/
|
|
18
|
+
const externalsToApply = [];
|
|
19
|
+
return {
|
|
20
|
+
[$getNameForward]: typeof implementation === "function" ? implementation : void 0,
|
|
21
|
+
applyExternals(newExternals) {
|
|
22
|
+
externalsToApply.push(newExternals);
|
|
23
|
+
},
|
|
24
|
+
resolve(ctx, argTypes, returnType, entryInput) {
|
|
25
|
+
const externalMap = {};
|
|
26
|
+
for (const externals of externalsToApply) applyExternals(externalMap, externals);
|
|
27
|
+
const id = ctx.getUniqueName(this);
|
|
28
|
+
if (typeof implementation === "string") {
|
|
29
|
+
if (!returnType) throw new Error("Explicit return type is required for string implementation");
|
|
30
|
+
const validArgNames = entryInput ? Object.fromEntries(entryInput.positionalArgs.map((a) => [a.schemaKey, ctx.makeNameValid(a.schemaKey)])) : void 0;
|
|
31
|
+
if (validArgNames && Object.keys(validArgNames).length > 0) applyExternals(externalMap, { in: validArgNames });
|
|
32
|
+
const replacedImpl = replaceExternalsInWgsl(ctx, externalMap, implementation);
|
|
33
|
+
let header = "";
|
|
34
|
+
let body = "";
|
|
35
|
+
if (fnAttribute !== "" && entryInput && validArgNames) {
|
|
36
|
+
const { dataSchema, positionalArgs } = entryInput;
|
|
37
|
+
const parts = [];
|
|
38
|
+
if (dataSchema && isArgUsedInBody("in", replacedImpl)) parts.push(`in: ${ctx.resolve(dataSchema).value}`);
|
|
39
|
+
for (const a of positionalArgs) {
|
|
40
|
+
const argName = validArgNames[a.schemaKey] ?? "";
|
|
41
|
+
if (argName !== "" && isArgUsedInBody(argName, replacedImpl)) parts.push(`${getAttributesString(a.type)}${argName}: ${ctx.resolve(a.type).value}`);
|
|
42
|
+
}
|
|
43
|
+
const input = `(${parts.join(", ")})`;
|
|
44
|
+
const attributes = isWgslData(returnType) ? getAttributesString(returnType) : "";
|
|
45
|
+
header = `${input}${returnType !== Void ? isWgslStruct(returnType) ? ` -> ${ctx.resolve(returnType).value} ` : ` -> ${attributes !== "" ? attributes : "@location(0)"} ${ctx.resolve(returnType).value} ` : " "}`;
|
|
46
|
+
body = replacedImpl;
|
|
47
|
+
} else {
|
|
48
|
+
const providedArgs = extractArgs(replacedImpl);
|
|
49
|
+
if (providedArgs.args.length !== argTypes.length) throw new Error(`WGSL implementation has ${providedArgs.args.length} arguments, while the shell has ${argTypes.length} arguments.`);
|
|
50
|
+
header = `(${providedArgs.args.map((argInfo, i) => `${argInfo.identifier}: ${checkAndReturnType(ctx, `parameter ${argInfo.identifier}`, argInfo.type, argTypes[i])}`).join(", ")})${returnType === Void ? " " : ` -> ${checkAndReturnType(ctx, "return type", providedArgs.ret?.type, returnType)} `}`;
|
|
51
|
+
body = replacedImpl.slice(providedArgs.range.end);
|
|
52
|
+
}
|
|
53
|
+
ctx.addDeclaration(`${fnAttribute}fn ${id}${header}${body}`);
|
|
54
|
+
return snip(id, returnType, "runtime");
|
|
55
|
+
}
|
|
56
|
+
const pluginData = getMetaData(implementation);
|
|
57
|
+
const pluginExternals = typeof pluginData?.externals === "function" ? pluginData.externals() : pluginData?.externals;
|
|
58
|
+
if (pluginExternals) applyExternals(externalMap, Object.fromEntries(Object.entries(pluginExternals).filter(([name]) => !(name in externalMap))));
|
|
59
|
+
const ast = pluginData?.ast;
|
|
60
|
+
if (!ast) throw new Error("Missing metadata for tgpu.fn function body (either missing 'use gpu' directive, or misconfigured `unplugin-typegpu`)");
|
|
61
|
+
const missingExternals = ast.externalNames.filter((name) => !(name in externalMap));
|
|
62
|
+
if (missingExternals.length > 0) throw new MissingLinksError(getName(this), missingExternals);
|
|
63
|
+
const maybeSecondArg = ast.params[1];
|
|
64
|
+
if (maybeSecondArg && maybeSecondArg.type === "i" && fnAttribute !== "") applyExternals(externalMap, { [maybeSecondArg.name]: undecorate(returnType) });
|
|
65
|
+
const { head, body, returnType: actualReturnType } = ctx.fnToWgsl({
|
|
66
|
+
functionType: fnAttribute.includes("@compute") ? "compute" : fnAttribute.includes("@vertex") ? "vertex" : fnAttribute.includes("@fragment") ? "fragment" : "normal",
|
|
67
|
+
argTypes,
|
|
68
|
+
entryInput,
|
|
69
|
+
params: ast.params,
|
|
70
|
+
returnType,
|
|
71
|
+
body: ast.body,
|
|
72
|
+
externalMap
|
|
73
|
+
});
|
|
74
|
+
ctx.addDeclaration(`${fnAttribute}fn ${id}${ctx.resolve(head).value}${ctx.resolve(body).value}`);
|
|
75
|
+
return snip(id, actualReturnType, "runtime");
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function isArgUsedInBody(argName, body) {
|
|
80
|
+
return new RegExp(`\\b${argName}\\b`).test(body);
|
|
81
|
+
}
|
|
82
|
+
function checkAndReturnType(ctx, name, wgslType, jsType) {
|
|
83
|
+
const resolvedJsType = ctx.resolve(jsType).value.replace(/\s/g, "");
|
|
84
|
+
if (!wgslType) return resolvedJsType;
|
|
85
|
+
const resolvedWgslType = wgslType.replace(/\s/g, "");
|
|
86
|
+
if (resolvedWgslType !== resolvedJsType) throw new Error(`Type mismatch between TGPU shell and WGSL code string: ${name}, JS type "${resolvedJsType}", WGSL type "${resolvedWgslType}".`);
|
|
87
|
+
return wgslType;
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { createFnCore };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { BuiltinClipDistances } from "../../builtin.js";
|
|
2
|
+
import { AnyAttribute } from "../../data/attributes.js";
|
|
3
|
+
import { BaseData, Bool, Decorated, F16, F32, I32, U32, Vec2f, Vec2h, Vec2i, Vec2u, Vec3f, Vec3h, Vec3i, Vec3u, Vec4f, Vec4h, Vec4i, Vec4u, Void } from "../../data/wgslTypes.js";
|
|
4
|
+
import { InferGPU } from "../../shared/repr.js";
|
|
5
|
+
//#region src/core/function/fnTypes.d.ts
|
|
6
|
+
type AnyFn = (...args: never[]) => unknown;
|
|
7
|
+
type InferArgs<T extends unknown[]> = { [Idx in keyof T]: InferGPU<T[Idx]> };
|
|
8
|
+
type InheritTupleValues<T, From> = { [K in keyof T]: K extends keyof From ? From[K] : never };
|
|
9
|
+
/**
|
|
10
|
+
* Returns a type that has arg and return types of `T`, but argument
|
|
11
|
+
* names of `From`
|
|
12
|
+
*
|
|
13
|
+
* Wrapped in an object type with `result` prop just so that it's easier
|
|
14
|
+
* to remove InheritArgNames<...> from Intellisense with Prettify<T>['result']
|
|
15
|
+
*/
|
|
16
|
+
type InheritArgNames<T extends AnyFn, From extends AnyFn> = {
|
|
17
|
+
result: (...args: Parameters<((...args: InheritTupleValues<Parameters<From>, Parameters<T>>) => ReturnType<T>) & T>) => ReturnType<T>;
|
|
18
|
+
};
|
|
19
|
+
type InferImplSchema<ImplSchema extends AnyFn> = (...args: InferArgs<Parameters<ImplSchema>>) => InferGPU<ReturnType<ImplSchema>>;
|
|
20
|
+
type Implementation<ImplSchema extends AnyFn = AnyFn> = string | InferImplSchema<ImplSchema>;
|
|
21
|
+
type BaseIOData = Bool | F32 | F16 | I32 | U32 | Vec2f | Vec3f | Vec4f | Vec2h | Vec3h | Vec4h | Vec2i | Vec3i | Vec4i | Vec2u | Vec3u | Vec4u;
|
|
22
|
+
type IOData = BaseIOData | Decorated<BaseIOData, AnyAttribute[]> | BuiltinClipDistances;
|
|
23
|
+
type IORecord<TElementType extends IOData = IOData> = Record<string, TElementType>;
|
|
24
|
+
/**
|
|
25
|
+
* Used for I/O definitions of entry functions.
|
|
26
|
+
*/
|
|
27
|
+
type IOLayout<TElementType extends IOData = IOData> = TElementType | IORecord<TElementType> | Void;
|
|
28
|
+
type InferIO<T> = T extends {
|
|
29
|
+
type: string;
|
|
30
|
+
} ? InferGPU<T> : T extends Record<string, unknown> ? { [K in keyof T]: InferGPU<T[K]> } : T;
|
|
31
|
+
interface PositionalArgInfo {
|
|
32
|
+
schemaKey: string;
|
|
33
|
+
type: BaseData;
|
|
34
|
+
}
|
|
35
|
+
interface SeparatedEntryArgs {
|
|
36
|
+
dataSchema: BaseData | undefined;
|
|
37
|
+
positionalArgs: PositionalArgInfo[];
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { AnyFn, BaseIOData, IOLayout, IORecord, Implementation, InferArgs, InferIO, InferImplSchema, InheritArgNames, SeparatedEntryArgs };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Decorate, HasCustomLocation, IsBuiltin } from "../../data/attributes.js";
|
|
2
|
+
import { BaseData, Location, WgslStruct } from "../../data/wgslTypes.js";
|
|
3
|
+
|
|
4
|
+
//#region src/core/function/ioSchema.d.ts
|
|
5
|
+
type WithLocations<T extends Record<string, BaseData>> = { [Key in keyof T]: IsBuiltin<T[Key]> extends true ? T[Key] : HasCustomLocation<T[Key]> extends true ? T[Key] : Decorate<T[Key], Location> };
|
|
6
|
+
type IOLayoutToSchema<T> = T extends BaseData ? HasCustomLocation<T> extends true ? T : Decorate<T, Location<0>> : T extends Record<string, BaseData> ? WgslStruct<WithLocations<T>> : T extends {
|
|
7
|
+
type: 'void';
|
|
8
|
+
} ? void : never;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { IOLayoutToSchema };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { isVoid } from "../../data/wgslTypes.js";
|
|
2
|
+
import { getCustomLocation, isData } from "../../data/dataTypes.js";
|
|
3
|
+
import { isBuiltin, location } from "../../data/attributes.js";
|
|
4
|
+
import { INTERNAL_createStruct } from "../../data/struct.js";
|
|
5
|
+
//#region src/core/function/ioSchema.ts
|
|
6
|
+
function withLocations(members, locations = {}) {
|
|
7
|
+
let nextLocation = 0;
|
|
8
|
+
const usedCustomLocations = /* @__PURE__ */ new Set();
|
|
9
|
+
return Object.fromEntries(Object.entries(members ?? {}).map(([key, member]) => {
|
|
10
|
+
const customLocation = getCustomLocation(member);
|
|
11
|
+
if (customLocation !== void 0) {
|
|
12
|
+
if (usedCustomLocations.has(customLocation)) throw new Error("Duplicate custom location attributes found");
|
|
13
|
+
usedCustomLocations.add(customLocation);
|
|
14
|
+
}
|
|
15
|
+
return [key, member];
|
|
16
|
+
}).map(([key, member]) => {
|
|
17
|
+
if (isBuiltin(member)) return [key, member];
|
|
18
|
+
if (getCustomLocation(member) !== void 0) return [key, member];
|
|
19
|
+
if (locations[key]) return [key, location(locations[key], member)];
|
|
20
|
+
while (usedCustomLocations.has(nextLocation)) nextLocation++;
|
|
21
|
+
return [key, location(nextLocation++, member)];
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
function separateBuiltins(schema, locations = {}) {
|
|
25
|
+
const positionalArgs = [];
|
|
26
|
+
const dataFields = {};
|
|
27
|
+
for (const [key, type] of Object.entries(schema)) if (isBuiltin(type)) positionalArgs.push({
|
|
28
|
+
schemaKey: key,
|
|
29
|
+
type
|
|
30
|
+
});
|
|
31
|
+
else dataFields[key] = type;
|
|
32
|
+
return {
|
|
33
|
+
dataSchema: Object.keys(dataFields).length > 0 ? INTERNAL_createStruct(withLocations(dataFields, locations), false) : void 0,
|
|
34
|
+
positionalArgs
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function separateAllAsPositional(schema) {
|
|
38
|
+
const withLocs = withLocations(schema);
|
|
39
|
+
return {
|
|
40
|
+
dataSchema: void 0,
|
|
41
|
+
positionalArgs: Object.entries(withLocs).map(([key, type]) => ({
|
|
42
|
+
schemaKey: key,
|
|
43
|
+
type
|
|
44
|
+
}))
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function createIoSchema(layout, locations = {}) {
|
|
48
|
+
return isData(layout) ? isVoid(layout) ? layout : isBuiltin(layout) ? layout : getCustomLocation(layout) !== void 0 ? layout : location(0, layout) : INTERNAL_createStruct(withLocations(layout, locations), false);
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { createIoSchema, separateAllAsPositional, separateBuiltins };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { $getNameForward } from "../../shared/symbols.js";
|
|
2
|
+
import { SelfResolvable } from "../../types.js";
|
|
3
|
+
import { BaseData } from "../../data/wgslTypes.js";
|
|
4
|
+
|
|
5
|
+
//#region src/core/function/shelllessImpl.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Shell-less functions are possible because we can infer the signature based solely on the context
|
|
8
|
+
* around the function.
|
|
9
|
+
*
|
|
10
|
+
* ## Arguments
|
|
11
|
+
* The snippets of the function's arguments are used to infer the types of the function's arguments.
|
|
12
|
+
* We only care that the arguments are of a concrete type (we concretize them if they're not). We
|
|
13
|
+
* cache these signatures based on the argument types, so that we can reuse them across calls.
|
|
14
|
+
*
|
|
15
|
+
* ## Return type
|
|
16
|
+
* In shelled functions, the return type is known when generating the body, but in the case of shell-less functions,
|
|
17
|
+
* we gather candidates for return types when visiting return statement nodes, and try to unify them into one type
|
|
18
|
+
* before generating the signature.
|
|
19
|
+
*
|
|
20
|
+
* TODO: This behavior can be refined by considering the "expected type" of the function call expression.
|
|
21
|
+
*/
|
|
22
|
+
interface ShelllessImpl extends SelfResolvable {
|
|
23
|
+
readonly resourceType: 'shellless-impl';
|
|
24
|
+
readonly argTypes: BaseData[];
|
|
25
|
+
readonly [$getNameForward]: unknown;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { ShelllessImpl };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
|
|
2
|
+
import { getName } from "../../shared/meta.js";
|
|
3
|
+
import { createFnCore } from "./fnCore.js";
|
|
4
|
+
//#region src/core/function/shelllessImpl.ts
|
|
5
|
+
function createShelllessImpl(argTypes, implementation) {
|
|
6
|
+
const core = createFnCore(implementation, "");
|
|
7
|
+
return {
|
|
8
|
+
[$internal]: true,
|
|
9
|
+
[$getNameForward]: core,
|
|
10
|
+
resourceType: "shellless-impl",
|
|
11
|
+
argTypes,
|
|
12
|
+
[$resolve](ctx) {
|
|
13
|
+
return core.resolve(ctx, argTypes, void 0);
|
|
14
|
+
},
|
|
15
|
+
toString() {
|
|
16
|
+
return `fn*:${getName(core) ?? "<unnamed>"}(${argTypes.map((t) => t.toString()).join(", ")})`;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { createShelllessImpl };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/core/function/templateUtils.ts
|
|
2
|
+
function stripTemplate(arg, ...values) {
|
|
3
|
+
return isTemplateStringsArray(arg) ? templateLiteralIdentity(arg, ...values) : arg;
|
|
4
|
+
}
|
|
5
|
+
function isTemplateStringsArray(value) {
|
|
6
|
+
return Array.isArray(value) && "raw" in value && Array.isArray(value.raw) && value.raw.every((item) => typeof item === "string");
|
|
7
|
+
}
|
|
8
|
+
function templateLiteralIdentity(strings, ...values) {
|
|
9
|
+
return strings.slice(1).reduce((acc, elem, index) => `${acc}${values[index]}${elem}`, strings[0]);
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { stripTemplate };
|