@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.
Files changed (137) hide show
  1. package/dist/chunk-2XXE34KS.js +344 -0
  2. package/dist/chunk-2XXE34KS.js.map +1 -0
  3. package/dist/chunk-3X2EGU7Z.cjs +52 -0
  4. package/dist/chunk-3X2EGU7Z.cjs.map +1 -0
  5. package/dist/chunk-AFFVFO4D.js +1689 -0
  6. package/dist/chunk-AFFVFO4D.js.map +1 -0
  7. package/dist/chunk-DGUM43GV.js +10 -0
  8. package/dist/chunk-DGUM43GV.js.map +1 -0
  9. package/{src/HoloScriptDebugger.ts → dist/chunk-DOY73HDH.js} +118 -257
  10. package/dist/chunk-DOY73HDH.js.map +1 -0
  11. package/dist/chunk-JEQ2X3Z6.cjs +12 -0
  12. package/dist/chunk-JEQ2X3Z6.cjs.map +1 -0
  13. package/dist/chunk-L6VLNVKP.cjs +1691 -0
  14. package/dist/chunk-L6VLNVKP.cjs.map +1 -0
  15. package/dist/chunk-MFNO57XL.cjs +347 -0
  16. package/dist/chunk-MFNO57XL.cjs.map +1 -0
  17. package/dist/chunk-R75MREOS.cjs +424 -0
  18. package/dist/chunk-R75MREOS.cjs.map +1 -0
  19. package/dist/chunk-SATNCODL.js +45 -0
  20. package/dist/chunk-SATNCODL.js.map +1 -0
  21. package/dist/chunk-T57ZL7KR.cjs +1281 -0
  22. package/dist/chunk-T57ZL7KR.cjs.map +1 -0
  23. package/dist/chunk-U72GEJZT.js +1279 -0
  24. package/dist/chunk-U72GEJZT.js.map +1 -0
  25. package/dist/debugger.cjs +20 -0
  26. package/dist/debugger.cjs.map +1 -0
  27. package/dist/debugger.d.cts +171 -0
  28. package/dist/debugger.d.ts +171 -0
  29. package/dist/debugger.js +7 -0
  30. package/dist/debugger.js.map +1 -0
  31. package/dist/index.cjs +6803 -0
  32. package/dist/index.cjs.map +1 -0
  33. package/dist/index.d.cts +4093 -0
  34. package/dist/index.d.ts +4093 -0
  35. package/dist/index.js +6715 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/parser.cjs +14 -0
  38. package/dist/parser.cjs.map +1 -0
  39. package/dist/parser.d.cts +172 -0
  40. package/dist/parser.d.ts +172 -0
  41. package/dist/parser.js +5 -0
  42. package/dist/parser.js.map +1 -0
  43. package/dist/runtime.cjs +14 -0
  44. package/dist/runtime.cjs.map +1 -0
  45. package/dist/runtime.d.cts +200 -0
  46. package/dist/runtime.d.ts +200 -0
  47. package/dist/runtime.js +5 -0
  48. package/dist/runtime.js.map +1 -0
  49. package/dist/type-checker.cjs +17 -0
  50. package/dist/type-checker.cjs.map +1 -0
  51. package/dist/type-checker.d.cts +105 -0
  52. package/dist/type-checker.d.ts +105 -0
  53. package/dist/type-checker.js +4 -0
  54. package/dist/type-checker.js.map +1 -0
  55. package/dist/types-4h8cbtF_.d.cts +329 -0
  56. package/dist/types-4h8cbtF_.d.ts +329 -0
  57. package/package.json +17 -13
  58. package/src/HoloScript2DParser.js +0 -227
  59. package/src/HoloScript2DParser.ts +0 -261
  60. package/src/HoloScriptCodeParser.js +0 -1102
  61. package/src/HoloScriptCodeParser.ts +0 -1188
  62. package/src/HoloScriptDebugger.js +0 -458
  63. package/src/HoloScriptParser.js +0 -338
  64. package/src/HoloScriptParser.ts +0 -397
  65. package/src/HoloScriptPlusParser.js +0 -371
  66. package/src/HoloScriptPlusParser.ts +0 -543
  67. package/src/HoloScriptRuntime.js +0 -1399
  68. package/src/HoloScriptRuntime.test.js +0 -351
  69. package/src/HoloScriptRuntime.test.ts +0 -436
  70. package/src/HoloScriptRuntime.ts +0 -1653
  71. package/src/HoloScriptTypeChecker.js +0 -356
  72. package/src/HoloScriptTypeChecker.ts +0 -475
  73. package/src/__tests__/GraphicsServices.test.js +0 -357
  74. package/src/__tests__/GraphicsServices.test.ts +0 -427
  75. package/src/__tests__/HoloScriptPlusParser.test.js +0 -317
  76. package/src/__tests__/HoloScriptPlusParser.test.ts +0 -392
  77. package/src/__tests__/integration.test.js +0 -336
  78. package/src/__tests__/integration.test.ts +0 -416
  79. package/src/__tests__/performance.bench.js +0 -218
  80. package/src/__tests__/performance.bench.ts +0 -262
  81. package/src/__tests__/type-checker.test.js +0 -60
  82. package/src/__tests__/type-checker.test.ts +0 -73
  83. package/src/index.js +0 -217
  84. package/src/index.ts +0 -426
  85. package/src/interop/Interoperability.js +0 -413
  86. package/src/interop/Interoperability.ts +0 -494
  87. package/src/logger.js +0 -42
  88. package/src/logger.ts +0 -57
  89. package/src/parser/EnhancedParser.js +0 -205
  90. package/src/parser/EnhancedParser.ts +0 -251
  91. package/src/parser/HoloScriptPlusParser.js +0 -928
  92. package/src/parser/HoloScriptPlusParser.ts +0 -1089
  93. package/src/runtime/HoloScriptPlusRuntime.js +0 -674
  94. package/src/runtime/HoloScriptPlusRuntime.ts +0 -861
  95. package/src/runtime/PerformanceTelemetry.js +0 -323
  96. package/src/runtime/PerformanceTelemetry.ts +0 -467
  97. package/src/runtime/RuntimeOptimization.js +0 -361
  98. package/src/runtime/RuntimeOptimization.ts +0 -416
  99. package/src/services/HololandGraphicsPipelineService.js +0 -506
  100. package/src/services/HololandGraphicsPipelineService.ts +0 -662
  101. package/src/services/PlatformPerformanceOptimizer.js +0 -356
  102. package/src/services/PlatformPerformanceOptimizer.ts +0 -503
  103. package/src/state/ReactiveState.js +0 -427
  104. package/src/state/ReactiveState.ts +0 -572
  105. package/src/tools/DeveloperExperience.js +0 -376
  106. package/src/tools/DeveloperExperience.ts +0 -438
  107. package/src/traits/AIDriverTrait.js +0 -322
  108. package/src/traits/AIDriverTrait.test.js +0 -329
  109. package/src/traits/AIDriverTrait.test.ts +0 -357
  110. package/src/traits/AIDriverTrait.ts +0 -474
  111. package/src/traits/LightingTrait.js +0 -313
  112. package/src/traits/LightingTrait.test.js +0 -410
  113. package/src/traits/LightingTrait.test.ts +0 -462
  114. package/src/traits/LightingTrait.ts +0 -505
  115. package/src/traits/MaterialTrait.js +0 -194
  116. package/src/traits/MaterialTrait.test.js +0 -286
  117. package/src/traits/MaterialTrait.test.ts +0 -329
  118. package/src/traits/MaterialTrait.ts +0 -324
  119. package/src/traits/RenderingTrait.js +0 -356
  120. package/src/traits/RenderingTrait.test.js +0 -363
  121. package/src/traits/RenderingTrait.test.ts +0 -427
  122. package/src/traits/RenderingTrait.ts +0 -555
  123. package/src/traits/VRTraitSystem.js +0 -740
  124. package/src/traits/VRTraitSystem.ts +0 -1040
  125. package/src/traits/VoiceInputTrait.js +0 -284
  126. package/src/traits/VoiceInputTrait.test.js +0 -226
  127. package/src/traits/VoiceInputTrait.test.ts +0 -252
  128. package/src/traits/VoiceInputTrait.ts +0 -401
  129. package/src/types/AdvancedTypeSystem.js +0 -226
  130. package/src/types/AdvancedTypeSystem.ts +0 -494
  131. package/src/types/HoloScriptPlus.d.ts +0 -853
  132. package/src/types.js +0 -6
  133. package/src/types.ts +0 -369
  134. package/tsconfig.json +0 -23
  135. package/tsup.config.d.ts +0 -2
  136. package/tsup.config.js +0 -18
  137. package/tsup.config.ts +0 -19
