@holoscript/core 6.0.4 → 7.0.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 (236) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/dist/compiler/index.d.ts +82 -0
  4. package/dist/constants.d.ts +3 -2
  5. package/dist/coordinators/index.d.ts +189 -0
  6. package/dist/index.d.ts +501 -19
  7. package/dist/paper-0c-spike/index.d.ts +29 -0
  8. package/dist/reconstruction/index.d.ts +78 -0
  9. package/dist/tools/index.d.ts +22 -1
  10. package/dist/traitDocs/traitDocs.d.ts +69 -0
  11. package/dist/traits/index.d.ts +61 -0
  12. package/package.json +105 -57
  13. package/dist/GLTFPipeline-DEN36VNK.js +0 -12
  14. package/dist/GLTFPipeline-YPCAK236.cjs +0 -33
  15. package/dist/HoloScriptPlusParser-BN6KVRCM.js +0 -692
  16. package/dist/HoloScriptPlusParser-NC5FE6AL.cjs +0 -697
  17. package/dist/USDZExporter-NTMBNTDB.js +0 -707
  18. package/dist/USDZExporter-UWGWNMMD.cjs +0 -709
  19. package/dist/chunk-27LWW5FU.cjs +0 -410
  20. package/dist/chunk-2CWOLHTE.js +0 -69
  21. package/dist/chunk-33LSUQDD.cjs +0 -835
  22. package/dist/chunk-3FJCK5XA.js +0 -2232
  23. package/dist/chunk-3FXV5S25.cjs +0 -633
  24. package/dist/chunk-3FYZOR7S.cjs +0 -69
  25. package/dist/chunk-3SAK5KFL.cjs +0 -83
  26. package/dist/chunk-4XSNJCLC.cjs +0 -1859
  27. package/dist/chunk-54FHG2MX.js +0 -655
  28. package/dist/chunk-56IF4NTA.js +0 -56
  29. package/dist/chunk-5BGSECRJ.cjs +0 -2237
  30. package/dist/chunk-5GLCTO44.js +0 -161
  31. package/dist/chunk-5O6TQC6M.cjs +0 -1871
  32. package/dist/chunk-5OEOHAAW.cjs +0 -682
  33. package/dist/chunk-5TOFIR6L.js +0 -407
  34. package/dist/chunk-5WUNN6ZN.cjs +0 -428
  35. package/dist/chunk-6TZPZCOJ.cjs +0 -1404
  36. package/dist/chunk-6UEHYZ7V.cjs +0 -773
  37. package/dist/chunk-6XSERL6L.js +0 -5678
  38. package/dist/chunk-72EQECGT.cjs +0 -908
  39. package/dist/chunk-7AGYRWKW.cjs +0 -507
  40. package/dist/chunk-7LCYLPW2.cjs +0 -663
  41. package/dist/chunk-A7PIMZGU.js +0 -263
  42. package/dist/chunk-ATSKSYVE.cjs +0 -51683
  43. package/dist/chunk-B5TCIAPQ.cjs +0 -117
  44. package/dist/chunk-BF2235SI.cjs +0 -5714
  45. package/dist/chunk-BKIGPPVM.js +0 -629
  46. package/dist/chunk-BND3ST2K.cjs +0 -662
  47. package/dist/chunk-BU7VWW2K.js +0 -2522
  48. package/dist/chunk-BWFJEM5A.js +0 -5419
  49. package/dist/chunk-CAUCGUEA.cjs +0 -130
  50. package/dist/chunk-CBJSLA2E.cjs +0 -5423
  51. package/dist/chunk-CDPGV4DN.js +0 -114
  52. package/dist/chunk-CLYEIWA5.cjs +0 -408
  53. package/dist/chunk-CS2EMTGF.js +0 -1966
  54. package/dist/chunk-DMG7C4H2.js +0 -975
  55. package/dist/chunk-DXJQDCFL.js +0 -468
  56. package/dist/chunk-E3FWRT3Z.js +0 -608
  57. package/dist/chunk-E3UALNFA.js +0 -421
  58. package/dist/chunk-EONILVMF.js +0 -762
  59. package/dist/chunk-EQV4R3EV.cjs +0 -769
  60. package/dist/chunk-F3HH56EB.cjs +0 -5538
  61. package/dist/chunk-F4IULT7N.js +0 -1488
  62. package/dist/chunk-FF3Q7ADR.js +0 -380
  63. package/dist/chunk-FFKU7BTK.cjs +0 -1046
  64. package/dist/chunk-FHQVYCH2.js +0 -70
  65. package/dist/chunk-FSF7EQVA.cjs +0 -1974
  66. package/dist/chunk-G4VZTCIB.js +0 -659
  67. package/dist/chunk-G7CT3EMP.cjs +0 -1002
  68. package/dist/chunk-GGHSW2NN.js +0 -51334
  69. package/dist/chunk-GVUR45UF.cjs +0 -777
  70. package/dist/chunk-H5Z7NASB.js +0 -9662
  71. package/dist/chunk-HE7ULERA.cjs +0 -697
  72. package/dist/chunk-HJJLD366.js +0 -1169
  73. package/dist/chunk-HPS76H7Q.js +0 -309
  74. package/dist/chunk-HQUEA5R6.cjs +0 -424
  75. package/dist/chunk-HYNTS5CP.js +0 -422
  76. package/dist/chunk-I6XZ5DZF.cjs +0 -488
  77. package/dist/chunk-IBDG74G2.cjs +0 -1219
  78. package/dist/chunk-IFNQFCTM.js +0 -3098
  79. package/dist/chunk-IHOUYQIA.js +0 -406
  80. package/dist/chunk-ILRBGFVD.cjs +0 -72
  81. package/dist/chunk-IWI6J7FX.js +0 -421
  82. package/dist/chunk-K3JDKWGI.cjs +0 -270
  83. package/dist/chunk-K6EKD26I.js +0 -630
  84. package/dist/chunk-KCQ5NDYC.cjs +0 -3172
  85. package/dist/chunk-KED34ILP.js +0 -832
  86. package/dist/chunk-KSGXLT74.cjs +0 -457
  87. package/dist/chunk-L4G4RLXX.js +0 -767
  88. package/dist/chunk-LDP5OK6G.js +0 -1216
  89. package/dist/chunk-LGGRPKTV.cjs +0 -735
  90. package/dist/chunk-LK5IAVH6.cjs +0 -1173
  91. package/dist/chunk-LSW7P7ML.js +0 -3675
  92. package/dist/chunk-LXJ4667L.cjs +0 -3874
  93. package/dist/chunk-LZ266PCM.cjs +0 -4499
  94. package/dist/chunk-MD6KDHVE.cjs +0 -237
  95. package/dist/chunk-MEASWI2Y.js +0 -126
  96. package/dist/chunk-MPXBVFHQ.js +0 -768
  97. package/dist/chunk-N5FTS757.cjs +0 -415
  98. package/dist/chunk-NCUKG4SK.cjs +0 -3075
  99. package/dist/chunk-NDQNIJEH.js +0 -1715
  100. package/dist/chunk-NOZZ46QU.js +0 -168
  101. package/dist/chunk-OFKWH2IP.js +0 -449
  102. package/dist/chunk-PHENW4MQ.js +0 -65
  103. package/dist/chunk-PMGODDJA.cjs +0 -319
  104. package/dist/chunk-Q4QX3AET.cjs +0 -1505
  105. package/dist/chunk-Q56TT7IL.js +0 -483
  106. package/dist/chunk-Q5JT3YML.cjs +0 -129
  107. package/dist/chunk-Q5SJOGHQ.cjs +0 -4256
  108. package/dist/chunk-QGKNANZ3.js +0 -3071
  109. package/dist/chunk-QLEAOI3Q.cjs +0 -424
  110. package/dist/chunk-R7MA7QWV.js +0 -732
  111. package/dist/chunk-RVYPEYPX.js +0 -678
  112. package/dist/chunk-S2N5TNMA.js +0 -1855
  113. package/dist/chunk-S565K7NK.js +0 -752
  114. package/dist/chunk-SDAMZIRE.js +0 -765
  115. package/dist/chunk-T36DDXSF.js +0 -4250
  116. package/dist/chunk-T4NKMBDL.js +0 -5474
  117. package/dist/chunk-T7LEXZUZ.cjs +0 -2526
  118. package/dist/chunk-TEWCN33Y.js +0 -694
  119. package/dist/chunk-TQSZUOW5.cjs +0 -793
  120. package/dist/chunk-TSH3MSQU.cjs +0 -129
  121. package/dist/chunk-UERJ3YJV.js +0 -504
  122. package/dist/chunk-UPJBDCVF.js +0 -1395
  123. package/dist/chunk-V3NN3HPP.js +0 -4462
  124. package/dist/chunk-VJ3L7CHT.cjs +0 -169
  125. package/dist/chunk-WB4Z63GG.js +0 -229
  126. package/dist/chunk-WDW67DZB.cjs +0 -9728
  127. package/dist/chunk-WGMEAYBG.js +0 -126
  128. package/dist/chunk-X4ZF6CNE.cjs +0 -473
  129. package/dist/chunk-X6SEAXAX.cjs +0 -3681
  130. package/dist/chunk-XCWFGZAA.js +0 -1043
  131. package/dist/chunk-XD6IYDUX.js +0 -903
  132. package/dist/chunk-XG23EUQX.cjs +0 -1717
  133. package/dist/chunk-XRKWN5PL.cjs +0 -173
  134. package/dist/chunk-XUILI4KB.cjs +0 -430
  135. package/dist/chunk-XUTX5CBW.js +0 -126
  136. package/dist/chunk-XWPNTWDN.cjs +0 -755
  137. package/dist/chunk-XXINBTZK.cjs +0 -633
  138. package/dist/chunk-YCXFCXDS.js +0 -1868
  139. package/dist/chunk-YQK5JNFK.js +0 -3725
  140. package/dist/chunk-YYXH45E2.js +0 -426
  141. package/dist/chunk-Z34RLXRA.cjs +0 -612
  142. package/dist/chunk-ZP4D3CSX.cjs +0 -72
  143. package/dist/cli/holoscript-runner.cjs +0 -2259
  144. package/dist/cli/holoscript-runner.js +0 -2234
  145. package/dist/codebase/index.cjs +0 -336
  146. package/dist/codebase/index.js +0 -331
  147. package/dist/compiler/agent-inference.cjs +0 -28
  148. package/dist/compiler/agent-inference.js +0 -5
  149. package/dist/compiler/android-xr.cjs +0 -19
  150. package/dist/compiler/android-xr.js +0 -9
  151. package/dist/compiler/android.cjs +0 -20
  152. package/dist/compiler/android.js +0 -10
  153. package/dist/compiler/ar.cjs +0 -20
  154. package/dist/compiler/ar.js +0 -8
  155. package/dist/compiler/babylon.cjs +0 -17
  156. package/dist/compiler/babylon.js +0 -11
  157. package/dist/compiler/coco.cjs +0 -27
  158. package/dist/compiler/coco.js +0 -4
  159. package/dist/compiler/domain-block-utils.cjs +0 -602
  160. package/dist/compiler/domain-block-utils.js +0 -8
  161. package/dist/compiler/dtdl.cjs +0 -24
  162. package/dist/compiler/dtdl.js +0 -8
  163. package/dist/compiler/gltf-pipeline.cjs +0 -39
  164. package/dist/compiler/gltf-pipeline.js +0 -4
  165. package/dist/compiler/godot.cjs +0 -15
  166. package/dist/compiler/godot.js +0 -9
  167. package/dist/compiler/incremental.cjs +0 -29
  168. package/dist/compiler/incremental.js +0 -4
  169. package/dist/compiler/index.cjs +0 -2578
  170. package/dist/compiler/index.js +0 -2383
  171. package/dist/compiler/ios.cjs +0 -20
  172. package/dist/compiler/ios.js +0 -10
  173. package/dist/compiler/multi-layer.cjs +0 -20
  174. package/dist/compiler/multi-layer.js +0 -11
  175. package/dist/compiler/nodetoy.cjs +0 -23
  176. package/dist/compiler/nodetoy.js +0 -4
  177. package/dist/compiler/openxr.cjs +0 -15
  178. package/dist/compiler/openxr.js +0 -9
  179. package/dist/compiler/playcanvas.cjs +0 -16
  180. package/dist/compiler/playcanvas.js +0 -10
  181. package/dist/compiler/r3f.cjs +0 -34
  182. package/dist/compiler/r3f.js +0 -12
  183. package/dist/compiler/remotion.cjs +0 -23
  184. package/dist/compiler/remotion.js +0 -4
  185. package/dist/compiler/reproducibility.cjs +0 -39
  186. package/dist/compiler/reproducibility.js +0 -4
  187. package/dist/compiler/sdf.cjs +0 -21
  188. package/dist/compiler/sdf.js +0 -9
  189. package/dist/compiler/semantic-scene.cjs +0 -31
  190. package/dist/compiler/semantic-scene.js +0 -4
  191. package/dist/compiler/state.cjs +0 -17
  192. package/dist/compiler/state.js +0 -7
  193. package/dist/compiler/trait-composition.cjs +0 -26
  194. package/dist/compiler/trait-composition.js +0 -5
  195. package/dist/compiler/unity.cjs +0 -15
  196. package/dist/compiler/unity.js +0 -9
  197. package/dist/compiler/unreal.cjs +0 -19
  198. package/dist/compiler/unreal.js +0 -9
  199. package/dist/compiler/urdf.cjs +0 -45
  200. package/dist/compiler/urdf.js +0 -9
  201. package/dist/compiler/usd-physics.cjs +0 -23
  202. package/dist/compiler/usd-physics.js +0 -6
  203. package/dist/compiler/visionos.cjs +0 -15
  204. package/dist/compiler/visionos.js +0 -9
  205. package/dist/compiler/vrchat.cjs +0 -19
  206. package/dist/compiler/vrchat.js +0 -9
  207. package/dist/compiler/vrr.cjs +0 -21
  208. package/dist/compiler/vrr.js +0 -9
  209. package/dist/compiler/wasm.cjs +0 -33
  210. package/dist/compiler/wasm.js +0 -9
  211. package/dist/compiler/webgpu.cjs +0 -15
  212. package/dist/compiler/webgpu.js +0 -9
  213. package/dist/debugger.cjs +0 -21
  214. package/dist/debugger.js +0 -8
  215. package/dist/entries/interop.cjs +0 -62
  216. package/dist/entries/interop.js +0 -5
  217. package/dist/entries/scripting.cjs +0 -68
  218. package/dist/entries/scripting.js +0 -11
  219. package/dist/index.cjs +0 -40921
  220. package/dist/index.js +0 -37763
  221. package/dist/math/vec3.cjs +0 -57
  222. package/dist/math/vec3.js +0 -4
  223. package/dist/ml-dsa-PHCWUBPX.cjs +0 -1178
  224. package/dist/ml-dsa-WYLJHJO6.js +0 -1178
  225. package/dist/parser.cjs +0 -27
  226. package/dist/parser.js +0 -10
  227. package/dist/playwright-5OSAPTNH.js +0 -98660
  228. package/dist/playwright-RL6GY4F7.cjs +0 -98673
  229. package/dist/runtime.cjs +0 -16
  230. package/dist/runtime.js +0 -7
  231. package/dist/storage/index.cjs +0 -37
  232. package/dist/storage/index.js +0 -4
  233. package/dist/traits/index.cjs +0 -14649
  234. package/dist/traits/index.js +0 -12243
  235. package/dist/type-checker.cjs +0 -18
  236. package/dist/type-checker.js +0 -5
