@rcrsr/rill 0.16.0 → 0.17.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/README.md +37 -21
- package/dist/ext/crypto/index.d.ts +3 -3
- package/dist/ext/crypto/index.js +61 -58
- package/dist/ext/exec/index.d.ts +3 -3
- package/dist/ext/exec/index.js +14 -8
- package/dist/ext/fetch/index.d.ts +3 -3
- package/dist/ext/fetch/index.js +16 -11
- package/dist/ext/fs/index.d.ts +3 -3
- package/dist/ext/fs/index.js +242 -239
- package/dist/ext/kv/index.d.ts +3 -3
- package/dist/ext/kv/index.js +197 -195
- package/dist/ext/kv/store.js +2 -1
- package/dist/ext-parse-bridge.d.ts +10 -0
- package/dist/ext-parse-bridge.js +10 -0
- package/dist/generated/introspection-data.d.ts +1 -1
- package/dist/generated/introspection-data.js +385 -296
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.js +2 -2
- package/dist/index.d.ts +15 -4
- package/dist/index.js +14 -5
- package/dist/parser/parser-types.js +12 -0
- package/dist/parser/parser-use.js +7 -1
- package/dist/runtime/core/callable.d.ts +20 -8
- package/dist/runtime/core/callable.js +63 -23
- package/dist/runtime/core/context.d.ts +0 -11
- package/dist/runtime/core/context.js +76 -75
- package/dist/runtime/core/eval/index.d.ts +2 -2
- package/dist/runtime/core/eval/index.js +11 -0
- package/dist/runtime/core/eval/mixins/closures.js +15 -15
- package/dist/runtime/core/eval/mixins/conversion.js +51 -110
- package/dist/runtime/core/eval/mixins/core.js +2 -2
- package/dist/runtime/core/eval/mixins/expressions.js +35 -27
- package/dist/runtime/core/eval/mixins/literals.js +3 -3
- package/dist/runtime/core/eval/mixins/types.js +44 -54
- package/dist/runtime/core/eval/mixins/variables.js +10 -8
- package/dist/runtime/core/field-descriptor.d.ts +3 -3
- package/dist/runtime/core/field-descriptor.js +2 -1
- package/dist/runtime/core/introspection.js +6 -6
- package/dist/runtime/core/markers.d.ts +12 -0
- package/dist/runtime/core/markers.js +7 -0
- package/dist/runtime/core/type-registrations.d.ts +136 -0
- package/dist/runtime/core/type-registrations.js +749 -0
- package/dist/runtime/core/type-structures.d.ts +128 -0
- package/dist/runtime/core/type-structures.js +12 -0
- package/dist/runtime/core/types.d.ts +15 -3
- package/dist/runtime/core/values.d.ts +62 -153
- package/dist/runtime/core/values.js +308 -524
- package/dist/runtime/ext/builtins.js +83 -64
- package/dist/runtime/ext/extensions.d.ts +30 -124
- package/dist/runtime/ext/extensions.js +0 -93
- package/dist/runtime/ext/test-context.d.ts +28 -0
- package/dist/runtime/ext/test-context.js +154 -0
- package/dist/runtime/index.d.ts +22 -8
- package/dist/runtime/index.js +18 -4
- package/dist/signature-parser.d.ts +2 -2
- package/dist/signature-parser.js +14 -14
- package/package.json +1 -1
|
@@ -23,21 +23,8 @@
|
|
|
23
23
|
* @internal
|
|
24
24
|
*/
|
|
25
25
|
import { RuntimeError } from '../../../../types.js';
|
|
26
|
-
import { inferType, checkType, isTypeValue,
|
|
26
|
+
import { inferType, checkType, isTypeValue, structureMatches, inferStructure, formatStructure, } from '../../values.js';
|
|
27
27
|
import { getVariable } from '../../context.js';
|
|
28
|
-
/**
|
|
29
|
-
* Leaf types that reject all type arguments.
|
|
30
|
-
* Extracted as module-level constant to avoid per-call allocation.
|
|
31
|
-
*/
|
|
32
|
-
const LEAF_TYPES = new Set([
|
|
33
|
-
'string',
|
|
34
|
-
'number',
|
|
35
|
-
'bool',
|
|
36
|
-
'vector',
|
|
37
|
-
'type',
|
|
38
|
-
'any',
|
|
39
|
-
'closure',
|
|
40
|
-
]);
|
|
41
28
|
/**
|
|
42
29
|
* TypesMixin implementation.
|
|
43
30
|
*
|
|
@@ -87,7 +74,7 @@ function createTypesMixin(Base) {
|
|
|
87
74
|
throw new RuntimeError('RILL-R004', 'list() requires exactly 1 type argument', location);
|
|
88
75
|
}
|
|
89
76
|
const element = await resolveArg(args[0]);
|
|
90
|
-
const structure = {
|
|
77
|
+
const structure = { kind: 'list', element };
|
|
91
78
|
return Object.freeze({
|
|
92
79
|
__rill_type: true,
|
|
93
80
|
typeName: name,
|
|
@@ -107,11 +94,11 @@ function createTypesMixin(Base) {
|
|
|
107
94
|
// EC-B6: Default type mismatch on uniform single-arg path
|
|
108
95
|
if (positional[0].defaultValue !== undefined) {
|
|
109
96
|
const defaultVal = await evaluateDefault(positional[0].defaultValue);
|
|
110
|
-
if (!
|
|
111
|
-
throw new RuntimeError('RILL-R004', `Default value for ${name} element must be ${
|
|
97
|
+
if (!structureMatches(defaultVal, valueType)) {
|
|
98
|
+
throw new RuntimeError('RILL-R004', `Default value for ${name} element must be ${formatStructure(valueType)}, got ${inferType(defaultVal)}`, location);
|
|
112
99
|
}
|
|
113
100
|
}
|
|
114
|
-
const structure = {
|
|
101
|
+
const structure = { kind: name, valueType };
|
|
115
102
|
return Object.freeze({
|
|
116
103
|
__rill_type: true,
|
|
117
104
|
typeName: name,
|
|
@@ -131,14 +118,14 @@ function createTypesMixin(Base) {
|
|
|
131
118
|
if (arg.defaultValue !== undefined) {
|
|
132
119
|
const defaultVal = await evaluateDefault(arg.defaultValue);
|
|
133
120
|
// EC-B6: Default type mismatch
|
|
134
|
-
if (!
|
|
135
|
-
throw new RuntimeError('RILL-R004', `Default value for field '${arg.name}' must be ${
|
|
121
|
+
if (!structureMatches(defaultVal, resolvedType)) {
|
|
122
|
+
throw new RuntimeError('RILL-R004', `Default value for field '${arg.name}' must be ${formatStructure(resolvedType)}, got ${inferType(defaultVal)}`, location);
|
|
136
123
|
}
|
|
137
124
|
fieldDef.defaultValue = defaultVal;
|
|
138
125
|
}
|
|
139
126
|
fields[arg.name] = fieldDef;
|
|
140
127
|
}
|
|
141
|
-
const structure = {
|
|
128
|
+
const structure = { kind: 'dict', fields };
|
|
142
129
|
return Object.freeze({
|
|
143
130
|
__rill_type: true,
|
|
144
131
|
typeName: name,
|
|
@@ -156,14 +143,17 @@ function createTypesMixin(Base) {
|
|
|
156
143
|
if (arg.defaultValue !== undefined) {
|
|
157
144
|
const defaultVal = await evaluateDefault(arg.defaultValue);
|
|
158
145
|
// EC-B6: Default type mismatch
|
|
159
|
-
if (!
|
|
160
|
-
throw new RuntimeError('RILL-R004', `Default value for field '${arg.name}' must be ${
|
|
146
|
+
if (!structureMatches(defaultVal, resolvedType)) {
|
|
147
|
+
throw new RuntimeError('RILL-R004', `Default value for field '${arg.name}' must be ${formatStructure(resolvedType)}, got ${inferType(defaultVal)}`, location);
|
|
161
148
|
}
|
|
162
149
|
fieldDef.defaultValue = defaultVal;
|
|
163
150
|
}
|
|
164
151
|
orderedFields.push(fieldDef);
|
|
165
152
|
}
|
|
166
|
-
const structure = {
|
|
153
|
+
const structure = {
|
|
154
|
+
kind: 'ordered',
|
|
155
|
+
fields: orderedFields,
|
|
156
|
+
};
|
|
167
157
|
return Object.freeze({
|
|
168
158
|
__rill_type: true,
|
|
169
159
|
typeName: name,
|
|
@@ -183,11 +173,11 @@ function createTypesMixin(Base) {
|
|
|
183
173
|
// EC-B6: Default type mismatch on uniform single-arg path
|
|
184
174
|
if (args[0].defaultValue !== undefined) {
|
|
185
175
|
const defaultVal = await evaluateDefault(args[0].defaultValue);
|
|
186
|
-
if (!
|
|
187
|
-
throw new RuntimeError('RILL-R004', `Default value for tuple element must be ${
|
|
176
|
+
if (!structureMatches(defaultVal, valueType)) {
|
|
177
|
+
throw new RuntimeError('RILL-R004', `Default value for tuple element must be ${formatStructure(valueType)}, got ${inferType(defaultVal)}`, location);
|
|
188
178
|
}
|
|
189
179
|
}
|
|
190
|
-
const structure = {
|
|
180
|
+
const structure = { kind: 'tuple', valueType };
|
|
191
181
|
return Object.freeze({
|
|
192
182
|
__rill_type: true,
|
|
193
183
|
typeName: 'tuple',
|
|
@@ -202,8 +192,8 @@ function createTypesMixin(Base) {
|
|
|
202
192
|
if (arg.defaultValue !== undefined) {
|
|
203
193
|
const defaultVal = await evaluateDefault(arg.defaultValue);
|
|
204
194
|
// EC-B6: Default type mismatch
|
|
205
|
-
if (!
|
|
206
|
-
throw new RuntimeError('RILL-R004', `Default value for tuple element must be ${
|
|
195
|
+
if (!structureMatches(defaultVal, resolvedType)) {
|
|
196
|
+
throw new RuntimeError('RILL-R004', `Default value for tuple element must be ${formatStructure(resolvedType)}, got ${inferType(defaultVal)}`, location);
|
|
207
197
|
}
|
|
208
198
|
fieldDef.defaultValue = defaultVal;
|
|
209
199
|
}
|
|
@@ -221,7 +211,7 @@ function createTypesMixin(Base) {
|
|
|
221
211
|
throw new RuntimeError('RILL-R004', `tuple() default values must be trailing: element at position ${i} has no default but a preceding element does`, location);
|
|
222
212
|
}
|
|
223
213
|
}
|
|
224
|
-
const structure = {
|
|
214
|
+
const structure = { kind: 'tuple', elements };
|
|
225
215
|
return Object.freeze({
|
|
226
216
|
__rill_type: true,
|
|
227
217
|
typeName: 'tuple',
|
|
@@ -254,11 +244,11 @@ function createTypesMixin(Base) {
|
|
|
254
244
|
return Object.freeze({
|
|
255
245
|
__rill_type: true,
|
|
256
246
|
typeName,
|
|
257
|
-
structure: {
|
|
247
|
+
structure: { kind: typeName },
|
|
258
248
|
});
|
|
259
249
|
}
|
|
260
|
-
// EC-B1: Leaf types reject all type arguments
|
|
261
|
-
if (
|
|
250
|
+
// EC-B1: Leaf types reject all type arguments (AC-4: derived from registrations)
|
|
251
|
+
if (this.ctx.leafTypes.has(typeName)) {
|
|
262
252
|
throw new RuntimeError('RILL-R004', `${typeName} does not accept type arguments`);
|
|
263
253
|
}
|
|
264
254
|
// Delegate to buildCollectionType with recursive resolveTypeRef
|
|
@@ -271,7 +261,7 @@ function createTypesMixin(Base) {
|
|
|
271
261
|
});
|
|
272
262
|
}
|
|
273
263
|
// Union type ref: (A | B) -- resolve each member recursively and
|
|
274
|
-
// return a RillTypeValue with structure: {
|
|
264
|
+
// return a RillTypeValue with structure: { kind: 'union', members: [...] }.
|
|
275
265
|
// typeName is set to a display string for error messages; the structure
|
|
276
266
|
// field carries the authoritative type shape for validation (DR-1).
|
|
277
267
|
if (typeRef.kind === 'union') {
|
|
@@ -280,9 +270,9 @@ function createTypesMixin(Base) {
|
|
|
280
270
|
const resolved = await this.resolveTypeRef(member, getVariableFn);
|
|
281
271
|
members.push(resolved.structure);
|
|
282
272
|
}
|
|
283
|
-
const structure = {
|
|
273
|
+
const structure = { kind: 'union', members };
|
|
284
274
|
const displayName = members
|
|
285
|
-
.map(
|
|
275
|
+
.map(formatStructure)
|
|
286
276
|
.join('|');
|
|
287
277
|
return Object.freeze({
|
|
288
278
|
__rill_type: true,
|
|
@@ -301,13 +291,13 @@ function createTypesMixin(Base) {
|
|
|
301
291
|
/**
|
|
302
292
|
* Assert that a value is of the expected type.
|
|
303
293
|
* Returns the value unchanged if assertion passes, throws on mismatch.
|
|
304
|
-
* Accepts a bare RillTypeName or a full
|
|
305
|
-
* When expected is a
|
|
306
|
-
* dispatches to
|
|
294
|
+
* Accepts a bare RillTypeName or a full TypeStructure.
|
|
295
|
+
* When expected is a TypeStructure with sub-fields (element, fields, elements),
|
|
296
|
+
* dispatches to structureMatches for deep validation.
|
|
307
297
|
* Exported for use by type assertion evaluation.
|
|
308
298
|
*/
|
|
309
299
|
assertType(value, expected, location) {
|
|
310
|
-
// Structural path: expected is a
|
|
300
|
+
// Structural path: expected is a TypeStructure object
|
|
311
301
|
if (typeof expected !== 'string') {
|
|
312
302
|
const hasSubFields = 'element' in expected ||
|
|
313
303
|
'fields' in expected ||
|
|
@@ -315,15 +305,15 @@ function createTypesMixin(Base) {
|
|
|
315
305
|
'members' in expected ||
|
|
316
306
|
'valueType' in expected;
|
|
317
307
|
if (hasSubFields) {
|
|
318
|
-
if (!
|
|
319
|
-
const expectedStr =
|
|
320
|
-
const actualStr =
|
|
308
|
+
if (!structureMatches(value, expected)) {
|
|
309
|
+
const expectedStr = formatStructure(expected);
|
|
310
|
+
const actualStr = formatStructure(inferStructure(value));
|
|
321
311
|
throw new RuntimeError('RILL-R004', `Type assertion failed: expected ${expectedStr}, got ${actualStr}`, location, { expectedType: expectedStr, actualType: actualStr });
|
|
322
312
|
}
|
|
323
313
|
return value;
|
|
324
314
|
}
|
|
325
315
|
// Bare structural type (no sub-fields): fall through using type name
|
|
326
|
-
expected = expected.
|
|
316
|
+
expected = expected.kind;
|
|
327
317
|
}
|
|
328
318
|
// Bare type name path
|
|
329
319
|
if (expected === 'any')
|
|
@@ -366,7 +356,7 @@ function createTypesMixin(Base) {
|
|
|
366
356
|
'members' in resolved.structure ||
|
|
367
357
|
'valueType' in resolved.structure;
|
|
368
358
|
if (hasSubFields) {
|
|
369
|
-
return
|
|
359
|
+
return structureMatches(value, resolved.structure);
|
|
370
360
|
}
|
|
371
361
|
return checkType(value, resolved.typeName);
|
|
372
362
|
}
|
|
@@ -409,9 +399,9 @@ function createTypesMixin(Base) {
|
|
|
409
399
|
const location = node.span.start;
|
|
410
400
|
return this.buildCollectionType(name, node.args, async (arg) => {
|
|
411
401
|
const resolved = await this.resolveTypeRef(arg.value, (varName) => getVariable(this.ctx, varName));
|
|
412
|
-
return resolved.structure.
|
|
402
|
+
return resolved.structure.kind === 'any' &&
|
|
413
403
|
resolved.typeName !== 'any'
|
|
414
|
-
? {
|
|
404
|
+
? { kind: resolved.typeName }
|
|
415
405
|
: resolved.structure;
|
|
416
406
|
}, async (node) => {
|
|
417
407
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -422,7 +412,7 @@ function createTypesMixin(Base) {
|
|
|
422
412
|
* Evaluate a closure signature literal into a RillTypeValue [IR-8].
|
|
423
413
|
*
|
|
424
414
|
* Creates a closure type value from |param: T, ...|: R syntax.
|
|
425
|
-
* Each parameter produces a [name,
|
|
415
|
+
* Each parameter produces a [name, TypeStructure] entry.
|
|
426
416
|
*
|
|
427
417
|
* Error contracts:
|
|
428
418
|
* - EC-8: missing return type -> RILL-R004 (enforced at parse time; node always has returnType)
|
|
@@ -430,14 +420,14 @@ function createTypesMixin(Base) {
|
|
|
430
420
|
*/
|
|
431
421
|
async evaluateClosureSigLiteral(node) {
|
|
432
422
|
const location = node.span.start;
|
|
433
|
-
// Helper: evaluate a type expression and extract
|
|
423
|
+
// Helper: evaluate a type expression and extract TypeStructure
|
|
434
424
|
const resolveTypeExpr = async (argVal) => {
|
|
435
425
|
if (!isTypeValue(argVal)) {
|
|
436
426
|
throw new RuntimeError('RILL-R004', `Parameter type must be a type value, got ${inferType(argVal)}`, location);
|
|
437
427
|
}
|
|
438
|
-
return argVal.structure.
|
|
428
|
+
return argVal.structure.kind === 'any' &&
|
|
439
429
|
argVal.typeName !== 'any'
|
|
440
|
-
? {
|
|
430
|
+
? { kind: argVal.typeName }
|
|
441
431
|
: argVal.structure;
|
|
442
432
|
};
|
|
443
433
|
// Evaluate parameter types
|
|
@@ -456,11 +446,11 @@ function createTypesMixin(Base) {
|
|
|
456
446
|
if (!isTypeValue(retVal)) {
|
|
457
447
|
throw new RuntimeError('RILL-R004', `Closure type literal requires return type after |, got ${inferType(retVal)}`, location);
|
|
458
448
|
}
|
|
459
|
-
const ret = retVal.structure.
|
|
449
|
+
const ret = retVal.structure.kind === 'any' &&
|
|
460
450
|
retVal.typeName !== 'any'
|
|
461
|
-
? {
|
|
451
|
+
? { kind: retVal.typeName }
|
|
462
452
|
: retVal.structure;
|
|
463
|
-
const structure = {
|
|
453
|
+
const structure = { kind: 'closure', params, ret };
|
|
464
454
|
return Object.freeze({
|
|
465
455
|
__rill_type: true,
|
|
466
456
|
typeName: 'closure',
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* @internal
|
|
32
32
|
*/
|
|
33
33
|
import { RuntimeError } from '../../../../types.js';
|
|
34
|
-
import {
|
|
34
|
+
import { formatStructure, inferType, isTypeValue, structureMatches, } from '../../values.js';
|
|
35
35
|
import { getVariable, hasVariable } from '../../context.js';
|
|
36
36
|
import { isDict, isCallable } from '../../callable.js';
|
|
37
37
|
/**
|
|
@@ -69,8 +69,8 @@ function createVariablesMixin(Base) {
|
|
|
69
69
|
if (explicitType !== undefined) {
|
|
70
70
|
if (typeof explicitType === 'object') {
|
|
71
71
|
// Structural type check
|
|
72
|
-
if (!
|
|
73
|
-
const expectedLabel =
|
|
72
|
+
if (!structureMatches(value, explicitType)) {
|
|
73
|
+
const expectedLabel = formatStructure(explicitType);
|
|
74
74
|
throw new RuntimeError('RILL-R001', `Type mismatch: cannot assign ${valueType} to $${name}:${expectedLabel}`, location, {
|
|
75
75
|
variableName: name,
|
|
76
76
|
expectedType: expectedLabel,
|
|
@@ -98,8 +98,8 @@ function createVariablesMixin(Base) {
|
|
|
98
98
|
if (lockedType !== undefined && lockedType !== 'any') {
|
|
99
99
|
if (typeof lockedType === 'object') {
|
|
100
100
|
// Structural locked type — validate full shape
|
|
101
|
-
if (!
|
|
102
|
-
const expectedLabel =
|
|
101
|
+
if (!structureMatches(value, lockedType)) {
|
|
102
|
+
const expectedLabel = formatStructure(lockedType);
|
|
103
103
|
throw new RuntimeError('RILL-R001', `Type mismatch: cannot assign ${valueType} to $${name} (locked as ${expectedLabel})`, location, {
|
|
104
104
|
variableName: name,
|
|
105
105
|
expectedType: expectedLabel,
|
|
@@ -120,7 +120,9 @@ function createVariablesMixin(Base) {
|
|
|
120
120
|
if (!this.ctx.variableTypes.has(name)) {
|
|
121
121
|
// Store structural type (object) directly so re-assignment checks
|
|
122
122
|
// validate the full shape. Fall back to valueType when no annotation.
|
|
123
|
-
const lockType = explicitType !== undefined
|
|
123
|
+
const lockType = explicitType !== undefined
|
|
124
|
+
? explicitType
|
|
125
|
+
: valueType;
|
|
124
126
|
this.ctx.variableTypes.set(name, lockType);
|
|
125
127
|
}
|
|
126
128
|
}
|
|
@@ -260,7 +262,7 @@ function createVariablesMixin(Base) {
|
|
|
260
262
|
value = value.typeName;
|
|
261
263
|
}
|
|
262
264
|
else if (field === 'signature') {
|
|
263
|
-
value =
|
|
265
|
+
value = formatStructure(value.structure);
|
|
264
266
|
}
|
|
265
267
|
else {
|
|
266
268
|
throw new RuntimeError('RILL-R003', `Type value has no property "${field}"`, this.getNodeLocation(node));
|
|
@@ -322,7 +324,7 @@ function createVariablesMixin(Base) {
|
|
|
322
324
|
return true;
|
|
323
325
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
324
326
|
const resolved = await this.resolveTypeRef(typeRef, (name) => getVariable(this.ctx, name));
|
|
325
|
-
return
|
|
327
|
+
return structureMatches(fieldValue, resolved.structure);
|
|
326
328
|
};
|
|
327
329
|
if (finalAccess.kind === 'literal') {
|
|
328
330
|
// Check if literal field exists in dict
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
10
|
import type { SourceLocation } from '../../types.js';
|
|
11
|
-
import type { RillFieldDef,
|
|
11
|
+
import type { RillFieldDef, TypeStructure } from './values.js';
|
|
12
12
|
/**
|
|
13
13
|
* Field descriptor — carries field name and structural type when accessing a
|
|
14
14
|
* dict-kind RillType field.
|
|
@@ -23,6 +23,6 @@ export interface RillFieldDescriptor {
|
|
|
23
23
|
*
|
|
24
24
|
* EC-1: Throws RILL-R003 when fieldName is absent from structuralType.fields.
|
|
25
25
|
*/
|
|
26
|
-
export declare function buildFieldDescriptor(structuralType:
|
|
27
|
-
|
|
26
|
+
export declare function buildFieldDescriptor(structuralType: TypeStructure & {
|
|
27
|
+
kind: 'dict';
|
|
28
28
|
}, fieldName: string, location: SourceLocation): RillFieldDescriptor;
|
|
@@ -14,7 +14,8 @@ import { RuntimeError } from '../../types.js';
|
|
|
14
14
|
* EC-1: Throws RILL-R003 when fieldName is absent from structuralType.fields.
|
|
15
15
|
*/
|
|
16
16
|
export function buildFieldDescriptor(structuralType, fieldName, location) {
|
|
17
|
-
const
|
|
17
|
+
const fields = structuralType.fields;
|
|
18
|
+
const fieldType = fields?.[fieldName];
|
|
18
19
|
if (fieldType === undefined) {
|
|
19
20
|
throw new RuntimeError('RILL-R003', `Shape has no field "${fieldName}"`, location);
|
|
20
21
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Functions for inspecting runtime context at runtime.
|
|
5
5
|
* These enable host applications to discover available functions and their signatures.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { formatStructure, formatValue } from './values.js';
|
|
8
8
|
import { isApplicationCallable, isRuntimeCallable, isScriptCallable, } from './callable.js';
|
|
9
9
|
import { LANGUAGE_REFERENCE } from '../../generated/introspection-data.js';
|
|
10
10
|
import { BUILTIN_FUNCTIONS } from '../ext/builtins.js';
|
|
@@ -40,7 +40,7 @@ export function getFunctions(ctx) {
|
|
|
40
40
|
if (callable.params) {
|
|
41
41
|
const params = callable.params.map((p) => ({
|
|
42
42
|
name: p.name,
|
|
43
|
-
type: p.type !== undefined ?
|
|
43
|
+
type: p.type !== undefined ? formatStructure(p.type) : 'any',
|
|
44
44
|
description: typeof p.annotations['description'] === 'string'
|
|
45
45
|
? p.annotations['description']
|
|
46
46
|
: '',
|
|
@@ -50,7 +50,7 @@ export function getFunctions(ctx) {
|
|
|
50
50
|
name,
|
|
51
51
|
description: callable.annotations?.['description'] ?? '',
|
|
52
52
|
params,
|
|
53
|
-
returnType:
|
|
53
|
+
returnType: formatStructure(callable.returnType.structure),
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
else {
|
|
@@ -93,7 +93,7 @@ export function getFunctions(ctx) {
|
|
|
93
93
|
// Convert params to ParamMetadata using RillParam.type (IC-5)
|
|
94
94
|
const params = value.params.map((p) => ({
|
|
95
95
|
name: p.name,
|
|
96
|
-
type: p.type !== undefined ?
|
|
96
|
+
type: p.type !== undefined ? formatStructure(p.type) : 'any',
|
|
97
97
|
description: typeof p.annotations['description'] === 'string'
|
|
98
98
|
? p.annotations['description']
|
|
99
99
|
: '',
|
|
@@ -131,7 +131,7 @@ function serializeParam(p) {
|
|
|
131
131
|
parts.push(`^(description: "${desc}") `);
|
|
132
132
|
}
|
|
133
133
|
// Name and type
|
|
134
|
-
const typeName = p.type !== undefined ?
|
|
134
|
+
const typeName = p.type !== undefined ? formatStructure(p.type) : 'any';
|
|
135
135
|
parts.push(`${p.name}: ${typeName}`);
|
|
136
136
|
// Default value
|
|
137
137
|
if (p.defaultValue !== undefined) {
|
|
@@ -189,7 +189,7 @@ export function generateManifest(ctx) {
|
|
|
189
189
|
if (!isApplicationCallable(callable) || callable.params === undefined) {
|
|
190
190
|
continue;
|
|
191
191
|
}
|
|
192
|
-
const signature = serializeClosureSignature(callable.params,
|
|
192
|
+
const signature = serializeClosureSignature(callable.params, formatStructure(callable.returnType.structure), callable.annotations?.['description'] ?? undefined);
|
|
193
193
|
entries.push(` "${name}": ${signature}`);
|
|
194
194
|
}
|
|
195
195
|
if (entries.length === 0) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared marker interfaces for forward declarations.
|
|
3
|
+
*
|
|
4
|
+
* These interfaces break circular dependencies between values.ts,
|
|
5
|
+
* type-structures.ts, and callable.ts. Actual types are defined in callable.ts.
|
|
6
|
+
*/
|
|
7
|
+
export interface CallableMarker {
|
|
8
|
+
readonly __type: 'callable';
|
|
9
|
+
}
|
|
10
|
+
export interface FieldDescriptorMarker {
|
|
11
|
+
readonly __rill_field_descriptor: true;
|
|
12
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Registration Definitions
|
|
3
|
+
*
|
|
4
|
+
* Defines the TypeDefinition interface, TypeProtocol interface, and
|
|
5
|
+
* BUILT_IN_TYPES registration array. Each of the 12 built-in types
|
|
6
|
+
* carries identity predicates, protocol functions (format, eq, compare,
|
|
7
|
+
* convertTo, serialize), and a methods record populated from BUILTIN_METHODS.
|
|
8
|
+
*
|
|
9
|
+
* Dispatch functions (inferType, formatValue, deepEquals, serializeValue,
|
|
10
|
+
* deserializeValue, copyValue) iterate registrations and delegate to
|
|
11
|
+
* per-type protocol implementations.
|
|
12
|
+
*
|
|
13
|
+
* Registration order:
|
|
14
|
+
* primitives -> discriminator-based -> structural -> list -> dict fallback
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
import type { TypeStructure, RillValue, RillFieldDef, RillTuple, RillOrdered, RillVector, RillTypeValue, RillIterator } from './values.js';
|
|
19
|
+
import type { RillFunction } from './callable.js';
|
|
20
|
+
import { isTuple, isVector, isOrdered, isTypeValue, isIterator, createTuple, createOrdered, createVector } from './values.js';
|
|
21
|
+
/**
|
|
22
|
+
* Protocol functions that define per-type behavior.
|
|
23
|
+
* Every type must provide `format`. All other protocols are optional.
|
|
24
|
+
*/
|
|
25
|
+
export interface TypeProtocol {
|
|
26
|
+
format: (v: RillValue) => string;
|
|
27
|
+
structure?: ((v: RillValue) => TypeStructure) | undefined;
|
|
28
|
+
eq?: ((a: RillValue, b: RillValue) => boolean) | undefined;
|
|
29
|
+
compare?: ((a: RillValue, b: RillValue) => number) | undefined;
|
|
30
|
+
convertTo?: Record<string, (v: RillValue) => RillValue> | undefined;
|
|
31
|
+
serialize?: ((v: RillValue) => unknown) | undefined;
|
|
32
|
+
deserialize?: ((data: unknown) => RillValue) | undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A single type registration record. Each of the 12 built-in types
|
|
36
|
+
* has exactly one TypeDefinition in the BUILT_IN_TYPES array.
|
|
37
|
+
*/
|
|
38
|
+
export interface TypeDefinition {
|
|
39
|
+
name: string;
|
|
40
|
+
identity: (v: RillValue) => boolean;
|
|
41
|
+
isLeaf: boolean;
|
|
42
|
+
immutable: boolean;
|
|
43
|
+
methods: Record<string, RillFunction>;
|
|
44
|
+
protocol: TypeProtocol;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* All 12 built-in type registrations.
|
|
48
|
+
*
|
|
49
|
+
* Registration order:
|
|
50
|
+
* 1. Primitives: string, number, bool
|
|
51
|
+
* 2. Discriminator-based: tuple, ordered, vector, type, closure, field_descriptor
|
|
52
|
+
* 3. Structural: iterator
|
|
53
|
+
* 4. list
|
|
54
|
+
* 5. dict (fallback, must be last)
|
|
55
|
+
*
|
|
56
|
+
* AC-1: 12 registrations, one per type.
|
|
57
|
+
* BC-2: Vector identity checked before dict fallback.
|
|
58
|
+
* EC-3: Iterator has no protocol.eq.
|
|
59
|
+
* EC-4: Bool has no protocol.compare.
|
|
60
|
+
* EC-8: Non-serializable types throw plain Error.
|
|
61
|
+
*/
|
|
62
|
+
export declare const BUILT_IN_TYPES: readonly TypeDefinition[];
|
|
63
|
+
/**
|
|
64
|
+
* Infer the Rill type name from a runtime value.
|
|
65
|
+
* Iterates registrations in order; returns first matching name.
|
|
66
|
+
* Returns 'string' as fallback (BC-1: null IS type string, not a coercion).
|
|
67
|
+
*
|
|
68
|
+
* IR-2: Return type widens from RillTypeName to string for extensibility.
|
|
69
|
+
*/
|
|
70
|
+
export declare function inferType(value: RillValue): string;
|
|
71
|
+
/**
|
|
72
|
+
* Format a value as a human-readable string.
|
|
73
|
+
* Determines type via inferType, then calls protocol.format.
|
|
74
|
+
* Falls back to String(value) when no registration matches.
|
|
75
|
+
*
|
|
76
|
+
* IR-3: Protocol dispatcher for formatting.
|
|
77
|
+
*/
|
|
78
|
+
export declare function formatValue(value: RillValue): string;
|
|
79
|
+
/**
|
|
80
|
+
* Deep equality comparison for two Rill values.
|
|
81
|
+
* Short-circuit: a === b returns true.
|
|
82
|
+
* Dispatches to left operand's protocol.eq.
|
|
83
|
+
* No protocol.eq returns false.
|
|
84
|
+
*
|
|
85
|
+
* IR-4: Container protocol.eq calls deepEquals recursively.
|
|
86
|
+
*/
|
|
87
|
+
export declare function deepEquals(a: RillValue, b: RillValue): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Serialize a Rill value for JSON transport.
|
|
90
|
+
* Dispatches to protocol.serialize; container types recurse.
|
|
91
|
+
*
|
|
92
|
+
* IR-7: Renamed from valueToJSON.
|
|
93
|
+
*/
|
|
94
|
+
export declare function serializeValue(value: RillValue): unknown;
|
|
95
|
+
/**
|
|
96
|
+
* Deserialize raw data into a Rill value.
|
|
97
|
+
* Dispatches to protocol.deserialize for the given type name.
|
|
98
|
+
* Falls back to raw value when no protocol.deserialize exists (primitives).
|
|
99
|
+
*
|
|
100
|
+
* IR-8: Raw value fallback rejects null/undefined inputs with RILL-R004.
|
|
101
|
+
* EC-9: Invalid data raises RILL-R004.
|
|
102
|
+
* EC-10: null/undefined input raises RILL-R004.
|
|
103
|
+
*/
|
|
104
|
+
export declare function deserializeValue(data: unknown, typeName: string): RillValue;
|
|
105
|
+
/**
|
|
106
|
+
* Copy a Rill value.
|
|
107
|
+
* Reads immutable flag from registration.
|
|
108
|
+
* Immutable types return same reference.
|
|
109
|
+
* Mutable types (list, dict, iterator) recurse.
|
|
110
|
+
*
|
|
111
|
+
* IR-9: Renamed from deepCopyRillValue.
|
|
112
|
+
*/
|
|
113
|
+
export declare function copyValue(value: RillValue): RillValue;
|
|
114
|
+
/**
|
|
115
|
+
* Populate registration `methods` fields from BUILTIN_METHODS.
|
|
116
|
+
*
|
|
117
|
+
* Called after builtins.ts finishes initialization to avoid circular
|
|
118
|
+
* dependency at module load time. The 6 method-bearing types (string,
|
|
119
|
+
* number, bool, list, dict, vector) receive their methods records;
|
|
120
|
+
* other types keep `methods: {}`.
|
|
121
|
+
*
|
|
122
|
+
* AC-3: Consolidates method data into registrations.
|
|
123
|
+
*
|
|
124
|
+
* MUTATION NOTE: BUILT_IN_TYPES is shallow-frozen (the array), but each
|
|
125
|
+
* registration object is mutable. This function relies on that mutability.
|
|
126
|
+
* If registration objects are ever deep-frozen (e.g. Object.freeze(reg)),
|
|
127
|
+
* this assignment will throw in strict mode. The runtime guard below catches
|
|
128
|
+
* that condition early with a clear error rather than a silent no-op.
|
|
129
|
+
*/
|
|
130
|
+
export declare function populateBuiltinMethods(builtinMethods: Record<string, Record<string, RillFunction>>): void;
|
|
131
|
+
export { createTuple, createOrdered, createVector };
|
|
132
|
+
export { isTuple, isVector, isTypeValue, isOrdered, isIterator };
|
|
133
|
+
/** @deprecated Use isIterator instead. */
|
|
134
|
+
export declare const isRillIterator: typeof isIterator;
|
|
135
|
+
export type { TypeStructure };
|
|
136
|
+
export type { RillValue, RillTuple, RillOrdered, RillVector, RillTypeValue, RillIterator, RillFieldDef, };
|