@holoscript/core 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-2XXE34KS.js +344 -0
- package/dist/chunk-2XXE34KS.js.map +1 -0
- package/dist/chunk-3X2EGU7Z.cjs +52 -0
- package/dist/chunk-3X2EGU7Z.cjs.map +1 -0
- package/dist/chunk-AFFVFO4D.js +1689 -0
- package/dist/chunk-AFFVFO4D.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +10 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/{src/HoloScriptDebugger.ts → dist/chunk-DOY73HDH.js} +118 -257
- package/dist/chunk-DOY73HDH.js.map +1 -0
- package/dist/chunk-JEQ2X3Z6.cjs +12 -0
- package/dist/chunk-JEQ2X3Z6.cjs.map +1 -0
- package/dist/chunk-L6VLNVKP.cjs +1691 -0
- package/dist/chunk-L6VLNVKP.cjs.map +1 -0
- package/dist/chunk-MFNO57XL.cjs +347 -0
- package/dist/chunk-MFNO57XL.cjs.map +1 -0
- package/dist/chunk-R75MREOS.cjs +424 -0
- package/dist/chunk-R75MREOS.cjs.map +1 -0
- package/dist/chunk-SATNCODL.js +45 -0
- package/dist/chunk-SATNCODL.js.map +1 -0
- package/dist/chunk-T57ZL7KR.cjs +1281 -0
- package/dist/chunk-T57ZL7KR.cjs.map +1 -0
- package/dist/chunk-U72GEJZT.js +1279 -0
- package/dist/chunk-U72GEJZT.js.map +1 -0
- package/dist/debugger.cjs +20 -0
- package/dist/debugger.cjs.map +1 -0
- package/dist/debugger.d.cts +171 -0
- package/dist/debugger.d.ts +171 -0
- package/dist/debugger.js +7 -0
- package/dist/debugger.js.map +1 -0
- package/dist/index.cjs +6803 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +4093 -0
- package/dist/index.d.ts +4093 -0
- package/dist/index.js +6715 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.cjs +14 -0
- package/dist/parser.cjs.map +1 -0
- package/dist/parser.d.cts +172 -0
- package/dist/parser.d.ts +172 -0
- package/dist/parser.js +5 -0
- package/dist/parser.js.map +1 -0
- package/dist/runtime.cjs +14 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +200 -0
- package/dist/runtime.d.ts +200 -0
- package/dist/runtime.js +5 -0
- package/dist/runtime.js.map +1 -0
- package/dist/type-checker.cjs +17 -0
- package/dist/type-checker.cjs.map +1 -0
- package/dist/type-checker.d.cts +105 -0
- package/dist/type-checker.d.ts +105 -0
- package/dist/type-checker.js +4 -0
- package/dist/type-checker.js.map +1 -0
- package/dist/types-4h8cbtF_.d.cts +329 -0
- package/dist/types-4h8cbtF_.d.ts +329 -0
- package/package.json +17 -13
- package/src/HoloScript2DParser.js +0 -227
- package/src/HoloScript2DParser.ts +0 -261
- package/src/HoloScriptCodeParser.js +0 -1102
- package/src/HoloScriptCodeParser.ts +0 -1188
- package/src/HoloScriptDebugger.js +0 -458
- package/src/HoloScriptParser.js +0 -338
- package/src/HoloScriptParser.ts +0 -397
- package/src/HoloScriptPlusParser.js +0 -371
- package/src/HoloScriptPlusParser.ts +0 -543
- package/src/HoloScriptRuntime.js +0 -1399
- package/src/HoloScriptRuntime.test.js +0 -351
- package/src/HoloScriptRuntime.test.ts +0 -436
- package/src/HoloScriptRuntime.ts +0 -1653
- package/src/HoloScriptTypeChecker.js +0 -356
- package/src/HoloScriptTypeChecker.ts +0 -475
- package/src/__tests__/GraphicsServices.test.js +0 -357
- package/src/__tests__/GraphicsServices.test.ts +0 -427
- package/src/__tests__/HoloScriptPlusParser.test.js +0 -317
- package/src/__tests__/HoloScriptPlusParser.test.ts +0 -392
- package/src/__tests__/integration.test.js +0 -336
- package/src/__tests__/integration.test.ts +0 -416
- package/src/__tests__/performance.bench.js +0 -218
- package/src/__tests__/performance.bench.ts +0 -262
- package/src/__tests__/type-checker.test.js +0 -60
- package/src/__tests__/type-checker.test.ts +0 -73
- package/src/index.js +0 -217
- package/src/index.ts +0 -426
- package/src/interop/Interoperability.js +0 -413
- package/src/interop/Interoperability.ts +0 -494
- package/src/logger.js +0 -42
- package/src/logger.ts +0 -57
- package/src/parser/EnhancedParser.js +0 -205
- package/src/parser/EnhancedParser.ts +0 -251
- package/src/parser/HoloScriptPlusParser.js +0 -928
- package/src/parser/HoloScriptPlusParser.ts +0 -1089
- package/src/runtime/HoloScriptPlusRuntime.js +0 -674
- package/src/runtime/HoloScriptPlusRuntime.ts +0 -861
- package/src/runtime/PerformanceTelemetry.js +0 -323
- package/src/runtime/PerformanceTelemetry.ts +0 -467
- package/src/runtime/RuntimeOptimization.js +0 -361
- package/src/runtime/RuntimeOptimization.ts +0 -416
- package/src/services/HololandGraphicsPipelineService.js +0 -506
- package/src/services/HololandGraphicsPipelineService.ts +0 -662
- package/src/services/PlatformPerformanceOptimizer.js +0 -356
- package/src/services/PlatformPerformanceOptimizer.ts +0 -503
- package/src/state/ReactiveState.js +0 -427
- package/src/state/ReactiveState.ts +0 -572
- package/src/tools/DeveloperExperience.js +0 -376
- package/src/tools/DeveloperExperience.ts +0 -438
- package/src/traits/AIDriverTrait.js +0 -322
- package/src/traits/AIDriverTrait.test.js +0 -329
- package/src/traits/AIDriverTrait.test.ts +0 -357
- package/src/traits/AIDriverTrait.ts +0 -474
- package/src/traits/LightingTrait.js +0 -313
- package/src/traits/LightingTrait.test.js +0 -410
- package/src/traits/LightingTrait.test.ts +0 -462
- package/src/traits/LightingTrait.ts +0 -505
- package/src/traits/MaterialTrait.js +0 -194
- package/src/traits/MaterialTrait.test.js +0 -286
- package/src/traits/MaterialTrait.test.ts +0 -329
- package/src/traits/MaterialTrait.ts +0 -324
- package/src/traits/RenderingTrait.js +0 -356
- package/src/traits/RenderingTrait.test.js +0 -363
- package/src/traits/RenderingTrait.test.ts +0 -427
- package/src/traits/RenderingTrait.ts +0 -555
- package/src/traits/VRTraitSystem.js +0 -740
- package/src/traits/VRTraitSystem.ts +0 -1040
- package/src/traits/VoiceInputTrait.js +0 -284
- package/src/traits/VoiceInputTrait.test.js +0 -226
- package/src/traits/VoiceInputTrait.test.ts +0 -252
- package/src/traits/VoiceInputTrait.ts +0 -401
- package/src/types/AdvancedTypeSystem.js +0 -226
- package/src/types/AdvancedTypeSystem.ts +0 -494
- package/src/types/HoloScriptPlus.d.ts +0 -853
- package/src/types.js +0 -6
- package/src/types.ts +0 -369
- package/tsconfig.json +0 -23
- package/tsup.config.d.ts +0 -2
- package/tsup.config.js +0 -18
- package/tsup.config.ts +0 -19
package/src/HoloScriptRuntime.ts
DELETED
|
@@ -1,1653 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HoloScript Runtime Engine
|
|
3
|
-
*
|
|
4
|
-
* Executes HoloScript AST in VR environment with spatial computation.
|
|
5
|
-
* Supports:
|
|
6
|
-
* - Orb creation and manipulation
|
|
7
|
-
* - Function definition and invocation with arguments
|
|
8
|
-
* - Connections and reactive data flow
|
|
9
|
-
* - Gates (conditionals)
|
|
10
|
-
* - Streams (data pipelines)
|
|
11
|
-
* - 2D UI elements
|
|
12
|
-
* - Built-in commands (show, hide, animate, pulse)
|
|
13
|
-
* - Expression evaluation
|
|
14
|
-
* - Event system
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { logger } from './logger';
|
|
18
|
-
import type {
|
|
19
|
-
ASTNode,
|
|
20
|
-
OrbNode,
|
|
21
|
-
MethodNode,
|
|
22
|
-
ConnectionNode,
|
|
23
|
-
GateNode,
|
|
24
|
-
StreamNode,
|
|
25
|
-
SpatialPosition,
|
|
26
|
-
HologramProperties,
|
|
27
|
-
HologramShape,
|
|
28
|
-
RuntimeContext,
|
|
29
|
-
ExecutionResult,
|
|
30
|
-
ParticleSystem,
|
|
31
|
-
TransformationNode,
|
|
32
|
-
UI2DNode,
|
|
33
|
-
} from './types';
|
|
34
|
-
import type { ImportLoader } from './types';
|
|
35
|
-
|
|
36
|
-
const RUNTIME_SECURITY_LIMITS = {
|
|
37
|
-
maxExecutionDepth: 50,
|
|
38
|
-
maxTotalNodes: 1000,
|
|
39
|
-
maxExecutionTimeMs: 5000,
|
|
40
|
-
maxParticlesPerSystem: 1000,
|
|
41
|
-
maxStringLength: 10000,
|
|
42
|
-
maxCallStackDepth: 100,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Event handler type
|
|
47
|
-
*/
|
|
48
|
-
type EventHandler = (data?: unknown) => void | Promise<void>;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Scope for variable resolution
|
|
52
|
-
*/
|
|
53
|
-
interface Scope {
|
|
54
|
-
variables: Map<string, unknown>;
|
|
55
|
-
parent?: Scope;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Animation state
|
|
60
|
-
*/
|
|
61
|
-
interface Animation {
|
|
62
|
-
target: string;
|
|
63
|
-
property: string;
|
|
64
|
-
from: number;
|
|
65
|
-
to: number;
|
|
66
|
-
duration: number;
|
|
67
|
-
startTime: number;
|
|
68
|
-
easing: string;
|
|
69
|
-
loop?: boolean;
|
|
70
|
-
yoyo?: boolean;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* UI Element state
|
|
75
|
-
*/
|
|
76
|
-
interface UIElementState {
|
|
77
|
-
type: string;
|
|
78
|
-
name: string;
|
|
79
|
-
properties: Record<string, unknown>;
|
|
80
|
-
value?: unknown;
|
|
81
|
-
visible: boolean;
|
|
82
|
-
enabled: boolean;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export class HoloScriptRuntime {
|
|
86
|
-
private context: RuntimeContext;
|
|
87
|
-
private particleSystems: Map<string, ParticleSystem> = new Map();
|
|
88
|
-
private executionHistory: ExecutionResult[] = [];
|
|
89
|
-
private startTime: number = 0;
|
|
90
|
-
private nodeCount: number = 0;
|
|
91
|
-
|
|
92
|
-
// Enhanced runtime state
|
|
93
|
-
private currentScope: Scope;
|
|
94
|
-
private callStack: string[] = [];
|
|
95
|
-
private eventHandlers: Map<string, EventHandler[]> = new Map();
|
|
96
|
-
private animations: Map<string, Animation> = new Map();
|
|
97
|
-
private uiElements: Map<string, UIElementState> = new Map();
|
|
98
|
-
private builtinFunctions: Map<string, (args: unknown[]) => unknown>;
|
|
99
|
-
|
|
100
|
-
constructor(_importLoader?: ImportLoader) {
|
|
101
|
-
this.context = this.createEmptyContext();
|
|
102
|
-
this.currentScope = { variables: this.context.variables };
|
|
103
|
-
this.builtinFunctions = this.initBuiltins();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Initialize built-in functions
|
|
108
|
-
*/
|
|
109
|
-
private initBuiltins(): Map<string, (args: unknown[]) => unknown> {
|
|
110
|
-
const builtins = new Map<string, (args: unknown[]) => unknown>();
|
|
111
|
-
|
|
112
|
-
// Display commands
|
|
113
|
-
builtins.set('show', (args) => {
|
|
114
|
-
const target = String(args[0]);
|
|
115
|
-
const element = this.uiElements.get(target);
|
|
116
|
-
if (element) element.visible = true;
|
|
117
|
-
const hologram = this.context.hologramState.get(target);
|
|
118
|
-
if (hologram) {
|
|
119
|
-
this.createParticleEffect(`${target}_show`, { x: 0, y: 0, z: 0 }, hologram.color, 15);
|
|
120
|
-
}
|
|
121
|
-
logger.info('show', { target });
|
|
122
|
-
return { shown: target };
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
builtins.set('hide', (args) => {
|
|
126
|
-
const target = String(args[0]);
|
|
127
|
-
const element = this.uiElements.get(target);
|
|
128
|
-
if (element) element.visible = false;
|
|
129
|
-
logger.info('hide', { target });
|
|
130
|
-
return { hidden: target };
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Animation commands
|
|
134
|
-
builtins.set('pulse', (args) => {
|
|
135
|
-
const target = String(args[0]);
|
|
136
|
-
const options = (args[1] as Record<string, unknown>) || {};
|
|
137
|
-
const duration = Number(options.duration) || 1000;
|
|
138
|
-
const color = String(options.color || '#ffffff');
|
|
139
|
-
|
|
140
|
-
const position = this.context.spatialMemory.get(target) || { x: 0, y: 0, z: 0 };
|
|
141
|
-
this.createParticleEffect(`${target}_pulse`, position, color, 30);
|
|
142
|
-
|
|
143
|
-
return { pulsing: target, duration };
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
builtins.set('animate', (args) => {
|
|
147
|
-
const target = String(args[0]);
|
|
148
|
-
const options = (args[1] as Record<string, unknown>) || {};
|
|
149
|
-
|
|
150
|
-
const animation: Animation = {
|
|
151
|
-
target,
|
|
152
|
-
property: String(options.property || 'position.y'),
|
|
153
|
-
from: Number(options.from || 0),
|
|
154
|
-
to: Number(options.to || 1),
|
|
155
|
-
duration: Number(options.duration || 1000),
|
|
156
|
-
startTime: Date.now(),
|
|
157
|
-
easing: String(options.easing || 'linear'),
|
|
158
|
-
loop: Boolean(options.loop),
|
|
159
|
-
yoyo: Boolean(options.yoyo),
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
this.animations.set(`${target}_${animation.property}`, animation);
|
|
163
|
-
return { animating: target, animation };
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
// Spatial commands
|
|
167
|
-
builtins.set('spawn', (args) => {
|
|
168
|
-
const target = String(args[0]);
|
|
169
|
-
const position = (args[1] as SpatialPosition) || { x: 0, y: 0, z: 0 };
|
|
170
|
-
|
|
171
|
-
this.context.spatialMemory.set(target, position);
|
|
172
|
-
this.createParticleEffect(`${target}_spawn`, position, '#00ff00', 25);
|
|
173
|
-
|
|
174
|
-
return { spawned: target, at: position };
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
builtins.set('move', (args) => {
|
|
178
|
-
const target = String(args[0]);
|
|
179
|
-
const position = (args[1] as SpatialPosition) || { x: 0, y: 0, z: 0 };
|
|
180
|
-
|
|
181
|
-
const current = this.context.spatialMemory.get(target);
|
|
182
|
-
if (current) {
|
|
183
|
-
this.context.spatialMemory.set(target, position);
|
|
184
|
-
this.createConnectionStream(target, `${target}_dest`, current, position, 'move');
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return { moved: target, to: position };
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// Data commands
|
|
191
|
-
builtins.set('set', (args) => {
|
|
192
|
-
const target = String(args[0]);
|
|
193
|
-
const value = args[1];
|
|
194
|
-
this.setVariable(target, value);
|
|
195
|
-
return { set: target, value };
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
builtins.set('get', (args) => {
|
|
199
|
-
const target = String(args[0]);
|
|
200
|
-
return this.getVariable(target);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// Math functions
|
|
204
|
-
builtins.set('add', (args) => Number(args[0]) + Number(args[1]));
|
|
205
|
-
builtins.set('subtract', (args) => Number(args[0]) - Number(args[1]));
|
|
206
|
-
builtins.set('multiply', (args) => Number(args[0]) * Number(args[1]));
|
|
207
|
-
builtins.set('divide', (args) => Number(args[1]) !== 0 ? Number(args[0]) / Number(args[1]) : 0);
|
|
208
|
-
builtins.set('mod', (args) => Number(args[0]) % Number(args[1]));
|
|
209
|
-
builtins.set('abs', (args) => Math.abs(Number(args[0])));
|
|
210
|
-
builtins.set('floor', (args) => Math.floor(Number(args[0])));
|
|
211
|
-
builtins.set('ceil', (args) => Math.ceil(Number(args[0])));
|
|
212
|
-
builtins.set('round', (args) => Math.round(Number(args[0])));
|
|
213
|
-
builtins.set('min', (args) => Math.min(...args.map(Number)));
|
|
214
|
-
builtins.set('max', (args) => Math.max(...args.map(Number)));
|
|
215
|
-
builtins.set('random', () => Math.random());
|
|
216
|
-
|
|
217
|
-
// String functions
|
|
218
|
-
builtins.set('concat', (args) => args.map(String).join(''));
|
|
219
|
-
builtins.set('length', (args) => {
|
|
220
|
-
const val = args[0];
|
|
221
|
-
if (typeof val === 'string') return val.length;
|
|
222
|
-
if (Array.isArray(val)) return val.length;
|
|
223
|
-
return 0;
|
|
224
|
-
});
|
|
225
|
-
builtins.set('substring', (args) => String(args[0]).substring(Number(args[1]), Number(args[2])));
|
|
226
|
-
builtins.set('uppercase', (args) => String(args[0]).toUpperCase());
|
|
227
|
-
builtins.set('lowercase', (args) => String(args[0]).toLowerCase());
|
|
228
|
-
|
|
229
|
-
// Array functions
|
|
230
|
-
builtins.set('push', (args) => {
|
|
231
|
-
const arr = args[0];
|
|
232
|
-
if (Array.isArray(arr)) {
|
|
233
|
-
arr.push(args[1]);
|
|
234
|
-
return arr;
|
|
235
|
-
}
|
|
236
|
-
return [args[0], args[1]];
|
|
237
|
-
});
|
|
238
|
-
builtins.set('pop', (args) => {
|
|
239
|
-
const arr = args[0];
|
|
240
|
-
if (Array.isArray(arr)) return arr.pop();
|
|
241
|
-
return undefined;
|
|
242
|
-
});
|
|
243
|
-
builtins.set('at', (args) => {
|
|
244
|
-
const arr = args[0];
|
|
245
|
-
const index = Number(args[1]);
|
|
246
|
-
if (Array.isArray(arr)) return arr[index];
|
|
247
|
-
return undefined;
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
// Console/Debug
|
|
251
|
-
builtins.set('log', (args) => {
|
|
252
|
-
logger.info('HoloScript log', { args });
|
|
253
|
-
return args[0];
|
|
254
|
-
});
|
|
255
|
-
builtins.set('print', (args) => {
|
|
256
|
-
const message = args.map(String).join(' ');
|
|
257
|
-
logger.info('print', { message });
|
|
258
|
-
return message;
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// Type checking
|
|
262
|
-
builtins.set('typeof', (args) => typeof args[0]);
|
|
263
|
-
builtins.set('isArray', (args) => Array.isArray(args[0]));
|
|
264
|
-
builtins.set('isNumber', (args) => typeof args[0] === 'number' && !isNaN(args[0] as number));
|
|
265
|
-
builtins.set('isString', (args) => typeof args[0] === 'string');
|
|
266
|
-
|
|
267
|
-
return builtins;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Execute a single AST node
|
|
272
|
-
*/
|
|
273
|
-
async executeNode(node: ASTNode): Promise<ExecutionResult> {
|
|
274
|
-
const startTime = Date.now();
|
|
275
|
-
|
|
276
|
-
try {
|
|
277
|
-
this.context.executionStack.push(node);
|
|
278
|
-
|
|
279
|
-
let result: ExecutionResult;
|
|
280
|
-
|
|
281
|
-
switch (node.type) {
|
|
282
|
-
case 'orb':
|
|
283
|
-
result = await this.executeOrb(node as OrbNode);
|
|
284
|
-
break;
|
|
285
|
-
case 'method':
|
|
286
|
-
case 'function':
|
|
287
|
-
result = await this.executeFunction(node as MethodNode);
|
|
288
|
-
break;
|
|
289
|
-
case 'connection':
|
|
290
|
-
result = await this.executeConnection(node as ConnectionNode);
|
|
291
|
-
break;
|
|
292
|
-
case 'gate':
|
|
293
|
-
result = await this.executeGate(node as GateNode);
|
|
294
|
-
break;
|
|
295
|
-
case 'stream':
|
|
296
|
-
result = await this.executeStream(node as StreamNode);
|
|
297
|
-
break;
|
|
298
|
-
case 'execute':
|
|
299
|
-
case 'call':
|
|
300
|
-
result = await this.executeCall(node as ASTNode & { target?: string; args?: unknown[] });
|
|
301
|
-
break;
|
|
302
|
-
case 'debug':
|
|
303
|
-
result = await this.executeDebug(node);
|
|
304
|
-
break;
|
|
305
|
-
case 'visualize':
|
|
306
|
-
result = await this.executeVisualize(node);
|
|
307
|
-
break;
|
|
308
|
-
case '2d-element':
|
|
309
|
-
result = await this.executeUIElement(node as unknown as UI2DNode);
|
|
310
|
-
break;
|
|
311
|
-
case 'nexus':
|
|
312
|
-
case 'building':
|
|
313
|
-
result = await this.executeStructure(node);
|
|
314
|
-
break;
|
|
315
|
-
case 'assignment':
|
|
316
|
-
result = await this.executeAssignment(node as ASTNode & { name: string; value: unknown });
|
|
317
|
-
break;
|
|
318
|
-
case 'return':
|
|
319
|
-
result = await this.executeReturn(node as ASTNode & { value: unknown });
|
|
320
|
-
break;
|
|
321
|
-
case 'generic':
|
|
322
|
-
result = await this.executeGeneric(node);
|
|
323
|
-
break;
|
|
324
|
-
case 'expression-statement':
|
|
325
|
-
result = await this.executeCall(node);
|
|
326
|
-
break;
|
|
327
|
-
default:
|
|
328
|
-
result = {
|
|
329
|
-
success: false,
|
|
330
|
-
error: `Unknown node type: ${node.type}`,
|
|
331
|
-
executionTime: Date.now() - startTime,
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
result.executionTime = Date.now() - startTime;
|
|
336
|
-
this.executionHistory.push(result);
|
|
337
|
-
this.context.executionStack.pop();
|
|
338
|
-
|
|
339
|
-
return result;
|
|
340
|
-
} catch (error) {
|
|
341
|
-
const execTime = Date.now() - startTime;
|
|
342
|
-
const errorResult: ExecutionResult = {
|
|
343
|
-
success: false,
|
|
344
|
-
error: error instanceof Error ? error.message : String(error),
|
|
345
|
-
executionTime: execTime,
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
this.executionHistory.push(errorResult);
|
|
349
|
-
this.context.executionStack.pop();
|
|
350
|
-
|
|
351
|
-
return errorResult;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* Execute multiple nodes in sequence
|
|
357
|
-
*/
|
|
358
|
-
async executeProgram(nodes: ASTNode[], depth: number = 0): Promise<ExecutionResult[]> {
|
|
359
|
-
if (depth === 0) {
|
|
360
|
-
this.startTime = Date.now();
|
|
361
|
-
this.nodeCount = 0;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
if (depth > RUNTIME_SECURITY_LIMITS.maxExecutionDepth) {
|
|
365
|
-
logger.error('Max execution depth exceeded', { depth });
|
|
366
|
-
return [{
|
|
367
|
-
success: false,
|
|
368
|
-
error: `Max execution depth exceeded (${RUNTIME_SECURITY_LIMITS.maxExecutionDepth})`,
|
|
369
|
-
executionTime: 0,
|
|
370
|
-
}];
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const results: ExecutionResult[] = [];
|
|
374
|
-
|
|
375
|
-
for (const node of nodes) {
|
|
376
|
-
this.nodeCount++;
|
|
377
|
-
if (this.nodeCount > RUNTIME_SECURITY_LIMITS.maxTotalNodes) {
|
|
378
|
-
logger.error('Max total nodes exceeded', { count: this.nodeCount });
|
|
379
|
-
results.push({
|
|
380
|
-
success: false,
|
|
381
|
-
error: 'Max total nodes exceeded',
|
|
382
|
-
executionTime: Date.now() - this.startTime,
|
|
383
|
-
});
|
|
384
|
-
break;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (Date.now() - this.startTime > RUNTIME_SECURITY_LIMITS.maxExecutionTimeMs) {
|
|
388
|
-
logger.error('Execution timeout', { duration: Date.now() - this.startTime });
|
|
389
|
-
results.push({
|
|
390
|
-
success: false,
|
|
391
|
-
error: 'Execution timeout',
|
|
392
|
-
executionTime: Date.now() - this.startTime,
|
|
393
|
-
});
|
|
394
|
-
break;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const result = await this.executeNode(node);
|
|
398
|
-
results.push(result);
|
|
399
|
-
|
|
400
|
-
// Stop on error (except visualize) or return statement
|
|
401
|
-
if (!result.success && node.type !== 'visualize') {
|
|
402
|
-
break;
|
|
403
|
-
}
|
|
404
|
-
if (node.type === 'return') {
|
|
405
|
-
break;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return results;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Call a function with arguments
|
|
414
|
-
*/
|
|
415
|
-
async callFunction(name: string, args: unknown[] = []): Promise<ExecutionResult> {
|
|
416
|
-
// Check built-in functions first
|
|
417
|
-
const builtin = this.builtinFunctions.get(name);
|
|
418
|
-
if (builtin) {
|
|
419
|
-
try {
|
|
420
|
-
const result = builtin(args);
|
|
421
|
-
return {
|
|
422
|
-
success: true,
|
|
423
|
-
output: result,
|
|
424
|
-
};
|
|
425
|
-
} catch (error) {
|
|
426
|
-
return {
|
|
427
|
-
success: false,
|
|
428
|
-
error: `Built-in function ${name} failed: ${error}`,
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// Check user-defined functions
|
|
434
|
-
const func = this.context.functions.get(name);
|
|
435
|
-
if (!func) {
|
|
436
|
-
return {
|
|
437
|
-
success: false,
|
|
438
|
-
error: `Function '${name}' not found`,
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Check call stack depth
|
|
443
|
-
if (this.callStack.length >= RUNTIME_SECURITY_LIMITS.maxCallStackDepth) {
|
|
444
|
-
return {
|
|
445
|
-
success: false,
|
|
446
|
-
error: `Max call stack depth exceeded (${RUNTIME_SECURITY_LIMITS.maxCallStackDepth})`,
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Create new scope
|
|
451
|
-
const parentScope = this.currentScope;
|
|
452
|
-
this.currentScope = {
|
|
453
|
-
variables: new Map(),
|
|
454
|
-
parent: parentScope,
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
// Bind parameters
|
|
458
|
-
func.parameters.forEach((param, index) => {
|
|
459
|
-
const value = index < args.length ? args[index] : param.defaultValue;
|
|
460
|
-
this.currentScope.variables.set(param.name, value);
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
// Push to call stack
|
|
464
|
-
this.callStack.push(name);
|
|
465
|
-
|
|
466
|
-
// Execute function body
|
|
467
|
-
let returnValue: unknown = undefined;
|
|
468
|
-
try {
|
|
469
|
-
const results = await this.executeProgram(func.body, this.callStack.length);
|
|
470
|
-
const lastResult = results[results.length - 1];
|
|
471
|
-
|
|
472
|
-
if (lastResult?.output !== undefined) {
|
|
473
|
-
returnValue = lastResult.output;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Visual effect
|
|
477
|
-
this.createExecutionEffect(name, func.position || { x: 0, y: 0, z: 0 });
|
|
478
|
-
|
|
479
|
-
return {
|
|
480
|
-
success: results.every(r => r.success),
|
|
481
|
-
output: returnValue,
|
|
482
|
-
hologram: func.hologram,
|
|
483
|
-
spatialPosition: func.position,
|
|
484
|
-
};
|
|
485
|
-
} finally {
|
|
486
|
-
// Restore scope
|
|
487
|
-
this.currentScope = parentScope;
|
|
488
|
-
this.callStack.pop();
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* Set a variable in current scope
|
|
494
|
-
*/
|
|
495
|
-
setVariable(name: string, value: unknown): void {
|
|
496
|
-
// Handle property access (e.g., "obj.prop")
|
|
497
|
-
if (name.includes('.')) {
|
|
498
|
-
const parts = name.split('.');
|
|
499
|
-
const objName = parts[0];
|
|
500
|
-
const propPath = parts.slice(1);
|
|
501
|
-
|
|
502
|
-
let obj = this.getVariable(objName);
|
|
503
|
-
if (obj === undefined || typeof obj !== 'object' || obj === null) {
|
|
504
|
-
obj = {};
|
|
505
|
-
this.currentScope.variables.set(objName, obj);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
let current = obj as Record<string, unknown>;
|
|
509
|
-
for (let i = 0; i < propPath.length - 1; i++) {
|
|
510
|
-
if (current[propPath[i]] === undefined || typeof current[propPath[i]] !== 'object') {
|
|
511
|
-
current[propPath[i]] = {};
|
|
512
|
-
}
|
|
513
|
-
current = current[propPath[i]] as Record<string, unknown>;
|
|
514
|
-
}
|
|
515
|
-
current[propPath[propPath.length - 1]] = value;
|
|
516
|
-
} else {
|
|
517
|
-
this.currentScope.variables.set(name, value);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* Get a variable from scope chain
|
|
523
|
-
*/
|
|
524
|
-
getVariable(name: string): unknown {
|
|
525
|
-
// Handle property access (e.g., "obj.prop")
|
|
526
|
-
if (name.includes('.')) {
|
|
527
|
-
const parts = name.split('.');
|
|
528
|
-
let value = this.getVariable(parts[0]);
|
|
529
|
-
|
|
530
|
-
for (let i = 1; i < parts.length && value !== undefined; i++) {
|
|
531
|
-
if (typeof value === 'object' && value !== null) {
|
|
532
|
-
value = (value as Record<string, unknown>)[parts[i]];
|
|
533
|
-
} else {
|
|
534
|
-
return undefined;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
return value;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
// Walk scope chain
|
|
541
|
-
let scope: Scope | undefined = this.currentScope;
|
|
542
|
-
while (scope) {
|
|
543
|
-
if (scope.variables.has(name)) {
|
|
544
|
-
return scope.variables.get(name);
|
|
545
|
-
}
|
|
546
|
-
scope = scope.parent;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// Check context variables
|
|
550
|
-
if (this.context.variables.has(name)) {
|
|
551
|
-
return this.context.variables.get(name);
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
// Fallback to functions map (for imported functions)
|
|
555
|
-
if (this.context.functions.has(name)) {
|
|
556
|
-
return this.context.functions.get(name);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
return undefined;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* Evaluate an expression
|
|
564
|
-
*/
|
|
565
|
-
evaluateExpression(expr: string): unknown {
|
|
566
|
-
if (!expr || typeof expr !== 'string') return expr;
|
|
567
|
-
|
|
568
|
-
expr = expr.trim();
|
|
569
|
-
|
|
570
|
-
// Security check
|
|
571
|
-
const suspicious = ['eval', 'process', 'require', '__proto__', 'constructor', 'Function'];
|
|
572
|
-
if (suspicious.some(kw => expr.toLowerCase().includes(kw))) {
|
|
573
|
-
logger.warn('Suspicious expression blocked', { expr });
|
|
574
|
-
return undefined;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// String literal
|
|
578
|
-
if ((expr.startsWith('"') && expr.endsWith('"')) || (expr.startsWith("'") && expr.endsWith("'"))) {
|
|
579
|
-
return expr.slice(1, -1);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Number literal
|
|
583
|
-
if (/^-?\d+(\.\d+)?$/.test(expr)) {
|
|
584
|
-
return parseFloat(expr);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// Boolean literal
|
|
588
|
-
if (expr === 'true') return true;
|
|
589
|
-
if (expr === 'false') return false;
|
|
590
|
-
if (expr === 'null') return null;
|
|
591
|
-
if (expr === 'undefined') return undefined;
|
|
592
|
-
|
|
593
|
-
// Array literal [a, b, c]
|
|
594
|
-
if (expr.startsWith('[') && expr.endsWith(']')) {
|
|
595
|
-
const inner = expr.slice(1, -1);
|
|
596
|
-
if (!inner.trim()) return [];
|
|
597
|
-
const elements = this.splitByComma(inner);
|
|
598
|
-
return elements.map(e => this.evaluateExpression(e.trim()));
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Object literal {a: 1, b: 2}
|
|
602
|
-
if (expr.startsWith('{') && expr.endsWith('}')) {
|
|
603
|
-
const inner = expr.slice(1, -1);
|
|
604
|
-
if (!inner.trim()) return {};
|
|
605
|
-
const pairs = this.splitByComma(inner);
|
|
606
|
-
const obj: Record<string, unknown> = {};
|
|
607
|
-
for (const pair of pairs) {
|
|
608
|
-
const colonIndex = pair.indexOf(':');
|
|
609
|
-
if (colonIndex > 0) {
|
|
610
|
-
const key = pair.slice(0, colonIndex).trim();
|
|
611
|
-
const value = pair.slice(colonIndex + 1).trim();
|
|
612
|
-
obj[key] = this.evaluateExpression(value);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
return obj;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
// Function call: name(args)
|
|
619
|
-
const funcMatch = expr.match(/^(\w+)\s*\((.*)?\)$/);
|
|
620
|
-
if (funcMatch) {
|
|
621
|
-
const [, funcName, argsStr] = funcMatch;
|
|
622
|
-
const args = argsStr ? this.splitByComma(argsStr).map(a => this.evaluateExpression(a.trim())) : [];
|
|
623
|
-
|
|
624
|
-
// Check builtins
|
|
625
|
-
const builtin = this.builtinFunctions.get(funcName);
|
|
626
|
-
if (builtin) {
|
|
627
|
-
return builtin(args);
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// Check user functions (but don't execute - just reference)
|
|
631
|
-
if (this.context.functions.has(funcName)) {
|
|
632
|
-
// For async execution, return a promise marker
|
|
633
|
-
return { __holoCall: funcName, args };
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
return undefined;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
// Binary operations: a + b, a - b, etc.
|
|
640
|
-
const binaryOps = [
|
|
641
|
-
{ pattern: /(.+)\s*\+\s*(.+)/, op: (a: unknown, b: unknown) => (typeof a === 'string' || typeof b === 'string') ? String(a) + String(b) : Number(a) + Number(b) },
|
|
642
|
-
{ pattern: /(.+)\s*-\s*(.+)/, op: (a: unknown, b: unknown) => Number(a) - Number(b) },
|
|
643
|
-
{ pattern: /(.+)\s*\*\s*(.+)/, op: (a: unknown, b: unknown) => Number(a) * Number(b) },
|
|
644
|
-
{ pattern: /(.+)\s*\/\s*(.+)/, op: (a: unknown, b: unknown) => Number(b) !== 0 ? Number(a) / Number(b) : 0 },
|
|
645
|
-
{ pattern: /(.+)\s*%\s*(.+)/, op: (a: unknown, b: unknown) => Number(a) % Number(b) },
|
|
646
|
-
];
|
|
647
|
-
|
|
648
|
-
for (const { pattern, op } of binaryOps) {
|
|
649
|
-
const match = expr.match(pattern);
|
|
650
|
-
if (match) {
|
|
651
|
-
const left = this.evaluateExpression(match[1]);
|
|
652
|
-
const right = this.evaluateExpression(match[2]);
|
|
653
|
-
return op(left, right);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
// Variable reference
|
|
658
|
-
return this.getVariable(expr);
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Split string by comma, respecting nesting
|
|
663
|
-
*/
|
|
664
|
-
private splitByComma(str: string): string[] {
|
|
665
|
-
const parts: string[] = [];
|
|
666
|
-
let current = '';
|
|
667
|
-
let depth = 0;
|
|
668
|
-
let inString = false;
|
|
669
|
-
let stringChar = '';
|
|
670
|
-
|
|
671
|
-
for (let i = 0; i < str.length; i++) {
|
|
672
|
-
const char = str[i];
|
|
673
|
-
|
|
674
|
-
if (!inString && (char === '"' || char === "'")) {
|
|
675
|
-
inString = true;
|
|
676
|
-
stringChar = char;
|
|
677
|
-
} else if (inString && char === stringChar && str[i - 1] !== '\\') {
|
|
678
|
-
inString = false;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
if (!inString) {
|
|
682
|
-
if (char === '(' || char === '[' || char === '{') depth++;
|
|
683
|
-
if (char === ')' || char === ']' || char === '}') depth--;
|
|
684
|
-
|
|
685
|
-
if (char === ',' && depth === 0) {
|
|
686
|
-
parts.push(current.trim());
|
|
687
|
-
current = '';
|
|
688
|
-
continue;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
current += char;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
if (current.trim()) {
|
|
696
|
-
parts.push(current.trim());
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
return parts;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
// ============================================================================
|
|
703
|
-
// Node Executors
|
|
704
|
-
// ============================================================================
|
|
705
|
-
|
|
706
|
-
private async executeOrb(node: OrbNode): Promise<ExecutionResult> {
|
|
707
|
-
if (node.position) {
|
|
708
|
-
this.context.spatialMemory.set(node.name, node.position);
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
// Create orb object with reactive properties
|
|
712
|
-
const orbData = {
|
|
713
|
-
__type: 'orb',
|
|
714
|
-
name: node.name,
|
|
715
|
-
properties: { ...node.properties },
|
|
716
|
-
position: node.position || { x: 0, y: 0, z: 0 },
|
|
717
|
-
hologram: node.hologram,
|
|
718
|
-
created: Date.now(),
|
|
719
|
-
// Methods bound to this orb
|
|
720
|
-
show: () => this.builtinFunctions.get('show')!([node.name]),
|
|
721
|
-
hide: () => this.builtinFunctions.get('hide')!([node.name]),
|
|
722
|
-
pulse: (opts?: Record<string, unknown>) => this.builtinFunctions.get('pulse')!([node.name, opts]),
|
|
723
|
-
};
|
|
724
|
-
|
|
725
|
-
this.context.variables.set(node.name, orbData);
|
|
726
|
-
|
|
727
|
-
if (node.hologram) {
|
|
728
|
-
this.context.hologramState.set(node.name, node.hologram);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
this.createParticleEffect(`${node.name}_creation`, node.position || { x: 0, y: 0, z: 0 }, '#00ffff', 20);
|
|
732
|
-
|
|
733
|
-
logger.info('Orb created', { name: node.name, properties: Object.keys(node.properties) });
|
|
734
|
-
|
|
735
|
-
return {
|
|
736
|
-
success: true,
|
|
737
|
-
output: orbData,
|
|
738
|
-
hologram: node.hologram,
|
|
739
|
-
spatialPosition: node.position,
|
|
740
|
-
};
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
private async executeFunction(node: MethodNode): Promise<ExecutionResult> {
|
|
744
|
-
this.context.functions.set(node.name, node);
|
|
745
|
-
|
|
746
|
-
const hologram: HologramProperties = {
|
|
747
|
-
shape: 'cube',
|
|
748
|
-
color: '#ff6b35',
|
|
749
|
-
size: 1.5,
|
|
750
|
-
glow: true,
|
|
751
|
-
interactive: true,
|
|
752
|
-
...node.hologram,
|
|
753
|
-
};
|
|
754
|
-
|
|
755
|
-
this.context.hologramState.set(node.name, hologram);
|
|
756
|
-
|
|
757
|
-
logger.info('Function defined', { name: node.name, params: node.parameters.map(p => p.name) });
|
|
758
|
-
|
|
759
|
-
return {
|
|
760
|
-
success: true,
|
|
761
|
-
output: `Function '${node.name}' defined with ${node.parameters.length} parameter(s)`,
|
|
762
|
-
hologram,
|
|
763
|
-
spatialPosition: node.position,
|
|
764
|
-
};
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
private async executeConnection(node: ConnectionNode): Promise<ExecutionResult> {
|
|
768
|
-
this.context.connections.push(node);
|
|
769
|
-
|
|
770
|
-
const fromPos = this.context.spatialMemory.get(node.from);
|
|
771
|
-
const toPos = this.context.spatialMemory.get(node.to);
|
|
772
|
-
|
|
773
|
-
if (fromPos && toPos) {
|
|
774
|
-
this.createConnectionStream(node.from, node.to, fromPos, toPos, node.dataType);
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
// Set up reactive binding if bidirectional
|
|
778
|
-
if (node.bidirectional) {
|
|
779
|
-
// When 'from' changes, update 'to'
|
|
780
|
-
this.on(`${node.from}.changed`, async (data) => {
|
|
781
|
-
this.setVariable(node.to, data);
|
|
782
|
-
this.emit(`${node.to}.changed`, data);
|
|
783
|
-
});
|
|
784
|
-
// When 'to' changes, update 'from'
|
|
785
|
-
this.on(`${node.to}.changed`, async (data) => {
|
|
786
|
-
this.setVariable(node.from, data);
|
|
787
|
-
this.emit(`${node.from}.changed`, data);
|
|
788
|
-
});
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
logger.info('Connection created', { from: node.from, to: node.to, dataType: node.dataType });
|
|
792
|
-
|
|
793
|
-
return {
|
|
794
|
-
success: true,
|
|
795
|
-
output: `Connected '${node.from}' to '${node.to}' (${node.dataType})`,
|
|
796
|
-
hologram: {
|
|
797
|
-
shape: 'cylinder',
|
|
798
|
-
color: this.getDataTypeColor(node.dataType),
|
|
799
|
-
size: 0.1,
|
|
800
|
-
glow: true,
|
|
801
|
-
interactive: false,
|
|
802
|
-
},
|
|
803
|
-
};
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
private async executeGate(node: GateNode): Promise<ExecutionResult> {
|
|
807
|
-
try {
|
|
808
|
-
const condition = this.evaluateCondition(node.condition);
|
|
809
|
-
const path = condition ? node.truePath : node.falsePath;
|
|
810
|
-
|
|
811
|
-
logger.info('Gate evaluation', { condition: node.condition, result: condition });
|
|
812
|
-
|
|
813
|
-
if (path.length > 0) {
|
|
814
|
-
await this.executeProgram(path, this.callStack.length + 1);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
return {
|
|
818
|
-
success: true,
|
|
819
|
-
output: `Gate: took ${condition ? 'true' : 'false'} path`,
|
|
820
|
-
hologram: {
|
|
821
|
-
shape: 'pyramid',
|
|
822
|
-
color: condition ? '#00ff00' : '#ff0000',
|
|
823
|
-
size: 1,
|
|
824
|
-
glow: true,
|
|
825
|
-
interactive: true,
|
|
826
|
-
},
|
|
827
|
-
};
|
|
828
|
-
} catch (error) {
|
|
829
|
-
return {
|
|
830
|
-
success: false,
|
|
831
|
-
error: `Gate execution failed: ${error}`,
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
private async executeStream(node: StreamNode): Promise<ExecutionResult> {
|
|
837
|
-
let data = this.getVariable(node.source);
|
|
838
|
-
|
|
839
|
-
logger.info('Stream processing', { name: node.name, source: node.source, transforms: node.transformations.length });
|
|
840
|
-
|
|
841
|
-
for (const transform of node.transformations) {
|
|
842
|
-
data = await this.applyTransformation(data, transform);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
this.setVariable(`${node.name}_result`, data);
|
|
846
|
-
this.createFlowingStream(node.name, node.position || { x: 0, y: 0, z: 0 }, data);
|
|
847
|
-
|
|
848
|
-
return {
|
|
849
|
-
success: true,
|
|
850
|
-
output: `Stream '${node.name}' processed ${Array.isArray(data) ? data.length : 1} item(s)`,
|
|
851
|
-
hologram: node.hologram,
|
|
852
|
-
spatialPosition: node.position,
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
private async executeCall(node: ASTNode & { target?: string; args?: unknown[] }): Promise<ExecutionResult> {
|
|
857
|
-
const funcName = node.target || '';
|
|
858
|
-
const args = node.args || [];
|
|
859
|
-
|
|
860
|
-
return this.callFunction(funcName, args);
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
private async executeDebug(node: ASTNode & { target?: string }): Promise<ExecutionResult> {
|
|
864
|
-
const debugInfo = {
|
|
865
|
-
variables: Object.fromEntries(this.currentScope.variables),
|
|
866
|
-
contextVariables: Object.fromEntries(this.context.variables),
|
|
867
|
-
functions: Array.from(this.context.functions.keys()),
|
|
868
|
-
connections: this.context.connections.length,
|
|
869
|
-
callStack: [...this.callStack],
|
|
870
|
-
uiElements: Array.from(this.uiElements.keys()),
|
|
871
|
-
animations: Array.from(this.animations.keys()),
|
|
872
|
-
executionHistory: this.executionHistory.slice(-10),
|
|
873
|
-
};
|
|
874
|
-
|
|
875
|
-
const debugOrb: HologramProperties = {
|
|
876
|
-
shape: 'pyramid',
|
|
877
|
-
color: '#ff1493',
|
|
878
|
-
size: 0.8,
|
|
879
|
-
glow: true,
|
|
880
|
-
interactive: true,
|
|
881
|
-
};
|
|
882
|
-
|
|
883
|
-
this.context.hologramState.set(`debug_${node.target || 'program'}`, debugOrb);
|
|
884
|
-
|
|
885
|
-
logger.info('Debug info', debugInfo);
|
|
886
|
-
|
|
887
|
-
return {
|
|
888
|
-
success: true,
|
|
889
|
-
output: debugInfo,
|
|
890
|
-
hologram: debugOrb,
|
|
891
|
-
};
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
private async executeVisualize(node: ASTNode & { target?: string }): Promise<ExecutionResult> {
|
|
895
|
-
const target = node.target || '';
|
|
896
|
-
const data = this.getVariable(target);
|
|
897
|
-
|
|
898
|
-
if (data === undefined) {
|
|
899
|
-
return {
|
|
900
|
-
success: false,
|
|
901
|
-
error: `No data found for '${target}'`,
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
const visHologram: HologramProperties = {
|
|
906
|
-
shape: 'cylinder',
|
|
907
|
-
color: '#32cd32',
|
|
908
|
-
size: 1.5,
|
|
909
|
-
glow: true,
|
|
910
|
-
interactive: true,
|
|
911
|
-
};
|
|
912
|
-
|
|
913
|
-
this.createDataVisualization(target, data, node.position || { x: 0, y: 0, z: 0 });
|
|
914
|
-
|
|
915
|
-
return {
|
|
916
|
-
success: true,
|
|
917
|
-
output: { visualizing: target, data },
|
|
918
|
-
hologram: visHologram,
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
private async executeUIElement(node: UI2DNode): Promise<ExecutionResult> {
|
|
923
|
-
const element: UIElementState = {
|
|
924
|
-
type: node.elementType,
|
|
925
|
-
name: node.name,
|
|
926
|
-
properties: { ...node.properties },
|
|
927
|
-
visible: true,
|
|
928
|
-
enabled: true,
|
|
929
|
-
};
|
|
930
|
-
|
|
931
|
-
// Set initial value based on element type
|
|
932
|
-
if (node.elementType === 'textinput') {
|
|
933
|
-
element.value = node.properties.value || '';
|
|
934
|
-
} else if (node.elementType === 'slider') {
|
|
935
|
-
element.value = node.properties.value || node.properties.min || 0;
|
|
936
|
-
} else if (node.elementType === 'toggle') {
|
|
937
|
-
element.value = node.properties.checked || false;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
this.uiElements.set(node.name, element);
|
|
941
|
-
|
|
942
|
-
// Register event handlers
|
|
943
|
-
if (node.events) {
|
|
944
|
-
for (const [eventName, handlerName] of Object.entries(node.events)) {
|
|
945
|
-
this.on(`${node.name}.${eventName}`, async () => {
|
|
946
|
-
await this.callFunction(handlerName);
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
logger.info('UI element created', { type: node.elementType, name: node.name });
|
|
952
|
-
|
|
953
|
-
return {
|
|
954
|
-
success: true,
|
|
955
|
-
output: element,
|
|
956
|
-
};
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
/**
|
|
960
|
-
* Execute generic voice commands
|
|
961
|
-
* Handles commands like: show, hide, animate, pulse, create
|
|
962
|
-
*/
|
|
963
|
-
private async executeGeneric(_node: ASTNode): Promise<ExecutionResult> {
|
|
964
|
-
const genericNode = _node as any;
|
|
965
|
-
const command = String(genericNode.command || '').trim().toLowerCase();
|
|
966
|
-
const tokens = command.split(/\s+/);
|
|
967
|
-
const action = tokens[0];
|
|
968
|
-
const target = tokens[1];
|
|
969
|
-
|
|
970
|
-
logger.info('Executing generic command', { command, action, target });
|
|
971
|
-
|
|
972
|
-
try {
|
|
973
|
-
let result: any;
|
|
974
|
-
|
|
975
|
-
switch (action) {
|
|
976
|
-
case 'show':
|
|
977
|
-
result = await this.executeShowCommand(target, genericNode);
|
|
978
|
-
break;
|
|
979
|
-
case 'hide':
|
|
980
|
-
result = await this.executeHideCommand(target, genericNode);
|
|
981
|
-
break;
|
|
982
|
-
case 'create':
|
|
983
|
-
case 'summon':
|
|
984
|
-
result = await this.executeCreateCommand(tokens.slice(1), genericNode);
|
|
985
|
-
break;
|
|
986
|
-
case 'animate':
|
|
987
|
-
result = await this.executeAnimateCommand(target, tokens.slice(2), genericNode);
|
|
988
|
-
break;
|
|
989
|
-
case 'pulse':
|
|
990
|
-
result = await this.executePulseCommand(target, tokens.slice(2), genericNode);
|
|
991
|
-
break;
|
|
992
|
-
case 'move':
|
|
993
|
-
result = await this.executeMoveCommand(target, tokens.slice(2), genericNode);
|
|
994
|
-
break;
|
|
995
|
-
case 'delete':
|
|
996
|
-
case 'remove':
|
|
997
|
-
result = await this.executeDeleteCommand(target, genericNode);
|
|
998
|
-
break;
|
|
999
|
-
default:
|
|
1000
|
-
// Default: create visual representation of the generic command
|
|
1001
|
-
logger.warn('Unknown voice command action', { action, command });
|
|
1002
|
-
result = {
|
|
1003
|
-
executed: false,
|
|
1004
|
-
message: `Unknown command: ${action}`,
|
|
1005
|
-
};
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
return {
|
|
1009
|
-
success: true,
|
|
1010
|
-
output: result,
|
|
1011
|
-
};
|
|
1012
|
-
} catch (error) {
|
|
1013
|
-
return {
|
|
1014
|
-
success: false,
|
|
1015
|
-
error: `Generic command execution failed: ${String(error)}`,
|
|
1016
|
-
};
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
/**
|
|
1021
|
-
* Execute 'show' command
|
|
1022
|
-
*/
|
|
1023
|
-
private async executeShowCommand(target: string, _node: any): Promise<any> {
|
|
1024
|
-
// Create or show orb for this target
|
|
1025
|
-
const hologram = _node.hologram || {
|
|
1026
|
-
shape: 'orb',
|
|
1027
|
-
color: '#00ffff',
|
|
1028
|
-
size: 0.8,
|
|
1029
|
-
glow: true,
|
|
1030
|
-
interactive: true,
|
|
1031
|
-
};
|
|
1032
|
-
|
|
1033
|
-
const position = _node.position || { x: 0, y: 0, z: 0 };
|
|
1034
|
-
this.context.spatialMemory.set(target, position);
|
|
1035
|
-
this.createParticleEffect(`${target}_show`, position, hologram.color, 15);
|
|
1036
|
-
|
|
1037
|
-
logger.info('Show command executed', { target, position });
|
|
1038
|
-
|
|
1039
|
-
return {
|
|
1040
|
-
showed: target,
|
|
1041
|
-
hologram,
|
|
1042
|
-
position,
|
|
1043
|
-
};
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
/**
|
|
1047
|
-
* Execute 'hide' command
|
|
1048
|
-
*/
|
|
1049
|
-
private async executeHideCommand(target: string, _node: any): Promise<any> {
|
|
1050
|
-
const position = this.context.spatialMemory.get(target) || { x: 0, y: 0, z: 0 };
|
|
1051
|
-
this.createParticleEffect(`${target}_hide`, position, '#ff0000', 10);
|
|
1052
|
-
|
|
1053
|
-
logger.info('Hide command executed', { target });
|
|
1054
|
-
|
|
1055
|
-
return {
|
|
1056
|
-
hidden: target,
|
|
1057
|
-
};
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
/**
|
|
1061
|
-
* Execute 'create' command
|
|
1062
|
-
*/
|
|
1063
|
-
private async executeCreateCommand(tokens: string[], _node: any): Promise<any> {
|
|
1064
|
-
if (tokens.length < 2) {
|
|
1065
|
-
return { error: 'Create command requires shape and name' };
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
const shape = tokens[0];
|
|
1069
|
-
const name = tokens[1];
|
|
1070
|
-
const position = _node.position || { x: 0, y: 0, z: 0 };
|
|
1071
|
-
|
|
1072
|
-
const hologram: HologramProperties = {
|
|
1073
|
-
shape: shape as HologramShape,
|
|
1074
|
-
color: _node.hologram?.color || '#00ffff',
|
|
1075
|
-
size: _node.hologram?.size || 1,
|
|
1076
|
-
glow: _node.hologram?.glow !== false,
|
|
1077
|
-
interactive: _node.hologram?.interactive !== false,
|
|
1078
|
-
};
|
|
1079
|
-
|
|
1080
|
-
this.context.spatialMemory.set(name, position);
|
|
1081
|
-
this.createParticleEffect(`${name}_create`, position, hologram.color, 20);
|
|
1082
|
-
|
|
1083
|
-
logger.info('Create command executed', { shape, name, position });
|
|
1084
|
-
|
|
1085
|
-
return {
|
|
1086
|
-
created: name,
|
|
1087
|
-
shape,
|
|
1088
|
-
hologram,
|
|
1089
|
-
position,
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
/**
|
|
1094
|
-
* Execute 'animate' command
|
|
1095
|
-
*/
|
|
1096
|
-
private async executeAnimateCommand(target: string, tokens: string[], _node: any): Promise<any> {
|
|
1097
|
-
const property = tokens[0] || 'position.y';
|
|
1098
|
-
const duration = parseInt(tokens[1] || '1000', 10);
|
|
1099
|
-
|
|
1100
|
-
const animation: Animation = {
|
|
1101
|
-
target,
|
|
1102
|
-
property,
|
|
1103
|
-
from: 0,
|
|
1104
|
-
to: 1,
|
|
1105
|
-
duration,
|
|
1106
|
-
startTime: Date.now(),
|
|
1107
|
-
easing: 'ease-in-out',
|
|
1108
|
-
};
|
|
1109
|
-
|
|
1110
|
-
this.animations.set(`${target}_${property}`, animation);
|
|
1111
|
-
|
|
1112
|
-
logger.info('Animate command executed', { target, property, duration });
|
|
1113
|
-
|
|
1114
|
-
return {
|
|
1115
|
-
animating: target,
|
|
1116
|
-
animation,
|
|
1117
|
-
};
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
/**
|
|
1121
|
-
* Execute 'pulse' command
|
|
1122
|
-
*/
|
|
1123
|
-
private async executePulseCommand(target: string, tokens: string[], _node: any): Promise<any> {
|
|
1124
|
-
const duration = parseInt(tokens[0] || '500', 10);
|
|
1125
|
-
const position = this.context.spatialMemory.get(target) || { x: 0, y: 0, z: 0 };
|
|
1126
|
-
|
|
1127
|
-
// Create pulsing particle effect
|
|
1128
|
-
this.createParticleEffect(`${target}_pulse`, position, '#ffff00', 30);
|
|
1129
|
-
|
|
1130
|
-
// Create animation for scale
|
|
1131
|
-
const animation: Animation = {
|
|
1132
|
-
target,
|
|
1133
|
-
property: 'scale',
|
|
1134
|
-
from: 1,
|
|
1135
|
-
to: 1.5,
|
|
1136
|
-
duration,
|
|
1137
|
-
startTime: Date.now(),
|
|
1138
|
-
easing: 'sine',
|
|
1139
|
-
yoyo: true,
|
|
1140
|
-
loop: true,
|
|
1141
|
-
};
|
|
1142
|
-
|
|
1143
|
-
this.animations.set(`${target}_pulse`, animation);
|
|
1144
|
-
|
|
1145
|
-
logger.info('Pulse command executed', { target, duration });
|
|
1146
|
-
|
|
1147
|
-
return {
|
|
1148
|
-
pulsing: target,
|
|
1149
|
-
duration,
|
|
1150
|
-
};
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
/**
|
|
1154
|
-
* Execute 'move' command
|
|
1155
|
-
*/
|
|
1156
|
-
private async executeMoveCommand(target: string, tokens: string[], _node: any): Promise<any> {
|
|
1157
|
-
const x = parseFloat(tokens[0] || '0');
|
|
1158
|
-
const y = parseFloat(tokens[1] || '0');
|
|
1159
|
-
const z = parseFloat(tokens[2] || '0');
|
|
1160
|
-
const position: SpatialPosition = { x, y, z };
|
|
1161
|
-
|
|
1162
|
-
const current = this.context.spatialMemory.get(target);
|
|
1163
|
-
if (current) {
|
|
1164
|
-
this.context.spatialMemory.set(target, position);
|
|
1165
|
-
this.createConnectionStream(target, `${target}_move`, current, position, 'movement');
|
|
1166
|
-
} else {
|
|
1167
|
-
this.context.spatialMemory.set(target, position);
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
logger.info('Move command executed', { target, position });
|
|
1171
|
-
|
|
1172
|
-
return {
|
|
1173
|
-
moved: target,
|
|
1174
|
-
to: position,
|
|
1175
|
-
};
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
/**
|
|
1179
|
-
* Execute 'delete' command
|
|
1180
|
-
*/
|
|
1181
|
-
private async executeDeleteCommand(target: string, _node: any): Promise<any> {
|
|
1182
|
-
const position = this.context.spatialMemory.get(target);
|
|
1183
|
-
if (position) {
|
|
1184
|
-
this.createParticleEffect(`${target}_delete`, position, '#ff0000', 15);
|
|
1185
|
-
this.context.spatialMemory.delete(target);
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
logger.info('Delete command executed', { target });
|
|
1189
|
-
|
|
1190
|
-
return {
|
|
1191
|
-
deleted: target,
|
|
1192
|
-
};
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
private async executeStructure(node: ASTNode): Promise<ExecutionResult> {
|
|
1196
|
-
// Handle nexus, building, and other structural elements
|
|
1197
|
-
const hologram: HologramProperties = node.hologram || {
|
|
1198
|
-
shape: node.type === 'nexus' ? 'sphere' : 'cube',
|
|
1199
|
-
color: node.type === 'nexus' ? '#9b59b6' : '#e74c3c',
|
|
1200
|
-
size: node.type === 'nexus' ? 3 : 4,
|
|
1201
|
-
glow: true,
|
|
1202
|
-
interactive: true,
|
|
1203
|
-
};
|
|
1204
|
-
|
|
1205
|
-
return {
|
|
1206
|
-
success: true,
|
|
1207
|
-
output: { type: node.type, created: true },
|
|
1208
|
-
hologram,
|
|
1209
|
-
spatialPosition: node.position,
|
|
1210
|
-
};
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
private async executeAssignment(node: ASTNode & { name: string; value: unknown }): Promise<ExecutionResult> {
|
|
1214
|
-
const value = this.evaluateExpression(String(node.value));
|
|
1215
|
-
this.setVariable(node.name, value);
|
|
1216
|
-
|
|
1217
|
-
return {
|
|
1218
|
-
success: true,
|
|
1219
|
-
output: { assigned: node.name, value },
|
|
1220
|
-
};
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
private async executeReturn(node: ASTNode & { value: unknown }): Promise<ExecutionResult> {
|
|
1224
|
-
const value = this.evaluateExpression(String(node.value));
|
|
1225
|
-
|
|
1226
|
-
return {
|
|
1227
|
-
success: true,
|
|
1228
|
-
output: value,
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
// ============================================================================
|
|
1233
|
-
// Condition Evaluation
|
|
1234
|
-
// ============================================================================
|
|
1235
|
-
|
|
1236
|
-
private evaluateCondition(condition: string): boolean {
|
|
1237
|
-
if (!condition) return false;
|
|
1238
|
-
|
|
1239
|
-
const suspiciousKeywords = ['eval', 'process', 'require', '__proto__', 'constructor'];
|
|
1240
|
-
if (suspiciousKeywords.some(kw => condition.toLowerCase().includes(kw))) {
|
|
1241
|
-
logger.warn('Suspicious condition blocked', { condition });
|
|
1242
|
-
return false;
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
try {
|
|
1246
|
-
// Boolean literals
|
|
1247
|
-
if (condition.trim().toLowerCase() === 'true') return true;
|
|
1248
|
-
if (condition.trim().toLowerCase() === 'false') return false;
|
|
1249
|
-
|
|
1250
|
-
// Comparison operators
|
|
1251
|
-
const comparisonPatterns: Array<{ regex: RegExp; logical?: string }> = [
|
|
1252
|
-
{ regex: /^(.+?)\s*(===|!==)\s*(.+)$/ },
|
|
1253
|
-
{ regex: /^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/ },
|
|
1254
|
-
{ regex: /^(.+?)\s*(&&)\s*(.+)$/, logical: 'and' },
|
|
1255
|
-
{ regex: /^(.+?)\s*(\|\|)\s*(.+)$/, logical: 'or' },
|
|
1256
|
-
];
|
|
1257
|
-
|
|
1258
|
-
for (const { regex, logical } of comparisonPatterns) {
|
|
1259
|
-
const match = condition.match(regex);
|
|
1260
|
-
if (match) {
|
|
1261
|
-
const [, leftExpr, operator, rightExpr] = match;
|
|
1262
|
-
const left = this.evaluateExpression(leftExpr.trim());
|
|
1263
|
-
const right = this.evaluateExpression(rightExpr.trim());
|
|
1264
|
-
|
|
1265
|
-
if (logical === 'and') return Boolean(left) && Boolean(right);
|
|
1266
|
-
if (logical === 'or') return Boolean(left) || Boolean(right);
|
|
1267
|
-
|
|
1268
|
-
switch (operator) {
|
|
1269
|
-
case '===': return left === right;
|
|
1270
|
-
case '!==': return left !== right;
|
|
1271
|
-
case '==': return left == right;
|
|
1272
|
-
case '!=': return left != right;
|
|
1273
|
-
case '>=': return Number(left) >= Number(right);
|
|
1274
|
-
case '<=': return Number(left) <= Number(right);
|
|
1275
|
-
case '>': return Number(left) > Number(right);
|
|
1276
|
-
case '<': return Number(left) < Number(right);
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
// Negation
|
|
1282
|
-
if (condition.startsWith('!')) {
|
|
1283
|
-
return !this.evaluateCondition(condition.slice(1).trim());
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
// Variable truthiness
|
|
1287
|
-
const value = this.evaluateExpression(condition.trim());
|
|
1288
|
-
return Boolean(value);
|
|
1289
|
-
} catch (error) {
|
|
1290
|
-
logger.error('Condition evaluation error', { condition, error });
|
|
1291
|
-
return false;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
// ============================================================================
|
|
1296
|
-
// Transformation
|
|
1297
|
-
// ============================================================================
|
|
1298
|
-
|
|
1299
|
-
private async applyTransformation(data: unknown, transform: TransformationNode): Promise<unknown> {
|
|
1300
|
-
const params = transform.parameters || {};
|
|
1301
|
-
|
|
1302
|
-
switch (transform.operation) {
|
|
1303
|
-
case 'filter': {
|
|
1304
|
-
if (!Array.isArray(data)) return data;
|
|
1305
|
-
const predicate = params.predicate as string;
|
|
1306
|
-
if (predicate) {
|
|
1307
|
-
return data.filter(item => {
|
|
1308
|
-
this.setVariable('_item', item);
|
|
1309
|
-
return this.evaluateCondition(predicate);
|
|
1310
|
-
});
|
|
1311
|
-
}
|
|
1312
|
-
return data.filter(item => item !== null && item !== undefined);
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
|
-
case 'map': {
|
|
1316
|
-
if (!Array.isArray(data)) return data;
|
|
1317
|
-
const mapper = params.mapper as string;
|
|
1318
|
-
if (mapper) {
|
|
1319
|
-
return data.map(item => {
|
|
1320
|
-
this.setVariable('_item', item);
|
|
1321
|
-
return this.evaluateExpression(mapper);
|
|
1322
|
-
});
|
|
1323
|
-
}
|
|
1324
|
-
return data.map(item => ({ value: item, processed: true }));
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
case 'reduce': {
|
|
1328
|
-
if (!Array.isArray(data)) return data;
|
|
1329
|
-
const initial = params.initial ?? 0;
|
|
1330
|
-
const reducer = params.reducer as string;
|
|
1331
|
-
if (reducer) {
|
|
1332
|
-
return data.reduce((acc, item) => {
|
|
1333
|
-
this.setVariable('_acc', acc);
|
|
1334
|
-
this.setVariable('_item', item);
|
|
1335
|
-
return this.evaluateExpression(reducer);
|
|
1336
|
-
}, initial);
|
|
1337
|
-
}
|
|
1338
|
-
return data.reduce((acc, item) => acc + (typeof item === 'number' ? item : 0), 0);
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
case 'sort': {
|
|
1342
|
-
if (!Array.isArray(data)) return data;
|
|
1343
|
-
const key = params.key as string;
|
|
1344
|
-
const desc = params.descending as boolean;
|
|
1345
|
-
const sorted = [...data].sort((a, b) => {
|
|
1346
|
-
const aVal = key ? (a as Record<string, unknown>)[key] : a;
|
|
1347
|
-
const bVal = key ? (b as Record<string, unknown>)[key] : b;
|
|
1348
|
-
if (aVal < bVal) return desc ? 1 : -1;
|
|
1349
|
-
if (aVal > bVal) return desc ? -1 : 1;
|
|
1350
|
-
return 0;
|
|
1351
|
-
});
|
|
1352
|
-
return sorted;
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
case 'sum':
|
|
1356
|
-
return Array.isArray(data) ? data.reduce((sum, item) => sum + (typeof item === 'number' ? item : 0), 0) : data;
|
|
1357
|
-
|
|
1358
|
-
case 'count':
|
|
1359
|
-
return Array.isArray(data) ? data.length : 1;
|
|
1360
|
-
|
|
1361
|
-
case 'unique':
|
|
1362
|
-
return Array.isArray(data) ? [...new Set(data)] : data;
|
|
1363
|
-
|
|
1364
|
-
case 'flatten':
|
|
1365
|
-
return Array.isArray(data) ? data.flat() : data;
|
|
1366
|
-
|
|
1367
|
-
case 'reverse':
|
|
1368
|
-
return Array.isArray(data) ? [...data].reverse() : data;
|
|
1369
|
-
|
|
1370
|
-
case 'take': {
|
|
1371
|
-
if (!Array.isArray(data)) return data;
|
|
1372
|
-
const count = Number(params.count) || 10;
|
|
1373
|
-
return data.slice(0, count);
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
case 'skip': {
|
|
1377
|
-
if (!Array.isArray(data)) return data;
|
|
1378
|
-
const count = Number(params.count) || 0;
|
|
1379
|
-
return data.slice(count);
|
|
1380
|
-
}
|
|
1381
|
-
|
|
1382
|
-
default:
|
|
1383
|
-
logger.warn('Unknown transformation', { operation: transform.operation });
|
|
1384
|
-
return data;
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
// ============================================================================
|
|
1389
|
-
// Event System
|
|
1390
|
-
// ============================================================================
|
|
1391
|
-
|
|
1392
|
-
/**
|
|
1393
|
-
* Register event handler
|
|
1394
|
-
*/
|
|
1395
|
-
on(event: string, handler: EventHandler): void {
|
|
1396
|
-
const handlers = this.eventHandlers.get(event) || [];
|
|
1397
|
-
handlers.push(handler);
|
|
1398
|
-
this.eventHandlers.set(event, handlers);
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
/**
|
|
1402
|
-
* Remove event handler
|
|
1403
|
-
*/
|
|
1404
|
-
off(event: string, handler?: EventHandler): void {
|
|
1405
|
-
if (!handler) {
|
|
1406
|
-
this.eventHandlers.delete(event);
|
|
1407
|
-
} else {
|
|
1408
|
-
const handlers = this.eventHandlers.get(event) || [];
|
|
1409
|
-
this.eventHandlers.set(event, handlers.filter(h => h !== handler));
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
/**
|
|
1414
|
-
* Emit event
|
|
1415
|
-
*/
|
|
1416
|
-
async emit(event: string, data?: unknown): Promise<void> {
|
|
1417
|
-
const handlers = this.eventHandlers.get(event) || [];
|
|
1418
|
-
for (const handler of handlers) {
|
|
1419
|
-
try {
|
|
1420
|
-
await handler(data);
|
|
1421
|
-
} catch (error) {
|
|
1422
|
-
logger.error('Event handler error', { event, error });
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
/**
|
|
1428
|
-
* Trigger UI event
|
|
1429
|
-
*/
|
|
1430
|
-
async triggerUIEvent(elementName: string, eventType: string, data?: unknown): Promise<void> {
|
|
1431
|
-
const element = this.uiElements.get(elementName);
|
|
1432
|
-
if (!element) {
|
|
1433
|
-
logger.warn('UI element not found', { elementName });
|
|
1434
|
-
return;
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
// Update element state based on event
|
|
1438
|
-
if (eventType === 'change' && data !== undefined) {
|
|
1439
|
-
element.value = data;
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
await this.emit(`${elementName}.${eventType}`, data);
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
// ============================================================================
|
|
1446
|
-
// Animation System
|
|
1447
|
-
// ============================================================================
|
|
1448
|
-
|
|
1449
|
-
/**
|
|
1450
|
-
* Update all animations
|
|
1451
|
-
*/
|
|
1452
|
-
updateAnimations(): void {
|
|
1453
|
-
const now = Date.now();
|
|
1454
|
-
|
|
1455
|
-
for (const [key, anim] of this.animations) {
|
|
1456
|
-
const elapsed = now - anim.startTime;
|
|
1457
|
-
let progress = Math.min(elapsed / anim.duration, 1);
|
|
1458
|
-
|
|
1459
|
-
// Apply easing
|
|
1460
|
-
progress = this.applyEasing(progress, anim.easing);
|
|
1461
|
-
|
|
1462
|
-
// Calculate current value
|
|
1463
|
-
let currentValue = anim.from + (anim.to - anim.from) * progress;
|
|
1464
|
-
|
|
1465
|
-
// Handle yoyo
|
|
1466
|
-
if (anim.yoyo && progress >= 1) {
|
|
1467
|
-
anim.startTime = now;
|
|
1468
|
-
[anim.from, anim.to] = [anim.to, anim.from];
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
// Update the property
|
|
1472
|
-
this.setVariable(`${anim.target}.${anim.property}`, currentValue);
|
|
1473
|
-
|
|
1474
|
-
// Remove completed non-looping animations
|
|
1475
|
-
if (progress >= 1 && !anim.loop && !anim.yoyo) {
|
|
1476
|
-
this.animations.delete(key);
|
|
1477
|
-
} else if (progress >= 1 && anim.loop) {
|
|
1478
|
-
anim.startTime = now;
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
private applyEasing(t: number, easing: string): number {
|
|
1484
|
-
switch (easing) {
|
|
1485
|
-
case 'easeIn':
|
|
1486
|
-
return t * t;
|
|
1487
|
-
case 'easeOut':
|
|
1488
|
-
return t * (2 - t);
|
|
1489
|
-
case 'easeInOut':
|
|
1490
|
-
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
1491
|
-
case 'easeInQuad':
|
|
1492
|
-
return t * t;
|
|
1493
|
-
case 'easeOutQuad':
|
|
1494
|
-
return t * (2 - t);
|
|
1495
|
-
case 'easeInOutQuad':
|
|
1496
|
-
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
1497
|
-
case 'linear':
|
|
1498
|
-
default:
|
|
1499
|
-
return t;
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
// ============================================================================
|
|
1504
|
-
// Particle Effects
|
|
1505
|
-
// ============================================================================
|
|
1506
|
-
|
|
1507
|
-
private createParticleEffect(name: string, position: SpatialPosition, color: string, count: number): void {
|
|
1508
|
-
const limitedCount = Math.min(count, RUNTIME_SECURITY_LIMITS.maxParticlesPerSystem);
|
|
1509
|
-
const particles: SpatialPosition[] = [];
|
|
1510
|
-
|
|
1511
|
-
for (let i = 0; i < limitedCount; i++) {
|
|
1512
|
-
particles.push({
|
|
1513
|
-
x: position.x + (Math.random() - 0.5) * 2,
|
|
1514
|
-
y: position.y + (Math.random() - 0.5) * 2,
|
|
1515
|
-
z: position.z + (Math.random() - 0.5) * 2,
|
|
1516
|
-
});
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
this.particleSystems.set(name, {
|
|
1520
|
-
particles,
|
|
1521
|
-
color,
|
|
1522
|
-
lifetime: 3000,
|
|
1523
|
-
speed: 0.01,
|
|
1524
|
-
});
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
private createConnectionStream(from: string, to: string, fromPos: SpatialPosition, toPos: SpatialPosition, dataType: string): void {
|
|
1528
|
-
const streamName = `connection_${from}_${to}`;
|
|
1529
|
-
const particles: SpatialPosition[] = [];
|
|
1530
|
-
const steps = 20;
|
|
1531
|
-
|
|
1532
|
-
for (let i = 0; i <= steps; i++) {
|
|
1533
|
-
const t = i / steps;
|
|
1534
|
-
particles.push({
|
|
1535
|
-
x: fromPos.x + (toPos.x - fromPos.x) * t,
|
|
1536
|
-
y: fromPos.y + (toPos.y - fromPos.y) * t,
|
|
1537
|
-
z: fromPos.z + (toPos.z - fromPos.z) * t,
|
|
1538
|
-
});
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
this.particleSystems.set(streamName, {
|
|
1542
|
-
particles,
|
|
1543
|
-
color: this.getDataTypeColor(dataType),
|
|
1544
|
-
lifetime: 5000,
|
|
1545
|
-
speed: 0.02,
|
|
1546
|
-
});
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
private createFlowingStream(name: string, position: SpatialPosition, data: unknown): void {
|
|
1550
|
-
const count = Array.isArray(data) ? Math.min(data.length, 50) : 10;
|
|
1551
|
-
this.createParticleEffect(`${name}_flow`, position, '#45b7d1', count);
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
private createExecutionEffect(name: string, position: SpatialPosition): void {
|
|
1555
|
-
this.createParticleEffect(`${name}_execution`, position, '#ff4500', 30);
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
private createDataVisualization(name: string, data: unknown, position: SpatialPosition): void {
|
|
1559
|
-
let count = 10;
|
|
1560
|
-
if (Array.isArray(data)) {
|
|
1561
|
-
count = Math.min(data.length, 100);
|
|
1562
|
-
} else if (typeof data === 'object' && data !== null) {
|
|
1563
|
-
count = Math.min(Object.keys(data).length * 5, 50);
|
|
1564
|
-
}
|
|
1565
|
-
this.createParticleEffect(`${name}_visualization`, position, '#32cd32', count);
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
private getDataTypeColor(dataType: string): string {
|
|
1569
|
-
const colors: Record<string, string> = {
|
|
1570
|
-
'string': '#ff6b35',
|
|
1571
|
-
'number': '#4ecdc4',
|
|
1572
|
-
'boolean': '#45b7d1',
|
|
1573
|
-
'object': '#96ceb4',
|
|
1574
|
-
'array': '#ffeaa7',
|
|
1575
|
-
'any': '#dda0dd',
|
|
1576
|
-
'move': '#ff69b4',
|
|
1577
|
-
};
|
|
1578
|
-
return colors[dataType] || '#ffffff';
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
// ============================================================================
|
|
1582
|
-
// Public API
|
|
1583
|
-
// ============================================================================
|
|
1584
|
-
|
|
1585
|
-
getParticleSystems(): Map<string, ParticleSystem> {
|
|
1586
|
-
return new Map(this.particleSystems);
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
updateParticles(deltaTime: number): void {
|
|
1590
|
-
for (const [name, system] of this.particleSystems) {
|
|
1591
|
-
system.lifetime -= deltaTime;
|
|
1592
|
-
system.particles.forEach(particle => {
|
|
1593
|
-
particle.x += (Math.random() - 0.5) * system.speed;
|
|
1594
|
-
particle.y += (Math.random() - 0.5) * system.speed;
|
|
1595
|
-
particle.z += (Math.random() - 0.5) * system.speed;
|
|
1596
|
-
});
|
|
1597
|
-
if (system.lifetime <= 0) {
|
|
1598
|
-
this.particleSystems.delete(name);
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
getContext(): RuntimeContext {
|
|
1604
|
-
return { ...this.context };
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
getUIElements(): Map<string, UIElementState> {
|
|
1608
|
-
return new Map(this.uiElements);
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
getUIElement(name: string): UIElementState | undefined {
|
|
1612
|
-
return this.uiElements.get(name);
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
getAnimations(): Map<string, Animation> {
|
|
1616
|
-
return new Map(this.animations);
|
|
1617
|
-
}
|
|
1618
|
-
|
|
1619
|
-
reset(): void {
|
|
1620
|
-
this.context = this.createEmptyContext();
|
|
1621
|
-
this.currentScope = { variables: this.context.variables };
|
|
1622
|
-
this.callStack = [];
|
|
1623
|
-
this.particleSystems.clear();
|
|
1624
|
-
this.executionHistory = [];
|
|
1625
|
-
this.eventHandlers.clear();
|
|
1626
|
-
this.animations.clear();
|
|
1627
|
-
this.uiElements.clear();
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
|
-
private createEmptyContext(): RuntimeContext {
|
|
1631
|
-
return {
|
|
1632
|
-
variables: new Map(),
|
|
1633
|
-
functions: new Map(),
|
|
1634
|
-
exports: new Map(),
|
|
1635
|
-
connections: [],
|
|
1636
|
-
spatialMemory: new Map(),
|
|
1637
|
-
hologramState: new Map(),
|
|
1638
|
-
executionStack: [],
|
|
1639
|
-
};
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
getExecutionHistory(): ExecutionResult[] {
|
|
1643
|
-
return [...this.executionHistory];
|
|
1644
|
-
}
|
|
1645
|
-
|
|
1646
|
-
getHologramStates(): Map<string, HologramProperties> {
|
|
1647
|
-
return new Map(this.context.hologramState);
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
getCallStack(): string[] {
|
|
1651
|
-
return [...this.callStack];
|
|
1652
|
-
}
|
|
1653
|
-
}
|