@thi.ng/shader-ast-js 0.7.68 → 1.0.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/CHANGELOG.md +25 -1
- package/README.md +12 -10
- package/api.d.ts +28 -2
- package/env/ivec2.js +24 -22
- package/env/ivec3.js +24 -22
- package/env/ivec4.js +24 -22
- package/env/mat2.js +20 -18
- package/env/uvec2.js +24 -22
- package/env/uvec3.js +24 -22
- package/env/uvec4.js +24 -22
- package/env/vec2.d.ts +2 -1
- package/env/vec2.js +52 -51
- package/env/vec3.d.ts +2 -1
- package/env/vec3.js +53 -52
- package/env/vec4.d.ts +2 -1
- package/env/vec4.js +52 -51
- package/env.js +51 -30
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +26 -11
- package/pool.d.ts +37 -0
- package/pool.js +68 -0
- package/runtime.d.ts +41 -28
- package/runtime.js +46 -40
- package/target.js +41 -13
package/pool.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { typedArray, } from "@thi.ng/api";
|
|
2
|
+
import { outOfBounds } from "@thi.ng/errors/out-of-bounds";
|
|
3
|
+
import { set } from "@thi.ng/vectors/set";
|
|
4
|
+
import { setC2, setC3, setC4 } from "@thi.ng/vectors/setc";
|
|
5
|
+
import { setN, setN2, setN3, setN4 } from "@thi.ng/vectors/setn";
|
|
6
|
+
/**
|
|
7
|
+
* Manager for re-using pre-allocated memory for various vector ops. If the
|
|
8
|
+
* compiled shader program includes a `main()` function, the pools will be reset
|
|
9
|
+
* automatically when that `main` function executes. Otherwise, users **MUST**
|
|
10
|
+
* call the {@link CompileResult.__reset} manually each time before invoking a
|
|
11
|
+
* compiled entry point function.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* Currently, the default capacity for each vector type is fixed at 2048 items.
|
|
15
|
+
* That means a shader program can create up to this number of temporary objects
|
|
16
|
+
* (per fragment/invocation). Should this number be insufficient, please submit
|
|
17
|
+
* an issue and explain your use case. Thanks!
|
|
18
|
+
*/
|
|
19
|
+
export class Pool {
|
|
20
|
+
constructor(type, size, cap) {
|
|
21
|
+
this.size = size;
|
|
22
|
+
this.cap = cap;
|
|
23
|
+
this.index = 0;
|
|
24
|
+
this.mem = typedArray(type, cap * size);
|
|
25
|
+
this.items = new Array(cap);
|
|
26
|
+
for (let i = 0; i < cap; i++) {
|
|
27
|
+
this.items[i] = this.mem.subarray(i * size, i * size + size);
|
|
28
|
+
}
|
|
29
|
+
const next = () => {
|
|
30
|
+
if (this.index > this.items.length)
|
|
31
|
+
outOfBounds(this.index);
|
|
32
|
+
return this.items[this.index++];
|
|
33
|
+
};
|
|
34
|
+
let from;
|
|
35
|
+
let uniform;
|
|
36
|
+
switch (this.size) {
|
|
37
|
+
case 2:
|
|
38
|
+
from = (x, y) => setC2(next(), x, y);
|
|
39
|
+
uniform = (n) => setN2(next(), n);
|
|
40
|
+
case 3:
|
|
41
|
+
from = (x, y, z) => setC3(next(), x, y, z);
|
|
42
|
+
uniform = (n) => setN3(next(), n);
|
|
43
|
+
case 4:
|
|
44
|
+
from = (x, y, z, w) => setC4(next(), x, y, z, w);
|
|
45
|
+
uniform = (n) => setN4(next(), n);
|
|
46
|
+
default:
|
|
47
|
+
from = (...args) => set(next(), args);
|
|
48
|
+
uniform = (n) => setN(next(), n);
|
|
49
|
+
}
|
|
50
|
+
this.next = next;
|
|
51
|
+
this.from = from;
|
|
52
|
+
this.uniform = uniform;
|
|
53
|
+
}
|
|
54
|
+
reset() {
|
|
55
|
+
this.index = 0;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const CAP = 2048;
|
|
60
|
+
export const POOL_VEC2 = new Pool("f32", 2, CAP);
|
|
61
|
+
export const POOL_VEC3 = new Pool("f32", 3, CAP);
|
|
62
|
+
export const POOL_VEC4 = new Pool("f32", 4, CAP);
|
|
63
|
+
export const POOL_IVEC2 = new Pool("i32", 2, CAP);
|
|
64
|
+
export const POOL_IVEC3 = new Pool("i32", 3, CAP);
|
|
65
|
+
export const POOL_IVEC4 = new Pool("i32", 4, CAP);
|
|
66
|
+
export const POOL_UVEC2 = new Pool("u32", 2, CAP);
|
|
67
|
+
export const POOL_UVEC3 = new Pool("u32", 3, CAP);
|
|
68
|
+
export const POOL_UVEC4 = new Pool("u32", 4, CAP);
|
package/runtime.d.ts
CHANGED
|
@@ -1,41 +1,54 @@
|
|
|
1
|
-
import type { Fn } from "@thi.ng/api";
|
|
1
|
+
import type { Fn, UIntArray } from "@thi.ng/api";
|
|
2
2
|
import { type IntBuffer } from "@thi.ng/pixel/int";
|
|
3
3
|
import type { ReadonlyVec, Vec } from "@thi.ng/vectors";
|
|
4
|
+
export interface RenderPixelOpts {
|
|
5
|
+
x?: number;
|
|
6
|
+
y?: number;
|
|
7
|
+
w?: number;
|
|
8
|
+
h?: number;
|
|
9
|
+
bufW: number;
|
|
10
|
+
bufH: number;
|
|
11
|
+
offsetX?: number;
|
|
12
|
+
offsetY?: number;
|
|
13
|
+
imgH?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Format conversion from float RGBA to packed integer.
|
|
16
|
+
*/
|
|
17
|
+
fmt: Fn<ReadonlyVec, number>;
|
|
18
|
+
}
|
|
19
|
+
export declare const rgbaBgra8888: (rgba: ReadonlyVec) => number;
|
|
20
|
+
export declare const rgbaRgb565: (rgba: ReadonlyVec) => number;
|
|
4
21
|
/**
|
|
5
22
|
* Low-level function used by {@link canvasRenderer} and {@link renderBuffer}.
|
|
6
|
-
* Applies shader function `fn` to each pixel in the given region of the
|
|
7
|
-
*
|
|
8
|
-
* `y` coords and `w`, `h` dimensions. The remaining
|
|
9
|
-
* `bufOffsetX`, `bufOffsetY` and `imgH` are used to
|
|
10
|
-
* of the given buffer in the full image to be
|
|
11
|
-
* where the target array only defines a
|
|
12
|
-
*
|
|
23
|
+
* Applies shader function `fn` to each pixel in the given region of the
|
|
24
|
+
* `pixels` buffer (e.g. a `Uint32Array`). The render region is defined via
|
|
25
|
+
* options. The top-left `x`, `y` coords and `w`, `h` dimensions. The remaining
|
|
26
|
+
* parameters `bufW`, `bufH`, `bufOffsetX`, `bufOffsetY` and `imgH` are used to
|
|
27
|
+
* define the actual location of the given buffer in the full image to be
|
|
28
|
+
* computed and to support use cases where the target array only defines a
|
|
29
|
+
* sub-region of the full image (e.g. when splitting rendering over multiple
|
|
30
|
+
* workers, each with their own buffer).
|
|
13
31
|
*
|
|
14
32
|
* @param fn -
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
17
|
-
* @param bufH -
|
|
18
|
-
* @param x -
|
|
19
|
-
* @param y -
|
|
20
|
-
* @param w -
|
|
21
|
-
* @param h -
|
|
22
|
-
* @param bufOffsetX -
|
|
23
|
-
* @param bufOffsetY -
|
|
24
|
-
* @param imgH -
|
|
33
|
+
* @param pixels -
|
|
34
|
+
* @param opts
|
|
25
35
|
*/
|
|
26
|
-
export declare const renderPixels: (fn: Fn<ReadonlyVec, Vec>,
|
|
36
|
+
export declare const renderPixels: (fn: Fn<ReadonlyVec, Vec>, pixels: UIntArray, { x, y, w, h, bufW, bufH, offsetX, offsetY, imgH, fmt }: RenderPixelOpts) => UIntArray;
|
|
27
37
|
/**
|
|
28
38
|
* Takes a
|
|
29
39
|
* [`IntBuffer`](https://docs.thi.ng/umbrella/pixel/classes/IntBuffer.html)
|
|
30
|
-
* pixel buffer from thi.ng/pixel
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
40
|
+
* pixel buffer from thi.ng/pixel, and options to define a buffer-local render
|
|
41
|
+
* region. Applies shader function `fn` to each pixel in that region (or the
|
|
42
|
+
* full buffer by default).
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* In case the buffer only defines a sub-region of a larger image,
|
|
46
|
+
* {@link RenderPixelOpts.offsetX}, {@link RenderPixelOpts.offsetY} and
|
|
47
|
+
* {@link RenderPixelOpts.imgH} can be given to configure the location and full
|
|
48
|
+
* image height.
|
|
35
49
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* height.
|
|
50
|
+
* The default target pixel format is `ABGR8888` using {@link rgbaBgra8888} as
|
|
51
|
+
* default {@link RenderPixelOpts.fmt} conversion.
|
|
39
52
|
*
|
|
40
53
|
* @param fn -
|
|
41
54
|
* @param buf -
|
|
@@ -47,7 +60,7 @@ export declare const renderPixels: (fn: Fn<ReadonlyVec, Vec>, u32: Uint32Array,
|
|
|
47
60
|
* @param bufOffsetY -
|
|
48
61
|
* @param imgH -
|
|
49
62
|
*/
|
|
50
|
-
export declare const renderBuffer: (fn: Fn<ReadonlyVec, Vec>, buf: IntBuffer,
|
|
63
|
+
export declare const renderBuffer: (fn: Fn<ReadonlyVec, Vec>, buf: IntBuffer, opts?: Partial<RenderPixelOpts>) => IntBuffer;
|
|
51
64
|
/**
|
|
52
65
|
* Higher order function accepting an `HTMLCanvasElement` and returning a render
|
|
53
66
|
* function which accepts the following parameters:
|
package/runtime.js
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
import { assert } from "@thi.ng/errors/assert";
|
|
2
1
|
import { clamp, clamp01 } from "@thi.ng/math/interval";
|
|
3
|
-
import { ABGR8888 } from "@thi.ng/pixel/format/abgr8888";
|
|
4
2
|
import { intBufferFromCanvas } from "@thi.ng/pixel/int";
|
|
5
|
-
const
|
|
3
|
+
export const rgbaBgra8888 = (rgba) => ((clamp01(rgba[0]) * 255.5) << 0) |
|
|
6
4
|
((clamp01(rgba[1]) * 255.5) << 8) |
|
|
7
5
|
((clamp01(rgba[2]) * 255.5) << 16) |
|
|
8
6
|
((clamp01(rgba[3]) * 255.5) << 24);
|
|
7
|
+
export const rgbaRgb565 = (rgba) => (((clamp01(rgba[0]) * 255.5) & 0xf8) << 8) |
|
|
8
|
+
(((clamp01(rgba[1]) * 255.5) & 0xfc) << 3) |
|
|
9
|
+
(((clamp01(rgba[2]) * 255.5) & 0xf8) >> 3);
|
|
9
10
|
const clampCoord = (x, maxW, w) => w !== undefined ? Math.min(x + w, maxW) : maxW;
|
|
10
11
|
/**
|
|
11
12
|
* Low-level function used by {@link canvasRenderer} and {@link renderBuffer}.
|
|
12
|
-
* Applies shader function `fn` to each pixel in the given region of the
|
|
13
|
-
*
|
|
14
|
-
* `y` coords and `w`, `h` dimensions. The remaining
|
|
15
|
-
* `bufOffsetX`, `bufOffsetY` and `imgH` are used to
|
|
16
|
-
* of the given buffer in the full image to be
|
|
17
|
-
* where the target array only defines a
|
|
18
|
-
*
|
|
13
|
+
* Applies shader function `fn` to each pixel in the given region of the
|
|
14
|
+
* `pixels` buffer (e.g. a `Uint32Array`). The render region is defined via
|
|
15
|
+
* options. The top-left `x`, `y` coords and `w`, `h` dimensions. The remaining
|
|
16
|
+
* parameters `bufW`, `bufH`, `bufOffsetX`, `bufOffsetY` and `imgH` are used to
|
|
17
|
+
* define the actual location of the given buffer in the full image to be
|
|
18
|
+
* computed and to support use cases where the target array only defines a
|
|
19
|
+
* sub-region of the full image (e.g. when splitting rendering over multiple
|
|
20
|
+
* workers, each with their own buffer).
|
|
19
21
|
*
|
|
20
22
|
* @param fn -
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
23
|
-
* @param bufH -
|
|
24
|
-
* @param x -
|
|
25
|
-
* @param y -
|
|
26
|
-
* @param w -
|
|
27
|
-
* @param h -
|
|
28
|
-
* @param bufOffsetX -
|
|
29
|
-
* @param bufOffsetY -
|
|
30
|
-
* @param imgH -
|
|
23
|
+
* @param pixels -
|
|
24
|
+
* @param opts
|
|
31
25
|
*/
|
|
32
|
-
export const renderPixels = (fn,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
26
|
+
export const renderPixels = (fn, pixels, { x, y, w, h, bufW, bufH, offsetX, offsetY, imgH, fmt }) => {
|
|
27
|
+
offsetX = offsetX || 0;
|
|
28
|
+
offsetY = offsetY || 0;
|
|
29
|
+
imgH = (imgH || bufH) - 1 - offsetY;
|
|
30
|
+
x = clamp(x || 0, 0, bufW);
|
|
31
|
+
y = clamp(y || 0, 0, bufH);
|
|
36
32
|
const x2 = clampCoord(x, bufW, w);
|
|
37
33
|
const y2 = clampCoord(y, bufH, h);
|
|
34
|
+
const fragCoord = [];
|
|
38
35
|
for (let yy = y; yy < y2; yy++) {
|
|
39
|
-
|
|
36
|
+
fragCoord[1] = imgH - yy;
|
|
40
37
|
let i = yy * bufW + x;
|
|
41
38
|
for (let xx = x; xx < x2; xx++) {
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
fragCoord[0] = xx + offsetX;
|
|
40
|
+
pixels[i++] = fmt(fn(fragCoord));
|
|
44
41
|
}
|
|
45
42
|
}
|
|
46
|
-
return
|
|
43
|
+
return pixels;
|
|
47
44
|
};
|
|
48
45
|
/**
|
|
49
46
|
* Takes a
|
|
50
47
|
* [`IntBuffer`](https://docs.thi.ng/umbrella/pixel/classes/IntBuffer.html)
|
|
51
|
-
* pixel buffer from thi.ng/pixel
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
48
|
+
* pixel buffer from thi.ng/pixel, and options to define a buffer-local render
|
|
49
|
+
* region. Applies shader function `fn` to each pixel in that region (or the
|
|
50
|
+
* full buffer by default).
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* In case the buffer only defines a sub-region of a larger image,
|
|
54
|
+
* {@link RenderPixelOpts.offsetX}, {@link RenderPixelOpts.offsetY} and
|
|
55
|
+
* {@link RenderPixelOpts.imgH} can be given to configure the location and full
|
|
56
|
+
* image height.
|
|
56
57
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* height.
|
|
58
|
+
* The default target pixel format is `ABGR8888` using {@link rgbaBgra8888} as
|
|
59
|
+
* default {@link RenderPixelOpts.fmt} conversion.
|
|
60
60
|
*
|
|
61
61
|
* @param fn -
|
|
62
62
|
* @param buf -
|
|
@@ -68,9 +68,15 @@ export const renderPixels = (fn, u32, bufW, bufH, x, y, w, h, bufOffsetX = 0, bu
|
|
|
68
68
|
* @param bufOffsetY -
|
|
69
69
|
* @param imgH -
|
|
70
70
|
*/
|
|
71
|
-
export const renderBuffer = (fn, buf,
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
export const renderBuffer = (fn, buf, opts) => {
|
|
72
|
+
renderPixels(fn, buf.data, {
|
|
73
|
+
fmt: rgbaBgra8888,
|
|
74
|
+
bufW: buf.width,
|
|
75
|
+
bufH: buf.height,
|
|
76
|
+
x: 0,
|
|
77
|
+
y: 0,
|
|
78
|
+
...opts,
|
|
79
|
+
});
|
|
74
80
|
return buf;
|
|
75
81
|
};
|
|
76
82
|
/**
|
|
@@ -87,7 +93,7 @@ export const canvasRenderer = (canvas) => {
|
|
|
87
93
|
const buf = intBufferFromCanvas(canvas);
|
|
88
94
|
const data = new ImageData(canvas.width, canvas.height);
|
|
89
95
|
return (fn, x = 0, y = 0, w = canvas.width, h = canvas.height) => {
|
|
90
|
-
renderBuffer(fn, buf, x, y, w, h);
|
|
96
|
+
renderBuffer(fn, buf, { x, y, w, h });
|
|
91
97
|
buf.blitCanvas(canvas, { data });
|
|
92
98
|
};
|
|
93
99
|
};
|
package/target.js
CHANGED
|
@@ -31,22 +31,25 @@ const OP_IDS = {
|
|
|
31
31
|
"<<": "lshift",
|
|
32
32
|
">>": "rshift",
|
|
33
33
|
};
|
|
34
|
-
const
|
|
35
|
-
"float",
|
|
36
|
-
"int",
|
|
37
|
-
"uint",
|
|
34
|
+
const VEC_TYPES = [
|
|
38
35
|
"vec2",
|
|
39
36
|
"vec3",
|
|
40
37
|
"vec4",
|
|
41
|
-
"bvec2",
|
|
42
|
-
"bvec3",
|
|
43
|
-
"bvec4",
|
|
44
38
|
"ivec2",
|
|
45
39
|
"ivec3",
|
|
46
40
|
"ivec4",
|
|
47
41
|
"uvec2",
|
|
48
42
|
"uvec3",
|
|
49
43
|
"uvec4",
|
|
44
|
+
];
|
|
45
|
+
const PRELUDE = [
|
|
46
|
+
"float",
|
|
47
|
+
"int",
|
|
48
|
+
"uint",
|
|
49
|
+
...VEC_TYPES,
|
|
50
|
+
"bvec2",
|
|
51
|
+
"bvec3",
|
|
52
|
+
"bvec4",
|
|
50
53
|
"mat2",
|
|
51
54
|
"mat3",
|
|
52
55
|
"mat4",
|
|
@@ -58,8 +61,10 @@ const PRELUDE = [
|
|
|
58
61
|
]
|
|
59
62
|
.map((x) => `const ${x} = env.${x};`)
|
|
60
63
|
.join("\n");
|
|
64
|
+
const POOL_PRELUDE = VEC_TYPES.map((x) => `const $${x} = env.pools.${x}.from;`).join("\n");
|
|
61
65
|
const COMPS = { x: 0, y: 1, z: 2, w: 3 };
|
|
62
66
|
const RE_SEMI = /[};]$/;
|
|
67
|
+
const RESET = `for(let t in env.pools) env.pools[t].reset();`;
|
|
63
68
|
const isIntOrBool = (l) => isInt(l) || isUint(l) || isBool(l);
|
|
64
69
|
const isVecOrMat = (l) => isVec(l) || isMat(l);
|
|
65
70
|
const swizzle = (id) => [...id].map((x) => COMPS[x]).join(", ");
|
|
@@ -79,6 +84,7 @@ export const targetJS = (opts) => {
|
|
|
79
84
|
: String;
|
|
80
85
|
const $list = (body, sep = ", ") => body.map(emit).join(sep);
|
|
81
86
|
const $fn = (name, args) => `${name}(${$list(args)})`;
|
|
87
|
+
const $vecFromPool = ({ val, info, type }) => !info ? `$${type}(${$list(val)})` : `env.${type}${info}(${$list(val)})`;
|
|
82
88
|
const $vec = ({ val, info, type }) => !info ? `[${$list(val)}]` : `env.${type}${info}(${$list(val)})`;
|
|
83
89
|
const $num = (v, f) => isNumber(v) ? String(v) : f(v);
|
|
84
90
|
const $float = (v, f) => (isNumber(v) ? ff(v) : f(v));
|
|
@@ -110,7 +116,19 @@ export const targetJS = (opts) => {
|
|
|
110
116
|
: undefined;
|
|
111
117
|
return res.join(" ");
|
|
112
118
|
},
|
|
113
|
-
fn: (t) =>
|
|
119
|
+
fn: (t) => {
|
|
120
|
+
let body;
|
|
121
|
+
if (t.id === "main") {
|
|
122
|
+
body = `{\n${RESET}\n${emit({
|
|
123
|
+
...t.scope,
|
|
124
|
+
global: true,
|
|
125
|
+
})}}`;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
body = emit(t.scope);
|
|
129
|
+
}
|
|
130
|
+
return `${buildComments(t)}\nfunction ${t.id}(${$list(t.args)}) ${body}`;
|
|
131
|
+
},
|
|
114
132
|
for: (t) => `for(${t.init ? emit(t.init) : ""}; ${emit(t.test)}; ${t.iter ? emit(t.iter) : ""}) ${emit(t.scope)}`,
|
|
115
133
|
idx: (t) => `${emit(t.val)}[${emit(t.id)}]`,
|
|
116
134
|
idxm: (t) => `${t.val.type}.idx(${emit(t.val)},${emit(t.id)})`,
|
|
@@ -132,15 +150,16 @@ export const targetJS = (opts) => {
|
|
|
132
150
|
case "vec2":
|
|
133
151
|
case "vec3":
|
|
134
152
|
case "vec4":
|
|
135
|
-
case "bvec2":
|
|
136
|
-
case "bvec3":
|
|
137
|
-
case "bvec4":
|
|
138
153
|
case "ivec2":
|
|
139
154
|
case "ivec3":
|
|
140
155
|
case "ivec4":
|
|
141
156
|
case "uvec2":
|
|
142
157
|
case "uvec3":
|
|
143
158
|
case "uvec4":
|
|
159
|
+
return $vecFromPool(t);
|
|
160
|
+
case "bvec2":
|
|
161
|
+
case "bvec3":
|
|
162
|
+
case "bvec4":
|
|
144
163
|
case "mat2":
|
|
145
164
|
case "mat3":
|
|
146
165
|
case "mat4":
|
|
@@ -185,7 +204,7 @@ export const targetJS = (opts) => {
|
|
|
185
204
|
scope: (t) => {
|
|
186
205
|
let res = $list(t.body, ";\n");
|
|
187
206
|
res += t.body.length && !RE_SEMI.test(res) ? ";" : "";
|
|
188
|
-
return
|
|
207
|
+
return t.global ? res : `{\n${res}\n}`;
|
|
189
208
|
},
|
|
190
209
|
swizzle: (t) => t.id.length > 1
|
|
191
210
|
? `env.swizzle${t.id.length}(${emit(t.val)}, ${swizzle(t.id)})`
|
|
@@ -197,7 +216,16 @@ export const targetJS = (opts) => {
|
|
|
197
216
|
Object.assign(emit, {
|
|
198
217
|
compile: (tree, env = JS_DEFAULT_ENV) => {
|
|
199
218
|
const exports = buildExports(tree);
|
|
200
|
-
return new Function("env", [
|
|
219
|
+
return new Function("env", [
|
|
220
|
+
PRELUDE,
|
|
221
|
+
POOL_PRELUDE,
|
|
222
|
+
emit(tree),
|
|
223
|
+
"return {",
|
|
224
|
+
`__reset: () => {${RESET}},`,
|
|
225
|
+
`__stats: () => Object.entries(env.pools).reduce((acc, [k, v]) => (acc[k] = v.index, acc), {}),`,
|
|
226
|
+
exports,
|
|
227
|
+
"};",
|
|
228
|
+
].join("\n"))(env);
|
|
201
229
|
},
|
|
202
230
|
});
|
|
203
231
|
return emit;
|