@holoscript/core 2.0.1 → 2.0.2
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/LICENSE +21 -0
- package/dist/chunk-3N67RLQP.cjs +1298 -0
- package/dist/chunk-3N67RLQP.cjs.map +1 -0
- package/dist/chunk-3X2EGU7Z.cjs +52 -0
- package/dist/chunk-3X2EGU7Z.cjs.map +1 -0
- package/dist/chunk-4CV4JOE5.js +24 -0
- package/dist/chunk-4CV4JOE5.js.map +1 -0
- package/dist/chunk-4OHVW4XR.cjs +1027 -0
- package/dist/chunk-4OHVW4XR.cjs.map +1 -0
- package/dist/chunk-CZLDE2OZ.cjs +28 -0
- package/dist/chunk-CZLDE2OZ.cjs.map +1 -0
- package/{src/HoloScriptRuntime.ts → dist/chunk-EU6CZMGJ.js} +437 -794
- package/dist/chunk-EU6CZMGJ.js.map +1 -0
- package/dist/chunk-KWYIVRIH.js +344 -0
- package/dist/chunk-KWYIVRIH.js.map +1 -0
- package/dist/chunk-MCP6D4LT.js +1025 -0
- package/dist/chunk-MCP6D4LT.js.map +1 -0
- package/dist/chunk-SATNCODL.js +45 -0
- package/dist/chunk-SATNCODL.js.map +1 -0
- package/dist/chunk-VMZN4EVR.cjs +347 -0
- package/dist/chunk-VMZN4EVR.cjs.map +1 -0
- package/{src/HoloScriptDebugger.ts → dist/chunk-VYIDLUCV.js} +118 -257
- package/dist/chunk-VYIDLUCV.js.map +1 -0
- package/dist/chunk-WFI4T3XB.cjs +424 -0
- package/dist/chunk-WFI4T3XB.cjs.map +1 -0
- package/dist/debugger.cjs +20 -0
- package/dist/debugger.cjs.map +1 -0
- package/dist/debugger.d.cts +171 -0
- package/dist/debugger.d.ts +171 -0
- package/dist/debugger.js +7 -0
- package/dist/debugger.js.map +1 -0
- package/dist/index.cjs +6006 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2482 -0
- package/dist/index.d.ts +2482 -0
- package/dist/index.js +5926 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.cjs +14 -0
- package/dist/parser.cjs.map +1 -0
- package/dist/parser.d.cts +139 -0
- package/dist/parser.d.ts +139 -0
- package/dist/parser.js +5 -0
- package/dist/parser.js.map +1 -0
- package/dist/runtime.cjs +14 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +180 -0
- package/dist/runtime.d.ts +180 -0
- package/dist/runtime.js +5 -0
- package/dist/runtime.js.map +1 -0
- package/dist/type-checker.cjs +17 -0
- package/dist/type-checker.cjs.map +1 -0
- package/dist/type-checker.d.cts +105 -0
- package/dist/type-checker.d.ts +105 -0
- package/dist/type-checker.js +4 -0
- package/dist/type-checker.js.map +1 -0
- package/dist/types-D6g4ACjP.d.cts +262 -0
- package/dist/types-D6g4ACjP.d.ts +262 -0
- package/package.json +11 -8
- package/src/HoloScript2DParser.js +0 -227
- package/src/HoloScript2DParser.ts +0 -261
- package/src/HoloScriptCodeParser.js +0 -1102
- package/src/HoloScriptCodeParser.ts +0 -1188
- package/src/HoloScriptDebugger.js +0 -458
- package/src/HoloScriptParser.js +0 -338
- package/src/HoloScriptParser.ts +0 -397
- package/src/HoloScriptPlusParser.js +0 -371
- package/src/HoloScriptPlusParser.ts +0 -543
- package/src/HoloScriptRuntime.js +0 -1399
- package/src/HoloScriptRuntime.test.js +0 -351
- package/src/HoloScriptRuntime.test.ts +0 -436
- package/src/HoloScriptTypeChecker.js +0 -356
- package/src/HoloScriptTypeChecker.ts +0 -475
- package/src/__tests__/GraphicsServices.test.js +0 -357
- package/src/__tests__/GraphicsServices.test.ts +0 -427
- package/src/__tests__/HoloScriptPlusParser.test.js +0 -317
- package/src/__tests__/HoloScriptPlusParser.test.ts +0 -392
- package/src/__tests__/integration.test.js +0 -336
- package/src/__tests__/integration.test.ts +0 -416
- package/src/__tests__/performance.bench.js +0 -218
- package/src/__tests__/performance.bench.ts +0 -262
- package/src/__tests__/type-checker.test.js +0 -60
- package/src/__tests__/type-checker.test.ts +0 -73
- package/src/index.js +0 -217
- package/src/index.ts +0 -426
- package/src/interop/Interoperability.js +0 -413
- package/src/interop/Interoperability.ts +0 -494
- package/src/logger.js +0 -42
- package/src/logger.ts +0 -57
- package/src/parser/EnhancedParser.js +0 -205
- package/src/parser/EnhancedParser.ts +0 -251
- package/src/parser/HoloScriptPlusParser.js +0 -928
- package/src/parser/HoloScriptPlusParser.ts +0 -1089
- package/src/runtime/HoloScriptPlusRuntime.js +0 -674
- package/src/runtime/HoloScriptPlusRuntime.ts +0 -861
- package/src/runtime/PerformanceTelemetry.js +0 -323
- package/src/runtime/PerformanceTelemetry.ts +0 -467
- package/src/runtime/RuntimeOptimization.js +0 -361
- package/src/runtime/RuntimeOptimization.ts +0 -416
- package/src/services/HololandGraphicsPipelineService.js +0 -506
- package/src/services/HololandGraphicsPipelineService.ts +0 -662
- package/src/services/PlatformPerformanceOptimizer.js +0 -356
- package/src/services/PlatformPerformanceOptimizer.ts +0 -503
- package/src/state/ReactiveState.js +0 -427
- package/src/state/ReactiveState.ts +0 -572
- package/src/tools/DeveloperExperience.js +0 -376
- package/src/tools/DeveloperExperience.ts +0 -438
- package/src/traits/AIDriverTrait.js +0 -322
- package/src/traits/AIDriverTrait.test.js +0 -329
- package/src/traits/AIDriverTrait.test.ts +0 -357
- package/src/traits/AIDriverTrait.ts +0 -474
- package/src/traits/LightingTrait.js +0 -313
- package/src/traits/LightingTrait.test.js +0 -410
- package/src/traits/LightingTrait.test.ts +0 -462
- package/src/traits/LightingTrait.ts +0 -505
- package/src/traits/MaterialTrait.js +0 -194
- package/src/traits/MaterialTrait.test.js +0 -286
- package/src/traits/MaterialTrait.test.ts +0 -329
- package/src/traits/MaterialTrait.ts +0 -324
- package/src/traits/RenderingTrait.js +0 -356
- package/src/traits/RenderingTrait.test.js +0 -363
- package/src/traits/RenderingTrait.test.ts +0 -427
- package/src/traits/RenderingTrait.ts +0 -555
- package/src/traits/VRTraitSystem.js +0 -740
- package/src/traits/VRTraitSystem.ts +0 -1040
- package/src/traits/VoiceInputTrait.js +0 -284
- package/src/traits/VoiceInputTrait.test.js +0 -226
- package/src/traits/VoiceInputTrait.test.ts +0 -252
- package/src/traits/VoiceInputTrait.ts +0 -401
- package/src/types/AdvancedTypeSystem.js +0 -226
- package/src/types/AdvancedTypeSystem.ts +0 -494
- package/src/types/HoloScriptPlus.d.ts +0 -853
- package/src/types.js +0 -6
- package/src/types.ts +0 -369
- package/tsconfig.json +0 -23
- package/tsup.config.d.ts +0 -2
- package/tsup.config.js +0 -18
- package/tsup.config.ts +0 -19
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @holoscript/core Advanced Type System
|
|
3
|
-
*
|
|
4
|
-
* Union types, generics, type inference, exhaustiveness checking
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Type inference engine
|
|
8
|
-
*/
|
|
9
|
-
export class TypeInferenceEngine {
|
|
10
|
-
constructor() {
|
|
11
|
-
this.typeEnvironment = new Map();
|
|
12
|
-
this.genericTypeVars = new Map();
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Infer type from value
|
|
16
|
-
*/
|
|
17
|
-
inferType(value) {
|
|
18
|
-
if (typeof value === 'number') {
|
|
19
|
-
return { kind: 'primitive', name: 'number' };
|
|
20
|
-
}
|
|
21
|
-
if (typeof value === 'string') {
|
|
22
|
-
return { kind: 'primitive', name: 'string' };
|
|
23
|
-
}
|
|
24
|
-
if (typeof value === 'boolean') {
|
|
25
|
-
return { kind: 'primitive', name: 'boolean' };
|
|
26
|
-
}
|
|
27
|
-
if (Array.isArray(value)) {
|
|
28
|
-
const elementType = value.length > 0 ? this.inferType(value[0]) : { kind: 'primitive', name: 'void' };
|
|
29
|
-
return { kind: 'array', elementType };
|
|
30
|
-
}
|
|
31
|
-
return { kind: 'primitive', name: 'void' };
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Check type compatibility
|
|
35
|
-
*/
|
|
36
|
-
isAssignableTo(from, to) {
|
|
37
|
-
// Same type
|
|
38
|
-
if (JSON.stringify(from) === JSON.stringify(to))
|
|
39
|
-
return true;
|
|
40
|
-
// Union type includes from
|
|
41
|
-
if (to.kind === 'union') {
|
|
42
|
-
return to.members.some((m) => this.isAssignableTo(from, m));
|
|
43
|
-
}
|
|
44
|
-
// Intersection type all match
|
|
45
|
-
if (from.kind === 'intersection') {
|
|
46
|
-
return from.members.every((m) => this.isAssignableTo(m, to));
|
|
47
|
-
}
|
|
48
|
-
// Array covariance
|
|
49
|
-
if (from.kind === 'array' && to.kind === 'array') {
|
|
50
|
-
return this.isAssignableTo(from.elementType, to.elementType);
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Unify types (for generics)
|
|
56
|
-
*/
|
|
57
|
-
unify(t1, t2) {
|
|
58
|
-
const substitutions = new Map();
|
|
59
|
-
// If t1 is a type variable
|
|
60
|
-
if (t1.kind === 'custom' && this.isTypeVariable(t1.name)) {
|
|
61
|
-
substitutions.set(t1.name, t2);
|
|
62
|
-
return substitutions;
|
|
63
|
-
}
|
|
64
|
-
// Structural unification
|
|
65
|
-
if (t1.kind === 'array' && t2.kind === 'array') {
|
|
66
|
-
return this.unify(t1.elementType, t2.elementType);
|
|
67
|
-
}
|
|
68
|
-
if (t1.kind === 'generic' && t2.kind === 'generic') {
|
|
69
|
-
if (t1.name === t2.name && t1.typeArgs.length === t2.typeArgs.length) {
|
|
70
|
-
for (let i = 0; i < t1.typeArgs.length; i++) {
|
|
71
|
-
const unified = this.unify(t1.typeArgs[i], t2.typeArgs[i]);
|
|
72
|
-
for (const [k, v] of unified) {
|
|
73
|
-
substitutions.set(k, v);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return substitutions;
|
|
79
|
-
}
|
|
80
|
-
isTypeVariable(name) {
|
|
81
|
-
return /^[A-Z]$/.test(name); // Single uppercase letter is type var
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Resolve generic type with type arguments
|
|
85
|
-
*/
|
|
86
|
-
resolveGeneric(generic, concreteTypes) {
|
|
87
|
-
const substitutions = new Map();
|
|
88
|
-
for (let i = 0; i < generic.typeArgs.length; i++) {
|
|
89
|
-
if (generic.typeArgs[i].kind === 'custom') {
|
|
90
|
-
substitutions.set(generic.typeArgs[i].name, concreteTypes[i]);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return this.substitute(generic, substitutions);
|
|
94
|
-
}
|
|
95
|
-
substitute(type, subs) {
|
|
96
|
-
if (type.kind === 'custom' && subs.has(type.name)) {
|
|
97
|
-
return subs.get(type.name);
|
|
98
|
-
}
|
|
99
|
-
if (type.kind === 'array') {
|
|
100
|
-
return {
|
|
101
|
-
kind: 'array',
|
|
102
|
-
elementType: this.substitute(type.elementType, subs),
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
if (type.kind === 'union') {
|
|
106
|
-
return {
|
|
107
|
-
kind: 'union',
|
|
108
|
-
members: type.members.map((m) => this.substitute(m, subs)),
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
return type;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Exhaustiveness checker for match statements
|
|
116
|
-
*/
|
|
117
|
-
export class ExhaustivenessChecker {
|
|
118
|
-
/**
|
|
119
|
-
* Check if all union members are covered in match statement
|
|
120
|
-
*/
|
|
121
|
-
checkMatch(unionType, casePatterns) {
|
|
122
|
-
const patterns = new Set(casePatterns.map((p) => p.toLowerCase()));
|
|
123
|
-
const uncovered = [];
|
|
124
|
-
for (const member of unionType.members) {
|
|
125
|
-
const caseName = this.getCaseName(member);
|
|
126
|
-
if (!patterns.has(caseName.toLowerCase()) && caseName !== '_') {
|
|
127
|
-
uncovered.push(caseName);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
isExhaustive: uncovered.length === 0 || patterns.has('_'),
|
|
132
|
-
uncoveredCases: uncovered,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
getCaseName(type) {
|
|
136
|
-
if (type.kind === 'literal') {
|
|
137
|
-
return String(type.value);
|
|
138
|
-
}
|
|
139
|
-
if (type.kind === 'custom') {
|
|
140
|
-
return type.name;
|
|
141
|
-
}
|
|
142
|
-
return type.kind;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Type checker for HoloScript+
|
|
147
|
-
*/
|
|
148
|
-
export class AdvancedTypeChecker {
|
|
149
|
-
constructor() {
|
|
150
|
-
this.types = new Map();
|
|
151
|
-
this.inference = new TypeInferenceEngine();
|
|
152
|
-
this.exhaustiveness = new ExhaustivenessChecker();
|
|
153
|
-
// Register built-in types
|
|
154
|
-
this.registerBuiltins();
|
|
155
|
-
}
|
|
156
|
-
registerBuiltins() {
|
|
157
|
-
this.types.set('Vector3', {
|
|
158
|
-
kind: 'custom',
|
|
159
|
-
name: 'Vector3',
|
|
160
|
-
properties: new Map([
|
|
161
|
-
['x', { kind: 'primitive', name: 'number' }],
|
|
162
|
-
['y', { kind: 'primitive', name: 'number' }],
|
|
163
|
-
['z', { kind: 'primitive', name: 'number' }],
|
|
164
|
-
]),
|
|
165
|
-
methods: new Map(),
|
|
166
|
-
});
|
|
167
|
-
this.types.set('Transform', {
|
|
168
|
-
kind: 'custom',
|
|
169
|
-
name: 'Transform',
|
|
170
|
-
properties: new Map([
|
|
171
|
-
['position', this.types.get('Vector3')],
|
|
172
|
-
['rotation', this.types.get('Vector3')],
|
|
173
|
-
['scale', this.types.get('Vector3')],
|
|
174
|
-
]),
|
|
175
|
-
methods: new Map(),
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Register a new type
|
|
180
|
-
*/
|
|
181
|
-
registerType(name, type) {
|
|
182
|
-
this.types.set(name, type);
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Get registered type
|
|
186
|
-
*/
|
|
187
|
-
getType(name) {
|
|
188
|
-
return this.types.get(name);
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Check union exhaustiveness
|
|
192
|
-
*/
|
|
193
|
-
checkUnionExhaustiveness(unionType, cases) {
|
|
194
|
-
return this.exhaustiveness.checkMatch(unionType, cases);
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Check type assignment
|
|
198
|
-
*/
|
|
199
|
-
checkAssignment(from, to) {
|
|
200
|
-
if (this.inference.isAssignableTo(from, to)) {
|
|
201
|
-
return { valid: true };
|
|
202
|
-
}
|
|
203
|
-
return {
|
|
204
|
-
valid: false,
|
|
205
|
-
error: `Type '${this.formatType(from)}' is not assignable to '${this.formatType(to)}'`,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
formatType(type) {
|
|
209
|
-
switch (type.kind) {
|
|
210
|
-
case 'primitive':
|
|
211
|
-
return type.name;
|
|
212
|
-
case 'array':
|
|
213
|
-
return `${this.formatType(type.elementType)}[]`;
|
|
214
|
-
case 'union':
|
|
215
|
-
return type.members.map((m) => this.formatType(m)).join(' | ');
|
|
216
|
-
case 'intersection':
|
|
217
|
-
return type.members.map((m) => this.formatType(m)).join(' & ');
|
|
218
|
-
case 'custom':
|
|
219
|
-
return type.name;
|
|
220
|
-
case 'literal':
|
|
221
|
-
return JSON.stringify(type.value);
|
|
222
|
-
default:
|
|
223
|
-
return 'unknown';
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
@@ -1,494 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @holoscript/core Advanced Type System
|
|
3
|
-
*
|
|
4
|
-
* Union types, generics, type inference, exhaustiveness checking
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export type HoloScriptType =
|
|
8
|
-
| PrimitiveType
|
|
9
|
-
| ArrayType
|
|
10
|
-
| UnionType
|
|
11
|
-
| IntersectionType
|
|
12
|
-
| GenericType
|
|
13
|
-
| LiteralType
|
|
14
|
-
| CustomType;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Primitive types
|
|
18
|
-
*/
|
|
19
|
-
export type PrimitiveTypeName = 'number' | 'string' | 'boolean' | 'void';
|
|
20
|
-
|
|
21
|
-
export interface PrimitiveType {
|
|
22
|
-
kind: 'primitive';
|
|
23
|
-
name: PrimitiveTypeName;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Array type: T[]
|
|
28
|
-
*/
|
|
29
|
-
export interface ArrayType {
|
|
30
|
-
kind: 'array';
|
|
31
|
-
elementType: HoloScriptType;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Union type: A | B | C
|
|
36
|
-
*/
|
|
37
|
-
export interface UnionType {
|
|
38
|
-
kind: 'union';
|
|
39
|
-
members: HoloScriptType[];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Intersection type: A & B
|
|
44
|
-
*/
|
|
45
|
-
export interface IntersectionType {
|
|
46
|
-
kind: 'intersection';
|
|
47
|
-
members: HoloScriptType[];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Generic type: Container<T>
|
|
52
|
-
*/
|
|
53
|
-
export interface GenericType {
|
|
54
|
-
kind: 'generic';
|
|
55
|
-
name: string;
|
|
56
|
-
typeArgs: HoloScriptType[];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Literal type: "idle" | "moving"
|
|
61
|
-
*/
|
|
62
|
-
export interface LiteralType {
|
|
63
|
-
kind: 'literal';
|
|
64
|
-
value: string | number | boolean;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Custom type: User-defined types
|
|
69
|
-
*/
|
|
70
|
-
export interface CustomType {
|
|
71
|
-
kind: 'custom';
|
|
72
|
-
name: string;
|
|
73
|
-
properties: Map<string, HoloScriptType>;
|
|
74
|
-
methods: Map<string, FunctionType>;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Function type
|
|
79
|
-
*/
|
|
80
|
-
export interface FunctionType {
|
|
81
|
-
kind: 'function';
|
|
82
|
-
parameters: { name: string; type: HoloScriptType }[];
|
|
83
|
-
returnType: HoloScriptType;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Type inference engine
|
|
88
|
-
*/
|
|
89
|
-
export class TypeInferenceEngine {
|
|
90
|
-
// Reserved for future type environment tracking
|
|
91
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
92
|
-
// private typeEnvironment: Map<string, HoloScriptType> = new Map();
|
|
93
|
-
// private genericTypeVars: Map<string, HoloScriptType> = new Map();
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Infer type from value
|
|
97
|
-
*/
|
|
98
|
-
inferType(value: any): HoloScriptType {
|
|
99
|
-
if (typeof value === 'number') {
|
|
100
|
-
return { kind: 'primitive', name: 'number' };
|
|
101
|
-
}
|
|
102
|
-
if (typeof value === 'string') {
|
|
103
|
-
return { kind: 'primitive', name: 'string' };
|
|
104
|
-
}
|
|
105
|
-
if (typeof value === 'boolean') {
|
|
106
|
-
return { kind: 'primitive', name: 'boolean' };
|
|
107
|
-
}
|
|
108
|
-
if (Array.isArray(value)) {
|
|
109
|
-
const elementType: HoloScriptType = value.length > 0 ? this.inferType(value[0]) : { kind: 'primitive', name: 'void' };
|
|
110
|
-
return { kind: 'array', elementType } as ArrayType;
|
|
111
|
-
}
|
|
112
|
-
return { kind: 'primitive', name: 'void' };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Check type compatibility
|
|
117
|
-
*/
|
|
118
|
-
isAssignableTo(from: HoloScriptType, to: HoloScriptType): boolean {
|
|
119
|
-
// Same type
|
|
120
|
-
if (JSON.stringify(from) === JSON.stringify(to)) return true;
|
|
121
|
-
|
|
122
|
-
// Union type includes from
|
|
123
|
-
if (to.kind === 'union') {
|
|
124
|
-
return to.members.some((m) => this.isAssignableTo(from, m));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Intersection type all match
|
|
128
|
-
if (from.kind === 'intersection') {
|
|
129
|
-
return from.members.every((m) => this.isAssignableTo(m, to));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Array covariance
|
|
133
|
-
if (from.kind === 'array' && to.kind === 'array') {
|
|
134
|
-
return this.isAssignableTo(from.elementType, to.elementType);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Unify types (for generics)
|
|
142
|
-
*/
|
|
143
|
-
unify(t1: HoloScriptType, t2: HoloScriptType): Map<string, HoloScriptType> {
|
|
144
|
-
const substitutions = new Map<string, HoloScriptType>();
|
|
145
|
-
|
|
146
|
-
// If t1 is a type variable
|
|
147
|
-
if (t1.kind === 'custom' && this.isTypeVariable(t1.name)) {
|
|
148
|
-
substitutions.set(t1.name, t2);
|
|
149
|
-
return substitutions;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Structural unification
|
|
153
|
-
if (t1.kind === 'array' && t2.kind === 'array') {
|
|
154
|
-
return this.unify(t1.elementType, t2.elementType);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (t1.kind === 'generic' && t2.kind === 'generic') {
|
|
158
|
-
if (t1.name === t2.name && t1.typeArgs.length === t2.typeArgs.length) {
|
|
159
|
-
for (let i = 0; i < t1.typeArgs.length; i++) {
|
|
160
|
-
const unified = this.unify(t1.typeArgs[i], t2.typeArgs[i]);
|
|
161
|
-
for (const [k, v] of unified) {
|
|
162
|
-
substitutions.set(k, v);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return substitutions;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
private isTypeVariable(name: string): boolean {
|
|
172
|
-
return /^[A-Z]$/.test(name); // Single uppercase letter is type var
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Resolve generic type with type arguments
|
|
177
|
-
*/
|
|
178
|
-
resolveGeneric(generic: GenericType, concreteTypes: HoloScriptType[]): HoloScriptType {
|
|
179
|
-
const substitutions = new Map<string, HoloScriptType>();
|
|
180
|
-
|
|
181
|
-
for (let i = 0; i < generic.typeArgs.length; i++) {
|
|
182
|
-
if (generic.typeArgs[i].kind === 'custom') {
|
|
183
|
-
substitutions.set((generic.typeArgs[i] as CustomType).name, concreteTypes[i]);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return this.substitute(generic, substitutions);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
private substitute(type: HoloScriptType, subs: Map<string, HoloScriptType>): HoloScriptType {
|
|
191
|
-
if (type.kind === 'custom' && subs.has((type as CustomType).name)) {
|
|
192
|
-
return subs.get((type as CustomType).name)!;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (type.kind === 'array') {
|
|
196
|
-
return {
|
|
197
|
-
kind: 'array',
|
|
198
|
-
elementType: this.substitute((type as ArrayType).elementType, subs),
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (type.kind === 'union') {
|
|
203
|
-
return {
|
|
204
|
-
kind: 'union',
|
|
205
|
-
members: (type as UnionType).members.map((m) => this.substitute(m, subs)),
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return type;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Exhaustiveness checker for match statements
|
|
215
|
-
*/
|
|
216
|
-
export class ExhaustivenessChecker {
|
|
217
|
-
/**
|
|
218
|
-
* Check if all union members are covered in match statement
|
|
219
|
-
*/
|
|
220
|
-
checkMatch(unionType: UnionType, casePatterns: string[]): {
|
|
221
|
-
isExhaustive: boolean;
|
|
222
|
-
uncoveredCases: string[];
|
|
223
|
-
} {
|
|
224
|
-
const patterns = new Set(casePatterns.map((p) => p.toLowerCase()));
|
|
225
|
-
|
|
226
|
-
const uncovered: string[] = [];
|
|
227
|
-
for (const member of unionType.members) {
|
|
228
|
-
const caseName = this.getCaseName(member);
|
|
229
|
-
if (!patterns.has(caseName.toLowerCase()) && caseName !== '_') {
|
|
230
|
-
uncovered.push(caseName);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
isExhaustive: uncovered.length === 0 || patterns.has('_'),
|
|
236
|
-
uncoveredCases: uncovered,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
private getCaseName(type: HoloScriptType): string {
|
|
241
|
-
if (type.kind === 'literal') {
|
|
242
|
-
return String((type as LiteralType).value);
|
|
243
|
-
}
|
|
244
|
-
if (type.kind === 'custom') {
|
|
245
|
-
return (type as CustomType).name;
|
|
246
|
-
}
|
|
247
|
-
return type.kind;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Type checker for HoloScript+
|
|
253
|
-
*/
|
|
254
|
-
export class AdvancedTypeChecker {
|
|
255
|
-
private inference: TypeInferenceEngine;
|
|
256
|
-
private exhaustiveness: ExhaustivenessChecker;
|
|
257
|
-
private types: Map<string, HoloScriptType> = new Map();
|
|
258
|
-
|
|
259
|
-
constructor() {
|
|
260
|
-
this.inference = new TypeInferenceEngine();
|
|
261
|
-
this.exhaustiveness = new ExhaustivenessChecker();
|
|
262
|
-
|
|
263
|
-
// Register built-in types
|
|
264
|
-
this.registerBuiltins();
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
private registerBuiltins(): void {
|
|
268
|
-
this.types.set('Vector3', {
|
|
269
|
-
kind: 'custom',
|
|
270
|
-
name: 'Vector3',
|
|
271
|
-
properties: new Map([
|
|
272
|
-
['x', { kind: 'primitive', name: 'number' }],
|
|
273
|
-
['y', { kind: 'primitive', name: 'number' }],
|
|
274
|
-
['z', { kind: 'primitive', name: 'number' }],
|
|
275
|
-
]),
|
|
276
|
-
methods: new Map(),
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
this.types.set('Transform', {
|
|
280
|
-
kind: 'custom',
|
|
281
|
-
name: 'Transform',
|
|
282
|
-
properties: new Map([
|
|
283
|
-
['position', this.types.get('Vector3')!],
|
|
284
|
-
['rotation', this.types.get('Vector3')!],
|
|
285
|
-
['scale', this.types.get('Vector3')!],
|
|
286
|
-
]),
|
|
287
|
-
methods: new Map(),
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Register a new type
|
|
293
|
-
*/
|
|
294
|
-
registerType(name: string, type: HoloScriptType): void {
|
|
295
|
-
this.types.set(name, type);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Get registered type
|
|
300
|
-
*/
|
|
301
|
-
getType(name: string): HoloScriptType | undefined {
|
|
302
|
-
return this.types.get(name);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Check union exhaustiveness
|
|
307
|
-
*/
|
|
308
|
-
checkUnionExhaustiveness(
|
|
309
|
-
unionType: UnionType,
|
|
310
|
-
cases: string[]
|
|
311
|
-
): { isExhaustive: boolean; uncoveredCases: string[] } {
|
|
312
|
-
return this.exhaustiveness.checkMatch(unionType, cases);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Check type assignment
|
|
317
|
-
*/
|
|
318
|
-
checkAssignment(from: HoloScriptType, to: HoloScriptType): { valid: boolean; error?: string } {
|
|
319
|
-
if (this.inference.isAssignableTo(from, to)) {
|
|
320
|
-
return { valid: true };
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return {
|
|
324
|
-
valid: false,
|
|
325
|
-
error: `Type '${this.formatType(from)}' is not assignable to '${this.formatType(to)}'`,
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
private formatType(type: HoloScriptType): string {
|
|
330
|
-
switch (type.kind) {
|
|
331
|
-
case 'primitive':
|
|
332
|
-
return (type as PrimitiveType).name;
|
|
333
|
-
case 'array':
|
|
334
|
-
return `${this.formatType((type as ArrayType).elementType)}[]`;
|
|
335
|
-
case 'union':
|
|
336
|
-
return (type as UnionType).members.map((m) => this.formatType(m)).join(' | ');
|
|
337
|
-
case 'intersection':
|
|
338
|
-
return (type as IntersectionType).members.map((m) => this.formatType(m)).join(' & ');
|
|
339
|
-
case 'custom':
|
|
340
|
-
return (type as CustomType).name;
|
|
341
|
-
case 'literal':
|
|
342
|
-
return JSON.stringify((type as LiteralType).value);
|
|
343
|
-
default:
|
|
344
|
-
return 'unknown';
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* HoloScript+ AST Types
|
|
351
|
-
*/
|
|
352
|
-
export interface HSPlusNode {
|
|
353
|
-
type: 'directive' | 'trait' | 'lifecycle' | 'state' | 'for' | 'if' | 'import' | 'component' | 'element' | 'fragment' | 'Program';
|
|
354
|
-
[key: string]: any;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
export interface HSPlusAST extends HSPlusNode {
|
|
358
|
-
type: 'Program';
|
|
359
|
-
body: HSPlusNode[];
|
|
360
|
-
version: string;
|
|
361
|
-
root: HSPlusNode;
|
|
362
|
-
imports: Array<{ path: string; alias: string }>;
|
|
363
|
-
hasState: boolean;
|
|
364
|
-
hasVRTraits: boolean;
|
|
365
|
-
hasControlFlow: boolean;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
export interface HSPlusDirective extends HSPlusNode {
|
|
369
|
-
type: 'directive' | 'trait' | 'lifecycle' | 'state' | 'for' | 'if' | 'import' | 'fragment';
|
|
370
|
-
name: string;
|
|
371
|
-
args: string[];
|
|
372
|
-
enableTypeScriptImports?: boolean;
|
|
373
|
-
enableVRTraits?: boolean;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
export interface HSPlusCompileResult {
|
|
377
|
-
success: boolean;
|
|
378
|
-
code?: string;
|
|
379
|
-
sourceMap?: any;
|
|
380
|
-
errors: Array<{ message: string; line: number; column: number }>;
|
|
381
|
-
ast?: any;
|
|
382
|
-
compiledExpressions?: any;
|
|
383
|
-
requiredCompanions?: string[];
|
|
384
|
-
features?: any;
|
|
385
|
-
warnings?: any[];
|
|
386
|
-
[key: string]: any;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
export interface HSPlusParserOptions {
|
|
390
|
-
sourceMap?: boolean;
|
|
391
|
-
strict?: boolean;
|
|
392
|
-
enableTypeScriptImports?: boolean;
|
|
393
|
-
enableVRTraits?: boolean;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
export type VRTraitName =
|
|
397
|
-
| 'grabbable'
|
|
398
|
-
| 'throwable'
|
|
399
|
-
| 'pointable'
|
|
400
|
-
| 'scalable'
|
|
401
|
-
| 'draggable'
|
|
402
|
-
| 'rotatable'
|
|
403
|
-
| 'clickable'
|
|
404
|
-
| 'hoverable'
|
|
405
|
-
| 'pressable'
|
|
406
|
-
| 'stackable'
|
|
407
|
-
| 'snappable'
|
|
408
|
-
| 'breakable';
|
|
409
|
-
|
|
410
|
-
export interface StateDeclaration {
|
|
411
|
-
name: string;
|
|
412
|
-
type: HoloScriptType;
|
|
413
|
-
initialValue?: any;
|
|
414
|
-
[key: string]: any;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
export interface LifecycleHook {
|
|
418
|
-
name: 'mounted' | 'updated' | 'destroyed';
|
|
419
|
-
handler: string;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
export interface VRLifecycleHook {
|
|
423
|
-
name: 'grabbed' | 'released' | 'pointed' | 'unpointed' | 'thrown';
|
|
424
|
-
handler: string;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
export interface ControllerHook {
|
|
428
|
-
name: 'trigger' | 'grip' | 'thumbstick' | 'button_a' | 'button_b';
|
|
429
|
-
handler: string;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Vector3 type for 3D coordinates
|
|
434
|
-
*/
|
|
435
|
-
export interface Vector3 {
|
|
436
|
-
x: number;
|
|
437
|
-
y: number;
|
|
438
|
-
z: number;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Color type for RGBA colors
|
|
443
|
-
*/
|
|
444
|
-
export interface Color {
|
|
445
|
-
r: number;
|
|
446
|
-
g: number;
|
|
447
|
-
b: number;
|
|
448
|
-
a?: number;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* VR Hand representation
|
|
453
|
-
*/
|
|
454
|
-
export interface VRHand {
|
|
455
|
-
position: Vector3;
|
|
456
|
-
rotation: Vector3;
|
|
457
|
-
pinch: number;
|
|
458
|
-
grip: number;
|
|
459
|
-
pointing: boolean;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* HoloScript+ Runtime built-in functions
|
|
464
|
-
*/
|
|
465
|
-
export interface HSPlusBuiltins {
|
|
466
|
-
log: (...args: any[]) => void;
|
|
467
|
-
warn: (...args: any[]) => void;
|
|
468
|
-
error: (...args: any[]) => void;
|
|
469
|
-
setTimeout: (fn: () => void, ms: number) => number;
|
|
470
|
-
clearTimeout: (id: number) => void;
|
|
471
|
-
setInterval: (fn: () => void, ms: number) => number;
|
|
472
|
-
clearInterval: (id: number) => void;
|
|
473
|
-
fetch: (url: string, options?: any) => Promise<any>;
|
|
474
|
-
emit: (event: string, data?: any) => void;
|
|
475
|
-
on: (event: string, handler: (data: any) => void) => void;
|
|
476
|
-
off: (event: string, handler?: (data: any) => void) => void;
|
|
477
|
-
[key: string]: any;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* HoloScript+ Runtime interface
|
|
482
|
-
*/
|
|
483
|
-
export interface HSPlusRuntime {
|
|
484
|
-
state: Record<string, any>;
|
|
485
|
-
props: Record<string, any>;
|
|
486
|
-
refs: Record<string, any>;
|
|
487
|
-
builtins: HSPlusBuiltins;
|
|
488
|
-
execute: (ast: HSPlusAST) => any;
|
|
489
|
-
evaluate: (expression: string) => any;
|
|
490
|
-
callMethod: (name: string, args: any[]) => any;
|
|
491
|
-
setState: (key: string, value: any) => void;
|
|
492
|
-
getState: (key: string) => any;
|
|
493
|
-
destroy: () => void;
|
|
494
|
-
}
|