@@ -1,2522 +0,0 @@
1
- import { logger } from './chunk-PHENW4MQ.js';
2
-
3
- // src/HoloScriptPersistenceParser.ts
4
- var HoloScriptPersistenceParser = class {
5
- constructor(context) {
6
- this.ctx = context;
7
- }
8
- /**
9
- * Parse memory primitive block
10
- * memory <Name> { semantic: SemanticMemory { ... }, episodic: EpisodicMemory { ... }, procedural: ProceduralMemory { ... } }
11
- */
12
- parseMemory() {
13
- const startToken = this.ctx.check("keyword", "memory");
14
- if (!startToken) {
15
- return null;
16
- }
17
- this.ctx.advance();
18
- const name = this.ctx.expectIdentifier() || "UnnamedMemory";
19
- const node = {
20
- type: "memory",
21
- name,
22
- position: [0, 0, 0]
23
- };
24
- if (this.ctx.check("punctuation", "{")) {
25
- this.ctx.advance();
26
- while (!this.ctx.check("punctuation", "}") && this.ctx.position < this.ctx.tokens.length) {
27
- this.ctx.skipNewlines();
28
- if (this.ctx.check("punctuation", "}")) break;
29
- const keyToken = this.ctx.currentToken();
30
- if (!keyToken || keyToken.type !== "identifier" && keyToken.type !== "keyword") {
31
- this.ctx.advance();
32
- continue;
33
- }
34
- const key = keyToken.value;
35
- this.ctx.advance();
36
- if (this.ctx.check("punctuation", ":")) {
37
- this.ctx.advance();
38
- }
39
- const typeToken = this.ctx.currentToken();
40
- if (typeToken && (typeToken.type === "identifier" || typeToken.type === "keyword")) {
41
- this.ctx.advance();
42
- if (this.ctx.check("punctuation", "{")) {
43
- const properties = this.ctx.parseObject();
44
- if (key === "semantic" && typeToken.value === "SemanticMemory") {
45
- node.semantic = {
46
- type: "semantic-memory",
47
- properties,
48
- position: [0, 0, 0]
49
- };
50
- } else if (key === "episodic" && typeToken.value === "EpisodicMemory") {
51
- node.episodic = {
52
- type: "episodic-memory",
53
- properties,
54
- position: [0, 0, 0]
55
- };
56
- } else if (key === "procedural" && typeToken.value === "ProceduralMemory") {
57
- node.procedural = {
58
- type: "procedural-memory",
59
- properties,
60
- position: [0, 0, 0]
61
- };
62
- }
63
- }
64
- }
65
- if (this.ctx.check("punctuation", ",")) {
66
- this.ctx.advance();
67
- }
68
- }
69
- this.ctx.expect("punctuation", "}");
70
- }
71
- return node;
72
- }
73
- };
74
-
75
- // src/HoloScriptCodeParser.ts
76
- var ObjectPool = class {
77
- constructor(createFn, resetFn, maxSize = 100) {
78
- this.pool = [];
79
- this.createFn = createFn;
80
- this.resetFn = resetFn;
81
- this.maxSize = maxSize;
82
- }
83
- /** Get an object from pool or create new one */
84
- acquire() {
85
- if (this.pool.length > 0) {
86
- return this.pool.pop();
87
- }
88
- return this.createFn();
89
- }
90
- /** Return object to pool for reuse */
91
- release(obj) {
92
- if (this.pool.length < this.maxSize) {
93
- this.resetFn(obj);
94
- this.pool.push(obj);
95
- }
96
- }
97
- /** Clear the pool */
98
- clear() {
99
- this.pool.length = 0;
100
- }
101
- /** Get pool statistics */
102
- get stats() {
103
- return { pooled: this.pool.length, maxSize: this.maxSize };
104
- }
105
- };
106
- var tokenPool = new ObjectPool(
107
- () => ({ type: "", value: "", line: 0, column: 0 }),
108
- (t) => {
109
- t.type = "";
110
- t.value = "";
111
- t.line = 0;
112
- t.column = 0;
113
- }
114
- );
115
- var arrayPool = new ObjectPool(
116
- () => [],
117
- (arr) => {
118
- arr.length = 0;
119
- },
120
- 50
121
- );
122
- var ParserPools = {
123
- token: tokenPool,
124
- array: arrayPool,
125
- clearAll: () => {
126
- tokenPool.clear();
127
- arrayPool.clear();
128
- },
129
- getStats: () => ({
130
- token: tokenPool.stats,
131
- array: arrayPool.stats
132
- })
133
- };
134
- var CODE_SECURITY_CONFIG = {
135
- maxCodeLength: 5e4,
136
- maxBlocks: 100,
137
- suspiciousKeywords: [
138
- "process",
139
- "require",
140
- "eval",
141
- "constructor",
142
- "prototype",
143
- "__proto__",
144
- "fs",
145
- "child_process",
146
- "exec",
147
- "spawn"
148
- ]
149
- };
150
- function stripCommentsAndStrings(code) {
151
- let result = "";
152
- let i = 0;
153
- while (i < code.length) {
154
- if (code[i] === "/" && code[i + 1] === "/") {
155
- while (i < code.length && code[i] !== "\n") i++;
156
- continue;
157
- }
158
- if (code[i] === "/" && code[i + 1] === "*") {
159
- i += 2;
160
- while (i < code.length - 1 && !(code[i] === "*" && code[i + 1] === "/")) i++;
161
- i += 2;
162
- continue;
163
- }
164
- if (code[i] === '"') {
165
- i++;
166
- while (i < code.length && code[i] !== '"') {
167
- if (code[i] === "\\" && i + 1 < code.length) i++;
168
- i++;
169
- }
170
- i++;
171
- continue;
172
- }
173
- if (code[i] === "'") {
174
- i++;
175
- while (i < code.length && code[i] !== "'") {
176
- if (code[i] === "\\" && i + 1 < code.length) i++;
177
- i++;
178
- }
179
- i++;
180
- continue;
181
- }
182
- result += code[i];
183
- i++;
184
- }
185
- return result;
186
- }
187
- var ERROR_CODES = {
188
- HS001: "Expected keyword - a required keyword is missing",
189
- HS002: "Expected identifier - a name is required here",
190
- HS003: "Expected operator - an operator like = or : is required",
191
- HS004: "Unexpected token - this token is not valid in this context",
192
- HS005: "Unclosed block - missing closing brace }",
193
- HS006: "Unclosed string - missing closing quote",
194
- HS007: "Invalid number - numeric literal is malformed",
195
- HS008: "Unknown keyword - this keyword is not recognized",
196
- HS009: "Too many items - limit exceeded for performance",
197
- HS010: "Security violation - blocked for security reasons"
198
- };
199
- var HoloScriptCodeParser = class {
200
- constructor() {
201
- this.errors = [];
202
- this.warnings = [];
203
- this.tokens = [];
204
- this.position = 0;
205
- /** Source code lines for error context */
206
- this.sourceLines = [];
207
- this.persistenceParser = new HoloScriptPersistenceParser(this);
208
- this.keywordSet = /* @__PURE__ */ new Set([
209
- "orb",
210
- "function",
211
- "connect",
212
- "to",
213
- "as",
214
- "gate",
215
- "stream",
216
- "from",
217
- "through",
218
- "return",
219
- "if",
220
- "else",
221
- "nexus",
222
- "building",
223
- "pillar",
224
- "foundation",
225
- "for",
226
- "while",
227
- "forEach",
228
- "in",
229
- "of",
230
- "break",
231
- "continue",
232
- "import",
233
- "export",
234
- "module",
235
- "use",
236
- "type",
237
- "interface",
238
- "extends",
239
- "implements",
240
- "is",
241
- "async",
242
- "await",
243
- "spawn",
244
- "parallel",
245
- "class",
246
- "new",
247
- "this",
248
- "super",
249
- "static",
250
- "private",
251
- "public",
252
- "try",
253
- "catch",
254
- "finally",
255
- "throw",
256
- "const",
257
- "let",
258
- "var",
259
- "animate",
260
- "modify",
261
- "pulse",
262
- "move",
263
- "show",
264
- "hide",
265
- "scale",
266
- "focus",
267
- "environment",
268
- "composition",
269
- "template",
270
- "settings",
271
- "chat",
272
- "migrate",
273
- // Shape keywords for 3D objects
274
- "cube",
275
- "sphere",
276
- "plane",
277
- "cylinder",
278
- "cone",
279
- "torus",
280
- "pyramid",
281
- "box",
282
- "mesh",
283
- "model",
284
- "object",
285
- "light",
286
- "camera",
287
- // System and component keywords (Phase 0: Hololand Bootstrap)
288
- "system",
289
- "component",
290
- "action",
291
- "props",
292
- // Additional scene keywords
293
- "npc",
294
- "player",
295
- "entity",
296
- "trigger",
297
- "zone",
298
- "portal",
299
- "spatial_group",
300
- "interactive",
301
- "traits",
302
- "on_interact",
303
- "on_collision",
304
- "on_enter",
305
- "on_exit",
306
- "using",
307
- "memory",
308
- "semantic",
309
- "episodic",
310
- "procedural"
311
- ]);
312
- }
313
- /**
314
- * Create a rich error with context and suggestions
315
- */
316
- createError(code, message, token, suggestion) {
317
- const line = token?.line || 0;
318
- const column = token?.column || 0;
319
- let context = "";
320
- if (this.sourceLines.length > 0 && line > 0) {
321
- const lines = [];
322
- if (line > 1) lines.push(`${line - 1} | ${this.sourceLines[line - 2] || ""}`);
323
- lines.push(`${line} | ${this.sourceLines[line - 1] || ""}`);
324
- lines.push(` ${" ".repeat(column)}^`);
325
- if (line < this.sourceLines.length)
326
- lines.push(`${line + 1} | ${this.sourceLines[line] || ""}`);
327
- context = lines.join("\n");
328
- }
329
- return {
330
- line,
331
- column,
332
- message,
333
- code,
334
- context,
335
- suggestion,
336
- severity: "error"
337
- };
338
- }
339
- /**
340
- * Find similar keywords for "did you mean" suggestions
341
- */
342
- findSimilarKeyword(word) {
343
- if (!word) return void 0;
344
- const lower = word.toLowerCase();
345
- let bestMatch;
346
- let bestScore = 0;
347
- for (const keyword of this.keywordSet) {
348
- const score = this.similarity(lower, keyword);
349
- if (score > bestScore && score > 0.6) {
350
- bestScore = score;
351
- bestMatch = keyword;
352
- }
353
- }
354
- return bestMatch;
355
- }
356
- /**
357
- * Simple Levenshtein-based similarity (0-1)
358
- */
359
- similarity(a, b) {
360
- if (a === b) return 1;
361
- if (a.length === 0 || b.length === 0) return 0;
362
- const len = Math.max(a.length, b.length);
363
- let matches = 0;
364
- for (let i = 0; i < Math.min(a.length, b.length); i++) {
365
- if (a[i] === b[i]) matches++;
366
- }
367
- if (a.startsWith(b) || b.startsWith(a)) {
368
- matches = Math.max(matches, Math.min(a.length, b.length));
369
- }
370
- return matches / len;
371
- }
372
- /**
373
- * Add error and continue parsing (error recovery)
374
- */
375
- addError(error) {
376
- if (!this.errors.some((e) => e.line === error.line && e.message === error.message)) {
377
- this.errors.push(error);
378
- }
379
- }
380
- /**
381
- * Recover from error by skipping to next statement boundary
382
- */
383
- synchronize() {
384
- while (this.position < this.tokens.length) {
385
- const token = this.currentToken();
386
- if (!token) break;
387
- if (token.type === "newline") {
388
- this.advance();
389
- break;
390
- }
391
- if (token.type === "keyword" && [
392
- "orb",
393
- "function",
394
- "gate",
395
- "for",
396
- "while",
397
- "if",
398
- "return",
399
- "object",
400
- "template",
401
- "composition",
402
- "spatial_group",
403
- "logic"
404
- ].includes(token.value)) {
405
- break;
406
- }
407
- if (token.type === "punctuation" && ["}", ";"].includes(token.value)) {
408
- this.advance();
409
- break;
410
- }
411
- this.advance();
412
- }
413
- }
414
- /**
415
- * Parse HoloScript code string into AST
416
- */
417
- parse(code) {
418
- this.errors = [];
419
- this.warnings = [];
420
- this.tokens = [];
421
- this.position = 0;
422
- this.sourceLines = code.split("\n");
423
- if (code.length > CODE_SECURITY_CONFIG.maxCodeLength) {
424
- return {
425
- success: false,
426
- ast: [],
427
- errors: [
428
- {
429
- line: 0,
430
- column: 0,
431
- message: `Code exceeds max length (${CODE_SECURITY_CONFIG.maxCodeLength})`,
432
- code: "HS009",
433
- severity: "error"
434
- }
435
- ],
436
- warnings: []
437
- };
438
- }
439
- const strippedCode = stripCommentsAndStrings(code).toLowerCase();
440
- for (const keyword of CODE_SECURITY_CONFIG.suspiciousKeywords) {
441
- const regex = new RegExp(`\\b${keyword}\\b`, "i");
442
- if (regex.test(strippedCode)) {
443
- logger.warn("Suspicious keyword detected", { keyword });
444
- return {
445
- success: false,
446
- ast: [],
447
- errors: [
448
- {
449
- line: 0,
450
- column: 0,
451
- message: `Suspicious keyword detected: ${keyword}`,
452
- code: "HS010",
453
- severity: "error"
454
- }
455
- ],
456
- warnings: []
457
- };
458
- }
459
- }
460
- try {
461
- this.tokens = this.tokenize(code);
462
- const ast = this.parseProgram();
463
- return {
464
- success: this.errors.length === 0,
465
- ast,
466
- errors: this.errors,
467
- warnings: this.warnings
468
- };
469
- } catch (error) {
470
- this.addError({
471
- line: 0,
472
- column: 0,
473
- message: String(error),
474
- code: "HS004",
475
- severity: "error"
476
- });
477
- return {
478
- success: false,
479
- ast: [],
480
- errors: this.errors,
481
- warnings: this.warnings
482
- };
483
- }
484
- }
485
- /**
486
- * Tokenize code into tokens
487
- */
488
- tokenize(code) {
489
- const tokens = [];
490
- let line = 1;
491
- let column = 1;
492
- let i = 0;
493
- while (i < code.length) {
494
- const char = code[i];
495
- if (char === " " || char === " " || char === "\r") {
496
- i++;
497
- column++;
498
- continue;
499
- }
500
- if (char === "\n") {
501
- tokens.push({ type: "newline", value: "\n", line, column });
502
- line++;
503
- column = 1;
504
- i++;
505
- continue;
506
- }
507
- if (char === "/" && code[i + 1] === "/") {
508
- while (i < code.length && code[i] !== "\n") {
509
- i++;
510
- }
511
- continue;
512
- }
513
- if (char === '"' || char === "'") {
514
- const quote = char;
515
- let str = "";
516
- const startCol = column;
517
- i++;
518
- column++;
519
- while (i < code.length && code[i] !== quote) {
520
- if (code[i] === "\\" && i + 1 < code.length) {
521
- str += code[i + 1];
522
- i += 2;
523
- column += 2;
524
- } else {
525
- str += code[i];
526
- i++;
527
- column++;
528
- }
529
- }
530
- i++;
531
- column++;
532
- tokens.push({ type: "string", value: str, line, column: startCol });
533
- continue;
534
- }
535
- if (/[0-9]/.test(char) || char === "-" && /[0-9]/.test(code[i + 1])) {
536
- let num = "";
537
- const startCol = column;
538
- while (i < code.length && /[0-9.\-]/.test(code[i])) {
539
- num += code[i];
540
- i++;
541
- column++;
542
- }
543
- tokens.push({ type: "number", value: num, line, column: startCol });
544
- continue;
545
- }
546
- if (/[a-zA-Z_]/.test(char)) {
547
- let ident = "";
548
- const startCol = column;
549
- while (i < code.length && /[a-zA-Z0-9_]/.test(code[i])) {
550
- ident += code[i];
551
- i++;
552
- column++;
553
- }
554
- const isKeyword = this.keywordSet.has(ident.toLowerCase());
555
- tokens.push({
556
- type: isKeyword ? "keyword" : "identifier",
557
- value: ident,
558
- line,
559
- column: startCol
560
- });
561
- continue;
562
- }
563
- const multiCharOps = [
564
- "===",
565
- "!==",
566
- "==",
567
- "!=",
568
- ">=",
569
- "<=",
570
- "&&",
571
- "||",
572
- "??",
573
- "?.",
574
- "++",
575
- "--",
576
- "+=",
577
- "-=",
578
- "*=",
579
- "/=",
580
- "%=",
581
- "=>",
582
- "->"
583
- ];
584
- let foundMultiOp = false;
585
- for (const op of multiCharOps) {
586
- if (code.substring(i, i + op.length) === op) {
587
- tokens.push({ type: "operator", value: op, line, column });
588
- i += op.length;
589
- column += op.length;
590
- foundMultiOp = true;
591
- break;
592
- }
593
- }
594
- if (foundMultiOp) continue;
595
- const punctuation = [
596
- "{",
597
- "}",
598
- "(",
599
- ")",
600
- "[",
601
- "]",
602
- ":",
603
- ",",
604
- ".",
605
- ";",
606
- "=",
607
- "<",
608
- ">",
609
- "+",
610
- "-",
611
- "*",
612
- "/",
613
- "%",
614
- "!",
615
- "&",
616
- "|",
617
- "?",
618
- "#",
619
- "@"
620
- ];
621
- if (punctuation.includes(char)) {
622
- tokens.push({ type: "punctuation", value: char, line, column });
623
- i++;
624
- column++;
625
- continue;
626
- }
627
- i++;
628
- column++;
629
- }
630
- return tokens;
631
- }
632
- /**
633
- * Parse program (list of declarations)
634
- */
635
- parseProgram() {
636
- const nodes = [];
637
- let blockCount = 0;
638
- const maxErrors = 50;
639
- while (this.position < this.tokens.length) {
640
- if (this.errors.length >= maxErrors) {
641
- this.addError({
642
- line: 0,
643
- column: 0,
644
- message: `Too many errors (${maxErrors}+), stopping parse`,
645
- code: "HS009",
646
- severity: "error"
647
- });
648
- break;
649
- }
650
- while (this.currentToken()?.type === "newline") {
651
- this.advance();
652
- }
653
- if (this.position >= this.tokens.length) break;
654
- blockCount++;
655
- if (blockCount > CODE_SECURITY_CONFIG.maxBlocks) {
656
- this.addError({
657
- line: 0,
658
- column: 0,
659
- message: "Too many blocks in program",
660
- code: "HS009",
661
- severity: "error"
662
- });
663
- break;
664
- }
665
- const errorCountBefore = this.errors.length;
666
- const node = this.parseDeclaration();
667
- if (node) {
668
- nodes.push(node);
669
- } else if (this.errors.length > errorCountBefore) {
670
- this.synchronize();
671
- }
672
- }
673
- return nodes;
674
- }
675
- /**
676
- * Parse a single declaration
677
- */
678
- parseDeclaration() {
679
- const token = this.currentToken();
680
- if (!token) return null;
681
- if (token.type === "keyword") {
682
- switch (token.value.toLowerCase()) {
683
- case "orb":
684
- case "object":
685
- return this.parseOrb();
686
- case "function":
687
- return this.parseFunction();
688
- case "connect":
689
- return this.parseConnection();
690
- case "gate":
691
- case "if":
692
- return this.parseGate();
693
- case "return":
694
- return this.parseReturn();
695
- case "stream":
696
- return this.parseStream();
697
- case "nexus":
698
- return this.parseNexus();
699
- case "building":
700
- case "class":
701
- return this.parseBuilding();
702
- // Phase 2: Loop constructs
703
- case "for":
704
- return this.parseForLoop();
705
- case "while":
706
- return this.parseWhileLoop();
707
- case "foreach":
708
- return this.parseForEachLoop();
709
- // Phase 2: Module system
710
- case "import":
711
- return this.parseImport();
712
- case "export":
713
- return this.parseExport();
714
- // Phase 2: Variable declarations
715
- // UI Extensions
716
- case "ui2d":
717
- case "card":
718
- case "metric":
719
- case "button":
720
- case "row":
721
- case "col":
722
- case "text":
723
- return this.parseUIElement();
724
- case "const":
725
- case "let":
726
- case "var":
727
- return this.parseVariableDeclaration();
728
- // DSL-first commands (Phase 54)
729
- case "animate":
730
- return this.parseAnimate();
731
- case "modify":
732
- return this.parseModify();
733
- case "scale":
734
- return this.parseScale();
735
- case "focus":
736
- return this.parseFocus();
737
- case "environment":
738
- return this.parseEnvironment();
739
- case "composition":
740
- return this.parseComposition();
741
- case "template":
742
- return this.parseTemplate();
743
- case "system":
744
- return this.parseSystem();
745
- case "component":
746
- return this.parseComponent();
747
- case "migrate":
748
- return this.parseMigration();
749
- case "settings":
750
- return this.parseSettings();
751
- case "chat":
752
- return this.parseChat();
753
- // Primitive 3D shapes (Phase 55)
754
- case "cube":
755
- case "sphere":
756
- case "plane":
757
- case "cylinder":
758
- case "cone":
759
- case "torus":
760
- case "pyramid":
761
- case "box":
762
- case "mesh":
763
- case "model":
764
- case "light":
765
- case "camera":
766
- return this.parsePrimitive();
767
- case "zone":
768
- return this.parseZone();
769
- case "memory":
770
- return this.parseMemory();
771
- default:
772
- return this.parseExpressionStatement();
773
- }
774
- }
775
- this.advance();
776
- return null;
777
- }
778
- /**
779
- * Parse for loop: for (init; condition; update) { body }
780
- */
781
- parseForLoop() {
782
- this.expect("keyword", "for");
783
- if (!this.check("punctuation", "(")) {
784
- this.errors.push({ line: 0, column: 0, message: "Expected ( after for" });
785
- return null;
786
- }
787
- this.advance();
788
- let init = "", condition = "", update = "";
789
- let depth = 0;
790
- while (this.position < this.tokens.length) {
791
- const t = this.currentToken();
792
- if (!t) break;
793
- if (t.value === ";" && depth === 0) {
794
- this.advance();
795
- break;
796
- }
797
- if (t.value === "(") depth++;
798
- if (t.value === ")") depth--;
799
- init += t.value + " ";
800
- this.advance();
801
- }
802
- depth = 0;
803
- while (this.position < this.tokens.length) {
804
- const t = this.currentToken();
805
- if (!t) break;
806
- if (t.value === ";" && depth === 0) {
807
- this.advance();
808
- break;
809
- }
810
- if (t.value === "(") depth++;
811
- if (t.value === ")") depth--;
812
- condition += t.value + " ";
813
- this.advance();
814
- }
815
- depth = 0;
816
- while (this.position < this.tokens.length) {
817
- const t = this.currentToken();
818
- if (!t) break;
819
- if (t.value === ")" && depth === 0) {
820
- this.advance();
821
- break;
822
- }
823
- if (t.value === "(") depth++;
824
- if (t.value === ")") depth--;
825
- update += t.value + " ";
826
- this.advance();
827
- }
828
- const body = [];
829
- if (this.check("punctuation", "{")) {
830
- this.advance();
831
- let braceDepth = 1;
832
- while (braceDepth > 0 && this.position < this.tokens.length) {
833
- if (this.check("punctuation", "{")) braceDepth++;
834
- if (this.check("punctuation", "}")) braceDepth--;
835
- this.advance();
836
- }
837
- }
838
- return {
839
- type: "for-loop",
840
- init: init.trim(),
841
- condition: this.parseConditionExpression(condition.trim()),
842
- update: update.trim(),
843
- body,
844
- position: [0, 0, 0]
845
- };
846
- }
847
- /**
848
- * Parse while loop: while (condition) { body }
849
- */
850
- parseWhileLoop() {
851
- this.expect("keyword", "while");
852
- let condition = "";
853
- if (this.check("punctuation", "(")) {
854
- this.advance();
855
- let depth = 1;
856
- while (depth > 0 && this.position < this.tokens.length) {
857
- const t = this.currentToken();
858
- if (!t) break;
859
- if (t.value === "(") depth++;
860
- if (t.value === ")") {
861
- depth--;
862
- if (depth === 0) {
863
- this.advance();
864
- break;
865
- }
866
- }
867
- condition += t.value + " ";
868
- this.advance();
869
- }
870
- }
871
- if (this.check("punctuation", "{")) {
872
- this.advance();
873
- let braceDepth = 1;
874
- while (braceDepth > 0 && this.position < this.tokens.length) {
875
- if (this.check("punctuation", "{")) braceDepth++;
876
- if (this.check("punctuation", "}")) braceDepth--;
877
- this.advance();
878
- }
879
- }
880
- return {
881
- type: "while-loop",
882
- condition: this.parseConditionExpression(condition.trim()),
883
- body: [],
884
- position: [0, 0, 0]
885
- };
886
- }
887
- /**
888
- * Parse forEach loop: forEach item in collection { body }
889
- */
890
- parseForEachLoop() {
891
- this.expect("keyword", "forEach");
892
- const variable = this.expectIdentifier();
893
- this.expect("keyword", "in");
894
- const collection = this.expectIdentifier();
895
- if (this.check("punctuation", "{")) {
896
- this.advance();
897
- let braceDepth = 1;
898
- while (braceDepth > 0 && this.position < this.tokens.length) {
899
- if (this.check("punctuation", "{")) braceDepth++;
900
- if (this.check("punctuation", "}")) braceDepth--;
901
- this.advance();
902
- }
903
- }
904
- return {
905
- type: "foreach-loop",
906
- variable: variable || "item",
907
- collection: collection || "items",
908
- body: [],
909
- position: [0, 0, 0]
910
- };
911
- }
912
- /**
913
- * Parse import: import { x, y } from "module"
914
- */
915
- parseImport() {
916
- this.expect("keyword", "import");
917
- const imports = [];
918
- let modulePath = "";
919
- let defaultImport;
920
- const current = this.currentToken();
921
- if (current?.type === "string") {
922
- modulePath = current.value;
923
- this.advance();
924
- return {
925
- type: "import",
926
- imports: [],
927
- modulePath,
928
- position: [0, 0, 0]
929
- };
930
- }
931
- if (this.check("punctuation", "{")) {
932
- this.advance();
933
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
934
- const name = this.expectIdentifier();
935
- if (name) imports.push(name);
936
- if (this.check("punctuation", ",")) this.advance();
937
- }
938
- this.expect("punctuation", "}");
939
- } else {
940
- defaultImport = this.expectIdentifier() || void 0;
941
- }
942
- if (this.check("keyword", "from")) {
943
- this.advance();
944
- const pathToken = this.currentToken();
945
- if (pathToken?.type === "string") {
946
- modulePath = pathToken.value;
947
- this.advance();
948
- }
949
- }
950
- return {
951
- type: "import",
952
- imports,
953
- defaultImport,
954
- modulePath,
955
- position: [0, 0, 0]
956
- };
957
- }
958
- /**
959
- * Parse export: export { x, y } or export function/orb
960
- */
961
- parseExport() {
962
- this.expect("keyword", "export");
963
- const next = this.currentToken();
964
- if (next?.type === "keyword") {
965
- const declaration = this.parseDeclaration();
966
- return {
967
- type: "export",
968
- declaration: declaration || void 0,
969
- position: [0, 0, 0]
970
- };
971
- }
972
- const exports$1 = [];
973
- if (this.check("punctuation", "{")) {
974
- this.advance();
975
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
976
- const name = this.expectIdentifier();
977
- if (name) exports$1.push(name);
978
- if (this.check("punctuation", ",")) this.advance();
979
- }
980
- this.expect("punctuation", "}");
981
- }
982
- return {
983
- type: "export",
984
- exports: exports$1,
985
- position: [0, 0, 0]
986
- };
987
- }
988
- /**
989
- * Parse variable declaration: const/let/var name = value
990
- */
991
- parseVariableDeclaration() {
992
- const kindToken = this.currentToken()?.value.toLowerCase();
993
- const kind = kindToken === "let" ? "let" : kindToken === "var" ? "var" : "const";
994
- this.advance();
995
- const name = this.expectIdentifier();
996
- if (!name) return null;
997
- let dataType;
998
- if (this.check("punctuation", ":")) {
999
- this.advance();
1000
- dataType = this.expectIdentifier() || void 0;
1001
- }
1002
- const result = {
1003
- type: "variable-declaration",
1004
- kind,
1005
- name,
1006
- dataType,
1007
- value: void 0,
1008
- position: [0, 0, 0]
1009
- };
1010
- if (this.check("punctuation", "=")) {
1011
- this.advance();
1012
- const valueToken = this.currentToken();
1013
- if (valueToken?.type === "string") {
1014
- result.value = valueToken.value;
1015
- this.advance();
1016
- } else if (valueToken?.type === "number") {
1017
- result.value = parseFloat(valueToken.value);
1018
- this.advance();
1019
- } else if (this.check("punctuation", "[")) {
1020
- result.value = this.parseArray();
1021
- } else if (this.check("punctuation", "{")) {
1022
- result.value = this.parseObject();
1023
- } else if (valueToken?.type === "identifier") {
1024
- if (valueToken.value === "true") {
1025
- result.value = true;
1026
- this.advance();
1027
- } else if (valueToken.value === "false") {
1028
- result.value = false;
1029
- this.advance();
1030
- } else {
1031
- let expression = "";
1032
- while (this.position < this.tokens.length) {
1033
- const t = this.currentToken();
1034
- if (!t || t.type === "newline" || t.type === "punctuation" && t.value === ";") break;
1035
- expression += t.value + " ";
1036
- this.advance();
1037
- }
1038
- result.value = expression.trim();
1039
- result.isExpression = true;
1040
- }
1041
- }
1042
- }
1043
- return result;
1044
- }
1045
- /**
1046
- * Parse orb declaration
1047
- */
1048
- parseOrb() {
1049
- const startToken = this.currentToken();
1050
- if (this.check("keyword", "orb") || this.check("keyword", "object")) {
1051
- this.advance();
1052
- } else {
1053
- this.expect("keyword", "orb");
1054
- }
1055
- let name = "";
1056
- if (this.check("punctuation", "#")) {
1057
- this.advance();
1058
- name = this.expectName() || `orb_${Date.now()}`;
1059
- } else {
1060
- name = this.expectName() || `orb_${Date.now()}`;
1061
- }
1062
- let template;
1063
- if (this.check("keyword", "using")) {
1064
- this.advance();
1065
- template = this.expectName() || void 0;
1066
- }
1067
- const properties = {};
1068
- const directives = [];
1069
- let position;
1070
- let hologram;
1071
- if (this.check("punctuation", "{")) {
1072
- this.advance();
1073
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1074
- this.skipNewlines();
1075
- if (this.check("punctuation", "}")) break;
1076
- if (this.check("punctuation", ",") || this.check("punctuation", ";")) {
1077
- this.advance();
1078
- continue;
1079
- }
1080
- const token = this.currentToken();
1081
- if (token?.type === "punctuation" && token.value === "@") {
1082
- const directive = this.parseDirective();
1083
- if (directive) directives.push(directive);
1084
- } else {
1085
- const prop = this.parseProperty();
1086
- if (prop) {
1087
- if (prop.key === "position" || prop.key === "at") {
1088
- position = this.parsePosition(prop.value);
1089
- } else if (prop.key === "color" || prop.key === "glow" || prop.key === "size") {
1090
- hologram = hologram || {
1091
- shape: "orb",
1092
- color: "#00ffff",
1093
- size: 0.5,
1094
- glow: true,
1095
- interactive: true
1096
- };
1097
- if (prop.key === "color") hologram.color = String(prop.value);
1098
- if (prop.key === "glow") hologram.glow = Boolean(prop.value);
1099
- if (prop.key === "size") hologram.size = Number(prop.value);
1100
- } else {
1101
- properties[prop.key] = prop.value;
1102
- }
1103
- } else {
1104
- this.advance();
1105
- }
1106
- }
1107
- this.skipNewlines();
1108
- }
1109
- this.expect("punctuation", "}");
1110
- }
1111
- return {
1112
- type: "orb",
1113
- name,
1114
- position: position || { x: 0, y: 0, z: 0 },
1115
- hologram: hologram || {
1116
- shape: "orb",
1117
- color: "#00ffff",
1118
- size: 0.5,
1119
- glow: true,
1120
- interactive: true
1121
- },
1122
- properties,
1123
- directives,
1124
- template,
1125
- methods: [],
1126
- children: [],
1127
- line: startToken?.line || 0
1128
- };
1129
- }
1130
- /**
1131
- * Parse HoloScript+ directive: @name(...) or @name { ... }
1132
- */
1133
- parseDirective() {
1134
- this.expect("punctuation", "@");
1135
- const name = this.expectIdentifier();
1136
- if (!name) return null;
1137
- if (name === "state") {
1138
- const body = this.parseObject();
1139
- return { type: "state", body };
1140
- }
1141
- if (name === "bindings") {
1142
- const bindings = this.parseBindingsBlock();
1143
- return { type: "bindings", bindings };
1144
- }
1145
- if (name.startsWith("on_")) {
1146
- let body = "";
1147
- if (this.check("punctuation", "{")) {
1148
- this.advance();
1149
- let braceDepth = 1;
1150
- while (braceDepth > 0 && this.position < this.tokens.length) {
1151
- const t = this.advance();
1152
- if (t.value === "{") braceDepth++;
1153
- if (t.value === "}") braceDepth--;
1154
- if (braceDepth > 0) {
1155
- const val = t.type === "string" ? JSON.stringify(t.value) : t.value;
1156
- body += val + " ";
1157
- } else if (braceDepth < 0) break;
1158
- }
1159
- } else {
1160
- const t = this.advance();
1161
- if (t) body = t.value;
1162
- }
1163
- return { type: "lifecycle", hook: name, body };
1164
- }
1165
- let config = {};
1166
- if (this.check("punctuation", "(")) {
1167
- this.advance();
1168
- while (!this.check("punctuation", ")") && this.position < this.tokens.length) {
1169
- const prop = this.parseProperty();
1170
- if (prop) {
1171
- config[prop.key] = prop.value;
1172
- }
1173
- if (this.check("punctuation", ",")) {
1174
- this.advance();
1175
- }
1176
- }
1177
- this.expect("punctuation", ")");
1178
- } else if (this.check("punctuation", "{")) {
1179
- config = this.parseObject();
1180
- }
1181
- return { type: "trait", name, config };
1182
- }
1183
- /**
1184
- * Parse @bindings { bind(expr) -> target.prop, ... }
1185
- */
1186
- parseBindingsBlock() {
1187
- const bindings = [];
1188
- if (!this.check("punctuation", "{")) {
1189
- return bindings;
1190
- }
1191
- this.advance();
1192
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1193
- this.skipNewlines();
1194
- if (this.check("identifier") && this.currentToken()?.value === "bind") {
1195
- this.advance();
1196
- let expression = "";
1197
- if (this.check("punctuation", "(")) {
1198
- this.advance();
1199
- let parenDepth = 1;
1200
- while (parenDepth > 0 && this.position < this.tokens.length) {
1201
- const t = this.advance();
1202
- if (t.value === "(") parenDepth++;
1203
- if (t.value === ")") parenDepth--;
1204
- if (parenDepth > 0) {
1205
- expression += t.value + " ";
1206
- }
1207
- }
1208
- expression = expression.trim();
1209
- }
1210
- if (this.check("punctuation", "-")) {
1211
- this.advance();
1212
- if (this.check("punctuation", ">")) {
1213
- this.advance();
1214
- }
1215
- }
1216
- const target = this.expectIdentifier() || "";
1217
- let property = "";
1218
- if (this.check("punctuation", ".")) {
1219
- this.advance();
1220
- property = this.expectIdentifier() || "";
1221
- }
1222
- if (expression && target && property) {
1223
- bindings.push({ expression, target, property });
1224
- }
1225
- } else {
1226
- this.advance();
1227
- }
1228
- this.skipNewlines();
1229
- }
1230
- this.expect("punctuation", "}");
1231
- return bindings;
1232
- }
1233
- // ============================================================================
1234
- // Phase 7: AI Persistence Memory Syntax
1235
- // ============================================================================
1236
- /**
1237
- * Parse memory primitive block
1238
- * memory <Name> { semantic: SemanticMemory { ... }, episodic: EpisodicMemory { ... }, procedural: ProceduralMemory { ... } }
1239
- *
1240
- * Defers to the modular HoloScriptPersistenceParser
1241
- */
1242
- parseMemory() {
1243
- return this.persistenceParser.parseMemory();
1244
- }
1245
- /**
1246
- * Parse function declaration
1247
- */
1248
- parseFunction() {
1249
- this.expect("keyword", "function");
1250
- const name = this.expectIdentifier();
1251
- if (!name) return null;
1252
- const parameters = [];
1253
- let returnType;
1254
- if (this.check("punctuation", "(")) {
1255
- this.advance();
1256
- while (!this.check("punctuation", ")") && this.position < this.tokens.length) {
1257
- const paramName = this.expectIdentifier();
1258
- if (!paramName) break;
1259
- let paramType = "any";
1260
- if (this.check("punctuation", ":")) {
1261
- this.advance();
1262
- paramType = this.expectIdentifier() || "any";
1263
- }
1264
- parameters.push({
1265
- type: "parameter",
1266
- name: paramName,
1267
- dataType: paramType
1268
- });
1269
- if (this.check("punctuation", ",")) {
1270
- this.advance();
1271
- }
1272
- }
1273
- this.expect("punctuation", ")");
1274
- }
1275
- if (this.check("punctuation", ":")) {
1276
- this.advance();
1277
- returnType = this.expectIdentifier() || void 0;
1278
- }
1279
- const body = [];
1280
- if (this.check("punctuation", "{")) {
1281
- this.advance();
1282
- let depth = 1;
1283
- while (depth > 0 && this.position < this.tokens.length) {
1284
- if (this.check("punctuation", "{")) depth++;
1285
- if (this.check("punctuation", "}")) depth--;
1286
- this.advance();
1287
- }
1288
- }
1289
- return {
1290
- type: "method",
1291
- name,
1292
- parameters,
1293
- body,
1294
- returnType,
1295
- position: [0, 0, 0],
1296
- hologram: { shape: "cube", color: "#ff6b35", size: 1.5, glow: true, interactive: true }
1297
- };
1298
- }
1299
- /**
1300
- * Parse connection
1301
- */
1302
- parseConnection() {
1303
- this.expect("keyword", "connect");
1304
- const from = this.expectIdentifier();
1305
- if (!from) return null;
1306
- this.expect("keyword", "to");
1307
- const to = this.expectIdentifier();
1308
- if (!to) return null;
1309
- let dataType = "any";
1310
- if (this.check("keyword", "as")) {
1311
- this.advance();
1312
- const typeStr = this.currentToken();
1313
- if (typeStr?.type === "string" || typeStr?.type === "identifier") {
1314
- dataType = typeStr.value;
1315
- this.advance();
1316
- }
1317
- }
1318
- return {
1319
- type: "connection",
1320
- from,
1321
- to,
1322
- dataType,
1323
- bidirectional: false
1324
- };
1325
- }
1326
- /**
1327
- * Parse scale block: scale <magnitude> { body }
1328
- */
1329
- parseScale() {
1330
- this.expect("keyword", "scale");
1331
- const magnitude = this.expectIdentifier() || "standard";
1332
- const multipliers = {
1333
- galactic: 1e6,
1334
- macro: 1e3,
1335
- standard: 1,
1336
- micro: 1e-3,
1337
- atomic: 1e-6
1338
- };
1339
- const body = [];
1340
- if (this.check("punctuation", "{")) {
1341
- this.advance();
1342
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1343
- this.skipNewlines();
1344
- const node = this.parseDeclaration();
1345
- if (node) body.push(node);
1346
- this.skipNewlines();
1347
- }
1348
- this.expect("punctuation", "}");
1349
- }
1350
- return {
1351
- type: "scale",
1352
- magnitude,
1353
- multiplier: multipliers[magnitude] || 1,
1354
- body,
1355
- position: [0, 0, 0]
1356
- };
1357
- }
1358
- /**
1359
- * Parse focus block: focus <target> { body }
1360
- */
1361
- parseFocus() {
1362
- this.expect("keyword", "focus");
1363
- const target = this.expectIdentifier() || "origin";
1364
- const body = [];
1365
- if (this.check("punctuation", "{")) {
1366
- this.advance();
1367
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1368
- this.skipNewlines();
1369
- const node = this.parseDeclaration();
1370
- if (node) body.push(node);
1371
- this.skipNewlines();
1372
- }
1373
- this.expect("punctuation", "}");
1374
- }
1375
- return {
1376
- type: "focus",
1377
- target,
1378
- body,
1379
- position: [0, 0, 0]
1380
- };
1381
- }
1382
- /**
1383
- * Parse environment declaration
1384
- * Supports: environment { ... } or environment #id { ... }
1385
- */
1386
- parseEnvironment() {
1387
- this.expect("keyword", "environment");
1388
- const settings = {};
1389
- let envId;
1390
- if (this.check("punctuation", "#")) {
1391
- this.advance();
1392
- envId = this.expectIdentifier() || void 0;
1393
- }
1394
- if (this.check("punctuation", "{")) {
1395
- this.advance();
1396
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1397
- this.skipNewlines();
1398
- if (this.check("punctuation", "}")) break;
1399
- if (this.check("punctuation", "@")) {
1400
- const directive = this.parseDirective();
1401
- if (directive) {
1402
- const dir = directive;
1403
- settings[`@${directive.type}`] = dir.args || dir.config || [];
1404
- }
1405
- continue;
1406
- }
1407
- const prop = this.parseProperty();
1408
- if (prop) {
1409
- settings[prop.key] = prop.value;
1410
- }
1411
- this.skipNewlines();
1412
- }
1413
- this.expect("punctuation", "}");
1414
- } else {
1415
- while (this.position < this.tokens.length && this.currentToken()?.type !== "newline" && !this.check("punctuation", "}")) {
1416
- const key = this.expectIdentifier();
1417
- if (!key) break;
1418
- settings[key] = this.parseLiteral();
1419
- }
1420
- }
1421
- if (envId) {
1422
- settings["id"] = envId;
1423
- }
1424
- return {
1425
- type: "environment",
1426
- settings
1427
- };
1428
- }
1429
- /**
1430
- * Parse primitive 3D shape declaration
1431
- * Supports: cylinder #id { ... }, sphere "name" { ... }, etc.
1432
- */
1433
- parsePrimitive() {
1434
- const startToken = this.currentToken();
1435
- const primitiveType = startToken?.value || "object";
1436
- this.advance();
1437
- let name = "";
1438
- let elementId;
1439
- if (this.check("punctuation", "#")) {
1440
- this.advance();
1441
- elementId = this.expectIdentifier() || void 0;
1442
- name = elementId || `${primitiveType}_${Date.now()}`;
1443
- } else {
1444
- name = this.expectName() || `${primitiveType}_${Date.now()}`;
1445
- }
1446
- let template;
1447
- if (this.check("keyword", "using")) {
1448
- this.advance();
1449
- template = this.expectName() || void 0;
1450
- }
1451
- const properties = {};
1452
- const directives = [];
1453
- let position;
1454
- if (this.check("punctuation", "{")) {
1455
- this.advance();
1456
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1457
- this.skipNewlines();
1458
- if (this.check("punctuation", "}")) break;
1459
- if (this.check("punctuation", ",") || this.check("punctuation", ";")) {
1460
- this.advance();
1461
- continue;
1462
- }
1463
- const token = this.currentToken();
1464
- if (token?.type === "punctuation" && token.value === "@") {
1465
- const directive = this.parseDirective();
1466
- if (directive) directives.push(directive);
1467
- } else {
1468
- const prop = this.parseProperty();
1469
- if (prop) {
1470
- if (prop.key === "position" || prop.key === "at") {
1471
- position = this.parsePosition(prop.value);
1472
- } else {
1473
- properties[prop.key] = prop.value;
1474
- }
1475
- } else {
1476
- this.advance();
1477
- }
1478
- }
1479
- this.skipNewlines();
1480
- }
1481
- this.expect("punctuation", "}");
1482
- }
1483
- properties["_primitiveType"] = primitiveType;
1484
- if (elementId) {
1485
- properties["id"] = elementId;
1486
- }
1487
- return {
1488
- type: "orb",
1489
- name,
1490
- position: position || { x: 0, y: 0, z: 0 },
1491
- hologram: {
1492
- shape: primitiveType,
1493
- color: "#00d4ff",
1494
- size: 1,
1495
- glow: false,
1496
- interactive: true
1497
- },
1498
- properties,
1499
- directives,
1500
- template,
1501
- methods: [],
1502
- children: [],
1503
- line: startToken?.line || 0
1504
- };
1505
- }
1506
- /**
1507
- * Parse zone declaration: zone "Name" { ... } or zone #id { ... }
1508
- */
1509
- parseZone() {
1510
- this.expect("keyword", "zone");
1511
- let name = "";
1512
- let zoneId;
1513
- if (this.check("punctuation", "#")) {
1514
- this.advance();
1515
- zoneId = this.expectIdentifier() || void 0;
1516
- name = zoneId || `zone_${Date.now()}`;
1517
- } else {
1518
- name = this.expectName() || `zone_${Date.now()}`;
1519
- }
1520
- const properties = {};
1521
- let position;
1522
- if (this.check("punctuation", "{")) {
1523
- this.advance();
1524
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1525
- this.skipNewlines();
1526
- if (this.check("punctuation", "}")) break;
1527
- const prop = this.parseProperty();
1528
- if (prop) {
1529
- if (prop.key === "position") {
1530
- position = this.parsePosition(prop.value);
1531
- properties["position"] = prop.value;
1532
- } else {
1533
- properties[prop.key] = prop.value;
1534
- }
1535
- } else {
1536
- const token = this.currentToken();
1537
- this.addError(
1538
- this.createError(
1539
- "HS004",
1540
- `Unexpected token in zone: ${token?.type || "unknown"}`,
1541
- token
1542
- )
1543
- );
1544
- this.advance();
1545
- }
1546
- this.skipNewlines();
1547
- }
1548
- this.expect("punctuation", "}");
1549
- }
1550
- return {
1551
- type: "zone",
1552
- name,
1553
- id: zoneId,
1554
- position,
1555
- events: {},
1556
- // Events are stored in properties for now
1557
- properties
1558
- };
1559
- }
1560
- /**
1561
- * Parse composition block
1562
- */
1563
- parseComposition() {
1564
- this.expect("keyword", "composition");
1565
- const name = this.expectName() || "unnamed";
1566
- const children = [];
1567
- if (this.check("punctuation", "{")) {
1568
- this.advance();
1569
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1570
- this.skipNewlines();
1571
- const node = this.parseDeclaration();
1572
- if (node) children.push(node);
1573
- this.skipNewlines();
1574
- }
1575
- this.expect("punctuation", "}");
1576
- }
1577
- return {
1578
- type: "composition",
1579
- name,
1580
- children
1581
- };
1582
- }
1583
- /**
1584
- * Parse template declaration
1585
- */
1586
- parseTemplate() {
1587
- this.expect("keyword", "template");
1588
- const name = this.expectName() || "template";
1589
- let version;
1590
- const params = [];
1591
- if (this.check("punctuation", "(")) {
1592
- this.advance();
1593
- while (!this.check("punctuation", ")") && this.position < this.tokens.length) {
1594
- const p = this.expectIdentifier();
1595
- if (p) params.push(p);
1596
- if (this.check("punctuation", ",")) this.advance();
1597
- }
1598
- this.expect("punctuation", ")");
1599
- }
1600
- const children = [];
1601
- const migrations = [];
1602
- const directives = [];
1603
- const properties = {};
1604
- if (this.check("punctuation", "{")) {
1605
- this.advance();
1606
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1607
- this.skipNewlines();
1608
- const token = this.currentToken();
1609
- if (token?.type === "punctuation" && token.value === "@") {
1610
- const startPos2 = this.position;
1611
- this.advance();
1612
- const dirName = this.expectIdentifier();
1613
- if (dirName === "version") {
1614
- this.expect("punctuation", "(");
1615
- const vStr = this.currentToken();
1616
- if (vStr?.type === "number") {
1617
- version = parseInt(vStr.value, 10);
1618
- this.advance();
1619
- }
1620
- this.expect("punctuation", ")");
1621
- directives.push({ type: "version", version });
1622
- this.skipNewlines();
1623
- continue;
1624
- } else {
1625
- this.position = startPos2;
1626
- const dir = this.parseDirective();
1627
- if (dir) directives.push(dir);
1628
- this.skipNewlines();
1629
- continue;
1630
- }
1631
- }
1632
- const startPos = this.position;
1633
- const errorCount = this.errors.length;
1634
- const node = this.parseDeclaration();
1635
- if (node && node.type !== "expression") {
1636
- if (node.type === "migration") {
1637
- migrations.push(node);
1638
- } else {
1639
- children.push(node);
1640
- }
1641
- this.skipNewlines();
1642
- continue;
1643
- }
1644
- this.position = startPos;
1645
- this.errors.length = errorCount;
1646
- const prop = this.parseProperty();
1647
- if (prop) {
1648
- properties[prop.key] = prop.value;
1649
- this.skipNewlines();
1650
- continue;
1651
- }
1652
- this.advance();
1653
- }
1654
- this.expect("punctuation", "}");
1655
- }
1656
- return {
1657
- type: "template",
1658
- name,
1659
- parameters: params,
1660
- children,
1661
- properties,
1662
- directives,
1663
- version,
1664
- migrations
1665
- };
1666
- }
1667
- /**
1668
- * Parse system declaration: system Name { state {}, on_start {}, action name() {}, ui {} }
1669
- *
1670
- * Systems are named trait+logic containers that auto-initialize within a composition.
1671
- * They encapsulate state, lifecycle hooks, actions, and optional UI.
1672
- *
1673
- * Syntax:
1674
- * system TutorialSystem {
1675
- * state { currentStep: 0, completed: false }
1676
- * on_start { ... }
1677
- * on_update { ... }
1678
- * action next() { ... }
1679
- * action skip() { ... }
1680
- * ui { ... }
1681
- * }
1682
- */
1683
- parseSystem() {
1684
- this.expect("keyword", "system");
1685
- const name = this.expectName() || "unnamed_system";
1686
- const state = {};
1687
- const actions = [];
1688
- const hooks = [];
1689
- const directives = [];
1690
- const properties = {};
1691
- const children = [];
1692
- const uiNodes = [];
1693
- if (this.check("punctuation", "{")) {
1694
- this.advance();
1695
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1696
- this.skipNewlines();
1697
- if (this.check("punctuation", "}")) break;
1698
- const token = this.currentToken();
1699
- if (token?.type === "punctuation" && token.value === "@") {
1700
- const directive = this.parseDirective();
1701
- if (directive) directives.push(directive);
1702
- this.skipNewlines();
1703
- continue;
1704
- }
1705
- if (token?.type === "keyword" || token?.type === "identifier") {
1706
- const val = token.value.toLowerCase();
1707
- if (val === "state") {
1708
- this.advance();
1709
- if (this.check("punctuation", "{")) {
1710
- const stateObj = this.parseObject();
1711
- Object.assign(state, stateObj);
1712
- }
1713
- this.skipNewlines();
1714
- continue;
1715
- }
1716
- if (val === "action") {
1717
- this.advance();
1718
- const actionName = this.expectIdentifier();
1719
- if (actionName) {
1720
- const params = [];
1721
- if (this.check("punctuation", "(")) {
1722
- this.advance();
1723
- while (!this.check("punctuation", ")") && this.position < this.tokens.length) {
1724
- const p = this.expectIdentifier();
1725
- if (p) params.push(p);
1726
- if (this.check("punctuation", ",")) this.advance();
1727
- }
1728
- this.expect("punctuation", ")");
1729
- }
1730
- const body = this.parseBlockBody();
1731
- actions.push({ name: actionName, params, body });
1732
- }
1733
- this.skipNewlines();
1734
- continue;
1735
- }
1736
- if (val.startsWith("on_")) {
1737
- this.advance();
1738
- const body = this.parseBlockBody();
1739
- hooks.push({ name: val, body });
1740
- this.skipNewlines();
1741
- continue;
1742
- }
1743
- if (val === "ui") {
1744
- this.advance();
1745
- if (this.check("punctuation", "{")) {
1746
- this.advance();
1747
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1748
- this.skipNewlines();
1749
- const node2 = this.parseDeclaration();
1750
- if (node2) uiNodes.push(node2);
1751
- this.skipNewlines();
1752
- }
1753
- this.expect("punctuation", "}");
1754
- }
1755
- this.skipNewlines();
1756
- continue;
1757
- }
1758
- const startPos = this.position;
1759
- const errorCount = this.errors.length;
1760
- const node = this.parseDeclaration();
1761
- if (node && node.type !== "expression") {
1762
- children.push(node);
1763
- this.skipNewlines();
1764
- continue;
1765
- }
1766
- this.position = startPos;
1767
- this.errors.length = errorCount;
1768
- const prop = this.parseProperty();
1769
- if (prop) {
1770
- properties[prop.key] = prop.value;
1771
- this.skipNewlines();
1772
- continue;
1773
- }
1774
- }
1775
- this.advance();
1776
- }
1777
- this.expect("punctuation", "}");
1778
- }
1779
- return {
1780
- type: "system",
1781
- id: name,
1782
- properties,
1783
- state: Object.keys(state).length > 0 ? state : void 0,
1784
- actions: actions.length > 0 ? actions : void 0,
1785
- hooks: hooks.length > 0 ? hooks : void 0,
1786
- ui: uiNodes.length > 0 ? uiNodes : void 0,
1787
- children: children.length > 0 ? children : void 0,
1788
- directives: directives.length > 0 ? directives : void 0
1789
- };
1790
- }
1791
- /**
1792
- * Parse component declaration: component Name { props {}, state {}, ui {}, action name() {} }
1793
- *
1794
- * Components are UI-focused declarations with props, state, and render/ui blocks.
1795
- *
1796
- * Syntax:
1797
- * component MobileControls {
1798
- * props { visible: true, joystickSize: 120 }
1799
- * state { isMoving: false }
1800
- * ui { ... }
1801
- * }
1802
- */
1803
- parseComponent() {
1804
- this.expect("keyword", "component");
1805
- const name = this.expectName() || "unnamed_component";
1806
- const props = {};
1807
- const state = {};
1808
- const actions = [];
1809
- const hooks = [];
1810
- const directives = [];
1811
- const properties = {};
1812
- const children = [];
1813
- const uiNodes = [];
1814
- if (this.check("punctuation", "{")) {
1815
- this.advance();
1816
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1817
- this.skipNewlines();
1818
- if (this.check("punctuation", "}")) break;
1819
- const token = this.currentToken();
1820
- if (token?.type === "punctuation" && token.value === "@") {
1821
- const directive = this.parseDirective();
1822
- if (directive) directives.push(directive);
1823
- this.skipNewlines();
1824
- continue;
1825
- }
1826
- if (token?.type === "keyword" || token?.type === "identifier") {
1827
- const val = token.value.toLowerCase();
1828
- if (val === "props") {
1829
- this.advance();
1830
- if (this.check("punctuation", "{")) {
1831
- const propsObj = this.parseObject();
1832
- Object.assign(props, propsObj);
1833
- }
1834
- this.skipNewlines();
1835
- continue;
1836
- }
1837
- if (val === "state") {
1838
- this.advance();
1839
- if (this.check("punctuation", "{")) {
1840
- const stateObj = this.parseObject();
1841
- Object.assign(state, stateObj);
1842
- }
1843
- this.skipNewlines();
1844
- continue;
1845
- }
1846
- if (val === "action") {
1847
- this.advance();
1848
- const actionName = this.expectIdentifier();
1849
- if (actionName) {
1850
- const params = [];
1851
- if (this.check("punctuation", "(")) {
1852
- this.advance();
1853
- while (!this.check("punctuation", ")") && this.position < this.tokens.length) {
1854
- const p = this.expectIdentifier();
1855
- if (p) params.push(p);
1856
- if (this.check("punctuation", ",")) this.advance();
1857
- }
1858
- this.expect("punctuation", ")");
1859
- }
1860
- const body = this.parseBlockBody();
1861
- actions.push({ name: actionName, params, body });
1862
- }
1863
- this.skipNewlines();
1864
- continue;
1865
- }
1866
- if (val.startsWith("on_")) {
1867
- this.advance();
1868
- const body = this.parseBlockBody();
1869
- hooks.push({ name: val, body });
1870
- this.skipNewlines();
1871
- continue;
1872
- }
1873
- if (val === "ui") {
1874
- this.advance();
1875
- if (this.check("punctuation", "{")) {
1876
- this.advance();
1877
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
1878
- this.skipNewlines();
1879
- const node2 = this.parseDeclaration();
1880
- if (node2) uiNodes.push(node2);
1881
- this.skipNewlines();
1882
- }
1883
- this.expect("punctuation", "}");
1884
- }
1885
- this.skipNewlines();
1886
- continue;
1887
- }
1888
- const startPos = this.position;
1889
- const errorCount = this.errors.length;
1890
- const node = this.parseDeclaration();
1891
- if (node && node.type !== "expression") {
1892
- children.push(node);
1893
- this.skipNewlines();
1894
- continue;
1895
- }
1896
- this.position = startPos;
1897
- this.errors.length = errorCount;
1898
- const prop = this.parseProperty();
1899
- if (prop) {
1900
- properties[prop.key] = prop.value;
1901
- this.skipNewlines();
1902
- continue;
1903
- }
1904
- }
1905
- this.advance();
1906
- }
1907
- this.expect("punctuation", "}");
1908
- }
1909
- return {
1910
- type: "component",
1911
- name,
1912
- props: Object.keys(props).length > 0 ? props : void 0,
1913
- state: Object.keys(state).length > 0 ? state : void 0,
1914
- actions: actions.length > 0 ? actions : void 0,
1915
- hooks: hooks.length > 0 ? hooks : void 0,
1916
- ui: uiNodes.length > 0 ? uiNodes : void 0,
1917
- children: children.length > 0 ? children : void 0,
1918
- directives: directives.length > 0 ? directives : void 0,
1919
- properties: Object.keys(properties).length > 0 ? properties : void 0
1920
- };
1921
- }
1922
- /**
1923
- * Parse a block body { ... } — captures everything between braces as a string.
1924
- * Used for action bodies and lifecycle hooks where we capture the raw body.
1925
- */
1926
- parseBlockBody() {
1927
- let body = "";
1928
- if (this.check("punctuation", "{")) {
1929
- this.advance();
1930
- let braceDepth = 1;
1931
- while (braceDepth > 0 && this.position < this.tokens.length) {
1932
- const t = this.advance();
1933
- if (t.value === "{") braceDepth++;
1934
- if (t.value === "}") braceDepth--;
1935
- if (braceDepth > 0) {
1936
- const val = t.type === "string" ? JSON.stringify(t.value) : t.value;
1937
- body += val + " ";
1938
- }
1939
- }
1940
- }
1941
- return body.trim();
1942
- }
1943
- /**
1944
- * Parse migration block: migrate from(n) { body }
1945
- */
1946
- parseMigration() {
1947
- this.expect("keyword", "migrate");
1948
- this.expect("keyword", "from");
1949
- this.expect("punctuation", "(");
1950
- let fromVersion = 0;
1951
- const vStr = this.currentToken();
1952
- if (vStr?.type === "number") {
1953
- fromVersion = parseInt(vStr.value, 10);
1954
- this.advance();
1955
- }
1956
- this.expect("punctuation", ")");
1957
- let body = "";
1958
- if (this.check("punctuation", "{")) {
1959
- this.advance();
1960
- let braceDepth = 1;
1961
- this.position;
1962
- while (braceDepth > 0 && this.position < this.tokens.length) {
1963
- const t = this.advance();
1964
- if (t.value === "{") braceDepth++;
1965
- if (t.value === "}") braceDepth--;
1966
- if (braceDepth > 0) {
1967
- const val = t.type === "string" ? JSON.stringify(t.value) : t.value;
1968
- body += val + " ";
1969
- }
1970
- }
1971
- }
1972
- return {
1973
- type: "migration",
1974
- fromVersion,
1975
- body: body.trim(),
1976
- position: [0, 0, 0]
1977
- };
1978
- }
1979
- /**
1980
- * Parse gate (conditional)
1981
- */
1982
- parseGate() {
1983
- const isIf = this.check("keyword", "if");
1984
- if (isIf) {
1985
- this.advance();
1986
- } else {
1987
- this.expect("keyword", "gate");
1988
- this.expectIdentifier();
1989
- }
1990
- let condition = "";
1991
- if (this.check("punctuation", "(")) {
1992
- this.advance();
1993
- while (!this.check("punctuation", ")") && this.position < this.tokens.length) {
1994
- const token = this.currentToken();
1995
- if (token) condition += token.value + " ";
1996
- this.advance();
1997
- }
1998
- this.expect("punctuation", ")");
1999
- }
2000
- const truePath = [];
2001
- if (this.check("punctuation", "{")) {
2002
- this.advance();
2003
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
2004
- const node = this.parseDeclaration();
2005
- if (node) truePath.push(node);
2006
- else this.advance();
2007
- }
2008
- this.expect("punctuation", "}");
2009
- }
2010
- const falsePath = [];
2011
- if (this.check("keyword", "else")) {
2012
- this.advance();
2013
- if (this.check("punctuation", "{")) {
2014
- this.advance();
2015
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
2016
- const node = this.parseDeclaration();
2017
- if (node) falsePath.push(node);
2018
- else this.advance();
2019
- }
2020
- this.expect("punctuation", "}");
2021
- } else {
2022
- const node = this.parseDeclaration();
2023
- if (node) falsePath.push(node);
2024
- }
2025
- }
2026
- return {
2027
- type: "gate",
2028
- condition: this.parseConditionExpression(condition.trim()),
2029
- truePath,
2030
- falsePath,
2031
- position: [0, 0, 0],
2032
- hologram: { shape: "pyramid", color: "#4ecdc4", size: 1, glow: true, interactive: true }
2033
- };
2034
- }
2035
- /**
2036
- * Parse return statement
2037
- */
2038
- parseReturn() {
2039
- this.expect("keyword", "return");
2040
- let expression = "";
2041
- let parenDepth = 0;
2042
- let braceDepth = 0;
2043
- let bracketDepth = 0;
2044
- while (this.position < this.tokens.length) {
2045
- const t = this.currentToken();
2046
- if (!t) break;
2047
- if (t.type === "newline" && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) break;
2048
- if (t.type === "punctuation" && t.value === ";" && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0)
2049
- break;
2050
- if (t.type === "punctuation") {
2051
- if (t.value === "(") parenDepth++;
2052
- else if (t.value === ")") parenDepth--;
2053
- else if (t.value === "{") braceDepth++;
2054
- else if (t.value === "}") braceDepth--;
2055
- else if (t.value === "[") bracketDepth++;
2056
- else if (t.value === "]") bracketDepth--;
2057
- }
2058
- expression += t.value + " ";
2059
- this.advance();
2060
- }
2061
- return {
2062
- type: "return",
2063
- value: expression.trim(),
2064
- // Use 'value' to match runtime's executeReturn
2065
- position: [0, 0, 0]
2066
- };
2067
- }
2068
- /**
2069
- * Parse generic expression statement (e.g. function call or assignment)
2070
- */
2071
- parseExpressionStatement() {
2072
- let expression = "";
2073
- let parenDepth = 0;
2074
- let braceDepth = 0;
2075
- let bracketDepth = 0;
2076
- while (this.position < this.tokens.length) {
2077
- const t = this.currentToken();
2078
- if (!t) break;
2079
- if (t.type === "newline" && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) break;
2080
- if (t.type === "punctuation" && t.value === ";" && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0)
2081
- break;
2082
- if (t.type === "punctuation") {
2083
- if (t.value === "(") parenDepth++;
2084
- else if (t.value === ")") parenDepth--;
2085
- else if (t.value === "{") braceDepth++;
2086
- else if (t.value === "}") braceDepth--;
2087
- else if (t.value === "[") bracketDepth++;
2088
- else if (t.value === "]") bracketDepth--;
2089
- }
2090
- expression += t.value + " ";
2091
- this.advance();
2092
- }
2093
- if (expression.trim().length === 0) {
2094
- this.advance();
2095
- return null;
2096
- }
2097
- return {
2098
- type: "expression-statement",
2099
- expression: expression.trim(),
2100
- position: [0, 0, 0]
2101
- };
2102
- }
2103
- /**
2104
- * Parse stream
2105
- */
2106
- parseStream() {
2107
- this.expect("keyword", "stream");
2108
- const name = this.expectIdentifier();
2109
- if (!name) return null;
2110
- let source = "unknown";
2111
- if (this.check("keyword", "from")) {
2112
- this.advance();
2113
- source = this.expectIdentifier() || "unknown";
2114
- }
2115
- if (this.check("punctuation", "{")) {
2116
- this.advance();
2117
- let depth = 1;
2118
- while (depth > 0 && this.position < this.tokens.length) {
2119
- if (this.check("punctuation", "{")) depth++;
2120
- if (this.check("punctuation", "}")) depth--;
2121
- this.advance();
2122
- }
2123
- }
2124
- return {
2125
- type: "stream",
2126
- name,
2127
- source,
2128
- transformations: [],
2129
- position: [0, 0, 0],
2130
- hologram: { shape: "cylinder", color: "#45b7d1", size: 2, glow: true, interactive: true }
2131
- };
2132
- }
2133
- /**
2134
- * Parse nexus (multi-agent hub)
2135
- */
2136
- parseNexus() {
2137
- this.expect("keyword", "nexus");
2138
- const name = this.expectIdentifier();
2139
- if (!name) return null;
2140
- if (this.check("punctuation", "{")) {
2141
- this.advance();
2142
- let depth = 1;
2143
- while (depth > 0 && this.position < this.tokens.length) {
2144
- if (this.check("punctuation", "{")) depth++;
2145
- if (this.check("punctuation", "}")) depth--;
2146
- this.advance();
2147
- }
2148
- }
2149
- return {
2150
- type: "nexus",
2151
- position: [0, 0, 0],
2152
- hologram: { shape: "sphere", color: "#9b59b6", size: 3, glow: true, interactive: true }
2153
- };
2154
- }
2155
- /**
2156
- * Parse building (class-like)
2157
- */
2158
- parseBuilding() {
2159
- this.expect("keyword", "building");
2160
- const name = this.expectName();
2161
- if (!name) return null;
2162
- if (this.check("punctuation", "{")) {
2163
- this.advance();
2164
- let depth = 1;
2165
- while (depth > 0 && this.position < this.tokens.length) {
2166
- if (this.check("punctuation", "{")) depth++;
2167
- if (this.check("punctuation", "}")) depth--;
2168
- this.advance();
2169
- }
2170
- }
2171
- return {
2172
- type: "building",
2173
- position: [0, 0, 0],
2174
- hologram: { shape: "cube", color: "#e74c3c", size: 4, glow: true, interactive: true }
2175
- };
2176
- }
2177
- /**
2178
- * Parse a literal value (string, number, boolean, array, or object)
2179
- */
2180
- parseLiteral() {
2181
- const token = this.currentToken();
2182
- if (!token) return null;
2183
- if (token.type === "string") {
2184
- this.advance();
2185
- return token.value;
2186
- }
2187
- if (token.type === "number") {
2188
- this.advance();
2189
- return parseFloat(token.value);
2190
- }
2191
- if (token.type === "identifier") {
2192
- const val = token.value.toLowerCase();
2193
- this.advance();
2194
- if (val === "true") return true;
2195
- if (val === "false") return false;
2196
- if (val === "null") return null;
2197
- return token.value;
2198
- }
2199
- if (this.check("punctuation", "[")) {
2200
- return this.parseArray();
2201
- }
2202
- if (this.check("punctuation", "{")) {
2203
- return this.parseObject();
2204
- }
2205
- this.advance();
2206
- return token.value;
2207
- }
2208
- /**
2209
- * Parse a property (key: value)
2210
- */
2211
- parseProperty() {
2212
- const key = this.expectIdentifier();
2213
- if (!key) return null;
2214
- if (!this.check("punctuation", ":")) {
2215
- return { key, value: true };
2216
- }
2217
- this.advance();
2218
- const value = this.parseLiteral();
2219
- return { key, value };
2220
- }
2221
- /**
2222
- * Parse array [...]
2223
- */
2224
- parseArray() {
2225
- const arr = [];
2226
- this.expect("punctuation", "[");
2227
- while (!this.check("punctuation", "]") && this.position < this.tokens.length) {
2228
- const token = this.currentToken();
2229
- if (token?.type === "string" || token?.type === "number" || token?.type === "identifier") {
2230
- if (token.type === "number") {
2231
- arr.push(parseFloat(token.value));
2232
- } else {
2233
- arr.push(token.value);
2234
- }
2235
- this.advance();
2236
- } else if (this.check("punctuation", ",")) {
2237
- this.advance();
2238
- } else {
2239
- this.addError(
2240
- this.createError("HS004", `Unexpected token in array: ${token?.type || "unknown"}`, token)
2241
- );
2242
- this.advance();
2243
- }
2244
- }
2245
- this.expect("punctuation", "]");
2246
- return arr;
2247
- }
2248
- /**
2249
- * Parse object {...}
2250
- */
2251
- parseObject() {
2252
- const obj = {};
2253
- this.expect("punctuation", "{");
2254
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
2255
- this.skipNewlines();
2256
- if (this.check("punctuation", "}")) break;
2257
- const prop = this.parseProperty();
2258
- if (prop) {
2259
- obj[prop.key] = prop.value;
2260
- } else {
2261
- const token = this.currentToken();
2262
- this.addError(
2263
- this.createError(
2264
- "HS004",
2265
- `Unexpected token in object: ${token?.type || "unknown"}`,
2266
- token
2267
- )
2268
- );
2269
- this.advance();
2270
- }
2271
- this.skipNewlines();
2272
- if (this.check("punctuation", ",")) {
2273
- this.advance();
2274
- }
2275
- }
2276
- this.expect("punctuation", "}");
2277
- return obj;
2278
- }
2279
- /**
2280
- * Parse position from value
2281
- */
2282
- parsePosition(value) {
2283
- if (Array.isArray(value)) {
2284
- return {
2285
- x: Number(value[0]) || 0,
2286
- y: Number(value[1]) || 0,
2287
- z: Number(value[2]) || 0
2288
- };
2289
- }
2290
- if (typeof value === "object" && value !== null) {
2291
- const v = value;
2292
- return {
2293
- x: Number(v.x) || 0,
2294
- y: Number(v.y) || 0,
2295
- z: Number(v.z) || 0
2296
- };
2297
- }
2298
- return { x: 0, y: 0, z: 0 };
2299
- }
2300
- // Helper methods
2301
- currentToken() {
2302
- return this.tokens[this.position];
2303
- }
2304
- advance() {
2305
- return this.tokens[this.position++];
2306
- }
2307
- check(type, value) {
2308
- const token = this.currentToken();
2309
- if (!token) return false;
2310
- if (token.type !== type) return false;
2311
- if (value !== void 0 && token.value.toLowerCase() !== value.toLowerCase()) return false;
2312
- return true;
2313
- }
2314
- expect(type, value) {
2315
- if (this.check(type, value)) {
2316
- this.advance();
2317
- return true;
2318
- }
2319
- const token = this.currentToken();
2320
- let suggestion;
2321
- if (type === "keyword" && value && token?.type === "identifier") {
2322
- const similar = this.findSimilarKeyword(token.value);
2323
- if (similar) {
2324
- suggestion = `Did you mean '${similar}'?`;
2325
- }
2326
- }
2327
- this.addError(
2328
- this.createError(
2329
- type === "keyword" ? "HS001" : type === "identifier" ? "HS002" : "HS003",
2330
- `Expected ${type}${value ? ` '${value}'` : ""}, got ${token?.type || "EOF"} '${token?.value || ""}'`,
2331
- token,
2332
- suggestion
2333
- )
2334
- );
2335
- return false;
2336
- }
2337
- expectIdentifier() {
2338
- const token = this.currentToken();
2339
- if (token && (token.type === "identifier" || token.type === "keyword")) {
2340
- this.advance();
2341
- return token.value;
2342
- }
2343
- this.addError(
2344
- this.createError(
2345
- "HS002",
2346
- `Expected identifier, got ${token?.type || "EOF"}`,
2347
- token,
2348
- token?.type === "number" ? "Identifiers cannot start with a number" : void 0
2349
- )
2350
- );
2351
- return null;
2352
- }
2353
- /**
2354
- * Expect an identifier OR a string literal for named declarations
2355
- * Allows both: composition MyScene { } and composition "MyScene" { }
2356
- */
2357
- expectName() {
2358
- const token = this.currentToken();
2359
- if (token?.type === "identifier" || token?.type === "keyword") {
2360
- this.advance();
2361
- return token.value;
2362
- }
2363
- if (token?.type === "string") {
2364
- this.advance();
2365
- const val = token.value;
2366
- if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
2367
- return val.slice(1, -1);
2368
- }
2369
- return val;
2370
- }
2371
- this.addError(
2372
- this.createError(
2373
- "HS002",
2374
- `Expected name (identifier or string), got ${token?.type || "EOF"}`,
2375
- token
2376
- )
2377
- );
2378
- return null;
2379
- }
2380
- /**
2381
- * Parse animate command: animate target property: "..." from: 0 to: 1 duration: 1000
2382
- */
2383
- parseAnimate() {
2384
- this.expect("keyword", "animate");
2385
- const target = this.expectIdentifier();
2386
- if (!target) return null;
2387
- const properties = {};
2388
- while (this.position < this.tokens.length) {
2389
- this.skipNewlines();
2390
- const t = this.currentToken();
2391
- if (!t || t.type === "newline" || t.type === "keyword" && this.keywordSet.has(t.value.toLowerCase()))
2392
- break;
2393
- const prop = this.parseProperty();
2394
- if (prop) {
2395
- properties[prop.key] = prop.value;
2396
- } else {
2397
- break;
2398
- }
2399
- }
2400
- return {
2401
- type: "expression-statement",
2402
- expression: `animate("${target}", ${JSON.stringify(properties)})`,
2403
- position: [0, 0, 0]
2404
- };
2405
- }
2406
- /**
2407
- * Parse modify command: modify target { prop: value }
2408
- */
2409
- parseModify() {
2410
- this.expect("keyword", "modify");
2411
- const target = this.expectIdentifier();
2412
- if (!target) return null;
2413
- const properties = {};
2414
- if (this.check("punctuation", "{")) {
2415
- this.advance();
2416
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
2417
- this.skipNewlines();
2418
- if (this.check("punctuation", "}")) break;
2419
- const prop = this.parseProperty();
2420
- if (prop) {
2421
- properties[prop.key] = prop.value;
2422
- }
2423
- this.skipNewlines();
2424
- }
2425
- this.expect("punctuation", "}");
2426
- }
2427
- return {
2428
- type: "expression-statement",
2429
- expression: `modify("${target}", ${JSON.stringify(properties)})`,
2430
- position: [0, 0, 0]
2431
- };
2432
- }
2433
- /**
2434
- * Parse UI Element: ui2d dashboard#id { ... }
2435
- */
2436
- parseUIElement() {
2437
- const typeToken = this.currentToken();
2438
- if (!typeToken) return null;
2439
- const elementType = typeToken.value;
2440
- this.advance();
2441
- let elementId = `${elementType}_${Date.now()}`;
2442
- const token = this.currentToken();
2443
- if (token?.type === "punctuation" && token.value === "#") {
2444
- this.advance();
2445
- const idToken = this.currentToken();
2446
- if (idToken) {
2447
- elementId = idToken.value;
2448
- this.advance();
2449
- }
2450
- } else if (token?.type === "identifier" && token.value.startsWith("#")) {
2451
- elementId = token.value.slice(1) || elementId;
2452
- this.advance();
2453
- }
2454
- const properties = {};
2455
- if (this.check("punctuation", "{")) {
2456
- this.advance();
2457
- while (!this.check("punctuation", "}") && this.position < this.tokens.length) {
2458
- this.skipNewlines();
2459
- if (this.check("punctuation", "}")) break;
2460
- const prop = this.parseProperty();
2461
- if (prop) {
2462
- properties[prop.key] = prop.value;
2463
- }
2464
- this.skipNewlines();
2465
- }
2466
- this.expect("punctuation", "}");
2467
- }
2468
- return {
2469
- type: "ui2d",
2470
- name: elementType,
2471
- properties: { id: elementId, ...properties },
2472
- position: [0, 0, 0]
2473
- };
2474
- }
2475
- /**
2476
- * Parse settings command: settings
2477
- */
2478
- parseSettings() {
2479
- this.expect("keyword", "settings");
2480
- return {
2481
- type: "expression-statement",
2482
- expression: "showSettings()",
2483
- position: [0, 0, 0]
2484
- };
2485
- }
2486
- parseChat() {
2487
- this.expect("keyword", "chat");
2488
- return {
2489
- type: "expression-statement",
2490
- expression: "openChat()",
2491
- position: [0, 0, 0]
2492
- };
2493
- }
2494
- /**
2495
- * Parse a condition string into a structured TypeGuardExpression if applicable,
2496
- * otherwise returns the string as-is.
2497
- */
2498
- parseConditionExpression(condition) {
2499
- const isPattern = /^([a-zA-Z_][a-zA-Z0-9_]*)\s+is\s+["']([^"']+)["']$/;
2500
- const match = condition.match(isPattern);
2501
- if (match) {
2502
- return {
2503
- type: "type-guard",
2504
- subject: match[1],
2505
- guardType: match[2],
2506
- line: 0,
2507
- // Simplified for now
2508
- column: 0
2509
- };
2510
- }
2511
- return condition;
2512
- }
2513
- skipNewlines() {
2514
- while (this.currentToken()?.type === "newline") {
2515
- this.advance();
2516
- }
2517
- }
2518
- };
2519
-
2520
- export { ERROR_CODES, HoloScriptCodeParser, ParserPools };
2521
- //# sourceMappingURL=chunk-BU7VWW2K.js.map
2522
- //# sourceMappingURL=chunk-BU7VWW2K.js.map