@shaderfrog/core 0.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/.eslintrc.json +3 -0
- package/.prettierrc.js +3 -0
- package/README.md +3 -0
- package/babel.config.js +6 -0
- package/package.json +47 -0
- package/src/ast/manipulate.ts +392 -0
- package/src/ast/shader-sections.ts +323 -0
- package/src/core/engine.ts +214 -0
- package/src/core/file.js +53 -0
- package/src/core/graph.ts +1007 -0
- package/src/core/nodes/code-nodes.ts +66 -0
- package/src/core/nodes/core-node.ts +48 -0
- package/src/core/nodes/data-nodes.ts +344 -0
- package/src/core/nodes/edge.ts +23 -0
- package/src/core/nodes/engine-node.ts +266 -0
- package/src/core/strategy.ts +520 -0
- package/src/core.test.ts +312 -0
- package/src/plugins/babylon/bablyengine.ts +670 -0
- package/src/plugins/babylon/examples.ts +512 -0
- package/src/plugins/babylon/importers.ts +69 -0
- package/src/plugins/babylon/index.ts +6 -0
- package/src/plugins/three/examples.ts +680 -0
- package/src/plugins/three/importers.ts +18 -0
- package/src/plugins/three/index.ts +6 -0
- package/src/plugins/three/threngine.tsx +571 -0
- package/src/util/ensure.ts +10 -0
- package/src/util/id.ts +2 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import { generate } from '@shaderfrog/glsl-parser';
|
|
2
|
+
import {
|
|
3
|
+
visit,
|
|
4
|
+
AstNode,
|
|
5
|
+
NodeVisitors,
|
|
6
|
+
Program,
|
|
7
|
+
Scope,
|
|
8
|
+
ScopeIndex,
|
|
9
|
+
DeclarationNode,
|
|
10
|
+
DeclarationStatementNode,
|
|
11
|
+
KeywordNode,
|
|
12
|
+
} from '@shaderfrog/glsl-parser/ast';
|
|
13
|
+
import { findAssignmentTo, findDeclarationOf } from '../ast/manipulate';
|
|
14
|
+
import { ComputedInput, GraphNode, mangleName } from './graph';
|
|
15
|
+
import { SourceNode } from './nodes/code-nodes';
|
|
16
|
+
import { InputCategory, nodeInput, NodeInput } from './nodes/core-node';
|
|
17
|
+
import { GraphDataType } from './nodes/data-nodes';
|
|
18
|
+
|
|
19
|
+
export enum StrategyType {
|
|
20
|
+
VARIABLE = 'Variable Names',
|
|
21
|
+
ASSIGNMENT_TO = 'Assignment To',
|
|
22
|
+
DECLARATION_OF = 'Variable Declaration',
|
|
23
|
+
TEXTURE_2D = 'Texture2D',
|
|
24
|
+
NAMED_ATTRIBUTE = 'Named Attribute',
|
|
25
|
+
UNIFORM = 'Uniform',
|
|
26
|
+
HARD_CODE = 'Hard Code Inputs',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface BaseStrategy {
|
|
30
|
+
type: StrategyType;
|
|
31
|
+
config: Object;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface AssignemntToStrategy extends BaseStrategy {
|
|
35
|
+
type: StrategyType.ASSIGNMENT_TO;
|
|
36
|
+
config: {
|
|
37
|
+
assignTo: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export const assignemntToStrategy = (
|
|
41
|
+
assignTo: string
|
|
42
|
+
): AssignemntToStrategy => ({
|
|
43
|
+
type: StrategyType.ASSIGNMENT_TO,
|
|
44
|
+
config: { assignTo },
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export interface Texture2DStrategy extends BaseStrategy {
|
|
48
|
+
type: StrategyType.TEXTURE_2D;
|
|
49
|
+
}
|
|
50
|
+
export const texture2DStrategy = (): Texture2DStrategy => ({
|
|
51
|
+
type: StrategyType.TEXTURE_2D,
|
|
52
|
+
config: {},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export interface UniformStrategy extends BaseStrategy {
|
|
56
|
+
type: StrategyType.UNIFORM;
|
|
57
|
+
}
|
|
58
|
+
export const uniformStrategy = (): UniformStrategy => ({
|
|
59
|
+
type: StrategyType.UNIFORM,
|
|
60
|
+
config: {},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export interface HardCodeStrategy extends BaseStrategy {
|
|
64
|
+
type: StrategyType.HARD_CODE;
|
|
65
|
+
config: { inputs: NodeInput[] };
|
|
66
|
+
}
|
|
67
|
+
export const hardCodeStrategy = (inputs: NodeInput[]): HardCodeStrategy => ({
|
|
68
|
+
type: StrategyType.HARD_CODE,
|
|
69
|
+
config: { inputs },
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export const namedAttributeStrategy = (
|
|
73
|
+
attributeName: string
|
|
74
|
+
): NamedAttributeStrategy => ({
|
|
75
|
+
type: StrategyType.NAMED_ATTRIBUTE,
|
|
76
|
+
config: { attributeName },
|
|
77
|
+
});
|
|
78
|
+
export interface NamedAttributeStrategy extends BaseStrategy {
|
|
79
|
+
type: StrategyType.NAMED_ATTRIBUTE;
|
|
80
|
+
config: {
|
|
81
|
+
attributeName: string;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const declarationOfStrategy = (
|
|
86
|
+
declarationOf: string
|
|
87
|
+
): DeclarationOfStrategy => ({
|
|
88
|
+
type: StrategyType.DECLARATION_OF,
|
|
89
|
+
config: { declarationOf },
|
|
90
|
+
});
|
|
91
|
+
export interface DeclarationOfStrategy extends BaseStrategy {
|
|
92
|
+
type: StrategyType.DECLARATION_OF;
|
|
93
|
+
config: {
|
|
94
|
+
declarationOf: string;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface VariableStrategy extends BaseStrategy {
|
|
99
|
+
type: StrategyType.VARIABLE;
|
|
100
|
+
}
|
|
101
|
+
export const variableStrategy = (): VariableStrategy => ({
|
|
102
|
+
type: StrategyType.VARIABLE,
|
|
103
|
+
config: {},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
export type Strategy =
|
|
107
|
+
| UniformStrategy
|
|
108
|
+
| AssignemntToStrategy
|
|
109
|
+
| Texture2DStrategy
|
|
110
|
+
| NamedAttributeStrategy
|
|
111
|
+
| VariableStrategy
|
|
112
|
+
| HardCodeStrategy
|
|
113
|
+
| DeclarationOfStrategy;
|
|
114
|
+
|
|
115
|
+
type StrategyImpl = (
|
|
116
|
+
node: SourceNode,
|
|
117
|
+
ast: AstNode | Program,
|
|
118
|
+
strategy: Strategy
|
|
119
|
+
) => ComputedInput[];
|
|
120
|
+
|
|
121
|
+
type Strategies = Record<StrategyType, StrategyImpl>;
|
|
122
|
+
|
|
123
|
+
const DATA_TYPE_MAP: Readonly<[GraphDataType, Set<string>][]> = [
|
|
124
|
+
['vector2', new Set(['bvec2', 'dvec2', 'ivec2', 'uvec2', 'vec2'])],
|
|
125
|
+
['number', new Set(['float', 'double', 'int', 'uint', 'atomic_uint'])],
|
|
126
|
+
['vector3', new Set(['bvec3', 'dvec3', 'ivec3', 'uvec3', 'vec3'])],
|
|
127
|
+
['vector4', new Set(['bvec4', 'dvec4', 'ivec4', 'uvec4', 'vec4'])],
|
|
128
|
+
['texture', new Set(['sampler2D'])],
|
|
129
|
+
['mat2', new Set(['mat2', 'dmat2'])],
|
|
130
|
+
['mat3', new Set(['mat3', 'dmat3'])],
|
|
131
|
+
['mat4', new Set(['mat4', 'dmat4'])],
|
|
132
|
+
['mat2x2', new Set(['mat2x2', 'dmat2x2'])],
|
|
133
|
+
['mat2x3', new Set(['mat2x3', 'dmat2x3'])],
|
|
134
|
+
['mat2x4', new Set(['mat2x4', 'dmat2x4'])],
|
|
135
|
+
['mat3x2', new Set(['mat3x2', 'dmat3x2'])],
|
|
136
|
+
['mat3x3', new Set(['mat3x3', 'dmat3x3'])],
|
|
137
|
+
['mat3x4', new Set(['mat3x4', 'dmat3x4'])],
|
|
138
|
+
['mat4x2', new Set(['mat4x2', 'dmat4x2'])],
|
|
139
|
+
['mat4x3', new Set(['mat4x3', 'dmat4x3'])],
|
|
140
|
+
['mat4x4', new Set(['mat4x4', 'dmat4x4'])],
|
|
141
|
+
];
|
|
142
|
+
/**
|
|
143
|
+
* Uncategorized:
|
|
144
|
+
*
|
|
145
|
+
"sampler1D"
|
|
146
|
+
"sampler3D"
|
|
147
|
+
"samplerCube"
|
|
148
|
+
"sampler1DShadow"
|
|
149
|
+
"sampler2DShadow"
|
|
150
|
+
"samplerCubeShadow"
|
|
151
|
+
"sampler1DArray"
|
|
152
|
+
"sampler2DArray"
|
|
153
|
+
"sampler1DArrayShadow"
|
|
154
|
+
"sampler2DArrayshadow"
|
|
155
|
+
"isampler1D"
|
|
156
|
+
"isampler2D"
|
|
157
|
+
"isampler3D"
|
|
158
|
+
"isamplerCube"
|
|
159
|
+
"isampler1Darray"
|
|
160
|
+
"isampler2DArray"
|
|
161
|
+
"usampler1D"
|
|
162
|
+
"usampler2D"
|
|
163
|
+
"usampler3D"
|
|
164
|
+
"usamplerCube"
|
|
165
|
+
"usampler1DArray"
|
|
166
|
+
"usampler2DArray"
|
|
167
|
+
"sampler2DRect"
|
|
168
|
+
"sampler2DRectshadow"
|
|
169
|
+
"isampler2DRect"
|
|
170
|
+
"usampler2DRect"
|
|
171
|
+
"samplerBuffer"
|
|
172
|
+
"isamplerBuffer"
|
|
173
|
+
"usamplerBuffer"
|
|
174
|
+
"samplerCubeArray"
|
|
175
|
+
"samplerCubeArrayShadow"
|
|
176
|
+
"isamplerCubeArray"
|
|
177
|
+
"usamplerCubeArray"
|
|
178
|
+
"sampler2DMS"
|
|
179
|
+
"isampler2DMS"
|
|
180
|
+
"usampler2DMS"
|
|
181
|
+
"sampler2DMSArray"
|
|
182
|
+
"isampler2DMSArray"
|
|
183
|
+
"usampler2DMSArray"
|
|
184
|
+
"image1D"
|
|
185
|
+
"iimage1D"
|
|
186
|
+
"uimage1D"
|
|
187
|
+
"image2D"
|
|
188
|
+
"iimage2D"
|
|
189
|
+
"uimage2D"
|
|
190
|
+
"image3D"
|
|
191
|
+
"iimage3D"
|
|
192
|
+
"uimage3D"
|
|
193
|
+
"image2DRect"
|
|
194
|
+
"iimage2DRect"
|
|
195
|
+
"uimage2DRect"
|
|
196
|
+
"imageCube"
|
|
197
|
+
"iimageCube"
|
|
198
|
+
"uimageCube"
|
|
199
|
+
"imageBuffer"
|
|
200
|
+
"iimageBuffer"
|
|
201
|
+
"uimageBuffer"
|
|
202
|
+
"image1DArray"
|
|
203
|
+
"iimage1DArray"
|
|
204
|
+
"uimage1DArray"
|
|
205
|
+
"image2DArray"
|
|
206
|
+
"iimage2DArray"
|
|
207
|
+
"uimage2DArray"
|
|
208
|
+
"imageCubeArray"
|
|
209
|
+
"iimageCubeArray"
|
|
210
|
+
"uimageCubeArray"
|
|
211
|
+
"image2DMS"
|
|
212
|
+
"iimage2DMS"
|
|
213
|
+
"uimage2DMS"
|
|
214
|
+
"image2DMArray"
|
|
215
|
+
"iimage2DMSArray"
|
|
216
|
+
"uimage2DMSArray"
|
|
217
|
+
"struct"
|
|
218
|
+
*/
|
|
219
|
+
|
|
220
|
+
const mapUniformType = (type: string): GraphDataType | undefined => {
|
|
221
|
+
const found = DATA_TYPE_MAP.find(([_, set]) => set.has(type));
|
|
222
|
+
if (found) {
|
|
223
|
+
return found[0];
|
|
224
|
+
}
|
|
225
|
+
// console.log(`Unknown uniform type, can't map to graph: ${type}`);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export const applyStrategy = (
|
|
229
|
+
strategy: Strategy,
|
|
230
|
+
node: SourceNode,
|
|
231
|
+
ast: AstNode | Program
|
|
232
|
+
) => strategyRunners[strategy.type](node, ast, strategy);
|
|
233
|
+
|
|
234
|
+
export const strategyRunners: Strategies = {
|
|
235
|
+
[StrategyType.HARD_CODE]: (graphNode, ast, strategy) => {
|
|
236
|
+
return (strategy as HardCodeStrategy).config.inputs.map((input) => [
|
|
237
|
+
input,
|
|
238
|
+
(filler) => filler,
|
|
239
|
+
]);
|
|
240
|
+
},
|
|
241
|
+
[StrategyType.UNIFORM]: (graphNode, ast, strategy) => {
|
|
242
|
+
const program = ast as Program;
|
|
243
|
+
return (program.program || []).flatMap<ComputedInput>((node) => {
|
|
244
|
+
// The uniform declration type, like vec4
|
|
245
|
+
const uniformType = (node as DeclarationStatementNode).declaration
|
|
246
|
+
?.specified_type?.specifier?.specifier?.token;
|
|
247
|
+
const graphDataType = mapUniformType(uniformType);
|
|
248
|
+
|
|
249
|
+
// If this is a uniform declaration line
|
|
250
|
+
if (
|
|
251
|
+
node.type === 'declaration_statement' &&
|
|
252
|
+
node.declaration?.specified_type?.qualifiers?.find(
|
|
253
|
+
(n: KeywordNode) => n.token === 'uniform'
|
|
254
|
+
)
|
|
255
|
+
// commented this out to allow for sampler2D uniforms to appear as inputs
|
|
256
|
+
// && uniformType !== 'sampler2D'
|
|
257
|
+
) {
|
|
258
|
+
// Capture all the declared names, removing mangling suffix
|
|
259
|
+
const { declarations } = node.declaration;
|
|
260
|
+
const names = declarations.map(
|
|
261
|
+
(d: any) => d.identifier.identifier
|
|
262
|
+
) as string[];
|
|
263
|
+
|
|
264
|
+
// Tricky code warning: The flow of preparing a node for the graph is:
|
|
265
|
+
// 1. Produce/mangle the AST (with unmangled names)
|
|
266
|
+
// 2. findInputs() (with unmangled names)
|
|
267
|
+
// 3. The AST is *then* mangled in graph.ts
|
|
268
|
+
// 4. Later, the inputs are filled in, and now, we have an input with
|
|
269
|
+
// the name "x" but the ast now has the mangled name "x_1". So
|
|
270
|
+
// here, we look for the *mangled* name in the strategy runner
|
|
271
|
+
return names.map<ComputedInput>((name) => [
|
|
272
|
+
nodeInput(
|
|
273
|
+
name,
|
|
274
|
+
`uniform_${name}`,
|
|
275
|
+
'uniform',
|
|
276
|
+
graphDataType,
|
|
277
|
+
new Set<InputCategory>(['code', 'data']),
|
|
278
|
+
true
|
|
279
|
+
),
|
|
280
|
+
(filler) => {
|
|
281
|
+
const mangledName = mangleName(name, graphNode);
|
|
282
|
+
// Remove the declaration line, or the declared uniform
|
|
283
|
+
if (declarations.length === 1) {
|
|
284
|
+
program.program.splice(program.program.indexOf(node), 1);
|
|
285
|
+
} else {
|
|
286
|
+
node.declaration.declarations =
|
|
287
|
+
node.declaration.declarations.filter(
|
|
288
|
+
(d: any) => d.identifier.identifier !== mangledName
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
// And rename all the references to said uniform
|
|
292
|
+
program.scopes[0].bindings[name].references.forEach((ref) => {
|
|
293
|
+
if (ref.type === 'identifier' && ref.identifier === mangledName) {
|
|
294
|
+
ref.identifier = generate(filler);
|
|
295
|
+
} else if (
|
|
296
|
+
ref.type === 'parameter_declaration' &&
|
|
297
|
+
'identifier' in ref.declaration &&
|
|
298
|
+
ref.declaration.identifier.identifier === mangledName
|
|
299
|
+
) {
|
|
300
|
+
ref.declaration.identifier.identifier = generate(filler);
|
|
301
|
+
} else if ('identifier' in ref) {
|
|
302
|
+
ref.identifier = generate(filler);
|
|
303
|
+
} else {
|
|
304
|
+
console.warn(
|
|
305
|
+
'Unknown uniform reference for',
|
|
306
|
+
graphNode.name,
|
|
307
|
+
'ref'
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
return ast;
|
|
313
|
+
},
|
|
314
|
+
]);
|
|
315
|
+
}
|
|
316
|
+
return [];
|
|
317
|
+
});
|
|
318
|
+
},
|
|
319
|
+
[StrategyType.ASSIGNMENT_TO]: (node, ast, strategy) => {
|
|
320
|
+
const cast = strategy as AssignemntToStrategy;
|
|
321
|
+
const assignNode = findAssignmentTo(ast, cast.config.assignTo);
|
|
322
|
+
|
|
323
|
+
const name = cast.config.assignTo;
|
|
324
|
+
return assignNode
|
|
325
|
+
? [
|
|
326
|
+
[
|
|
327
|
+
nodeInput(
|
|
328
|
+
name,
|
|
329
|
+
`filler_${name}`,
|
|
330
|
+
'filler',
|
|
331
|
+
undefined, // Data type for what plugs into this filler
|
|
332
|
+
new Set<InputCategory>(['code', 'data']),
|
|
333
|
+
false
|
|
334
|
+
),
|
|
335
|
+
(fillerAst) => {
|
|
336
|
+
assignNode.expression.right = fillerAst;
|
|
337
|
+
return ast;
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
]
|
|
341
|
+
: [];
|
|
342
|
+
},
|
|
343
|
+
[StrategyType.DECLARATION_OF]: (node, ast, strategy) => {
|
|
344
|
+
const cast = strategy as DeclarationOfStrategy;
|
|
345
|
+
const declaration = findDeclarationOf(ast, cast.config.declarationOf);
|
|
346
|
+
const name = cast.config.declarationOf;
|
|
347
|
+
return declaration
|
|
348
|
+
? [
|
|
349
|
+
[
|
|
350
|
+
nodeInput(
|
|
351
|
+
name,
|
|
352
|
+
`filler_${name}`,
|
|
353
|
+
'filler',
|
|
354
|
+
undefined, // Data type for what plugs into this filler
|
|
355
|
+
new Set<InputCategory>(['code', 'data']),
|
|
356
|
+
false
|
|
357
|
+
),
|
|
358
|
+
(fillerAst) => {
|
|
359
|
+
declaration.initializer = fillerAst;
|
|
360
|
+
return ast;
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
]
|
|
364
|
+
: [];
|
|
365
|
+
},
|
|
366
|
+
[StrategyType.TEXTURE_2D]: (node, ast, strategy) => {
|
|
367
|
+
let texture2Dcalls: [string, AstNode, string, AstNode[]][] = [];
|
|
368
|
+
const seen: { [key: string]: number } = {};
|
|
369
|
+
const visitors: NodeVisitors = {
|
|
370
|
+
function_call: {
|
|
371
|
+
enter: (path) => {
|
|
372
|
+
if (
|
|
373
|
+
// TODO: 100 vs 300
|
|
374
|
+
// @ts-ignore
|
|
375
|
+
(path.node.identifier?.specifier?.identifier === 'texture2D' ||
|
|
376
|
+
// @ts-ignore
|
|
377
|
+
path.node.identifier?.specifier?.identifier === 'texture') &&
|
|
378
|
+
path.key
|
|
379
|
+
) {
|
|
380
|
+
if (!path.parent) {
|
|
381
|
+
throw new Error(
|
|
382
|
+
'This error is impossible. A function call always has a parent.'
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const name = generate(path.node.args[0]);
|
|
387
|
+
seen[name] = (seen[name] || 0) + 1;
|
|
388
|
+
texture2Dcalls.push([
|
|
389
|
+
name,
|
|
390
|
+
path.parent as AstNode,
|
|
391
|
+
path.key,
|
|
392
|
+
// Remove the first argument and comma
|
|
393
|
+
(path.node.args as AstNode[]).slice(2),
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
visit(ast, visitors);
|
|
400
|
+
const names = new Set(
|
|
401
|
+
Object.entries(seen).reduce<string[]>(
|
|
402
|
+
(arr, [name, count]) => [...arr, ...(count > 1 ? [name] : [])],
|
|
403
|
+
[]
|
|
404
|
+
)
|
|
405
|
+
);
|
|
406
|
+
const inputs = texture2Dcalls.map<ComputedInput>(
|
|
407
|
+
([name, parent, key, texture2dArgs], index) => {
|
|
408
|
+
// Suffix input name if it's used more than once
|
|
409
|
+
const iName = names.has(name) ? `${name}_${index}` : name;
|
|
410
|
+
return [
|
|
411
|
+
nodeInput(
|
|
412
|
+
iName,
|
|
413
|
+
`filler_${iName}`,
|
|
414
|
+
'filler',
|
|
415
|
+
'vector4', // Data type for what plugs into this filler
|
|
416
|
+
new Set<InputCategory>(['code', 'data']),
|
|
417
|
+
false
|
|
418
|
+
),
|
|
419
|
+
(fillerAst) => {
|
|
420
|
+
// @ts-ignore
|
|
421
|
+
parent[key] = fillerAst;
|
|
422
|
+
return ast;
|
|
423
|
+
},
|
|
424
|
+
texture2dArgs,
|
|
425
|
+
];
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
return inputs;
|
|
430
|
+
},
|
|
431
|
+
[StrategyType.NAMED_ATTRIBUTE]: (node, ast, strategy) => {
|
|
432
|
+
const program = ast as Program;
|
|
433
|
+
const cast = strategy as NamedAttributeStrategy;
|
|
434
|
+
const { attributeName } = cast.config;
|
|
435
|
+
return [
|
|
436
|
+
[
|
|
437
|
+
nodeInput(
|
|
438
|
+
attributeName,
|
|
439
|
+
`filler_${attributeName}`,
|
|
440
|
+
'filler',
|
|
441
|
+
undefined, // Data type for what plugs into this filler
|
|
442
|
+
new Set<InputCategory>(['code', 'data']),
|
|
443
|
+
true
|
|
444
|
+
),
|
|
445
|
+
(fillerAst) => {
|
|
446
|
+
Object.entries(program.scopes[0].bindings).forEach(
|
|
447
|
+
([name, binding]: [string, any]) => {
|
|
448
|
+
binding.references.forEach((ref: AstNode) => {
|
|
449
|
+
if (
|
|
450
|
+
ref.type === 'identifier' &&
|
|
451
|
+
ref.identifier === attributeName
|
|
452
|
+
) {
|
|
453
|
+
ref.identifier = generate(fillerAst);
|
|
454
|
+
} else if (
|
|
455
|
+
ref.type === 'parameter_declaration' &&
|
|
456
|
+
'identifier' in ref.declaration &&
|
|
457
|
+
ref.declaration.identifier.identifier === attributeName
|
|
458
|
+
) {
|
|
459
|
+
ref.declaration.identifier.identifier = generate(fillerAst);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
);
|
|
464
|
+
return ast;
|
|
465
|
+
},
|
|
466
|
+
],
|
|
467
|
+
];
|
|
468
|
+
},
|
|
469
|
+
[StrategyType.VARIABLE]: (node, ast, strategy) => {
|
|
470
|
+
const program = ast as Program;
|
|
471
|
+
return Object.values(
|
|
472
|
+
(program.scopes as Scope[]).reduce<ScopeIndex>(
|
|
473
|
+
(acc, scope) => ({ ...acc, ...scope.bindings }),
|
|
474
|
+
{}
|
|
475
|
+
)
|
|
476
|
+
).flatMap((binding: any) => {
|
|
477
|
+
return (binding.references as AstNode[]).reduce<ComputedInput[]>(
|
|
478
|
+
(acc, ref) => {
|
|
479
|
+
let identifier: string, replacer;
|
|
480
|
+
|
|
481
|
+
if (ref.type === 'declaration') {
|
|
482
|
+
identifier = ref.identifier.identifier;
|
|
483
|
+
replacer = (fillerAst: AstNode | Program) => {
|
|
484
|
+
ref.identifier.identifier = generate(fillerAst);
|
|
485
|
+
return ast;
|
|
486
|
+
};
|
|
487
|
+
} else if (ref.type === 'identifier') {
|
|
488
|
+
identifier = ref.identifier;
|
|
489
|
+
replacer = (fillerAst: AstNode | Program) => {
|
|
490
|
+
ref.identifier = generate(fillerAst);
|
|
491
|
+
return ast;
|
|
492
|
+
};
|
|
493
|
+
// } else if (ref.type === 'parameter_declaration') {
|
|
494
|
+
// identifier = ref.declaration.identifier.identifier;
|
|
495
|
+
// replacer = (fillerAst: AstNode) => {
|
|
496
|
+
// ref.declaration.identifier.identifier = generate(fillerAst);
|
|
497
|
+
// };
|
|
498
|
+
} else {
|
|
499
|
+
return acc;
|
|
500
|
+
}
|
|
501
|
+
return [
|
|
502
|
+
...acc,
|
|
503
|
+
[
|
|
504
|
+
nodeInput(
|
|
505
|
+
identifier,
|
|
506
|
+
`filler_${identifier}`,
|
|
507
|
+
'filler',
|
|
508
|
+
undefined, // Data type for what plugs into this filler
|
|
509
|
+
new Set<InputCategory>(['code', 'data']),
|
|
510
|
+
false
|
|
511
|
+
),
|
|
512
|
+
replacer,
|
|
513
|
+
],
|
|
514
|
+
];
|
|
515
|
+
},
|
|
516
|
+
[]
|
|
517
|
+
);
|
|
518
|
+
});
|
|
519
|
+
},
|
|
520
|
+
};
|