@rcrsr/rill 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ast-nodes.d.ts +14 -4
- package/dist/ast-unions.d.ts +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -0
- package/dist/error-registry.js +228 -0
- package/dist/ext/crypto/index.js +5 -5
- package/dist/ext/exec/index.js +3 -3
- package/dist/ext/fetch/index.js +4 -4
- package/dist/ext/fetch/request.js +1 -1
- package/dist/ext/fs/index.js +101 -114
- package/dist/ext/fs/sandbox.d.ts +18 -0
- package/dist/ext/fs/sandbox.js +33 -0
- package/dist/ext/kv/index.js +12 -12
- package/dist/ext/kv/store.d.ts +1 -1
- package/dist/ext/kv/store.js +1 -1
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.js +2 -2
- package/dist/highlight-map.js +1 -0
- package/dist/index.d.ts +1 -15
- package/dist/index.js +1 -14
- package/dist/lexer/operators.js +1 -0
- package/dist/parser/helpers.js +1 -0
- package/dist/parser/parser-expr.js +44 -5
- package/dist/parser/parser-literals.js +111 -4
- package/dist/parser/parser-shape.js +2 -2
- package/dist/parser/parser-use.js +19 -2
- package/dist/parser/parser.d.ts +2 -0
- package/dist/parser/parser.js +2 -0
- package/dist/runtime/core/callable.d.ts +5 -6
- package/dist/runtime/core/callable.js +10 -17
- package/dist/runtime/core/context.d.ts +2 -2
- package/dist/runtime/core/context.js +8 -8
- package/dist/runtime/core/eval/base.d.ts +2 -2
- package/dist/runtime/core/eval/base.js +2 -0
- package/dist/runtime/core/eval/evaluator.d.ts +1 -1
- package/dist/runtime/core/eval/index.d.ts +2 -2
- package/dist/runtime/core/eval/mixins/closures.js +367 -27
- package/dist/runtime/core/eval/mixins/collections.js +81 -6
- package/dist/runtime/core/eval/mixins/control-flow.js +1 -1
- package/dist/runtime/core/eval/mixins/conversion.js +17 -12
- package/dist/runtime/core/eval/mixins/core.js +15 -2
- package/dist/runtime/core/eval/mixins/expressions.js +3 -2
- package/dist/runtime/core/eval/mixins/extraction.js +2 -3
- package/dist/runtime/core/eval/mixins/list-dispatch.js +1 -1
- package/dist/runtime/core/eval/mixins/literals.js +14 -3
- package/dist/runtime/core/eval/mixins/types.js +30 -1
- package/dist/runtime/core/eval/mixins/variables.js +3 -1
- package/dist/runtime/core/execute.d.ts +1 -1
- package/dist/runtime/core/field-descriptor.d.ts +1 -1
- package/dist/runtime/core/introspection.d.ts +2 -2
- package/dist/runtime/core/introspection.js +2 -1
- package/dist/runtime/core/resolvers.d.ts +1 -1
- package/dist/runtime/core/signals.d.ts +6 -1
- package/dist/runtime/core/signals.js +9 -0
- package/dist/runtime/core/types/constructors.d.ts +54 -0
- package/dist/runtime/core/types/constructors.js +201 -0
- package/dist/runtime/core/types/guards.d.ts +42 -0
- package/dist/runtime/core/types/guards.js +88 -0
- package/dist/runtime/core/types/index.d.ts +18 -0
- package/dist/runtime/core/types/index.js +19 -0
- package/dist/runtime/core/types/operations.d.ts +98 -0
- package/dist/runtime/core/types/operations.js +804 -0
- package/dist/runtime/core/{type-registrations.d.ts → types/registrations.d.ts} +12 -22
- package/dist/runtime/core/{type-registrations.js → types/registrations.js} +94 -92
- package/dist/runtime/core/{types.d.ts → types/runtime.d.ts} +8 -8
- package/dist/runtime/core/{type-structures.d.ts → types/structures.d.ts} +21 -3
- package/dist/runtime/core/values.d.ts +13 -102
- package/dist/runtime/core/values.js +26 -722
- package/dist/runtime/ext/builtins.js +9 -8
- package/dist/runtime/ext/extensions.d.ts +2 -2
- package/dist/runtime/ext/extensions.js +2 -1
- package/dist/runtime/ext/test-context.d.ts +2 -2
- package/dist/runtime/ext/test-context.js +3 -2
- package/dist/runtime/index.d.ts +8 -22
- package/dist/runtime/index.js +10 -16
- package/dist/signature-parser.d.ts +1 -1
- package/dist/token-types.d.ts +1 -0
- package/dist/token-types.js +1 -0
- package/package.json +1 -1
- /package/dist/runtime/core/{markers.d.ts → types/markers.d.ts} +0 -0
- /package/dist/runtime/core/{markers.js → types/markers.js} +0 -0
- /package/dist/runtime/core/{types.js → types/runtime.js} +0 -0
- /package/dist/runtime/core/{type-structures.js → types/structures.js} +0 -0
|
@@ -4,691 +4,27 @@
|
|
|
4
4
|
* Core value types that flow through Rill programs.
|
|
5
5
|
* Public API for host applications.
|
|
6
6
|
*
|
|
7
|
+
* Structural operations (structureEquals, structureMatches, formatStructure,
|
|
8
|
+
* inferStructure, commonType) live in types/operations.ts and are re-exported.
|
|
9
|
+
*
|
|
7
10
|
* Dispatch functions (inferType, formatValue, deepEquals, serializeValue,
|
|
8
11
|
* copyValue) re-export from type-registrations.ts protocol implementations.
|
|
9
12
|
*/
|
|
10
|
-
import { RuntimeError } from '../../types.js';
|
|
11
13
|
import { VALID_TYPE_NAMES } from '../../constants.js';
|
|
12
|
-
import { isCallable, isDict } from './
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const legacy = ts;
|
|
25
|
-
if (typeof legacy['type'] === 'string') {
|
|
26
|
-
return { ...legacy, kind: legacy['type'] };
|
|
27
|
-
}
|
|
28
|
-
return ts;
|
|
29
|
-
}
|
|
30
|
-
/** Type guard for RillTuple (spread args) */
|
|
31
|
-
export function isTuple(value) {
|
|
32
|
-
return (typeof value === 'object' &&
|
|
33
|
-
value !== null &&
|
|
34
|
-
'__rill_tuple' in value &&
|
|
35
|
-
value.__rill_tuple === true);
|
|
36
|
-
}
|
|
37
|
-
/** Type guard for RillVector */
|
|
38
|
-
export function isVector(value) {
|
|
39
|
-
return (typeof value === 'object' &&
|
|
40
|
-
value !== null &&
|
|
41
|
-
'__rill_vector' in value &&
|
|
42
|
-
value.__rill_vector === true);
|
|
43
|
-
}
|
|
44
|
-
/** Type guard for RillOrdered (named spread args) */
|
|
45
|
-
export function isOrdered(value) {
|
|
46
|
-
return (typeof value === 'object' &&
|
|
47
|
-
value !== null &&
|
|
48
|
-
'__rill_ordered' in value &&
|
|
49
|
-
value.__rill_ordered === true);
|
|
50
|
-
}
|
|
51
|
-
/** Type guard for RillTypeValue */
|
|
52
|
-
export function isTypeValue(value) {
|
|
53
|
-
return (typeof value === 'object' &&
|
|
54
|
-
value !== null &&
|
|
55
|
-
'__rill_type' in value &&
|
|
56
|
-
value.__rill_type === true);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Create ordered from entries array (named, preserves insertion order).
|
|
60
|
-
* Entries may be 2-element [name, value] or 3-element [name, value, default]
|
|
61
|
-
* tuples; the third element carries a default value for `.^input` reflection.
|
|
62
|
-
*/
|
|
63
|
-
export function createOrdered(entries) {
|
|
64
|
-
return Object.freeze({ __rill_ordered: true, entries: [...entries] });
|
|
65
|
-
}
|
|
66
|
-
/** Create tuple from entries array (positional, preserves order) */
|
|
67
|
-
export function createTuple(entries) {
|
|
68
|
-
return Object.freeze({ __rill_tuple: true, entries: [...entries] });
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Create vector from Float32Array with model name.
|
|
72
|
-
* @throws {Error} if data.length is 0 (zero-dimension vectors not allowed)
|
|
73
|
-
*/
|
|
74
|
-
export function createVector(data, model) {
|
|
75
|
-
if (data.length === 0) {
|
|
76
|
-
throw new Error('Vector data must have at least one dimension');
|
|
77
|
-
}
|
|
78
|
-
return { __rill_vector: true, data, model };
|
|
79
|
-
}
|
|
14
|
+
import { isCallable as _isCallableGuard, isDict, isIterator, isOrdered, isStream, isTuple, isTypeValue, isVector, } from './types/guards.js';
|
|
15
|
+
/** isCallable guard widened to narrow to full RillCallable (not just CallableMarker) */
|
|
16
|
+
const isCallable = _isCallableGuard;
|
|
17
|
+
import { inferType as registryInferType, formatValue as registryFormatValue, deepEquals as registryDeepEquals, serializeValue as registrySerializeValue, } from './types/registrations.js';
|
|
18
|
+
// Re-export guards from canonical source (types/guards.ts)
|
|
19
|
+
export { isCallable, isDict, isIterator, isOrdered, isStream, isTuple, isTypeValue, isVector, };
|
|
20
|
+
// Value constructors re-exported from canonical source (types/constructors.ts)
|
|
21
|
+
export { copyValue, createOrdered, createTuple, createVector, emptyForType, } from './types/constructors.js';
|
|
22
|
+
// Structural operations re-exported from types/operations.ts
|
|
23
|
+
export { commonType, compareStructuredFields, formatStructure, inferElementType, inferStructure, paramToFieldDef, structureEquals, structureMatches, } from './types/operations.js';
|
|
24
|
+
// Re-import for local use (toNative, structureToTypeValue)
|
|
25
|
+
import { formatStructure, inferStructure } from './types/operations.js';
|
|
80
26
|
/** Infer the Rill type from a runtime value. Delegates to type-registrations. */
|
|
81
27
|
export const inferType = registryInferType;
|
|
82
|
-
/**
|
|
83
|
-
* Infer the element type for a homogeneous list.
|
|
84
|
-
* Empty arrays return { kind: 'any' }.
|
|
85
|
-
* Mixed types throw RILL-R002.
|
|
86
|
-
*/
|
|
87
|
-
export function inferElementType(elements) {
|
|
88
|
-
if (elements.length === 0)
|
|
89
|
-
return { kind: 'any' };
|
|
90
|
-
const firstElem = elements[0];
|
|
91
|
-
let accType = inferStructure(firstElem);
|
|
92
|
-
for (let i = 1; i < elements.length; i++) {
|
|
93
|
-
const elem = elements[i];
|
|
94
|
-
const elemType = inferStructure(elem);
|
|
95
|
-
const merged = commonType(accType, elemType);
|
|
96
|
-
if (merged === null) {
|
|
97
|
-
throw new RuntimeError('RILL-R002', `List elements must be the same type: expected ${formatStructure(accType)}, got ${formatStructure(elemType)} at index ${i}`);
|
|
98
|
-
}
|
|
99
|
-
accType = merged;
|
|
100
|
-
}
|
|
101
|
-
return accType;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Merge uniform value types from two sides of the same compound type.
|
|
105
|
-
* Sub-case A: both carry valueType -> recurse commonType.
|
|
106
|
-
* Sub-case B: both carry structural fields -> extract value types, merge all.
|
|
107
|
-
* Returns the merged TypeStructure on success, undefined when no uniform merge applies.
|
|
108
|
-
*/
|
|
109
|
-
function mergeUniformValueType(aValue, bValue, aFields, bFields) {
|
|
110
|
-
// Sub-case A: both carry valueType
|
|
111
|
-
if (aValue !== undefined && bValue !== undefined) {
|
|
112
|
-
const merged = commonType(aValue, bValue);
|
|
113
|
-
if (merged !== null)
|
|
114
|
-
return merged;
|
|
115
|
-
return undefined;
|
|
116
|
-
}
|
|
117
|
-
// Sub-case B: both carry structural fields
|
|
118
|
-
if (aFields !== undefined && bFields !== undefined) {
|
|
119
|
-
const allTypes = [
|
|
120
|
-
...aFields.map((f) => f.type),
|
|
121
|
-
...bFields.map((f) => f.type),
|
|
122
|
-
];
|
|
123
|
-
if (allTypes.length === 0)
|
|
124
|
-
return undefined;
|
|
125
|
-
let merged = allTypes[0];
|
|
126
|
-
for (let i = 1; i < allTypes.length; i++) {
|
|
127
|
-
const next = commonType(merged, allTypes[i]);
|
|
128
|
-
if (next === null)
|
|
129
|
-
return undefined;
|
|
130
|
-
merged = next;
|
|
131
|
-
}
|
|
132
|
-
return merged;
|
|
133
|
-
}
|
|
134
|
-
return undefined;
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Return the most specific shared type for two TypeStructure values.
|
|
138
|
-
* Returns null when types are incompatible at the top level.
|
|
139
|
-
*
|
|
140
|
-
* Cascade priority:
|
|
141
|
-
* 1. Any-narrowing: if either side is `any`, return the other
|
|
142
|
-
* 2. Structural match: delegate to structureEquals; on true, return a
|
|
143
|
-
* 3. Recursive list: merge inner element types
|
|
144
|
-
* 3b. Uniform valueType: merge dict/tuple/ordered value types
|
|
145
|
-
* 4. Bare type fallback: same compound type but structural mismatch
|
|
146
|
-
* 5. Incompatible: different top-level types return null
|
|
147
|
-
*/
|
|
148
|
-
export function commonType(a, b) {
|
|
149
|
-
// 1. Any-narrowing
|
|
150
|
-
if (a.kind === 'any')
|
|
151
|
-
return b;
|
|
152
|
-
if (b.kind === 'any')
|
|
153
|
-
return a;
|
|
154
|
-
// 5. Incompatible top-level types (checked early to short-circuit)
|
|
155
|
-
if (a.kind !== b.kind)
|
|
156
|
-
return null;
|
|
157
|
-
// 2. Structural match
|
|
158
|
-
if (structureEquals(a, b))
|
|
159
|
-
return a;
|
|
160
|
-
// 3. Recursive list element merging
|
|
161
|
-
if (a.kind === 'list' && b.kind === 'list') {
|
|
162
|
-
const aList = a;
|
|
163
|
-
const bList = b;
|
|
164
|
-
if (aList.element !== undefined && bList.element !== undefined) {
|
|
165
|
-
const inner = commonType(aList.element, bList.element);
|
|
166
|
-
if (inner !== null)
|
|
167
|
-
return { kind: 'list', element: inner };
|
|
168
|
-
}
|
|
169
|
-
return { kind: 'list' };
|
|
170
|
-
}
|
|
171
|
-
// 3b. Uniform valueType merging for dict/tuple/ordered
|
|
172
|
-
if (a.kind === 'dict' && b.kind === 'dict') {
|
|
173
|
-
const aDict = a;
|
|
174
|
-
const bDict = b;
|
|
175
|
-
const merged = mergeUniformValueType(aDict.valueType, bDict.valueType, aDict.fields ? Object.values(aDict.fields) : undefined, bDict.fields ? Object.values(bDict.fields) : undefined);
|
|
176
|
-
if (merged !== undefined)
|
|
177
|
-
return { kind: 'dict', valueType: merged };
|
|
178
|
-
}
|
|
179
|
-
if (a.kind === 'tuple' && b.kind === 'tuple') {
|
|
180
|
-
const aTuple = a;
|
|
181
|
-
const bTuple = b;
|
|
182
|
-
const merged = mergeUniformValueType(aTuple.valueType, bTuple.valueType, aTuple.elements, bTuple.elements);
|
|
183
|
-
if (merged !== undefined)
|
|
184
|
-
return { kind: 'tuple', valueType: merged };
|
|
185
|
-
}
|
|
186
|
-
if (a.kind === 'ordered' && b.kind === 'ordered') {
|
|
187
|
-
const aOrd = a;
|
|
188
|
-
const bOrd = b;
|
|
189
|
-
const merged = mergeUniformValueType(aOrd.valueType, bOrd.valueType, aOrd.fields, bOrd.fields);
|
|
190
|
-
if (merged !== undefined)
|
|
191
|
-
return { kind: 'ordered', valueType: merged };
|
|
192
|
-
}
|
|
193
|
-
// 4. Bare type fallback for compound types.
|
|
194
|
-
// The cast is safe for closure/dict/tuple/ordered (all sub-fields optional).
|
|
195
|
-
// For union, members is required by TypeStructure but omitted here intentionally:
|
|
196
|
-
// bare union signals structural incompatibility without enumerating members.
|
|
197
|
-
if (a.kind === 'closure' ||
|
|
198
|
-
a.kind === 'dict' ||
|
|
199
|
-
a.kind === 'tuple' ||
|
|
200
|
-
a.kind === 'ordered' ||
|
|
201
|
-
a.kind === 'union') {
|
|
202
|
-
return { kind: a.kind };
|
|
203
|
-
}
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
/** Compare two structural types for equality. */
|
|
207
|
-
export function structureEquals(a, b) {
|
|
208
|
-
if (a.kind !== b.kind)
|
|
209
|
-
return false;
|
|
210
|
-
// Leaf variants compare by kind alone
|
|
211
|
-
if (a.kind === 'number' ||
|
|
212
|
-
a.kind === 'string' ||
|
|
213
|
-
a.kind === 'bool' ||
|
|
214
|
-
a.kind === 'vector' ||
|
|
215
|
-
a.kind === 'type' ||
|
|
216
|
-
a.kind === 'any') {
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
if (a.kind === 'list' && b.kind === 'list') {
|
|
220
|
-
const aList = a;
|
|
221
|
-
const bList = b;
|
|
222
|
-
if (aList.element === undefined && bList.element === undefined)
|
|
223
|
-
return true;
|
|
224
|
-
if (aList.element === undefined || bList.element === undefined)
|
|
225
|
-
return false;
|
|
226
|
-
return structureEquals(aList.element, bList.element);
|
|
227
|
-
}
|
|
228
|
-
if (a.kind === 'dict' && b.kind === 'dict') {
|
|
229
|
-
const aDict = a;
|
|
230
|
-
const bDict = b;
|
|
231
|
-
// Uniform valueType comparison
|
|
232
|
-
const aHasValue = aDict.valueType !== undefined;
|
|
233
|
-
const bHasValue = bDict.valueType !== undefined;
|
|
234
|
-
if (aHasValue || bHasValue) {
|
|
235
|
-
if (!aHasValue || !bHasValue)
|
|
236
|
-
return false;
|
|
237
|
-
return structureEquals(aDict.valueType, bDict.valueType);
|
|
238
|
-
}
|
|
239
|
-
// Structural fields comparison
|
|
240
|
-
if (aDict.fields === undefined && bDict.fields === undefined)
|
|
241
|
-
return true;
|
|
242
|
-
if (aDict.fields === undefined || bDict.fields === undefined)
|
|
243
|
-
return false;
|
|
244
|
-
const aKeys = Object.keys(aDict.fields).sort();
|
|
245
|
-
const bKeys = Object.keys(bDict.fields).sort();
|
|
246
|
-
if (aKeys.length !== bKeys.length)
|
|
247
|
-
return false;
|
|
248
|
-
for (let i = 0; i < aKeys.length; i++) {
|
|
249
|
-
const key = aKeys[i];
|
|
250
|
-
if (key !== bKeys[i])
|
|
251
|
-
return false;
|
|
252
|
-
const aField = aDict.fields[key];
|
|
253
|
-
const bField = bDict.fields[key];
|
|
254
|
-
const aHasDefault = aField.defaultValue !== undefined;
|
|
255
|
-
const bHasDefault = bField.defaultValue !== undefined;
|
|
256
|
-
if (aHasDefault !== bHasDefault)
|
|
257
|
-
return false;
|
|
258
|
-
if (!structureEquals(aField.type, bField.type))
|
|
259
|
-
return false;
|
|
260
|
-
if (aHasDefault && bHasDefault) {
|
|
261
|
-
if (!deepEquals(aField.defaultValue, bField.defaultValue))
|
|
262
|
-
return false;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
267
|
-
if (a.kind === 'tuple' && b.kind === 'tuple') {
|
|
268
|
-
const aTuple = a;
|
|
269
|
-
const bTuple = b;
|
|
270
|
-
// Uniform valueType comparison
|
|
271
|
-
const aHasValue = aTuple.valueType !== undefined;
|
|
272
|
-
const bHasValue = bTuple.valueType !== undefined;
|
|
273
|
-
if (aHasValue || bHasValue) {
|
|
274
|
-
if (!aHasValue || !bHasValue)
|
|
275
|
-
return false;
|
|
276
|
-
return structureEquals(aTuple.valueType, bTuple.valueType);
|
|
277
|
-
}
|
|
278
|
-
// Structural elements comparison
|
|
279
|
-
if (aTuple.elements === undefined && bTuple.elements === undefined)
|
|
280
|
-
return true;
|
|
281
|
-
if (aTuple.elements === undefined || bTuple.elements === undefined)
|
|
282
|
-
return false;
|
|
283
|
-
if (aTuple.elements.length !== bTuple.elements.length)
|
|
284
|
-
return false;
|
|
285
|
-
for (let i = 0; i < aTuple.elements.length; i++) {
|
|
286
|
-
const aElem = aTuple.elements[i];
|
|
287
|
-
const bElem = bTuple.elements[i];
|
|
288
|
-
if (!structureEquals(aElem.type, bElem.type))
|
|
289
|
-
return false;
|
|
290
|
-
const aDefault = aElem.defaultValue;
|
|
291
|
-
const bDefault = bElem.defaultValue;
|
|
292
|
-
if (aDefault === undefined && bDefault === undefined)
|
|
293
|
-
continue;
|
|
294
|
-
if (aDefault === undefined || bDefault === undefined)
|
|
295
|
-
return false;
|
|
296
|
-
if (!deepEquals(aDefault, bDefault))
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
return true;
|
|
300
|
-
}
|
|
301
|
-
if (a.kind === 'ordered' && b.kind === 'ordered') {
|
|
302
|
-
const aOrd = a;
|
|
303
|
-
const bOrd = b;
|
|
304
|
-
// Uniform valueType comparison
|
|
305
|
-
const aHasValue = aOrd.valueType !== undefined;
|
|
306
|
-
const bHasValue = bOrd.valueType !== undefined;
|
|
307
|
-
if (aHasValue || bHasValue) {
|
|
308
|
-
if (!aHasValue || !bHasValue)
|
|
309
|
-
return false;
|
|
310
|
-
return structureEquals(aOrd.valueType, bOrd.valueType);
|
|
311
|
-
}
|
|
312
|
-
// Structural fields comparison
|
|
313
|
-
if (aOrd.fields === undefined && bOrd.fields === undefined)
|
|
314
|
-
return true;
|
|
315
|
-
if (aOrd.fields === undefined || bOrd.fields === undefined)
|
|
316
|
-
return false;
|
|
317
|
-
if (aOrd.fields.length !== bOrd.fields.length)
|
|
318
|
-
return false;
|
|
319
|
-
for (let i = 0; i < aOrd.fields.length; i++) {
|
|
320
|
-
const aField = aOrd.fields[i];
|
|
321
|
-
const bField = bOrd.fields[i];
|
|
322
|
-
if (aField.name !== bField.name)
|
|
323
|
-
return false;
|
|
324
|
-
if (!structureEquals(aField.type, bField.type))
|
|
325
|
-
return false;
|
|
326
|
-
const aDefault = aField.defaultValue;
|
|
327
|
-
const bDefault = bField.defaultValue;
|
|
328
|
-
if (aDefault === undefined && bDefault === undefined)
|
|
329
|
-
continue;
|
|
330
|
-
if (aDefault === undefined || bDefault === undefined)
|
|
331
|
-
return false;
|
|
332
|
-
if (!deepEquals(aDefault, bDefault))
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
return true;
|
|
336
|
-
}
|
|
337
|
-
if (a.kind === 'union' && b.kind === 'union') {
|
|
338
|
-
const aUnion = a;
|
|
339
|
-
const bUnion = b;
|
|
340
|
-
if (aUnion.members.length !== bUnion.members.length)
|
|
341
|
-
return false;
|
|
342
|
-
for (let i = 0; i < aUnion.members.length; i++) {
|
|
343
|
-
if (!structureEquals(aUnion.members[i], bUnion.members[i]))
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
return true;
|
|
347
|
-
}
|
|
348
|
-
if (a.kind === 'closure' && b.kind === 'closure') {
|
|
349
|
-
const aCls = a;
|
|
350
|
-
const bCls = b;
|
|
351
|
-
if (aCls.params === undefined && bCls.params === undefined) {
|
|
352
|
-
// Both absent: compare ret
|
|
353
|
-
}
|
|
354
|
-
else if (aCls.params === undefined || bCls.params === undefined) {
|
|
355
|
-
return false;
|
|
356
|
-
}
|
|
357
|
-
else {
|
|
358
|
-
if (aCls.params.length !== bCls.params.length)
|
|
359
|
-
return false;
|
|
360
|
-
for (let i = 0; i < aCls.params.length; i++) {
|
|
361
|
-
const aParam = aCls.params[i];
|
|
362
|
-
const bParam = bCls.params[i];
|
|
363
|
-
if (aParam.name !== bParam.name)
|
|
364
|
-
return false;
|
|
365
|
-
if (!structureEquals(aParam.type, bParam.type))
|
|
366
|
-
return false;
|
|
367
|
-
const aDefault = aParam.defaultValue;
|
|
368
|
-
const bDefault = bParam.defaultValue;
|
|
369
|
-
if (aDefault === undefined && bDefault === undefined)
|
|
370
|
-
continue;
|
|
371
|
-
if (aDefault === undefined || bDefault === undefined)
|
|
372
|
-
return false;
|
|
373
|
-
if (!deepEquals(aDefault, bDefault))
|
|
374
|
-
return false;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
if (aCls.ret === undefined && bCls.ret === undefined)
|
|
378
|
-
return true;
|
|
379
|
-
if (aCls.ret === undefined || bCls.ret === undefined)
|
|
380
|
-
return false;
|
|
381
|
-
return structureEquals(aCls.ret, bCls.ret);
|
|
382
|
-
}
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
/** @deprecated Use structureEquals instead. */
|
|
386
|
-
export const structuralTypeEquals = structureEquals;
|
|
387
|
-
/** Infer the structural type descriptor for any Rill value. */
|
|
388
|
-
export function inferStructure(value) {
|
|
389
|
-
if (value === null || typeof value === 'string') {
|
|
390
|
-
return { kind: 'string' };
|
|
391
|
-
}
|
|
392
|
-
if (typeof value === 'number') {
|
|
393
|
-
return { kind: 'number' };
|
|
394
|
-
}
|
|
395
|
-
if (typeof value === 'boolean') {
|
|
396
|
-
return { kind: 'bool' };
|
|
397
|
-
}
|
|
398
|
-
if (isTypeValue(value)) {
|
|
399
|
-
return { kind: 'type' };
|
|
400
|
-
}
|
|
401
|
-
if (Array.isArray(value)) {
|
|
402
|
-
return { kind: 'list', element: inferElementType(value) };
|
|
403
|
-
}
|
|
404
|
-
if (isTuple(value)) {
|
|
405
|
-
return {
|
|
406
|
-
kind: 'tuple',
|
|
407
|
-
elements: value.entries.map((e) => ({
|
|
408
|
-
type: inferStructure(e),
|
|
409
|
-
})),
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
if (isOrdered(value)) {
|
|
413
|
-
return {
|
|
414
|
-
kind: 'ordered',
|
|
415
|
-
fields: value.entries.map(([k, v]) => ({
|
|
416
|
-
name: k,
|
|
417
|
-
type: inferStructure(v),
|
|
418
|
-
})),
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
if (isVector(value)) {
|
|
422
|
-
return { kind: 'vector' };
|
|
423
|
-
}
|
|
424
|
-
if (isCallable(value)) {
|
|
425
|
-
const params = (value.params ?? []).map((p) => paramToFieldDef(p.name, p.type ?? { kind: 'any' }, p.defaultValue));
|
|
426
|
-
const ret = value.returnType.structure;
|
|
427
|
-
return { kind: 'closure', params, ret };
|
|
428
|
-
}
|
|
429
|
-
if (typeof value === 'object') {
|
|
430
|
-
const dict = value;
|
|
431
|
-
const fields = {};
|
|
432
|
-
for (const [k, v] of Object.entries(dict)) {
|
|
433
|
-
fields[k] = { type: inferStructure(v) };
|
|
434
|
-
}
|
|
435
|
-
return { kind: 'dict', fields };
|
|
436
|
-
}
|
|
437
|
-
throw new RuntimeError('RILL-R004', `Cannot infer structural type for ${formatValue(value)}`);
|
|
438
|
-
}
|
|
439
|
-
/** @deprecated Use inferStructure instead. */
|
|
440
|
-
export const inferStructuralType = inferStructure;
|
|
441
|
-
/**
|
|
442
|
-
* Check if a value matches a structural type descriptor.
|
|
443
|
-
* Used for runtime type checking (`:?` operator).
|
|
444
|
-
*/
|
|
445
|
-
export function structureMatches(value, type) {
|
|
446
|
-
type = normalizeStructure(type);
|
|
447
|
-
if (typeof value === 'undefined') {
|
|
448
|
-
throw new RuntimeError('RILL-R004', 'Cannot type-check non-value');
|
|
449
|
-
}
|
|
450
|
-
if (type.kind === 'any')
|
|
451
|
-
return true;
|
|
452
|
-
// Leaf primitive variants: match by inferred type name
|
|
453
|
-
if (type.kind === 'number' ||
|
|
454
|
-
type.kind === 'string' ||
|
|
455
|
-
type.kind === 'bool' ||
|
|
456
|
-
type.kind === 'vector' ||
|
|
457
|
-
type.kind === 'type') {
|
|
458
|
-
return inferType(value) === type.kind;
|
|
459
|
-
}
|
|
460
|
-
if (type.kind === 'list') {
|
|
461
|
-
const t = type;
|
|
462
|
-
if (!Array.isArray(value))
|
|
463
|
-
return false;
|
|
464
|
-
if (t.element === undefined)
|
|
465
|
-
return true;
|
|
466
|
-
if (t.element.kind === 'any')
|
|
467
|
-
return true;
|
|
468
|
-
return value.every((elem) => structureMatches(elem, t.element));
|
|
469
|
-
}
|
|
470
|
-
if (type.kind === 'dict') {
|
|
471
|
-
const t = type;
|
|
472
|
-
if (!isDict(value))
|
|
473
|
-
return false;
|
|
474
|
-
if (t.valueType !== undefined) {
|
|
475
|
-
const vals = Object.values(value);
|
|
476
|
-
return vals.every((v) => structureMatches(v, t.valueType));
|
|
477
|
-
}
|
|
478
|
-
if (t.fields === undefined)
|
|
479
|
-
return true;
|
|
480
|
-
const dictKeys = Object.keys(t.fields);
|
|
481
|
-
if (dictKeys.length === 0)
|
|
482
|
-
return true;
|
|
483
|
-
const dict = value;
|
|
484
|
-
for (const key of dictKeys) {
|
|
485
|
-
if (!(key in dict)) {
|
|
486
|
-
const field = t.fields[key];
|
|
487
|
-
if (field.defaultValue !== undefined)
|
|
488
|
-
continue;
|
|
489
|
-
return false;
|
|
490
|
-
}
|
|
491
|
-
const field = t.fields[key];
|
|
492
|
-
if (!structureMatches(dict[key], field.type))
|
|
493
|
-
return false;
|
|
494
|
-
}
|
|
495
|
-
return true;
|
|
496
|
-
}
|
|
497
|
-
if (type.kind === 'tuple') {
|
|
498
|
-
const t = type;
|
|
499
|
-
if (!isTuple(value))
|
|
500
|
-
return false;
|
|
501
|
-
if (t.valueType !== undefined) {
|
|
502
|
-
return value.entries.every((v) => structureMatches(v, t.valueType));
|
|
503
|
-
}
|
|
504
|
-
if (t.elements === undefined)
|
|
505
|
-
return true;
|
|
506
|
-
if (t.elements.length === 0)
|
|
507
|
-
return value.entries.length === 0;
|
|
508
|
-
if (value.entries.length > t.elements.length)
|
|
509
|
-
return false;
|
|
510
|
-
if (value.entries.length < t.elements.length) {
|
|
511
|
-
for (let i = value.entries.length; i < t.elements.length; i++) {
|
|
512
|
-
const field = t.elements[i];
|
|
513
|
-
if (field.defaultValue === undefined)
|
|
514
|
-
return false;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
for (let i = 0; i < value.entries.length; i++) {
|
|
518
|
-
if (!structureMatches(value.entries[i], t.elements[i].type))
|
|
519
|
-
return false;
|
|
520
|
-
}
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
if (type.kind === 'ordered') {
|
|
524
|
-
const t = type;
|
|
525
|
-
if (!isOrdered(value))
|
|
526
|
-
return false;
|
|
527
|
-
if (t.valueType !== undefined) {
|
|
528
|
-
return value.entries.every(([, v]) => structureMatches(v, t.valueType));
|
|
529
|
-
}
|
|
530
|
-
if (t.fields === undefined)
|
|
531
|
-
return true;
|
|
532
|
-
if (t.fields.length === 0)
|
|
533
|
-
return value.entries.length === 0;
|
|
534
|
-
if (value.entries.length > t.fields.length)
|
|
535
|
-
return false;
|
|
536
|
-
if (value.entries.length < t.fields.length) {
|
|
537
|
-
for (let i = value.entries.length; i < t.fields.length; i++) {
|
|
538
|
-
const field = t.fields[i];
|
|
539
|
-
if (field.defaultValue === undefined)
|
|
540
|
-
return false;
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
for (let i = 0; i < value.entries.length; i++) {
|
|
544
|
-
const field = t.fields[i];
|
|
545
|
-
const [actualName, actualValue] = value.entries[i];
|
|
546
|
-
if (actualName !== field.name)
|
|
547
|
-
return false;
|
|
548
|
-
if (!structureMatches(actualValue, field.type))
|
|
549
|
-
return false;
|
|
550
|
-
}
|
|
551
|
-
return true;
|
|
552
|
-
}
|
|
553
|
-
if (type.kind === 'closure') {
|
|
554
|
-
const t = type;
|
|
555
|
-
if (!isCallable(value))
|
|
556
|
-
return false;
|
|
557
|
-
if (t.params === undefined)
|
|
558
|
-
return true;
|
|
559
|
-
const valueParams = value.params ?? [];
|
|
560
|
-
if (valueParams.length !== t.params.length)
|
|
561
|
-
return false;
|
|
562
|
-
for (let i = 0; i < t.params.length; i++) {
|
|
563
|
-
const field = t.params[i];
|
|
564
|
-
const param = valueParams[i];
|
|
565
|
-
if (param.name !== field.name)
|
|
566
|
-
return false;
|
|
567
|
-
const paramType = param.type ?? { kind: 'any' };
|
|
568
|
-
if (!structureEquals(paramType, field.type))
|
|
569
|
-
return false;
|
|
570
|
-
}
|
|
571
|
-
const retType = value.returnType.structure;
|
|
572
|
-
if (t.ret === undefined)
|
|
573
|
-
return true;
|
|
574
|
-
return structureEquals(retType, t.ret);
|
|
575
|
-
}
|
|
576
|
-
if (type.kind === 'union') {
|
|
577
|
-
const t = type;
|
|
578
|
-
return t.members.some((member) => structureMatches(value, member));
|
|
579
|
-
}
|
|
580
|
-
return false;
|
|
581
|
-
}
|
|
582
|
-
/** @deprecated Use structureMatches instead. */
|
|
583
|
-
export const structuralTypeMatches = structureMatches;
|
|
584
|
-
/** Build a closure param field definition from name, type, and optional default. */
|
|
585
|
-
export function paramToFieldDef(name, type, defaultValue) {
|
|
586
|
-
const field = { name, type };
|
|
587
|
-
if (defaultValue !== undefined)
|
|
588
|
-
field.defaultValue = defaultValue;
|
|
589
|
-
return field;
|
|
590
|
-
}
|
|
591
|
-
/** Format a RillValue as a rill literal for use in type signatures. */
|
|
592
|
-
function formatRillLiteral(value) {
|
|
593
|
-
if (typeof value === 'string') {
|
|
594
|
-
const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
595
|
-
return `"${escaped}"`;
|
|
596
|
-
}
|
|
597
|
-
if (typeof value === 'number')
|
|
598
|
-
return String(value);
|
|
599
|
-
if (typeof value === 'boolean')
|
|
600
|
-
return value ? 'true' : 'false';
|
|
601
|
-
if (value === null)
|
|
602
|
-
return 'null';
|
|
603
|
-
return formatValue(value);
|
|
604
|
-
}
|
|
605
|
-
/** Format a structural type descriptor as a human-readable string. */
|
|
606
|
-
export function formatStructure(type) {
|
|
607
|
-
if (type.kind === 'any' ||
|
|
608
|
-
type.kind === 'number' ||
|
|
609
|
-
type.kind === 'string' ||
|
|
610
|
-
type.kind === 'bool' ||
|
|
611
|
-
type.kind === 'vector' ||
|
|
612
|
-
type.kind === 'type') {
|
|
613
|
-
return type.kind;
|
|
614
|
-
}
|
|
615
|
-
if (type.kind === 'list') {
|
|
616
|
-
const t = type;
|
|
617
|
-
if (t.element === undefined)
|
|
618
|
-
return 'list';
|
|
619
|
-
return `list(${formatStructure(t.element)})`;
|
|
620
|
-
}
|
|
621
|
-
if (type.kind === 'dict') {
|
|
622
|
-
const t = type;
|
|
623
|
-
if (t.valueType !== undefined && t.fields === undefined) {
|
|
624
|
-
return `dict(${formatStructure(t.valueType)})`;
|
|
625
|
-
}
|
|
626
|
-
if (t.fields === undefined)
|
|
627
|
-
return 'dict';
|
|
628
|
-
const parts = Object.keys(t.fields)
|
|
629
|
-
.sort()
|
|
630
|
-
.map((k) => {
|
|
631
|
-
const field = t.fields[k];
|
|
632
|
-
const base = `${k}: ${formatStructure(field.type)}`;
|
|
633
|
-
if (field.defaultValue === undefined)
|
|
634
|
-
return base;
|
|
635
|
-
return `${base} = ${formatRillLiteral(field.defaultValue)}`;
|
|
636
|
-
});
|
|
637
|
-
return `dict(${parts.join(', ')})`;
|
|
638
|
-
}
|
|
639
|
-
if (type.kind === 'tuple') {
|
|
640
|
-
const t = type;
|
|
641
|
-
if (t.valueType !== undefined && t.elements === undefined) {
|
|
642
|
-
return `tuple(${formatStructure(t.valueType)})`;
|
|
643
|
-
}
|
|
644
|
-
if (t.elements === undefined)
|
|
645
|
-
return 'tuple';
|
|
646
|
-
const parts = t.elements.map((field) => {
|
|
647
|
-
const base = formatStructure(field.type);
|
|
648
|
-
if (field.defaultValue === undefined)
|
|
649
|
-
return base;
|
|
650
|
-
return `${base} = ${formatRillLiteral(field.defaultValue)}`;
|
|
651
|
-
});
|
|
652
|
-
return `tuple(${parts.join(', ')})`;
|
|
653
|
-
}
|
|
654
|
-
if (type.kind === 'ordered') {
|
|
655
|
-
const t = type;
|
|
656
|
-
if (t.valueType !== undefined && t.fields === undefined) {
|
|
657
|
-
return `ordered(${formatStructure(t.valueType)})`;
|
|
658
|
-
}
|
|
659
|
-
if (t.fields === undefined)
|
|
660
|
-
return 'ordered';
|
|
661
|
-
const parts = t.fields.map((field) => {
|
|
662
|
-
const base = `${field.name}: ${formatStructure(field.type)}`;
|
|
663
|
-
if (field.defaultValue === undefined)
|
|
664
|
-
return base;
|
|
665
|
-
return `${base} = ${formatRillLiteral(field.defaultValue)}`;
|
|
666
|
-
});
|
|
667
|
-
return `ordered(${parts.join(', ')})`;
|
|
668
|
-
}
|
|
669
|
-
if (type.kind === 'closure') {
|
|
670
|
-
const t = type;
|
|
671
|
-
if (t.params === undefined)
|
|
672
|
-
return 'closure';
|
|
673
|
-
const params = t.params
|
|
674
|
-
.map((field) => {
|
|
675
|
-
const base = `${field.name}: ${formatStructure(field.type)}`;
|
|
676
|
-
if (field.defaultValue === undefined)
|
|
677
|
-
return base;
|
|
678
|
-
return `${base} = ${formatRillLiteral(field.defaultValue)}`;
|
|
679
|
-
})
|
|
680
|
-
.join(', ');
|
|
681
|
-
const ret = t.ret !== undefined ? formatStructure(t.ret) : 'any';
|
|
682
|
-
return `|${params}| :${ret}`;
|
|
683
|
-
}
|
|
684
|
-
if (type.kind === 'union') {
|
|
685
|
-
const t = type;
|
|
686
|
-
return t.members.map(formatStructure).join('|');
|
|
687
|
-
}
|
|
688
|
-
return 'any';
|
|
689
|
-
}
|
|
690
|
-
/** @deprecated Use formatStructure instead. */
|
|
691
|
-
export const formatStructuralType = formatStructure;
|
|
692
28
|
/**
|
|
693
29
|
* Check if a value is of the expected type.
|
|
694
30
|
* Returns true if the value matches the expected type, false otherwise.
|
|
@@ -729,8 +65,6 @@ export function isEmpty(value) {
|
|
|
729
65
|
export const formatValue = registryFormatValue;
|
|
730
66
|
/** Serialize a Rill value for JSON transport. Delegates to type-registrations. */
|
|
731
67
|
export const serializeValue = registrySerializeValue;
|
|
732
|
-
/** @deprecated Use serializeValue instead. */
|
|
733
|
-
export const valueToJSON = serializeValue;
|
|
734
68
|
/**
|
|
735
69
|
* Convert a RillValue to a NativeResult for host consumption.
|
|
736
70
|
* Non-representable types (closures, vectors, type values, iterators) produce descriptor objects.
|
|
@@ -776,6 +110,17 @@ function toNativeValue(value) {
|
|
|
776
110
|
signature: formatStructure(value.structure),
|
|
777
111
|
};
|
|
778
112
|
}
|
|
113
|
+
if (isStream(value)) {
|
|
114
|
+
const descriptor = {
|
|
115
|
+
__type: 'stream',
|
|
116
|
+
done: value.done,
|
|
117
|
+
};
|
|
118
|
+
const chunkType = value['__rill_stream_chunk_type'];
|
|
119
|
+
const retType = value['__rill_stream_ret_type'];
|
|
120
|
+
descriptor['chunkType'] = chunkType ? formatStructure(chunkType) : null;
|
|
121
|
+
descriptor['resolutionType'] = retType ? formatStructure(retType) : null;
|
|
122
|
+
return descriptor;
|
|
123
|
+
}
|
|
779
124
|
if (isIterator(value)) {
|
|
780
125
|
return { done: value.done };
|
|
781
126
|
}
|
|
@@ -815,8 +160,6 @@ export function structureToTypeValue(type) {
|
|
|
815
160
|
structure: type,
|
|
816
161
|
});
|
|
817
162
|
}
|
|
818
|
-
/** @deprecated Use structureToTypeValue instead. */
|
|
819
|
-
export const rillTypeToTypeValue = structureToTypeValue;
|
|
820
163
|
/**
|
|
821
164
|
* Check if a type is a collection (dict, ordered, tuple) with defined
|
|
822
165
|
* fields or elements. Used to decide if an empty collection can be
|
|
@@ -833,46 +176,7 @@ export function hasCollectionFields(type) {
|
|
|
833
176
|
(!!type.elements ||
|
|
834
177
|
!!type.valueType)));
|
|
835
178
|
}
|
|
836
|
-
/**
|
|
837
|
-
* Create an empty collection value matching the given TypeStructure.
|
|
838
|
-
* Assumes the type is dict, ordered, or tuple.
|
|
839
|
-
*/
|
|
840
|
-
export function emptyForType(type) {
|
|
841
|
-
if (type.kind === 'dict')
|
|
842
|
-
return {};
|
|
843
|
-
if (type.kind === 'ordered')
|
|
844
|
-
return createOrdered([]);
|
|
845
|
-
if (type.kind === 'tuple')
|
|
846
|
-
return createTuple([]);
|
|
847
|
-
return {};
|
|
848
|
-
}
|
|
849
179
|
/** Check if a key name is reserved */
|
|
850
180
|
export function isReservedMethod(name) {
|
|
851
181
|
return RESERVED_DICT_METHODS.includes(name);
|
|
852
182
|
}
|
|
853
|
-
/**
|
|
854
|
-
* Type guard for Rill iterator (lazy sequence).
|
|
855
|
-
* An iterator is a dict with:
|
|
856
|
-
* - done: boolean - whether iteration is complete
|
|
857
|
-
* - next: callable - function to get next iterator
|
|
858
|
-
* - value: any (only required when not done) - current element
|
|
859
|
-
*/
|
|
860
|
-
export function isIterator(value) {
|
|
861
|
-
if (!isDict(value))
|
|
862
|
-
return false;
|
|
863
|
-
const dict = value;
|
|
864
|
-
if (!('done' in dict && typeof dict['done'] === 'boolean'))
|
|
865
|
-
return false;
|
|
866
|
-
if (!('next' in dict && isCallable(dict['next'])))
|
|
867
|
-
return false;
|
|
868
|
-
// 'value' field only required when not done
|
|
869
|
-
if (!dict['done'] && !('value' in dict))
|
|
870
|
-
return false;
|
|
871
|
-
return true;
|
|
872
|
-
}
|
|
873
|
-
/** @deprecated Use isIterator instead. */
|
|
874
|
-
export const isRillIterator = isIterator;
|
|
875
|
-
/** Copy a RillValue. Delegates to type-registrations. */
|
|
876
|
-
export const copyValue = registryCopyValue;
|
|
877
|
-
/** @deprecated Use copyValue instead. */
|
|
878
|
-
export const deepCopyRillValue = copyValue;
|