@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.
Files changed (57) hide show
  1. package/README.md +37 -21
  2. package/dist/ext/crypto/index.d.ts +3 -3
  3. package/dist/ext/crypto/index.js +61 -58
  4. package/dist/ext/exec/index.d.ts +3 -3
  5. package/dist/ext/exec/index.js +14 -8
  6. package/dist/ext/fetch/index.d.ts +3 -3
  7. package/dist/ext/fetch/index.js +16 -11
  8. package/dist/ext/fs/index.d.ts +3 -3
  9. package/dist/ext/fs/index.js +242 -239
  10. package/dist/ext/kv/index.d.ts +3 -3
  11. package/dist/ext/kv/index.js +197 -195
  12. package/dist/ext/kv/store.js +2 -1
  13. package/dist/ext-parse-bridge.d.ts +10 -0
  14. package/dist/ext-parse-bridge.js +10 -0
  15. package/dist/generated/introspection-data.d.ts +1 -1
  16. package/dist/generated/introspection-data.js +385 -296
  17. package/dist/generated/version-data.d.ts +1 -1
  18. package/dist/generated/version-data.js +2 -2
  19. package/dist/index.d.ts +15 -4
  20. package/dist/index.js +14 -5
  21. package/dist/parser/parser-types.js +12 -0
  22. package/dist/parser/parser-use.js +7 -1
  23. package/dist/runtime/core/callable.d.ts +20 -8
  24. package/dist/runtime/core/callable.js +63 -23
  25. package/dist/runtime/core/context.d.ts +0 -11
  26. package/dist/runtime/core/context.js +76 -75
  27. package/dist/runtime/core/eval/index.d.ts +2 -2
  28. package/dist/runtime/core/eval/index.js +11 -0
  29. package/dist/runtime/core/eval/mixins/closures.js +15 -15
  30. package/dist/runtime/core/eval/mixins/conversion.js +51 -110
  31. package/dist/runtime/core/eval/mixins/core.js +2 -2
  32. package/dist/runtime/core/eval/mixins/expressions.js +35 -27
  33. package/dist/runtime/core/eval/mixins/literals.js +3 -3
  34. package/dist/runtime/core/eval/mixins/types.js +44 -54
  35. package/dist/runtime/core/eval/mixins/variables.js +10 -8
  36. package/dist/runtime/core/field-descriptor.d.ts +3 -3
  37. package/dist/runtime/core/field-descriptor.js +2 -1
  38. package/dist/runtime/core/introspection.js +6 -6
  39. package/dist/runtime/core/markers.d.ts +12 -0
  40. package/dist/runtime/core/markers.js +7 -0
  41. package/dist/runtime/core/type-registrations.d.ts +136 -0
  42. package/dist/runtime/core/type-registrations.js +749 -0
  43. package/dist/runtime/core/type-structures.d.ts +128 -0
  44. package/dist/runtime/core/type-structures.js +12 -0
  45. package/dist/runtime/core/types.d.ts +15 -3
  46. package/dist/runtime/core/values.d.ts +62 -153
  47. package/dist/runtime/core/values.js +308 -524
  48. package/dist/runtime/ext/builtins.js +83 -64
  49. package/dist/runtime/ext/extensions.d.ts +30 -124
  50. package/dist/runtime/ext/extensions.js +0 -93
  51. package/dist/runtime/ext/test-context.d.ts +28 -0
  52. package/dist/runtime/ext/test-context.js +154 -0
  53. package/dist/runtime/index.d.ts +22 -8
  54. package/dist/runtime/index.js +18 -4
  55. package/dist/signature-parser.d.ts +2 -2
  56. package/dist/signature-parser.js +14 -14
  57. package/package.json +1 -1