@@ -1,1188 +0,0 @@
1
- /**
2
- * HoloScript Code Parser
3
- *
4
- * Parses HoloScript code strings into AST nodes that can be executed
5
- * by the HoloScriptRuntime.
6
- *
7
- * Syntax Reference:
8
- * - orb <name> { properties }
9
- * - function <name>(<params>): <return> { body }
10
- * - connect <from> to <to> [as <type>]
11
- * - gate <name> { condition, true_path, false_path }
12
- * - stream <name> from <source> { transformations }
13
- */
14
-
15
- import { logger } from './logger';
16
- import type {
17
- ASTNode,
18
- OrbNode,
19
- MethodNode,
20
- ParameterNode,
21
- ConnectionNode,
22
- GateNode,
23
- StreamNode,
24
- SpatialPosition,
25
- HologramProperties,
26
- ForLoopNode,
27
- WhileLoopNode,
28
- ForEachLoopNode,
29
- ImportNode,
30
- ExportNode,
31
- VariableDeclarationNode,
32
- } from './types';
33
-
34
- // Security configuration
35
- const CODE_SECURITY_CONFIG = {
36
- maxCodeLength: 50000,
37
- maxBlocks: 100,
38
- maxNestingDepth: 10,
39
- suspiciousKeywords: [
40
- 'process', 'require', 'eval', 'import', 'constructor',
41
- 'prototype', '__proto__', 'fs', 'child_process', 'exec', 'spawn',
42
- ],
43
- };
44
-
45
- export interface ParseResult {
46
- success: boolean;
47
- ast: ASTNode[];
48
- errors: ParseError[];
49
- warnings: string[];
50
- }
51
-
52
- export interface ParseError {
53
- line: number;
54
- column: number;
55
- message: string;
56
- }
57
-
58
- interface Token {
59
- type: 'keyword' | 'identifier' | 'number' | 'string' | 'operator' | 'punctuation' | 'newline';
60
- value: string;
61
- line: number;
62
- column: number;
63
- }
64
-
65
- export class HoloScriptCodeParser {
66
- private errors: ParseError[] = [];
67
- private warnings: string[] = [];
68
- private tokens: Token[] = [];
69
- private position: number = 0;
70
- private keywordSet: Set<string>;
71
-
72
- constructor() {
73
- // Pre-compute keyword set for O(1) lookup instead of O(n) array search
74
- this.keywordSet = new Set([
75
- 'orb', 'function', 'connect', 'to', 'as', 'gate', 'stream', 'from', 'through', 'return',
76
- 'if', 'else', 'nexus', 'building', 'pillar', 'foundation',
77
- 'for', 'while', 'forEach', 'in', 'of', 'break', 'continue',
78
- 'import', 'export', 'module', 'use',
79
- 'type', 'interface', 'extends', 'implements',
80
- 'async', 'await', 'spawn', 'parallel',
81
- 'class', 'new', 'this', 'super', 'static', 'private', 'public',
82
- 'try', 'catch', 'finally', 'throw',
83
- 'const', 'let', 'var',
84
- 'animate', 'modify', 'pulse', 'move', 'show', 'hide',
85
- ]);
86
- }
87
-
88
- /**
89
- * Parse HoloScript code string into AST
90
- */
91
- parse(code: string): ParseResult {
92
- this.errors = [];
93
- this.warnings = [];
94
- this.tokens = [];
95
- this.position = 0;
96
-
97
- // Security: Check code length
98
- if (code.length > CODE_SECURITY_CONFIG.maxCodeLength) {
99
- return {
100
- success: false,
101
- ast: [],
102
- errors: [{ line: 0, column: 0, message: `Code exceeds max length (${CODE_SECURITY_CONFIG.maxCodeLength})` }],
103
- warnings: [],
104
- };
105
- }
106
-
107
- // Security: Check for suspicious keywords
108
- for (const keyword of CODE_SECURITY_CONFIG.suspiciousKeywords) {
109
- if (code.toLowerCase().includes(keyword)) {
110
- logger.warn('Suspicious keyword detected', { keyword });
111
- return {
112
- success: false,
113
- ast: [],
114
- errors: [{ line: 0, column: 0, message: `Suspicious keyword detected: ${keyword}` }],
115
- warnings: [],
116
- };
117
- }
118
- }
119
-
120
- try {
121
- // Tokenize
122
- this.tokens = this.tokenize(code);
123
-
124
- // Parse tokens into AST
125
- const ast = this.parseProgram();
126
-
127
- return {
128
- success: this.errors.length === 0,
129
- ast,
130
- errors: this.errors,
131
- warnings: this.warnings,
132
- };
133
- } catch (error) {
134
- return {
135
- success: false,
136
- ast: [],
137
- errors: [{ line: 0, column: 0, message: String(error) }],
138
- warnings: this.warnings,
139
- };
140
- }
141
- }
142
-
143
- /**
144
- * Tokenize code into tokens
145
- */
146
- private tokenize(code: string): Token[] {
147
- const tokens: Token[] = [];
148
- let line = 1;
149
- let column = 1;
150
- let i = 0;
151
-
152
- while (i < code.length) {
153
- const char = code[i];
154
-
155
- // Skip whitespace (except newlines)
156
- if (char === ' ' || char === '\t' || char === '\r') {
157
- i++;
158
- column++;
159
- continue;
160
- }
161
-
162
- // Newline
163
- if (char === '\n') {
164
- tokens.push({ type: 'newline', value: '\n', line, column });
165
- line++;
166
- column = 1;
167
- i++;
168
- continue;
169
- }
170
-
171
- // Comments (skip)
172
- if (char === '/' && code[i + 1] === '/') {
173
- while (i < code.length && code[i] !== '\n') {
174
- i++;
175
- }
176
- continue;
177
- }
178
-
179
- // String
180
- if (char === '"' || char === "'") {
181
- const quote = char;
182
- let str = '';
183
- const startCol = column;
184
- i++;
185
- column++;
186
-
187
- while (i < code.length && code[i] !== quote) {
188
- if (code[i] === '\\' && i + 1 < code.length) {
189
- str += code[i + 1];
190
- i += 2;
191
- column += 2;
192
- } else {
193
- str += code[i];
194
- i++;
195
- column++;
196
- }
197
- }
198
-
199
- i++; // Skip closing quote
200
- column++;
201
-
202
- tokens.push({ type: 'string', value: str, line, column: startCol });
203
- continue;
204
- }
205
-
206
- // Number
207
- if (/[0-9]/.test(char) || (char === '-' && /[0-9]/.test(code[i + 1]))) {
208
- let num = '';
209
- const startCol = column;
210
-
211
- while (i < code.length && /[0-9.\-]/.test(code[i])) {
212
- num += code[i];
213
- i++;
214
- column++;
215
- }
216
-
217
- tokens.push({ type: 'number', value: num, line, column: startCol });
218
- continue;
219
- }
220
-
221
- // Identifier or keyword
222
- if (/[a-zA-Z_]/.test(char)) {
223
- let ident = '';
224
- const startCol = column;
225
-
226
- while (i < code.length && /[a-zA-Z0-9_]/.test(code[i])) {
227
- ident += code[i];
228
- i++;
229
- column++;
230
- }
231
-
232
- const isKeyword = this.keywordSet.has(ident.toLowerCase());
233
- tokens.push({
234
- type: isKeyword ? 'keyword' : 'identifier',
235
- value: ident,
236
- line,
237
- column: startCol,
238
- });
239
- continue;
240
- }
241
-
242
- // Multi-character operators (must check before single-char)
243
- const multiCharOps = ['===', '!==', '==', '!=', '>=', '<=', '&&', '||', '++', '--', '+=', '-=', '*=', '/=', '%=', '=>', '->'];
244
- let foundMultiOp = false;
245
- for (const op of multiCharOps) {
246
- if (code.substring(i, i + op.length) === op) {
247
- tokens.push({ type: 'operator', value: op, line, column });
248
- i += op.length;
249
- column += op.length;
250
- foundMultiOp = true;
251
- break;
252
- }
253
- }
254
- if (foundMultiOp) continue;
255
-
256
- // Operators and punctuation
257
- const punctuation = ['{', '}', '(', ')', '[', ']', ':', ',', '.', ';', '=', '<', '>', '+', '-', '*', '/', '%', '!', '&', '|', '?'];
258
- if (punctuation.includes(char)) {
259
- tokens.push({ type: 'punctuation', value: char, line, column });
260
- i++;
261
- column++;
262
- continue;
263
- }
264
-
265
- // Unknown character - skip
266
- i++;
267
- column++;
268
- }
269
-
270
- return tokens;
271
- }
272
-
273
- /**
274
- * Parse program (list of declarations)
275
- */
276
- private parseProgram(): ASTNode[] {
277
- const nodes: ASTNode[] = [];
278
- let blockCount = 0;
279
-
280
- while (this.position < this.tokens.length) {
281
- // Skip newlines
282
- while (this.currentToken()?.type === 'newline') {
283
- this.advance();
284
- }
285
-
286
- if (this.position >= this.tokens.length) break;
287
-
288
- // Security: limit blocks
289
- blockCount++;
290
- if (blockCount > CODE_SECURITY_CONFIG.maxBlocks) {
291
- this.errors.push({ line: 0, column: 0, message: 'Too many blocks in program' });
292
- break;
293
- }
294
-
295
- const node = this.parseDeclaration();
296
- if (node) {
297
- nodes.push(node);
298
- }
299
- }
300
-
301
- return nodes;
302
- }
303
-
304
- /**
305
- * Parse a single declaration
306
- */
307
- private parseDeclaration(): ASTNode | null {
308
- const token = this.currentToken();
309
- if (!token) return null;
310
-
311
- if (token.type === 'keyword') {
312
- switch (token.value.toLowerCase()) {
313
- case 'orb':
314
- return this.parseOrb();
315
- case 'function':
316
- return this.parseFunction();
317
- case 'connect':
318
- return this.parseConnection();
319
- case 'gate':
320
- case 'if':
321
- return this.parseGate();
322
- case 'stream':
323
- return this.parseStream();
324
- case 'nexus':
325
- return this.parseNexus();
326
- case 'building':
327
- case 'class':
328
- return this.parseBuilding();
329
- // Phase 2: Loop constructs
330
- case 'for':
331
- return this.parseForLoop();
332
- case 'while':
333
- return this.parseWhileLoop();
334
- case 'foreach':
335
- return this.parseForEachLoop();
336
- // Phase 2: Module system
337
- case 'import':
338
- return this.parseImport();
339
- case 'export':
340
- return this.parseExport();
341
- // Phase 2: Variable declarations
342
- // UI Extensions
343
- case 'ui2d':
344
- case 'card':
345
- case 'metric':
346
- case 'button':
347
- case 'row':
348
- case 'col':
349
- case 'text':
350
- return this.parseUIElement();
351
- case 'const':
352
- case 'let':
353
- case 'var':
354
- return this.parseVariableDeclaration();
355
- // DSL-first commands (Phase 54)
356
- case 'animate':
357
- return this.parseAnimate();
358
- case 'modify':
359
- return this.parseModify();
360
- default:
361
- this.advance();
362
- return null;
363
- }
364
- }
365
-
366
- // Skip unrecognized tokens
367
- this.advance();
368
- return null;
369
- }
370
-
371
- /**
372
- * Parse for loop: for (init; condition; update) { body }
373
- */
374
- private parseForLoop(): ForLoopNode | null {
375
- this.expect('keyword', 'for');
376
-
377
- if (!this.check('punctuation', '(')) {
378
- this.errors.push({ line: 0, column: 0, message: 'Expected ( after for' });
379
- return null;
380
- }
381
- this.advance();
382
-
383
- // Parse init, condition, update (simplified - collect as strings)
384
- let init = '', condition = '', update = '';
385
- let depth = 0;
386
-
387
- // Parse init (until first ;)
388
- while (this.position < this.tokens.length) {
389
- const t = this.currentToken();
390
- if (!t) break;
391
- if (t.value === ';' && depth === 0) { this.advance(); break; }
392
- if (t.value === '(') depth++;
393
- if (t.value === ')') depth--;
394
- init += t.value + ' ';
395
- this.advance();
396
- }
397
-
398
- // Parse condition (until second ;)
399
- depth = 0;
400
- while (this.position < this.tokens.length) {
401
- const t = this.currentToken();
402
- if (!t) break;
403
- if (t.value === ';' && depth === 0) { this.advance(); break; }
404
- if (t.value === '(') depth++;
405
- if (t.value === ')') depth--;
406
- condition += t.value + ' ';
407
- this.advance();
408
- }
409
-
410
- // Parse update (until ))
411
- depth = 0;
412
- while (this.position < this.tokens.length) {
413
- const t = this.currentToken();
414
- if (!t) break;
415
- if (t.value === ')' && depth === 0) { this.advance(); break; }
416
- if (t.value === '(') depth++;
417
- if (t.value === ')') depth--;
418
- update += t.value + ' ';
419
- this.advance();
420
- }
421
-
422
- // Parse body
423
- const body: ASTNode[] = [];
424
- if (this.check('punctuation', '{')) {
425
- this.advance();
426
- let braceDepth = 1;
427
- while (braceDepth > 0 && this.position < this.tokens.length) {
428
- if (this.check('punctuation', '{')) braceDepth++;
429
- if (this.check('punctuation', '}')) braceDepth--;
430
- this.advance();
431
- }
432
- }
433
-
434
- return {
435
- type: 'for-loop',
436
- init: init.trim(),
437
- condition: condition.trim(),
438
- update: update.trim(),
439
- body,
440
- position: { x: 0, y: 0, z: 0 },
441
- };
442
- }
443
-
444
- /**
445
- * Parse while loop: while (condition) { body }
446
- */
447
- private parseWhileLoop(): WhileLoopNode | null {
448
- this.expect('keyword', 'while');
449
-
450
- let condition = '';
451
- if (this.check('punctuation', '(')) {
452
- this.advance();
453
- let depth = 1;
454
- while (depth > 0 && this.position < this.tokens.length) {
455
- const t = this.currentToken();
456
- if (!t) break;
457
- if (t.value === '(') depth++;
458
- if (t.value === ')') { depth--; if (depth === 0) { this.advance(); break; } }
459
- condition += t.value + ' ';
460
- this.advance();
461
- }
462
- }
463
-
464
- // Parse body
465
- if (this.check('punctuation', '{')) {
466
- this.advance();
467
- let braceDepth = 1;
468
- while (braceDepth > 0 && this.position < this.tokens.length) {
469
- if (this.check('punctuation', '{')) braceDepth++;
470
- if (this.check('punctuation', '}')) braceDepth--;
471
- this.advance();
472
- }
473
- }
474
-
475
- return {
476
- type: 'while-loop',
477
- condition: condition.trim(),
478
- body: [],
479
- position: { x: 0, y: 0, z: 0 },
480
- };
481
- }
482
-
483
- /**
484
- * Parse forEach loop: forEach item in collection { body }
485
- */
486
- private parseForEachLoop(): ForEachLoopNode | null {
487
- this.expect('keyword', 'forEach');
488
-
489
- const variable = this.expectIdentifier();
490
- this.expect('keyword', 'in');
491
- const collection = this.expectIdentifier();
492
-
493
- // Parse body
494
- if (this.check('punctuation', '{')) {
495
- this.advance();
496
- let braceDepth = 1;
497
- while (braceDepth > 0 && this.position < this.tokens.length) {
498
- if (this.check('punctuation', '{')) braceDepth++;
499
- if (this.check('punctuation', '}')) braceDepth--;
500
- this.advance();
501
- }
502
- }
503
-
504
- return {
505
- type: 'foreach-loop',
506
- variable: variable || 'item',
507
- collection: collection || 'items',
508
- body: [],
509
- position: { x: 0, y: 0, z: 0 },
510
- };
511
- }
512
-
513
- /**
514
- * Parse import: import { x, y } from "module"
515
- */
516
- private parseImport(): ImportNode | null {
517
- this.expect('keyword', 'import');
518
-
519
- const imports: string[] = [];
520
- let modulePath = '';
521
- let defaultImport: string | undefined;
522
-
523
- // Check for default import or named imports
524
- if (this.check('punctuation', '{')) {
525
- this.advance();
526
- while (!this.check('punctuation', '}') && this.position < this.tokens.length) {
527
- const name = this.expectIdentifier();
528
- if (name) imports.push(name);
529
- if (this.check('punctuation', ',')) this.advance();
530
- }
531
- this.expect('punctuation', '}');
532
- } else {
533
- // Default import
534
- defaultImport = this.expectIdentifier() || undefined;
535
- }
536
-
537
- // from "module"
538
- if (this.check('keyword', 'from')) {
539
- this.advance();
540
- const pathToken = this.currentToken();
541
- if (pathToken?.type === 'string') {
542
- modulePath = pathToken.value;
543
- this.advance();
544
- }
545
- }
546
-
547
- return {
548
- type: 'import',
549
- imports,
550
- defaultImport,
551
- modulePath,
552
- position: { x: 0, y: 0, z: 0 },
553
- };
554
- }
555
-
556
- /**
557
- * Parse export: export { x, y } or export function/orb
558
- */
559
- private parseExport(): ExportNode | null {
560
- this.expect('keyword', 'export');
561
-
562
- // Check if exporting a declaration
563
- const next = this.currentToken();
564
- if (next?.type === 'keyword') {
565
- const declaration = this.parseDeclaration();
566
- return {
567
- type: 'export',
568
- declaration: declaration || undefined,
569
- position: { x: 0, y: 0, z: 0 },
570
- };
571
- }
572
-
573
- // Named exports
574
- const exports: string[] = [];
575
- if (this.check('punctuation', '{')) {
576
- this.advance();
577
- while (!this.check('punctuation', '}') && this.position < this.tokens.length) {
578
- const name = this.expectIdentifier();
579
- if (name) exports.push(name);
580
- if (this.check('punctuation', ',')) this.advance();
581
- }
582
- this.expect('punctuation', '}');
583
- }
584
-
585
- return {
586
- type: 'export',
587
- exports,
588
- position: { x: 0, y: 0, z: 0 },
589
- };
590
- }
591
-
592
- /**
593
- * Parse variable declaration: const/let/var name = value
594
- */
595
- private parseVariableDeclaration(): VariableDeclarationNode | null {
596
- const kindToken = this.currentToken()?.value.toLowerCase();
597
- const kind: 'const' | 'let' | 'var' = kindToken === 'let' ? 'let' : kindToken === 'var' ? 'var' : 'const';
598
- this.advance();
599
-
600
- const name = this.expectIdentifier();
601
- if (!name) return null;
602
-
603
- let dataType: string | undefined;
604
- if (this.check('punctuation', ':')) {
605
- this.advance();
606
- dataType = this.expectIdentifier() || undefined;
607
- }
608
-
609
- let value: unknown;
610
- if (this.check('punctuation', '=')) {
611
- this.advance();
612
- const valueToken = this.currentToken();
613
- if (valueToken?.type === 'string') {
614
- value = valueToken.value;
615
- this.advance();
616
- } else if (valueToken?.type === 'number') {
617
- value = parseFloat(valueToken.value);
618
- this.advance();
619
- } else if (valueToken?.type === 'identifier') {
620
- if (valueToken.value === 'true') value = true;
621
- else if (valueToken.value === 'false') value = false;
622
- else value = valueToken.value;
623
- this.advance();
624
- } else if (this.check('punctuation', '[')) {
625
- value = this.parseArray();
626
- } else if (this.check('punctuation', '{')) {
627
- value = this.parseObject();
628
- }
629
- }
630
-
631
- return {
632
- type: 'variable-declaration',
633
- kind,
634
- name,
635
- dataType,
636
- value,
637
- position: { x: 0, y: 0, z: 0 },
638
- };
639
- }
640
-
641
- /**
642
- * Parse orb declaration
643
- */
644
- private parseOrb(): OrbNode | null {
645
- this.expect('keyword', 'orb');
646
- const name = this.expectIdentifier();
647
- if (!name) return null;
648
-
649
- const properties: Record<string, unknown> = {};
650
- let position: SpatialPosition | undefined;
651
- let hologram: HologramProperties | undefined;
652
-
653
- if (this.check('punctuation', '{')) {
654
- this.advance(); // {
655
-
656
- while (!this.check('punctuation', '}') && this.position < this.tokens.length) {
657
- this.skipNewlines();
658
- if (this.check('punctuation', '}')) break;
659
-
660
- const prop = this.parseProperty();
661
- if (prop) {
662
- // Handle special properties
663
- if (prop.key === 'position' || prop.key === 'at') {
664
- position = this.parsePosition(prop.value);
665
- } else if (prop.key === 'color' || prop.key === 'glow' || prop.key === 'size') {
666
- hologram = hologram || { shape: 'orb', color: '#00ffff', size: 1, glow: true, interactive: true };
667
- if (prop.key === 'color') hologram.color = String(prop.value);
668
- if (prop.key === 'glow') hologram.glow = Boolean(prop.value);
669
- if (prop.key === 'size') hologram.size = Number(prop.value);
670
- } else {
671
- properties[prop.key] = prop.value;
672
- }
673
- }
674
-
675
- this.skipNewlines();
676
- }
677
-
678
- this.expect('punctuation', '}');
679
- }
680
-
681
- return {
682
- type: 'orb',
683
- name,
684
- position: position || { x: 0, y: 0, z: 0 },
685
- hologram: hologram || { shape: 'orb', color: '#00ffff', size: 1, glow: true, interactive: true },
686
- properties,
687
- methods: [],
688
- };
689
- }
690
-
691
- /**
692
- * Parse function declaration
693
- */
694
- private parseFunction(): MethodNode | null {
695
- this.expect('keyword', 'function');
696
- const name = this.expectIdentifier();
697
- if (!name) return null;
698
-
699
- const parameters: ParameterNode[] = [];
700
- let returnType: string | undefined;
701
-
702
- // Parse parameters
703
- if (this.check('punctuation', '(')) {
704
- this.advance(); // (
705
-
706
- while (!this.check('punctuation', ')') && this.position < this.tokens.length) {
707
- const paramName = this.expectIdentifier();
708
- if (!paramName) break;
709
-
710
- let paramType = 'any';
711
- if (this.check('punctuation', ':')) {
712
- this.advance(); // :
713
- paramType = this.expectIdentifier() || 'any';
714
- }
715
-
716
- parameters.push({
717
- type: 'parameter',
718
- name: paramName,
719
- dataType: paramType,
720
- });
721
-
722
- if (this.check('punctuation', ',')) {
723
- this.advance();
724
- }
725
- }
726
-
727
- this.expect('punctuation', ')');
728
- }
729
-
730
- // Parse return type
731
- if (this.check('punctuation', ':')) {
732
- this.advance();
733
- returnType = this.expectIdentifier() || undefined;
734
- }
735
-
736
- // Parse body
737
- const body: ASTNode[] = [];
738
- if (this.check('punctuation', '{')) {
739
- this.advance(); // {
740
- // Skip body parsing for now - just find closing brace
741
- let depth = 1;
742
- while (depth > 0 && this.position < this.tokens.length) {
743
- if (this.check('punctuation', '{')) depth++;
744
- if (this.check('punctuation', '}')) depth--;
745
- this.advance();
746
- }
747
- }
748
-
749
- return {
750
- type: 'method',
751
- name,
752
- parameters,
753
- body,
754
- returnType,
755
- position: { x: 0, y: 0, z: 0 },
756
- hologram: { shape: 'cube', color: '#ff6b35', size: 1.5, glow: true, interactive: true },
757
- };
758
- }
759
-
760
- /**
761
- * Parse connection
762
- */
763
- private parseConnection(): ConnectionNode | null {
764
- this.expect('keyword', 'connect');
765
- const from = this.expectIdentifier();
766
- if (!from) return null;
767
-
768
- this.expect('keyword', 'to');
769
- const to = this.expectIdentifier();
770
- if (!to) return null;
771
-
772
- let dataType = 'any';
773
- if (this.check('keyword', 'as')) {
774
- this.advance();
775
- const typeStr = this.currentToken();
776
- if (typeStr?.type === 'string' || typeStr?.type === 'identifier') {
777
- dataType = typeStr.value;
778
- this.advance();
779
- }
780
- }
781
-
782
- return {
783
- type: 'connection',
784
- from,
785
- to,
786
- dataType,
787
- bidirectional: false,
788
- };
789
- }
790
-
791
- /**
792
- * Parse gate (conditional)
793
- */
794
- private parseGate(): GateNode | null {
795
- this.expect('keyword', 'gate');
796
- this.expectIdentifier(); // Gate name (consumed but not currently stored)
797
-
798
- let condition = '';
799
- if (this.check('punctuation', '(')) {
800
- this.advance();
801
- // Parse condition expression
802
- while (!this.check('punctuation', ')') && this.position < this.tokens.length) {
803
- const token = this.currentToken();
804
- if (token) condition += token.value + ' ';
805
- this.advance();
806
- }
807
- this.expect('punctuation', ')');
808
- }
809
-
810
- // Parse body if present
811
- if (this.check('punctuation', '{')) {
812
- this.advance();
813
- let depth = 1;
814
- while (depth > 0 && this.position < this.tokens.length) {
815
- if (this.check('punctuation', '{')) depth++;
816
- if (this.check('punctuation', '}')) depth--;
817
- this.advance();
818
- }
819
- }
820
-
821
- return {
822
- type: 'gate',
823
- condition: condition.trim(),
824
- truePath: [],
825
- falsePath: [],
826
- position: { x: 0, y: 0, z: 0 },
827
- hologram: { shape: 'pyramid', color: '#4ecdc4', size: 1, glow: true, interactive: true },
828
- };
829
- }
830
-
831
- /**
832
- * Parse stream
833
- */
834
- private parseStream(): StreamNode | null {
835
- this.expect('keyword', 'stream');
836
- const name = this.expectIdentifier();
837
- if (!name) return null;
838
-
839
- let source = 'unknown';
840
- if (this.check('keyword', 'from')) {
841
- this.advance();
842
- source = this.expectIdentifier() || 'unknown';
843
- }
844
-
845
- // Parse body if present
846
- if (this.check('punctuation', '{')) {
847
- this.advance();
848
- let depth = 1;
849
- while (depth > 0 && this.position < this.tokens.length) {
850
- if (this.check('punctuation', '{')) depth++;
851
- if (this.check('punctuation', '}')) depth--;
852
- this.advance();
853
- }
854
- }
855
-
856
- return {
857
- type: 'stream',
858
- name,
859
- source,
860
- transformations: [],
861
- position: { x: 0, y: 0, z: 0 },
862
- hologram: { shape: 'cylinder', color: '#45b7d1', size: 2, glow: true, interactive: true },
863
- };
864
- }
865
-
866
- /**
867
- * Parse nexus (multi-agent hub)
868
- */
869
- private parseNexus(): ASTNode | null {
870
- this.expect('keyword', 'nexus');
871
- const name = this.expectIdentifier();
872
- if (!name) return null;
873
-
874
- if (this.check('punctuation', '{')) {
875
- this.advance();
876
- let depth = 1;
877
- while (depth > 0 && this.position < this.tokens.length) {
878
- if (this.check('punctuation', '{')) depth++;
879
- if (this.check('punctuation', '}')) depth--;
880
- this.advance();
881
- }
882
- }
883
-
884
- return {
885
- type: 'nexus',
886
- position: { x: 0, y: 0, z: 0 },
887
- hologram: { shape: 'sphere', color: '#9b59b6', size: 3, glow: true, interactive: true },
888
- };
889
- }
890
-
891
- /**
892
- * Parse building (class-like)
893
- */
894
- private parseBuilding(): ASTNode | null {
895
- this.expect('keyword', 'building');
896
- const name = this.expectIdentifier();
897
- if (!name) return null;
898
-
899
- if (this.check('punctuation', '{')) {
900
- this.advance();
901
- let depth = 1;
902
- while (depth > 0 && this.position < this.tokens.length) {
903
- if (this.check('punctuation', '{')) depth++;
904
- if (this.check('punctuation', '}')) depth--;
905
- this.advance();
906
- }
907
- }
908
-
909
- return {
910
- type: 'building',
911
- position: { x: 0, y: 0, z: 0 },
912
- hologram: { shape: 'cube', color: '#e74c3c', size: 4, glow: true, interactive: true },
913
- };
914
- }
915
-
916
- /**
917
- * Parse a property (key: value)
918
- */
919
- private parseProperty(): { key: string; value: unknown } | null {
920
- const key = this.expectIdentifier();
921
- if (!key) return null;
922
-
923
- if (!this.check('punctuation', ':')) {
924
- return { key, value: true }; // Flag-style property
925
- }
926
-
927
- this.advance(); // :
928
-
929
- const valueToken = this.currentToken();
930
- if (!valueToken) return null;
931
-
932
- let value: unknown;
933
- if (valueToken.type === 'string') {
934
- value = valueToken.value;
935
- this.advance();
936
- } else if (valueToken.type === 'number') {
937
- value = parseFloat(valueToken.value);
938
- this.advance();
939
- } else if (valueToken.type === 'identifier') {
940
- if (valueToken.value === 'true') value = true;
941
- else if (valueToken.value === 'false') value = false;
942
- else value = valueToken.value;
943
- this.advance();
944
- } else if (this.check('punctuation', '[')) {
945
- value = this.parseArray();
946
- } else if (this.check('punctuation', '{')) {
947
- value = this.parseObject();
948
- } else {
949
- value = valueToken.value;
950
- this.advance();
951
- }
952
-
953
- return { key, value };
954
- }
955
-
956
- /**
957
- * Parse array [...]
958
- */
959
- private parseArray(): unknown[] {
960
- const arr: unknown[] = [];
961
- this.expect('punctuation', '[');
962
-
963
- while (!this.check('punctuation', ']') && this.position < this.tokens.length) {
964
- const token = this.currentToken();
965
- if (token?.type === 'string' || token?.type === 'number' || token?.type === 'identifier') {
966
- if (token.type === 'number') {
967
- arr.push(parseFloat(token.value));
968
- } else {
969
- arr.push(token.value);
970
- }
971
- this.advance();
972
- }
973
-
974
- if (this.check('punctuation', ',')) {
975
- this.advance();
976
- }
977
- }
978
-
979
- this.expect('punctuation', ']');
980
- return arr;
981
- }
982
-
983
- /**
984
- * Parse object {...}
985
- */
986
- private parseObject(): Record<string, unknown> {
987
- const obj: Record<string, unknown> = {};
988
- this.expect('punctuation', '{');
989
-
990
- while (!this.check('punctuation', '}') && this.position < this.tokens.length) {
991
- this.skipNewlines();
992
- if (this.check('punctuation', '}')) break;
993
-
994
- const prop = this.parseProperty();
995
- if (prop) {
996
- obj[prop.key] = prop.value;
997
- }
998
-
999
- this.skipNewlines();
1000
- if (this.check('punctuation', ',')) {
1001
- this.advance();
1002
- }
1003
- }
1004
-
1005
- this.expect('punctuation', '}');
1006
- return obj;
1007
- }
1008
-
1009
- /**
1010
- * Parse position from value
1011
- */
1012
- private parsePosition(value: unknown): SpatialPosition {
1013
- if (typeof value === 'object' && value !== null) {
1014
- const v = value as Record<string, unknown>;
1015
- return {
1016
- x: Number(v.x) || 0,
1017
- y: Number(v.y) || 0,
1018
- z: Number(v.z) || 0,
1019
- };
1020
- }
1021
- return { x: 0, y: 0, z: 0 };
1022
- }
1023
-
1024
- // Helper methods
1025
-
1026
- private currentToken(): Token | undefined {
1027
- return this.tokens[this.position];
1028
- }
1029
-
1030
- private advance(): Token | undefined {
1031
- return this.tokens[this.position++];
1032
- }
1033
-
1034
- private check(type: string, value?: string): boolean {
1035
- const token = this.currentToken();
1036
- if (!token) return false;
1037
- if (token.type !== type) return false;
1038
- if (value !== undefined && token.value.toLowerCase() !== value.toLowerCase()) return false;
1039
- return true;
1040
- }
1041
-
1042
- private expect(type: string, value?: string): boolean {
1043
- if (this.check(type, value)) {
1044
- this.advance();
1045
- return true;
1046
- }
1047
- const token = this.currentToken();
1048
- this.errors.push({
1049
- line: token?.line || 0,
1050
- column: token?.column || 0,
1051
- message: `Expected ${type}${value ? ` '${value}'` : ''}, got ${token?.type || 'EOF'} '${token?.value || ''}'`,
1052
- });
1053
- return false;
1054
- }
1055
-
1056
- private expectIdentifier(): string | null {
1057
- const token = this.currentToken();
1058
- if (token?.type === 'identifier' || token?.type === 'keyword') {
1059
- this.advance();
1060
- return token.value;
1061
- }
1062
- this.errors.push({
1063
- line: token?.line || 0,
1064
- column: token?.column || 0,
1065
- message: `Expected identifier, got ${token?.type || 'EOF'}`,
1066
- });
1067
- return null;
1068
- }
1069
-
1070
- /**
1071
- * Parse animate command: animate target property: "..." from: 0 to: 1 duration: 1000
1072
- */
1073
- private parseAnimate(): ASTNode | null {
1074
- this.expect('keyword', 'animate');
1075
- const target = this.expectIdentifier();
1076
- if (!target) return null;
1077
-
1078
- const properties: Record<string, unknown> = {};
1079
-
1080
- // Parse inline properties
1081
- while (this.position < this.tokens.length) {
1082
- this.skipNewlines();
1083
- const t = this.currentToken();
1084
- if (!t || t.type === 'newline' || (t.type === 'keyword' && this.keywordSet.has(t.value.toLowerCase()))) break;
1085
-
1086
- const prop = this.parseProperty();
1087
- if (prop) {
1088
- properties[prop.key] = prop.value;
1089
- } else {
1090
- break;
1091
- }
1092
- }
1093
-
1094
- return {
1095
- type: 'expression-statement',
1096
- expression: `animate("${target}", ${JSON.stringify(properties)})`,
1097
- position: { x: 0, y: 0, z: 0 },
1098
- } as ASTNode;
1099
- }
1100
-
1101
- /**
1102
- * Parse modify command: modify target { prop: value }
1103
- */
1104
- private parseModify(): ASTNode | null {
1105
- this.expect('keyword', 'modify');
1106
- const target = this.expectIdentifier();
1107
- if (!target) return null;
1108
-
1109
- const properties: Record<string, unknown> = {};
1110
-
1111
- if (this.check('punctuation', '{')) {
1112
- this.advance();
1113
- while (!this.check('punctuation', '}') && this.position < this.tokens.length) {
1114
- this.skipNewlines();
1115
- if (this.check('punctuation', '}')) break;
1116
-
1117
- const prop = this.parseProperty();
1118
- if (prop) {
1119
- properties[prop.key] = prop.value;
1120
- }
1121
- this.skipNewlines();
1122
- }
1123
- this.expect('punctuation', '}');
1124
- }
1125
-
1126
- return {
1127
- type: 'expression-statement',
1128
- expression: `modify("${target}", ${JSON.stringify(properties)})`,
1129
- position: { x: 0, y: 0, z: 0 },
1130
- } as ASTNode;
1131
- }
1132
-
1133
- /**
1134
- * Parse UI Element: ui2d dashboard#id { ... }
1135
- */
1136
- private parseUIElement(): ASTNode | null {
1137
- const typeToken = this.currentToken();
1138
- if (!typeToken) return null;
1139
-
1140
- const elementType = typeToken.value;
1141
- this.advance();
1142
-
1143
- let elementId = `${elementType}_${Date.now()}`;
1144
-
1145
- // Check for ID syntax
1146
- if (this.currentToken()?.type === 'punctuation' && this.currentToken()?.value === '#') {
1147
- this.advance();
1148
- const idToken = this.currentToken();
1149
- if (idToken) {
1150
- elementId = idToken.value;
1151
- this.advance();
1152
- }
1153
- } else if (this.currentToken()?.type === 'identifier' && this.currentToken()?.value.startsWith('#')) {
1154
- elementId = this.currentToken()?.value.slice(1) || elementId;
1155
- this.advance();
1156
- }
1157
-
1158
- const properties: Record<string, any> = {};
1159
-
1160
- if (this.check('punctuation', '{')) {
1161
- this.advance();
1162
- while (!this.check('punctuation', '}') && this.position < this.tokens.length) {
1163
- this.skipNewlines();
1164
- if (this.check('punctuation', '}')) break;
1165
-
1166
- const prop = this.parseProperty();
1167
- if (prop) {
1168
- properties[prop.key] = prop.value;
1169
- }
1170
- this.skipNewlines();
1171
- }
1172
- this.expect('punctuation', '}');
1173
- }
1174
-
1175
- return {
1176
- type: 'ui2d',
1177
- name: elementType,
1178
- properties: { id: elementId, ...properties },
1179
- position: { x: 0, y: 0, z: 0 }
1180
- } as ASTNode;
1181
- }
1182
-
1183
- private skipNewlines(): void {
1184
- while (this.currentToken()?.type === 'newline') {
1185
- this.advance();
1186
- }
1187
- }
1188
- }