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