@@ -0,0 +1,749 @@
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 { isTuple, isVector, isOrdered, isTypeValue, isIterator, createTuple, createOrdered, createVector, formatStructure, structureEquals, } from './values.js';
19
+ import { isCallable, isDict, isScriptCallable, callableEquals, } from './callable.js';
20
+ import { RuntimeError } from '../../types.js';
21
+ // ============================================================
22
+ // IDENTITY HELPERS
23
+ // ============================================================
24
+ /** Identity predicate for field_descriptor values. */
25
+ function isFieldDescriptor(value) {
26
+ return (typeof value === 'object' &&
27
+ value !== null &&
28
+ '__rill_field_descriptor' in value &&
29
+ value['__rill_field_descriptor'] === true);
30
+ }
31
+ /** Identity predicate for closure values. */
32
+ function isClosure(value) {
33
+ return isCallable(value);
34
+ }
35
+ // ============================================================
36
+ // PROTOCOL IMPLEMENTATIONS: FORMAT
37
+ // ============================================================
38
+ function formatString(v) {
39
+ if (v === null)
40
+ return 'type(null)';
41
+ return v;
42
+ }
43
+ function formatNumber(v) {
44
+ return String(v);
45
+ }
46
+ function formatBool(v) {
47
+ return v ? 'true' : 'false';
48
+ }
49
+ function formatTuple(v) {
50
+ const t = v;
51
+ return `tuple[${t.entries.map(formatValue).join(', ')}]`;
52
+ }
53
+ function formatOrdered(v) {
54
+ const o = v;
55
+ const parts = o.entries.map(([k, val]) => `${k}: ${formatValue(val)}`);
56
+ return `ordered[${parts.join(', ')}]`;
57
+ }
58
+ function formatVector(v) {
59
+ const vec = v;
60
+ return `vector(${vec.model}, ${vec.data.length}d)`;
61
+ }
62
+ function formatTypeValue(v) {
63
+ const tv = v;
64
+ return formatStructure(tv.structure);
65
+ }
66
+ function formatClosure(_v) {
67
+ return 'type(closure)';
68
+ }
69
+ function formatFieldDescriptor(_v) {
70
+ return 'type(field_descriptor)';
71
+ }
72
+ function formatIterator(_v) {
73
+ return 'type(iterator)';
74
+ }
75
+ function formatList(v) {
76
+ const arr = v;
77
+ return `list[${arr.map(formatValue).join(', ')}]`;
78
+ }
79
+ function formatDict(v) {
80
+ const dict = v;
81
+ const parts = Object.entries(dict).map(([k, val]) => `${k}: ${formatValue(val)}`);
82
+ return `dict[${parts.join(', ')}]`;
83
+ }
84
+ // ============================================================
85
+ // PROTOCOL IMPLEMENTATIONS: EQ
86
+ // ============================================================
87
+ function eqString(a, b) {
88
+ return a === b;
89
+ }
90
+ function eqNumber(a, b) {
91
+ return a === b;
92
+ }
93
+ function eqBool(a, b) {
94
+ return a === b;
95
+ }
96
+ function eqTuple(a, b) {
97
+ if (!isTuple(a) || !isTuple(b))
98
+ return false;
99
+ if (a.entries.length !== b.entries.length)
100
+ return false;
101
+ for (let i = 0; i < a.entries.length; i++) {
102
+ const aVal = a.entries[i];
103
+ const bVal = b.entries[i];
104
+ if (aVal === undefined || bVal === undefined) {
105
+ if (aVal !== bVal)
106
+ return false;
107
+ }
108
+ else if (!deepEquals(aVal, bVal)) {
109
+ return false;
110
+ }
111
+ }
112
+ return true;
113
+ }
114
+ function eqOrdered(a, b) {
115
+ if (!isOrdered(a) || !isOrdered(b))
116
+ return false;
117
+ if (a.entries.length !== b.entries.length)
118
+ return false;
119
+ for (let i = 0; i < a.entries.length; i++) {
120
+ const aEntry = a.entries[i];
121
+ const bEntry = b.entries[i];
122
+ if (aEntry === undefined || bEntry === undefined)
123
+ return false;
124
+ if (aEntry[0] !== bEntry[0])
125
+ return false;
126
+ if (!deepEquals(aEntry[1], bEntry[1]))
127
+ return false;
128
+ }
129
+ return true;
130
+ }
131
+ function eqVector(a, b) {
132
+ if (!isVector(a) || !isVector(b))
133
+ return false;
134
+ if (a.model !== b.model)
135
+ return false;
136
+ if (a.data.length !== b.data.length)
137
+ return false;
138
+ for (let i = 0; i < a.data.length; i++) {
139
+ if (a.data[i] !== b.data[i])
140
+ return false;
141
+ }
142
+ return true;
143
+ }
144
+ function eqTypeValue(a, b) {
145
+ if (!isTypeValue(a) || !isTypeValue(b))
146
+ return false;
147
+ return structureEquals(a.structure, b.structure);
148
+ }
149
+ function eqClosure(a, b) {
150
+ if (!isCallable(a) || !isCallable(b))
151
+ return false;
152
+ // Script callables: structural equality
153
+ if (isScriptCallable(a) && isScriptCallable(b)) {
154
+ return callableEquals(a, b, deepEquals);
155
+ }
156
+ // Runtime/application callables: reference equality
157
+ return a === b;
158
+ }
159
+ function eqFieldDescriptor(a, b) {
160
+ // Field descriptors use reference equality
161
+ return a === b;
162
+ }
163
+ function eqList(a, b) {
164
+ if (!Array.isArray(a) || !Array.isArray(b))
165
+ return false;
166
+ if (a.length !== b.length)
167
+ return false;
168
+ for (let i = 0; i < a.length; i++) {
169
+ const aElem = a[i];
170
+ const bElem = b[i];
171
+ if (aElem === undefined || bElem === undefined) {
172
+ if (aElem !== bElem)
173
+ return false;
174
+ }
175
+ else if (!deepEquals(aElem, bElem)) {
176
+ return false;
177
+ }
178
+ }
179
+ return true;
180
+ }
181
+ function eqDict(a, b) {
182
+ const aDict = a;
183
+ const bDict = b;
184
+ const aKeys = Object.keys(aDict);
185
+ const bKeys = Object.keys(bDict);
186
+ if (aKeys.length !== bKeys.length)
187
+ return false;
188
+ for (const key of aKeys) {
189
+ if (!(key in bDict))
190
+ return false;
191
+ const aVal = aDict[key];
192
+ const bVal = bDict[key];
193
+ if (aVal === undefined || bVal === undefined) {
194
+ if (aVal !== bVal)
195
+ return false;
196
+ }
197
+ else if (!deepEquals(aVal, bVal)) {
198
+ return false;
199
+ }
200
+ }
201
+ return true;
202
+ }
203
+ // ============================================================
204
+ // PROTOCOL IMPLEMENTATIONS: COMPARE
205
+ // ============================================================
206
+ function compareString(a, b) {
207
+ const sa = a;
208
+ const sb = b;
209
+ if (sa < sb)
210
+ return -1;
211
+ if (sa > sb)
212
+ return 1;
213
+ return 0;
214
+ }
215
+ function compareNumber(a, b) {
216
+ return a - b;
217
+ }
218
+ // ============================================================
219
+ // PROTOCOL IMPLEMENTATIONS: CONVERT-TO
220
+ // ============================================================
221
+ /**
222
+ * String convertTo targets.
223
+ * - string -> number: parse numeric string
224
+ * - string -> bool: "true"/"false" only
225
+ */
226
+ const stringConvertTo = {
227
+ number: (v) => {
228
+ const str = v;
229
+ const parsed = Number(str);
230
+ if (isNaN(parsed) || str.trim() === '') {
231
+ throw new Error(`cannot convert string "${str}" to number`);
232
+ }
233
+ return parsed;
234
+ },
235
+ bool: (v) => {
236
+ const s = v;
237
+ if (s === 'true')
238
+ return true;
239
+ if (s === 'false')
240
+ return false;
241
+ throw new Error(`cannot convert string "${s}" to bool`);
242
+ },
243
+ };
244
+ /**
245
+ * Number convertTo targets.
246
+ * - number -> string: via String()
247
+ * - number -> bool: 0 -> false, 1 -> true
248
+ */
249
+ const numberConvertTo = {
250
+ string: (v) => String(v),
251
+ bool: (v) => {
252
+ const n = v;
253
+ if (n === 0)
254
+ return false;
255
+ if (n === 1)
256
+ return true;
257
+ throw new Error(`cannot convert number ${n} to bool`);
258
+ },
259
+ };
260
+ /**
261
+ * Bool convertTo targets.
262
+ * - bool -> string: "true"/"false"
263
+ * - bool -> number: true -> 1, false -> 0
264
+ */
265
+ const boolConvertTo = {
266
+ string: (v) => (v ? 'true' : 'false'),
267
+ number: (v) => (v ? 1 : 0),
268
+ };
269
+ /**
270
+ * Tuple convertTo targets.
271
+ * - tuple -> list: extract entries
272
+ */
273
+ const tupleConvertTo = {
274
+ list: (v) => v.entries,
275
+ string: (v) => formatTuple(v),
276
+ };
277
+ /**
278
+ * Ordered convertTo targets.
279
+ * - ordered -> dict: convert entries to plain object
280
+ */
281
+ const orderedConvertTo = {
282
+ dict: (v) => {
283
+ const o = v;
284
+ const result = {};
285
+ for (const [key, value] of o.entries) {
286
+ result[key] = value;
287
+ }
288
+ return result;
289
+ },
290
+ string: (v) => formatOrdered(v),
291
+ };
292
+ /**
293
+ * List convertTo targets.
294
+ * - list -> tuple: wrap in tuple
295
+ * - list -> string: format
296
+ */
297
+ const listConvertTo = {
298
+ tuple: (v) => createTuple(v),
299
+ string: (v) => formatList(v),
300
+ };
301
+ /**
302
+ * Dict convertTo targets.
303
+ * - dict -> string: format
304
+ */
305
+ const dictConvertTo = {
306
+ string: (v) => formatDict(v),
307
+ };
308
+ /**
309
+ * Vector convertTo targets.
310
+ * - vector -> string: format
311
+ */
312
+ const vectorConvertTo = {
313
+ string: (v) => formatVector(v),
314
+ };
315
+ /**
316
+ * Type value convertTo targets.
317
+ * - type -> string: format
318
+ */
319
+ const typeConvertTo = {
320
+ string: (v) => formatTypeValue(v),
321
+ };
322
+ /**
323
+ * Closure convertTo targets.
324
+ * - closure -> string: format
325
+ */
326
+ const closureConvertTo = {
327
+ string: (_v) => 'type(closure)',
328
+ };
329
+ /**
330
+ * Iterator convertTo targets.
331
+ * - iterator -> string: format
332
+ */
333
+ const iteratorConvertTo = {
334
+ string: (_v) => 'type(iterator)',
335
+ };
336
+ // ============================================================
337
+ // PROTOCOL IMPLEMENTATIONS: SERIALIZE
338
+ // ============================================================
339
+ function serializeString(v) {
340
+ if (v === null)
341
+ return null;
342
+ return v;
343
+ }
344
+ function serializeNumber(v) {
345
+ return v;
346
+ }
347
+ function serializeBool(v) {
348
+ return v;
349
+ }
350
+ function serializeList(v) {
351
+ return v.map(serializeListElement);
352
+ }
353
+ /** Recursive serialization for list elements. */
354
+ function serializeListElement(v) {
355
+ if (v === null)
356
+ return null;
357
+ if (typeof v === 'string')
358
+ return v;
359
+ if (typeof v === 'number')
360
+ return v;
361
+ if (typeof v === 'boolean')
362
+ return v;
363
+ if (Array.isArray(v))
364
+ return v.map(serializeListElement);
365
+ if (isCallable(v))
366
+ throw new Error('closures are not JSON-serializable');
367
+ if (isTuple(v))
368
+ throw new Error('tuples are not JSON-serializable');
369
+ if (isOrdered(v))
370
+ throw new Error('ordered values are not JSON-serializable');
371
+ if (isVector(v))
372
+ throw new Error('vectors are not JSON-serializable');
373
+ if (isTypeValue(v))
374
+ throw new Error('type values are not JSON-serializable');
375
+ if (isIterator(v))
376
+ throw new Error('iterators are not JSON-serializable');
377
+ // Plain dict
378
+ const dict = v;
379
+ const result = {};
380
+ for (const [k, val] of Object.entries(dict)) {
381
+ result[k] = serializeListElement(val);
382
+ }
383
+ return result;
384
+ }
385
+ function serializeDict(v) {
386
+ const dict = v;
387
+ const result = {};
388
+ for (const [k, val] of Object.entries(dict)) {
389
+ result[k] = serializeListElement(val);
390
+ }
391
+ return result;
392
+ }
393
+ function throwNotSerializable(typeName) {
394
+ return (_v) => {
395
+ throw new Error(`${typeName}s are not JSON-serializable`);
396
+ };
397
+ }
398
+ // ============================================================
399
+ // BUILT-IN TYPE REGISTRATIONS
400
+ // ============================================================
401
+ /**
402
+ * All 12 built-in type registrations.
403
+ *
404
+ * Registration order:
405
+ * 1. Primitives: string, number, bool
406
+ * 2. Discriminator-based: tuple, ordered, vector, type, closure, field_descriptor
407
+ * 3. Structural: iterator
408
+ * 4. list
409
+ * 5. dict (fallback, must be last)
410
+ *
411
+ * AC-1: 12 registrations, one per type.
412
+ * BC-2: Vector identity checked before dict fallback.
413
+ * EC-3: Iterator has no protocol.eq.
414
+ * EC-4: Bool has no protocol.compare.
415
+ * EC-8: Non-serializable types throw plain Error.
416
+ */
417
+ export const BUILT_IN_TYPES = Object.freeze([
418
+ // ---- Primitives ----
419
+ {
420
+ name: 'string',
421
+ identity: (v) => typeof v === 'string' || v === null,
422
+ isLeaf: true,
423
+ immutable: true,
424
+ methods: {},
425
+ protocol: {
426
+ format: formatString,
427
+ eq: eqString,
428
+ compare: compareString,
429
+ convertTo: stringConvertTo,
430
+ serialize: serializeString,
431
+ },
432
+ },
433
+ {
434
+ name: 'number',
435
+ identity: (v) => typeof v === 'number',
436
+ isLeaf: true,
437
+ immutable: true,
438
+ methods: {},
439
+ protocol: {
440
+ format: formatNumber,
441
+ eq: eqNumber,
442
+ compare: compareNumber,
443
+ convertTo: numberConvertTo,
444
+ serialize: serializeNumber,
445
+ },
446
+ },
447
+ {
448
+ name: 'bool',
449
+ // EC-4: no protocol.compare (ordering unsupported for bool)
450
+ identity: (v) => typeof v === 'boolean',
451
+ isLeaf: true,
452
+ immutable: true,
453
+ methods: {},
454
+ protocol: {
455
+ format: formatBool,
456
+ eq: eqBool,
457
+ convertTo: boolConvertTo,
458
+ serialize: serializeBool,
459
+ },
460
+ },
461
+ // ---- Discriminator-based ----
462
+ {
463
+ name: 'tuple',
464
+ identity: (v) => isTuple(v),
465
+ isLeaf: false,
466
+ immutable: true,
467
+ methods: {},
468
+ protocol: {
469
+ format: formatTuple,
470
+ eq: eqTuple,
471
+ convertTo: tupleConvertTo,
472
+ serialize: throwNotSerializable('tuple'),
473
+ },
474
+ },
475
+ {
476
+ name: 'ordered',
477
+ identity: (v) => isOrdered(v),
478
+ isLeaf: false,
479
+ immutable: true,
480
+ methods: {},
481
+ protocol: {
482
+ format: formatOrdered,
483
+ eq: eqOrdered,
484
+ convertTo: orderedConvertTo,
485
+ serialize: throwNotSerializable('ordered value'),
486
+ },
487
+ },
488
+ {
489
+ // BC-2: Vector identity checked before dict fallback
490
+ name: 'vector',
491
+ identity: (v) => isVector(v),
492
+ isLeaf: true,
493
+ immutable: true,
494
+ methods: {},
495
+ protocol: {
496
+ format: formatVector,
497
+ eq: eqVector,
498
+ convertTo: vectorConvertTo,
499
+ serialize: throwNotSerializable('vector'),
500
+ },
501
+ },
502
+ {
503
+ name: 'type',
504
+ identity: (v) => isTypeValue(v),
505
+ isLeaf: true,
506
+ immutable: true,
507
+ methods: {},
508
+ protocol: {
509
+ format: formatTypeValue,
510
+ eq: eqTypeValue,
511
+ convertTo: typeConvertTo,
512
+ serialize: throwNotSerializable('type value'),
513
+ },
514
+ },
515
+ {
516
+ name: 'closure',
517
+ identity: (v) => isClosure(v),
518
+ isLeaf: true,
519
+ immutable: true,
520
+ methods: {},
521
+ protocol: {
522
+ format: formatClosure,
523
+ eq: eqClosure,
524
+ convertTo: closureConvertTo,
525
+ serialize: throwNotSerializable('closure'),
526
+ },
527
+ },
528
+ {
529
+ name: 'field_descriptor',
530
+ identity: isFieldDescriptor,
531
+ isLeaf: true,
532
+ immutable: true,
533
+ methods: {},
534
+ protocol: {
535
+ format: formatFieldDescriptor,
536
+ eq: eqFieldDescriptor,
537
+ serialize: throwNotSerializable('field_descriptor'),
538
+ },
539
+ },
540
+ // ---- Structural ----
541
+ {
542
+ // EC-3: iterator has no protocol.eq (equality raises RILL-R002)
543
+ name: 'iterator',
544
+ identity: (v) => isIterator(v),
545
+ isLeaf: false,
546
+ immutable: false,
547
+ methods: {},
548
+ protocol: {
549
+ format: formatIterator,
550
+ convertTo: iteratorConvertTo,
551
+ serialize: throwNotSerializable('iterator'),
552
+ },
553
+ },
554
+ // ---- List ----
555
+ {
556
+ name: 'list',
557
+ identity: (v) => Array.isArray(v) && !isTuple(v) && !isOrdered(v),
558
+ isLeaf: false,
559
+ immutable: false,
560
+ methods: {},
561
+ protocol: {
562
+ format: formatList,
563
+ eq: eqList,
564
+ convertTo: listConvertTo,
565
+ serialize: serializeList,
566
+ },
567
+ },
568
+ // ---- Dict fallback (must be last) ----
569
+ {
570
+ name: 'dict',
571
+ identity: (v) => isDict(v),
572
+ isLeaf: false,
573
+ immutable: false,
574
+ methods: {},
575
+ protocol: {
576
+ format: formatDict,
577
+ eq: eqDict,
578
+ convertTo: dictConvertTo,
579
+ serialize: serializeDict,
580
+ },
581
+ },
582
+ ]);
583
+ // ============================================================
584
+ // DISPATCH FUNCTIONS
585
+ // ============================================================
586
+ /**
587
+ * Infer the Rill type name from a runtime value.
588
+ * Iterates registrations in order; returns first matching name.
589
+ * Returns 'string' as fallback (BC-1: null IS type string, not a coercion).
590
+ *
591
+ * IR-2: Return type widens from RillTypeName to string for extensibility.
592
+ */
593
+ export function inferType(value) {
594
+ for (const reg of BUILT_IN_TYPES) {
595
+ if (reg.identity(value))
596
+ return reg.name;
597
+ }
598
+ return 'string';
599
+ }
600
+ /**
601
+ * Format a value as a human-readable string.
602
+ * Determines type via inferType, then calls protocol.format.
603
+ * Falls back to String(value) when no registration matches.
604
+ *
605
+ * IR-3: Protocol dispatcher for formatting.
606
+ */
607
+ export function formatValue(value) {
608
+ for (const reg of BUILT_IN_TYPES) {
609
+ if (reg.identity(value))
610
+ return reg.protocol.format(value);
611
+ }
612
+ return String(value);
613
+ }
614
+ /**
615
+ * Deep equality comparison for two Rill values.
616
+ * Short-circuit: a === b returns true.
617
+ * Dispatches to left operand's protocol.eq.
618
+ * No protocol.eq returns false.
619
+ *
620
+ * IR-4: Container protocol.eq calls deepEquals recursively.
621
+ */
622
+ export function deepEquals(a, b) {
623
+ if (a === b)
624
+ return true;
625
+ for (const reg of BUILT_IN_TYPES) {
626
+ if (reg.identity(a)) {
627
+ if (!reg.protocol.eq)
628
+ return false;
629
+ return reg.protocol.eq(a, b);
630
+ }
631
+ }
632
+ return false;
633
+ }
634
+ /**
635
+ * Serialize a Rill value for JSON transport.
636
+ * Dispatches to protocol.serialize; container types recurse.
637
+ *
638
+ * IR-7: Renamed from valueToJSON.
639
+ */
640
+ export function serializeValue(value) {
641
+ for (const reg of BUILT_IN_TYPES) {
642
+ if (reg.identity(value)) {
643
+ if (reg.protocol.serialize)
644
+ return reg.protocol.serialize(value);
645
+ break;
646
+ }
647
+ }
648
+ return value;
649
+ }
650
+ /**
651
+ * Deserialize raw data into a Rill value.
652
+ * Dispatches to protocol.deserialize for the given type name.
653
+ * Falls back to raw value when no protocol.deserialize exists (primitives).
654
+ *
655
+ * IR-8: Raw value fallback rejects null/undefined inputs with RILL-R004.
656
+ * EC-9: Invalid data raises RILL-R004.
657
+ * EC-10: null/undefined input raises RILL-R004.
658
+ */
659
+ export function deserializeValue(data, typeName) {
660
+ if (data === null || data === undefined) {
661
+ throw new RuntimeError('RILL-R004', `Cannot deserialize null as ${typeName}`);
662
+ }
663
+ for (const reg of BUILT_IN_TYPES) {
664
+ if (reg.name === typeName) {
665
+ if (reg.protocol.deserialize)
666
+ return reg.protocol.deserialize(data);
667
+ return data;
668
+ }
669
+ }
670
+ throw new RuntimeError('RILL-R004', `Cannot deserialize as ${typeName}`);
671
+ }
672
+ /**
673
+ * Copy a Rill value.
674
+ * Reads immutable flag from registration.
675
+ * Immutable types return same reference.
676
+ * Mutable types (list, dict, iterator) recurse.
677
+ *
678
+ * IR-9: Renamed from deepCopyRillValue.
679
+ */
680
+ export function copyValue(value) {
681
+ if (value === null || typeof value !== 'object')
682
+ return value;
683
+ for (const reg of BUILT_IN_TYPES) {
684
+ if (reg.identity(value)) {
685
+ if (reg.immutable)
686
+ return value;
687
+ break;
688
+ }
689
+ }
690
+ // Mutable: list or dict, recurse
691
+ if (Array.isArray(value)) {
692
+ return value.map(copyValue);
693
+ }
694
+ const dict = value;
695
+ const copy = {};
696
+ for (const [k, v] of Object.entries(dict)) {
697
+ copy[k] = copyValue(v);
698
+ }
699
+ return copy;
700
+ }
701
+ // ============================================================
702
+ // METHOD POPULATION
703
+ // ============================================================
704
+ /** Names of types that carry methods from BUILTIN_METHODS. */
705
+ const METHOD_BEARING_TYPES = new Set([
706
+ 'string',
707
+ 'number',
708
+ 'bool',
709
+ 'list',
710
+ 'dict',
711
+ 'vector',
712
+ ]);
713
+ /**
714
+ * Populate registration `methods` fields from BUILTIN_METHODS.
715
+ *
716
+ * Called after builtins.ts finishes initialization to avoid circular
717
+ * dependency at module load time. The 6 method-bearing types (string,
718
+ * number, bool, list, dict, vector) receive their methods records;
719
+ * other types keep `methods: {}`.
720
+ *
721
+ * AC-3: Consolidates method data into registrations.
722
+ *
723
+ * MUTATION NOTE: BUILT_IN_TYPES is shallow-frozen (the array), but each
724
+ * registration object is mutable. This function relies on that mutability.
725
+ * If registration objects are ever deep-frozen (e.g. Object.freeze(reg)),
726
+ * this assignment will throw in strict mode. The runtime guard below catches
727
+ * that condition early with a clear error rather than a silent no-op.
728
+ */
729
+ export function populateBuiltinMethods(builtinMethods) {
730
+ for (const reg of BUILT_IN_TYPES) {
731
+ if (METHOD_BEARING_TYPES.has(reg.name) && reg.name in builtinMethods) {
732
+ if (Object.isFrozen(reg)) {
733
+ throw new Error(`populateBuiltinMethods: registration '${reg.name}' is frozen; cannot assign methods`);
734
+ }
735
+ reg.methods =
736
+ builtinMethods[reg.name];
737
+ }
738
+ }
739
+ }
740
+ // ============================================================
741
+ // RE-EXPORTED FACTORY FUNCTIONS
742
+ // ============================================================
743
+ export { createTuple, createOrdered, createVector };
744
+ // ============================================================
745
+ // RE-EXPORTED GUARD FUNCTIONS
746
+ // ============================================================
747
+ export { isTuple, isVector, isTypeValue, isOrdered, isIterator };
748
+ /** @deprecated Use isIterator instead. */
749
+ export const isRillIterator = isIterator;