@rcrsr/rill 0.15.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 (316) hide show
  1. package/README.md +37 -21
  2. package/dist/ast-nodes.d.ts +2 -13
  3. package/dist/ast-nodes.js +0 -1
  4. package/dist/ast-unions.d.ts +0 -1
  5. package/dist/ast-unions.js +0 -1
  6. package/dist/constants.d.ts +0 -1
  7. package/dist/constants.js +0 -1
  8. package/dist/error-classes.d.ts +0 -1
  9. package/dist/error-classes.js +0 -1
  10. package/dist/error-formatter.d.ts +0 -1
  11. package/dist/error-formatter.js +0 -1
  12. package/dist/error-registry.d.ts +0 -1
  13. package/dist/error-registry.js +32 -1
  14. package/dist/ext/crypto/index.d.ts +3 -4
  15. package/dist/ext/crypto/index.js +66 -64
  16. package/dist/ext/exec/index.d.ts +3 -4
  17. package/dist/ext/exec/index.js +17 -12
  18. package/dist/ext/exec/runner.d.ts +0 -1
  19. package/dist/ext/exec/runner.js +0 -1
  20. package/dist/ext/fetch/index.d.ts +3 -4
  21. package/dist/ext/fetch/index.js +23 -49
  22. package/dist/ext/fetch/request.d.ts +0 -1
  23. package/dist/ext/fetch/request.js +0 -1
  24. package/dist/ext/fs/index.d.ts +3 -4
  25. package/dist/ext/fs/index.js +268 -266
  26. package/dist/ext/fs/sandbox.d.ts +0 -1
  27. package/dist/ext/fs/sandbox.js +0 -1
  28. package/dist/ext/kv/index.d.ts +3 -4
  29. package/dist/ext/kv/index.js +216 -215
  30. package/dist/ext/kv/store.d.ts +0 -1
  31. package/dist/ext/kv/store.js +2 -2
  32. package/dist/ext-parse-bridge.d.ts +10 -0
  33. package/dist/ext-parse-bridge.js +10 -0
  34. package/dist/generated/introspection-data.d.ts +1 -2
  35. package/dist/generated/introspection-data.js +385 -297
  36. package/dist/generated/version-data.d.ts +1 -2
  37. package/dist/generated/version-data.js +2 -3
  38. package/dist/highlight-map.d.ts +0 -1
  39. package/dist/highlight-map.js +0 -1
  40. package/dist/index.d.ts +15 -5
  41. package/dist/index.js +14 -6
  42. package/dist/lexer/errors.d.ts +0 -1
  43. package/dist/lexer/errors.js +0 -1
  44. package/dist/lexer/helpers.d.ts +0 -1
  45. package/dist/lexer/helpers.js +0 -1
  46. package/dist/lexer/index.d.ts +0 -1
  47. package/dist/lexer/index.js +0 -1
  48. package/dist/lexer/operators.d.ts +0 -1
  49. package/dist/lexer/operators.js +0 -1
  50. package/dist/lexer/readers.d.ts +0 -1
  51. package/dist/lexer/readers.js +0 -1
  52. package/dist/lexer/state.d.ts +0 -1
  53. package/dist/lexer/state.js +0 -1
  54. package/dist/lexer/tokenizer.d.ts +0 -1
  55. package/dist/lexer/tokenizer.js +0 -1
  56. package/dist/parser/helpers.d.ts +0 -1
  57. package/dist/parser/helpers.js +0 -1
  58. package/dist/parser/index.d.ts +0 -1
  59. package/dist/parser/index.js +0 -1
  60. package/dist/parser/parser-collect.d.ts +0 -1
  61. package/dist/parser/parser-collect.js +0 -1
  62. package/dist/parser/parser-control.d.ts +0 -1
  63. package/dist/parser/parser-control.js +0 -1
  64. package/dist/parser/parser-expr.d.ts +0 -1
  65. package/dist/parser/parser-expr.js +0 -1
  66. package/dist/parser/parser-extract.d.ts +0 -1
  67. package/dist/parser/parser-extract.js +0 -1
  68. package/dist/parser/parser-functions.d.ts +0 -1
  69. package/dist/parser/parser-functions.js +0 -1
  70. package/dist/parser/parser-literals.d.ts +0 -1
  71. package/dist/parser/parser-literals.js +4 -2
  72. package/dist/parser/parser-script.d.ts +0 -1
  73. package/dist/parser/parser-script.js +0 -1
  74. package/dist/parser/parser-shape.d.ts +2 -3
  75. package/dist/parser/parser-shape.js +8 -52
  76. package/dist/parser/parser-types.d.ts +28 -2
  77. package/dist/parser/parser-types.js +76 -13
  78. package/dist/parser/parser-use.d.ts +0 -1
  79. package/dist/parser/parser-use.js +7 -2
  80. package/dist/parser/parser-variables.d.ts +0 -1
  81. package/dist/parser/parser-variables.js +0 -1
  82. package/dist/parser/parser.d.ts +0 -1
  83. package/dist/parser/parser.js +0 -1
  84. package/dist/parser/state.d.ts +0 -1
  85. package/dist/parser/state.js +0 -1
  86. package/dist/runtime/core/callable.d.ts +59 -20
  87. package/dist/runtime/core/callable.js +188 -39
  88. package/dist/runtime/core/context.d.ts +0 -12
  89. package/dist/runtime/core/context.js +77 -77
  90. package/dist/runtime/core/equals.d.ts +0 -1
  91. package/dist/runtime/core/equals.js +35 -3
  92. package/dist/runtime/core/eval/base.d.ts +0 -1
  93. package/dist/runtime/core/eval/base.js +0 -1
  94. package/dist/runtime/core/eval/evaluator.d.ts +0 -1
  95. package/dist/runtime/core/eval/evaluator.js +0 -1
  96. package/dist/runtime/core/eval/index.d.ts +2 -3
  97. package/dist/runtime/core/eval/index.js +11 -1
  98. package/dist/runtime/core/eval/mixins/annotations.d.ts +0 -1
  99. package/dist/runtime/core/eval/mixins/annotations.js +0 -1
  100. package/dist/runtime/core/eval/mixins/closures.d.ts +0 -1
  101. package/dist/runtime/core/eval/mixins/closures.js +92 -70
  102. package/dist/runtime/core/eval/mixins/collections.d.ts +0 -1
  103. package/dist/runtime/core/eval/mixins/collections.js +9 -4
  104. package/dist/runtime/core/eval/mixins/control-flow.d.ts +0 -1
  105. package/dist/runtime/core/eval/mixins/control-flow.js +0 -1
  106. package/dist/runtime/core/eval/mixins/conversion.d.ts +0 -1
  107. package/dist/runtime/core/eval/mixins/conversion.js +196 -188
  108. package/dist/runtime/core/eval/mixins/core.d.ts +0 -1
  109. package/dist/runtime/core/eval/mixins/core.js +2 -3
  110. package/dist/runtime/core/eval/mixins/expressions.d.ts +0 -1
  111. package/dist/runtime/core/eval/mixins/expressions.js +35 -28
  112. package/dist/runtime/core/eval/mixins/extraction.d.ts +0 -1
  113. package/dist/runtime/core/eval/mixins/extraction.js +8 -9
  114. package/dist/runtime/core/eval/mixins/list-dispatch.d.ts +0 -1
  115. package/dist/runtime/core/eval/mixins/list-dispatch.js +0 -1
  116. package/dist/runtime/core/eval/mixins/literals.d.ts +0 -1
  117. package/dist/runtime/core/eval/mixins/literals.js +6 -10
  118. package/dist/runtime/core/eval/mixins/types.d.ts +2 -1
  119. package/dist/runtime/core/eval/mixins/types.js +231 -261
  120. package/dist/runtime/core/eval/mixins/use.d.ts +0 -1
  121. package/dist/runtime/core/eval/mixins/use.js +0 -1
  122. package/dist/runtime/core/eval/mixins/variables.d.ts +0 -1
  123. package/dist/runtime/core/eval/mixins/variables.js +16 -15
  124. package/dist/runtime/core/eval/types.d.ts +0 -1
  125. package/dist/runtime/core/eval/types.js +0 -1
  126. package/dist/runtime/core/execute.d.ts +0 -1
  127. package/dist/runtime/core/execute.js +0 -1
  128. package/dist/runtime/core/field-descriptor.d.ts +4 -5
  129. package/dist/runtime/core/field-descriptor.js +2 -2
  130. package/dist/runtime/core/introspection.d.ts +0 -1
  131. package/dist/runtime/core/introspection.js +6 -7
  132. package/dist/runtime/core/markers.d.ts +12 -0
  133. package/dist/runtime/core/markers.js +7 -0
  134. package/dist/runtime/core/resolvers.d.ts +0 -1
  135. package/dist/runtime/core/resolvers.js +0 -1
  136. package/dist/runtime/core/signals.d.ts +0 -1
  137. package/dist/runtime/core/signals.js +0 -1
  138. package/dist/runtime/core/type-registrations.d.ts +136 -0
  139. package/dist/runtime/core/type-registrations.js +749 -0
  140. package/dist/runtime/core/type-structures.d.ts +128 -0
  141. package/dist/runtime/core/type-structures.js +12 -0
  142. package/dist/runtime/core/types.d.ts +15 -4
  143. package/dist/runtime/core/types.js +0 -1
  144. package/dist/runtime/core/values.d.ts +88 -146
  145. package/dist/runtime/core/values.js +466 -470
  146. package/dist/runtime/ext/builtins.d.ts +0 -1
  147. package/dist/runtime/ext/builtins.js +125 -80
  148. package/dist/runtime/ext/extensions.d.ts +30 -125
  149. package/dist/runtime/ext/extensions.js +0 -94
  150. package/dist/runtime/ext/test-context.d.ts +28 -0
  151. package/dist/runtime/ext/test-context.js +154 -0
  152. package/dist/runtime/index.d.ts +22 -9
  153. package/dist/runtime/index.js +18 -5
  154. package/dist/signature-parser.d.ts +2 -3
  155. package/dist/signature-parser.js +19 -17
  156. package/dist/source-location.d.ts +0 -1
  157. package/dist/source-location.js +0 -1
  158. package/dist/token-types.d.ts +0 -1
  159. package/dist/token-types.js +0 -1
  160. package/dist/types.d.ts +0 -1
  161. package/dist/types.js +0 -1
  162. package/dist/value-types.d.ts +15 -12
  163. package/dist/value-types.js +0 -1
  164. package/package.json +2 -1
  165. package/dist/ast-nodes.d.ts.map +0 -1
  166. package/dist/ast-nodes.js.map +0 -1
  167. package/dist/ast-unions.d.ts.map +0 -1
  168. package/dist/ast-unions.js.map +0 -1
  169. package/dist/constants.d.ts.map +0 -1
  170. package/dist/constants.js.map +0 -1
  171. package/dist/error-classes.d.ts.map +0 -1
  172. package/dist/error-classes.js.map +0 -1
  173. package/dist/error-formatter.d.ts.map +0 -1
  174. package/dist/error-formatter.js.map +0 -1
  175. package/dist/error-registry.d.ts.map +0 -1
  176. package/dist/error-registry.js.map +0 -1
  177. package/dist/ext/crypto/index.d.ts.map +0 -1
  178. package/dist/ext/crypto/index.js.map +0 -1
  179. package/dist/ext/exec/index.d.ts.map +0 -1
  180. package/dist/ext/exec/index.js.map +0 -1
  181. package/dist/ext/exec/runner.d.ts.map +0 -1
  182. package/dist/ext/exec/runner.js.map +0 -1
  183. package/dist/ext/fetch/index.d.ts.map +0 -1
  184. package/dist/ext/fetch/index.js.map +0 -1
  185. package/dist/ext/fetch/request.d.ts.map +0 -1
  186. package/dist/ext/fetch/request.js.map +0 -1
  187. package/dist/ext/fs/index.d.ts.map +0 -1
  188. package/dist/ext/fs/index.js.map +0 -1
  189. package/dist/ext/fs/sandbox.d.ts.map +0 -1
  190. package/dist/ext/fs/sandbox.js.map +0 -1
  191. package/dist/ext/kv/index.d.ts.map +0 -1
  192. package/dist/ext/kv/index.js.map +0 -1
  193. package/dist/ext/kv/store.d.ts.map +0 -1
  194. package/dist/ext/kv/store.js.map +0 -1
  195. package/dist/generated/introspection-data.d.ts.map +0 -1
  196. package/dist/generated/introspection-data.js.map +0 -1
  197. package/dist/generated/version-data.d.ts.map +0 -1
  198. package/dist/generated/version-data.js.map +0 -1
  199. package/dist/highlight-map.d.ts.map +0 -1
  200. package/dist/highlight-map.js.map +0 -1
  201. package/dist/index.d.ts.map +0 -1
  202. package/dist/index.js.map +0 -1
  203. package/dist/lexer/errors.d.ts.map +0 -1
  204. package/dist/lexer/errors.js.map +0 -1
  205. package/dist/lexer/helpers.d.ts.map +0 -1
  206. package/dist/lexer/helpers.js.map +0 -1
  207. package/dist/lexer/index.d.ts.map +0 -1
  208. package/dist/lexer/index.js.map +0 -1
  209. package/dist/lexer/operators.d.ts.map +0 -1
  210. package/dist/lexer/operators.js.map +0 -1
  211. package/dist/lexer/readers.d.ts.map +0 -1
  212. package/dist/lexer/readers.js.map +0 -1
  213. package/dist/lexer/state.d.ts.map +0 -1
  214. package/dist/lexer/state.js.map +0 -1
  215. package/dist/lexer/tokenizer.d.ts.map +0 -1
  216. package/dist/lexer/tokenizer.js.map +0 -1
  217. package/dist/parser/helpers.d.ts.map +0 -1
  218. package/dist/parser/helpers.js.map +0 -1
  219. package/dist/parser/index.d.ts.map +0 -1
  220. package/dist/parser/index.js.map +0 -1
  221. package/dist/parser/parser-collect.d.ts.map +0 -1
  222. package/dist/parser/parser-collect.js.map +0 -1
  223. package/dist/parser/parser-control.d.ts.map +0 -1
  224. package/dist/parser/parser-control.js.map +0 -1
  225. package/dist/parser/parser-expr.d.ts.map +0 -1
  226. package/dist/parser/parser-expr.js.map +0 -1
  227. package/dist/parser/parser-extract.d.ts.map +0 -1
  228. package/dist/parser/parser-extract.js.map +0 -1
  229. package/dist/parser/parser-functions.d.ts.map +0 -1
  230. package/dist/parser/parser-functions.js.map +0 -1
  231. package/dist/parser/parser-literals.d.ts.map +0 -1
  232. package/dist/parser/parser-literals.js.map +0 -1
  233. package/dist/parser/parser-script.d.ts.map +0 -1
  234. package/dist/parser/parser-script.js.map +0 -1
  235. package/dist/parser/parser-shape.d.ts.map +0 -1
  236. package/dist/parser/parser-shape.js.map +0 -1
  237. package/dist/parser/parser-types.d.ts.map +0 -1
  238. package/dist/parser/parser-types.js.map +0 -1
  239. package/dist/parser/parser-use.d.ts.map +0 -1
  240. package/dist/parser/parser-use.js.map +0 -1
  241. package/dist/parser/parser-variables.d.ts.map +0 -1
  242. package/dist/parser/parser-variables.js.map +0 -1
  243. package/dist/parser/parser.d.ts.map +0 -1
  244. package/dist/parser/parser.js.map +0 -1
  245. package/dist/parser/state.d.ts.map +0 -1
  246. package/dist/parser/state.js.map +0 -1
  247. package/dist/runtime/core/callable.d.ts.map +0 -1
  248. package/dist/runtime/core/callable.js.map +0 -1
  249. package/dist/runtime/core/context.d.ts.map +0 -1
  250. package/dist/runtime/core/context.js.map +0 -1
  251. package/dist/runtime/core/equals.d.ts.map +0 -1
  252. package/dist/runtime/core/equals.js.map +0 -1
  253. package/dist/runtime/core/eval/base.d.ts.map +0 -1
  254. package/dist/runtime/core/eval/base.js.map +0 -1
  255. package/dist/runtime/core/eval/evaluator.d.ts.map +0 -1
  256. package/dist/runtime/core/eval/evaluator.js.map +0 -1
  257. package/dist/runtime/core/eval/index.d.ts.map +0 -1
  258. package/dist/runtime/core/eval/index.js.map +0 -1
  259. package/dist/runtime/core/eval/mixins/annotations.d.ts.map +0 -1
  260. package/dist/runtime/core/eval/mixins/annotations.js.map +0 -1
  261. package/dist/runtime/core/eval/mixins/closures.d.ts.map +0 -1
  262. package/dist/runtime/core/eval/mixins/closures.js.map +0 -1
  263. package/dist/runtime/core/eval/mixins/collections.d.ts.map +0 -1
  264. package/dist/runtime/core/eval/mixins/collections.js.map +0 -1
  265. package/dist/runtime/core/eval/mixins/control-flow.d.ts.map +0 -1
  266. package/dist/runtime/core/eval/mixins/control-flow.js.map +0 -1
  267. package/dist/runtime/core/eval/mixins/conversion.d.ts.map +0 -1
  268. package/dist/runtime/core/eval/mixins/conversion.js.map +0 -1
  269. package/dist/runtime/core/eval/mixins/core.d.ts.map +0 -1
  270. package/dist/runtime/core/eval/mixins/core.js.map +0 -1
  271. package/dist/runtime/core/eval/mixins/expressions.d.ts.map +0 -1
  272. package/dist/runtime/core/eval/mixins/expressions.js.map +0 -1
  273. package/dist/runtime/core/eval/mixins/extraction.d.ts.map +0 -1
  274. package/dist/runtime/core/eval/mixins/extraction.js.map +0 -1
  275. package/dist/runtime/core/eval/mixins/list-dispatch.d.ts.map +0 -1
  276. package/dist/runtime/core/eval/mixins/list-dispatch.js.map +0 -1
  277. package/dist/runtime/core/eval/mixins/literals.d.ts.map +0 -1
  278. package/dist/runtime/core/eval/mixins/literals.js.map +0 -1
  279. package/dist/runtime/core/eval/mixins/types.d.ts.map +0 -1
  280. package/dist/runtime/core/eval/mixins/types.js.map +0 -1
  281. package/dist/runtime/core/eval/mixins/use.d.ts.map +0 -1
  282. package/dist/runtime/core/eval/mixins/use.js.map +0 -1
  283. package/dist/runtime/core/eval/mixins/variables.d.ts.map +0 -1
  284. package/dist/runtime/core/eval/mixins/variables.js.map +0 -1
  285. package/dist/runtime/core/eval/types.d.ts.map +0 -1
  286. package/dist/runtime/core/eval/types.js.map +0 -1
  287. package/dist/runtime/core/execute.d.ts.map +0 -1
  288. package/dist/runtime/core/execute.js.map +0 -1
  289. package/dist/runtime/core/field-descriptor.d.ts.map +0 -1
  290. package/dist/runtime/core/field-descriptor.js.map +0 -1
  291. package/dist/runtime/core/introspection.d.ts.map +0 -1
  292. package/dist/runtime/core/introspection.js.map +0 -1
  293. package/dist/runtime/core/resolvers.d.ts.map +0 -1
  294. package/dist/runtime/core/resolvers.js.map +0 -1
  295. package/dist/runtime/core/signals.d.ts.map +0 -1
  296. package/dist/runtime/core/signals.js.map +0 -1
  297. package/dist/runtime/core/types.d.ts.map +0 -1
  298. package/dist/runtime/core/types.js.map +0 -1
  299. package/dist/runtime/core/values.d.ts.map +0 -1
  300. package/dist/runtime/core/values.js.map +0 -1
  301. package/dist/runtime/ext/builtins.d.ts.map +0 -1
  302. package/dist/runtime/ext/builtins.js.map +0 -1
  303. package/dist/runtime/ext/extensions.d.ts.map +0 -1
  304. package/dist/runtime/ext/extensions.js.map +0 -1
  305. package/dist/runtime/index.d.ts.map +0 -1
  306. package/dist/runtime/index.js.map +0 -1
  307. package/dist/signature-parser.d.ts.map +0 -1
  308. package/dist/signature-parser.js.map +0 -1
  309. package/dist/source-location.d.ts.map +0 -1
  310. package/dist/source-location.js.map +0 -1
  311. package/dist/token-types.d.ts.map +0 -1
  312. package/dist/token-types.js.map +0 -1
  313. package/dist/types.d.ts.map +0 -1
  314. package/dist/types.js.map +0 -1
  315. package/dist/value-types.d.ts.map +0 -1
  316. package/dist/value-types.js.map +0 -1
@@ -3,18 +3,29 @@
3
3
  *
4
4
  * Core value types that flow through Rill programs.
5
5
  * Public API for host applications.
6
+ *
7
+ * Dispatch functions (inferType, formatValue, deepEquals, serializeValue,
8
+ * copyValue) re-export from type-registrations.ts protocol implementations.
6
9
  */
7
10
  import { RuntimeError } from '../../types.js';
8
11
  import { VALID_TYPE_NAMES } from '../../constants.js';
9
- import { callableEquals, isCallable, isDict, isScriptCallable, } from './callable.js';
12
+ import { isCallable, isDict } from './callable.js';
13
+ import { inferType as registryInferType, formatValue as registryFormatValue, deepEquals as registryDeepEquals, serializeValue as registrySerializeValue, copyValue as registryCopyValue, } from './type-registrations.js';
10
14
  /**
11
- * Type guard to distinguish the `{ type, defaultValue }` form of RillFieldType
12
- * from a plain RillType.
15
+ * Normalize a TypeStructure that may use the legacy `.type` discriminator.
16
+ * During migration, some code (builtins.ts, ext/) constructs objects with
17
+ * `{ type: 'string' }` instead of `{ kind: 'string' }`. This function
18
+ * converts legacy format to current format on the fly.
13
19
  */
14
- export function isFieldTypeWithDefault(fieldType) {
15
- return (typeof fieldType === 'object' &&
16
- fieldType !== null &&
17
- 'defaultValue' in fieldType);
20
+ function normalizeStructure(ts) {
21
+ if (ts.kind !== undefined)
22
+ return ts;
23
+ // Legacy format: { type: 'string' } → { kind: 'string' }
24
+ const legacy = ts;
25
+ if (typeof legacy['type'] === 'string') {
26
+ return { ...legacy, kind: legacy['type'] };
27
+ }
28
+ return ts;
18
29
  }
19
30
  /** Type guard for RillTuple (spread args) */
20
31
  export function isTuple(value) {
@@ -44,7 +55,11 @@ export function isTypeValue(value) {
44
55
  '__rill_type' in value &&
45
56
  value.__rill_type === true);
46
57
  }
47
- /** Create ordered from entries array (named, preserves insertion order) */
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
+ */
48
63
  export function createOrdered(entries) {
49
64
  return Object.freeze({ __rill_ordered: true, entries: [...entries] });
50
65
  }
@@ -62,98 +77,185 @@ export function createVector(data, model) {
62
77
  }
63
78
  return { __rill_vector: true, data, model };
64
79
  }
65
- /** Infer the Rill type from a runtime value */
66
- export function inferType(value) {
67
- if (value === null)
68
- return 'string'; // null treated as empty string
69
- if (typeof value === 'string')
70
- return 'string';
71
- if (typeof value === 'number')
72
- return 'number';
73
- if (typeof value === 'boolean')
74
- return 'bool';
75
- if (isTuple(value))
76
- return 'tuple';
77
- if (isOrdered(value))
78
- return 'ordered';
79
- if (isVector(value))
80
- return 'vector';
81
- if (Array.isArray(value))
82
- return 'list';
83
- if (isTypeValue(value))
84
- return 'type';
85
- if (isRillIterator(value))
86
- return 'iterator';
87
- if (typeof value === 'object' &&
88
- '__type' in value &&
89
- value.__type === 'callable') {
90
- return 'closure';
91
- }
92
- if (typeof value === 'object')
93
- return 'dict';
94
- return 'string'; // fallback
95
- }
80
+ /** Infer the Rill type from a runtime value. Delegates to type-registrations. */
81
+ export const inferType = registryInferType;
96
82
  /**
97
83
  * Infer the element type for a homogeneous list.
98
- * Empty arrays return { type: 'any' }.
84
+ * Empty arrays return { kind: 'any' }.
99
85
  * Mixed types throw RILL-R002.
100
86
  */
101
87
  export function inferElementType(elements) {
102
88
  if (elements.length === 0)
103
- return { type: 'any' };
89
+ return { kind: 'any' };
104
90
  const firstElem = elements[0];
105
- const firstType = inferStructuralType(firstElem);
91
+ let accType = inferStructure(firstElem);
106
92
  for (let i = 1; i < elements.length; i++) {
107
93
  const elem = elements[i];
108
- const elemType = inferStructuralType(elem);
109
- if (!structuralTypeEquals(firstType, elemType)) {
110
- throw new RuntimeError('RILL-R002', `List elements must be the same type: expected ${formatStructuralType(firstType)}, got ${formatStructuralType(elemType)} at index ${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;
111
131
  }
132
+ return merged;
112
133
  }
113
- return firstType;
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;
114
205
  }
115
206
  /** Compare two structural types for equality. */
116
- export function structuralTypeEquals(a, b) {
117
- if (a.type !== b.type)
207
+ export function structureEquals(a, b) {
208
+ if (a.kind !== b.kind)
118
209
  return false;
119
- // Leaf variants compare by type alone
120
- if (a.type === 'number' ||
121
- a.type === 'string' ||
122
- a.type === 'bool' ||
123
- a.type === 'vector' ||
124
- a.type === 'type' ||
125
- a.type === 'any') {
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') {
126
217
  return true;
127
218
  }
128
- if (a.type === 'list' && b.type === 'list') {
129
- if (a.element === undefined && b.element === undefined)
219
+ if (a.kind === 'list' && b.kind === 'list') {
220
+ const aList = a;
221
+ const bList = b;
222
+ if (aList.element === undefined && bList.element === undefined)
130
223
  return true;
131
- if (a.element === undefined || b.element === undefined)
224
+ if (aList.element === undefined || bList.element === undefined)
132
225
  return false;
133
- return structuralTypeEquals(a.element, b.element);
134
- }
135
- if (a.type === 'dict' && b.type === 'dict') {
136
- if (a.fields === undefined && b.fields === undefined)
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)
137
241
  return true;
138
- if (a.fields === undefined || b.fields === undefined)
242
+ if (aDict.fields === undefined || bDict.fields === undefined)
139
243
  return false;
140
- const aKeys = Object.keys(a.fields).sort();
141
- const bKeys = Object.keys(b.fields).sort();
244
+ const aKeys = Object.keys(aDict.fields).sort();
245
+ const bKeys = Object.keys(bDict.fields).sort();
142
246
  if (aKeys.length !== bKeys.length)
143
247
  return false;
144
248
  for (let i = 0; i < aKeys.length; i++) {
145
249
  const key = aKeys[i];
146
250
  if (key !== bKeys[i])
147
251
  return false;
148
- const aField = a.fields[key];
149
- const bField = b.fields[key];
150
- const aHasDefault = isFieldTypeWithDefault(aField);
151
- const bHasDefault = isFieldTypeWithDefault(bField);
252
+ const aField = aDict.fields[key];
253
+ const bField = bDict.fields[key];
254
+ const aHasDefault = aField.defaultValue !== undefined;
255
+ const bHasDefault = bField.defaultValue !== undefined;
152
256
  if (aHasDefault !== bHasDefault)
153
257
  return false;
154
- const aType = aHasDefault ? aField.type : aField;
155
- const bType = bHasDefault ? bField.type : bField;
156
- if (!structuralTypeEquals(aType, bType))
258
+ if (!structureEquals(aField.type, bField.type))
157
259
  return false;
158
260
  if (aHasDefault && bHasDefault) {
159
261
  if (!deepEquals(aField.defaultValue, bField.defaultValue))
@@ -162,20 +264,31 @@ export function structuralTypeEquals(a, b) {
162
264
  }
163
265
  return true;
164
266
  }
165
- if (a.type === 'tuple' && b.type === 'tuple') {
166
- if (a.elements === undefined && b.elements === undefined)
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)
167
280
  return true;
168
- if (a.elements === undefined || b.elements === undefined)
281
+ if (aTuple.elements === undefined || bTuple.elements === undefined)
169
282
  return false;
170
- if (a.elements.length !== b.elements.length)
283
+ if (aTuple.elements.length !== bTuple.elements.length)
171
284
  return false;
172
- for (let i = 0; i < a.elements.length; i++) {
173
- const aElem = a.elements[i];
174
- const bElem = b.elements[i];
175
- if (!structuralTypeEquals(aElem[0], bElem[0]))
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))
176
289
  return false;
177
- const aDefault = aElem[1];
178
- const bDefault = bElem[1];
290
+ const aDefault = aElem.defaultValue;
291
+ const bDefault = bElem.defaultValue;
179
292
  if (aDefault === undefined && bDefault === undefined)
180
293
  continue;
181
294
  if (aDefault === undefined || bDefault === undefined)
@@ -185,22 +298,33 @@ export function structuralTypeEquals(a, b) {
185
298
  }
186
299
  return true;
187
300
  }
188
- if (a.type === 'ordered' && b.type === 'ordered') {
189
- if (a.fields === undefined && b.fields === undefined)
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)
190
314
  return true;
191
- if (a.fields === undefined || b.fields === undefined)
315
+ if (aOrd.fields === undefined || bOrd.fields === undefined)
192
316
  return false;
193
- if (a.fields.length !== b.fields.length)
317
+ if (aOrd.fields.length !== bOrd.fields.length)
194
318
  return false;
195
- for (let i = 0; i < a.fields.length; i++) {
196
- const aField = a.fields[i];
197
- const bField = b.fields[i];
198
- if (aField[0] !== bField[0])
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)
199
323
  return false;
200
- if (!structuralTypeEquals(aField[1], bField[1]))
324
+ if (!structureEquals(aField.type, bField.type))
201
325
  return false;
202
- const aDefault = aField[2];
203
- const bDefault = bField[2];
326
+ const aDefault = aField.defaultValue;
327
+ const bDefault = bField.defaultValue;
204
328
  if (aDefault === undefined && bDefault === undefined)
205
329
  continue;
206
330
  if (aDefault === undefined || bDefault === undefined)
@@ -210,34 +334,38 @@ export function structuralTypeEquals(a, b) {
210
334
  }
211
335
  return true;
212
336
  }
213
- if (a.type === 'union' && b.type === 'union') {
214
- if (a.members.length !== b.members.length)
337
+ if (a.kind === 'union' && b.kind === 'union') {
338
+ const aUnion = a;
339
+ const bUnion = b;
340
+ if (aUnion.members.length !== bUnion.members.length)
215
341
  return false;
216
- for (let i = 0; i < a.members.length; i++) {
217
- if (!structuralTypeEquals(a.members[i], b.members[i]))
342
+ for (let i = 0; i < aUnion.members.length; i++) {
343
+ if (!structureEquals(aUnion.members[i], bUnion.members[i]))
218
344
  return false;
219
345
  }
220
346
  return true;
221
347
  }
222
- if (a.type === 'closure' && b.type === 'closure') {
223
- if (a.params === undefined && b.params === undefined) {
348
+ if (a.kind === 'closure' && b.kind === 'closure') {
349
+ const aCls = a;
350
+ const bCls = b;
351
+ if (aCls.params === undefined && bCls.params === undefined) {
224
352
  // Both absent: compare ret
225
353
  }
226
- else if (a.params === undefined || b.params === undefined) {
354
+ else if (aCls.params === undefined || bCls.params === undefined) {
227
355
  return false;
228
356
  }
229
357
  else {
230
- if (a.params.length !== b.params.length)
358
+ if (aCls.params.length !== bCls.params.length)
231
359
  return false;
232
- for (let i = 0; i < a.params.length; i++) {
233
- const aParam = a.params[i];
234
- const bParam = b.params[i];
235
- if (aParam[0] !== bParam[0])
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)
236
364
  return false;
237
- if (!structuralTypeEquals(aParam[1], bParam[1]))
365
+ if (!structureEquals(aParam.type, bParam.type))
238
366
  return false;
239
- const aDefault = aParam[2];
240
- const bDefault = bParam[2];
367
+ const aDefault = aParam.defaultValue;
368
+ const bDefault = bParam.defaultValue;
241
369
  if (aDefault === undefined && bDefault === undefined)
242
370
  continue;
243
371
  if (aDefault === undefined || bDefault === undefined)
@@ -246,184 +374,219 @@ export function structuralTypeEquals(a, b) {
246
374
  return false;
247
375
  }
248
376
  }
249
- if (a.ret === undefined && b.ret === undefined)
377
+ if (aCls.ret === undefined && bCls.ret === undefined)
250
378
  return true;
251
- if (a.ret === undefined || b.ret === undefined)
379
+ if (aCls.ret === undefined || bCls.ret === undefined)
252
380
  return false;
253
- return structuralTypeEquals(a.ret, b.ret);
381
+ return structureEquals(aCls.ret, bCls.ret);
254
382
  }
255
383
  return false;
256
384
  }
385
+ /** @deprecated Use structureEquals instead. */
386
+ export const structuralTypeEquals = structureEquals;
257
387
  /** Infer the structural type descriptor for any Rill value. */
258
- export function inferStructuralType(value) {
388
+ export function inferStructure(value) {
259
389
  if (value === null || typeof value === 'string') {
260
- return { type: 'string' };
390
+ return { kind: 'string' };
261
391
  }
262
392
  if (typeof value === 'number') {
263
- return { type: 'number' };
393
+ return { kind: 'number' };
264
394
  }
265
395
  if (typeof value === 'boolean') {
266
- return { type: 'bool' };
396
+ return { kind: 'bool' };
267
397
  }
268
398
  if (isTypeValue(value)) {
269
- return { type: 'type' };
399
+ return { kind: 'type' };
270
400
  }
271
401
  if (Array.isArray(value)) {
272
- return { type: 'list', element: inferElementType(value) };
402
+ return { kind: 'list', element: inferElementType(value) };
273
403
  }
274
404
  if (isTuple(value)) {
275
405
  return {
276
- type: 'tuple',
277
- elements: value.entries.map((e) => [
278
- inferStructuralType(e),
279
- ]),
406
+ kind: 'tuple',
407
+ elements: value.entries.map((e) => ({
408
+ type: inferStructure(e),
409
+ })),
280
410
  };
281
411
  }
282
412
  if (isOrdered(value)) {
283
413
  return {
284
- type: 'ordered',
285
- fields: value.entries.map(([k, v]) => [
286
- k,
287
- inferStructuralType(v),
288
- ]),
414
+ kind: 'ordered',
415
+ fields: value.entries.map(([k, v]) => ({
416
+ name: k,
417
+ type: inferStructure(v),
418
+ })),
289
419
  };
290
420
  }
291
421
  if (isVector(value)) {
292
- return { type: 'vector' };
422
+ return { kind: 'vector' };
293
423
  }
294
424
  if (isCallable(value)) {
295
- const params = (value.params ?? []).map((p) => paramToTypeTuple(p.name, p.type ?? { type: 'any' }, p.defaultValue));
425
+ const params = (value.params ?? []).map((p) => paramToFieldDef(p.name, p.type ?? { kind: 'any' }, p.defaultValue));
296
426
  const ret = value.returnType.structure;
297
- return { type: 'closure', params, ret };
427
+ return { kind: 'closure', params, ret };
298
428
  }
299
429
  if (typeof value === 'object') {
300
430
  const dict = value;
301
431
  const fields = {};
302
432
  for (const [k, v] of Object.entries(dict)) {
303
- fields[k] = inferStructuralType(v);
433
+ fields[k] = { type: inferStructure(v) };
304
434
  }
305
- return { type: 'dict', fields };
435
+ return { kind: 'dict', fields };
306
436
  }
307
437
  throw new RuntimeError('RILL-R004', `Cannot infer structural type for ${formatValue(value)}`);
308
438
  }
439
+ /** @deprecated Use inferStructure instead. */
440
+ export const inferStructuralType = inferStructure;
309
441
  /**
310
442
  * Check if a value matches a structural type descriptor.
311
443
  * Used for runtime type checking (`:?` operator).
312
444
  */
313
- export function structuralTypeMatches(value, type) {
445
+ export function structureMatches(value, type) {
446
+ type = normalizeStructure(type);
314
447
  if (typeof value === 'undefined') {
315
448
  throw new RuntimeError('RILL-R004', 'Cannot type-check non-value');
316
449
  }
317
- if (type.type === 'any')
450
+ if (type.kind === 'any')
318
451
  return true;
319
452
  // Leaf primitive variants: match by inferred type name
320
- if (type.type === 'number' ||
321
- type.type === 'string' ||
322
- type.type === 'bool' ||
323
- type.type === 'vector' ||
324
- type.type === 'type') {
325
- return inferType(value) === type.type;
326
- }
327
- if (type.type === 'list') {
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;
328
462
  if (!Array.isArray(value))
329
463
  return false;
330
- // Absent element sub-field: matches any list value
331
- if (type.element === undefined)
464
+ if (t.element === undefined)
332
465
  return true;
333
- if (type.element.type === 'any')
466
+ if (t.element.kind === 'any')
334
467
  return true;
335
- return value.every((elem) => structuralTypeMatches(elem, type.element));
468
+ return value.every((elem) => structureMatches(elem, t.element));
336
469
  }
337
- if (type.type === 'dict') {
470
+ if (type.kind === 'dict') {
471
+ const t = type;
338
472
  if (!isDict(value))
339
473
  return false;
340
- // Absent fields sub-field: matches any dict value
341
- if (type.fields === undefined)
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)
342
479
  return true;
343
- const dictKeys = Object.keys(type.fields);
344
- // Empty fields object matches any dict
480
+ const dictKeys = Object.keys(t.fields);
345
481
  if (dictKeys.length === 0)
346
482
  return true;
347
483
  const dict = value;
348
484
  for (const key of dictKeys) {
349
- if (!(key in dict))
485
+ if (!(key in dict)) {
486
+ const field = t.fields[key];
487
+ if (field.defaultValue !== undefined)
488
+ continue;
350
489
  return false;
351
- const fieldType = type.fields[key];
352
- const resolvedType = isFieldTypeWithDefault(fieldType)
353
- ? fieldType.type
354
- : fieldType;
355
- if (!structuralTypeMatches(dict[key], resolvedType))
490
+ }
491
+ const field = t.fields[key];
492
+ if (!structureMatches(dict[key], field.type))
356
493
  return false;
357
494
  }
358
495
  return true;
359
496
  }
360
- if (type.type === 'tuple') {
497
+ if (type.kind === 'tuple') {
498
+ const t = type;
361
499
  if (!isTuple(value))
362
500
  return false;
363
- // Absent elements sub-field: matches any tuple value
364
- if (type.elements === undefined)
501
+ if (t.valueType !== undefined) {
502
+ return value.entries.every((v) => structureMatches(v, t.valueType));
503
+ }
504
+ if (t.elements === undefined)
365
505
  return true;
366
- if (type.elements.length === 0)
506
+ if (t.elements.length === 0)
367
507
  return value.entries.length === 0;
368
- if (value.entries.length !== type.elements.length)
508
+ if (value.entries.length > t.elements.length)
369
509
  return false;
370
- for (let i = 0; i < type.elements.length; i++) {
371
- if (!structuralTypeMatches(value.entries[i], type.elements[i][0]))
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))
372
519
  return false;
373
520
  }
374
521
  return true;
375
522
  }
376
- if (type.type === 'ordered') {
523
+ if (type.kind === 'ordered') {
524
+ const t = type;
377
525
  if (!isOrdered(value))
378
526
  return false;
379
- // Absent fields sub-field: matches any ordered value
380
- if (type.fields === undefined)
527
+ if (t.valueType !== undefined) {
528
+ return value.entries.every(([, v]) => structureMatches(v, t.valueType));
529
+ }
530
+ if (t.fields === undefined)
381
531
  return true;
382
- if (type.fields.length === 0)
532
+ if (t.fields.length === 0)
383
533
  return value.entries.length === 0;
384
- if (value.entries.length !== type.fields.length)
534
+ if (value.entries.length > t.fields.length)
385
535
  return false;
386
- for (let i = 0; i < type.fields.length; i++) {
387
- const [expectedName, expectedType] = type.fields[i];
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];
388
545
  const [actualName, actualValue] = value.entries[i];
389
- if (actualName !== expectedName)
546
+ if (actualName !== field.name)
390
547
  return false;
391
- if (!structuralTypeMatches(actualValue, expectedType))
548
+ if (!structureMatches(actualValue, field.type))
392
549
  return false;
393
550
  }
394
551
  return true;
395
552
  }
396
- if (type.type === 'closure') {
553
+ if (type.kind === 'closure') {
554
+ const t = type;
397
555
  if (!isCallable(value))
398
556
  return false;
399
- // Absent params sub-field: matches any closure value of that compound type
400
- if (type.params === undefined)
557
+ if (t.params === undefined)
401
558
  return true;
402
559
  const valueParams = value.params ?? [];
403
- if (valueParams.length !== type.params.length)
560
+ if (valueParams.length !== t.params.length)
404
561
  return false;
405
- for (let i = 0; i < type.params.length; i++) {
406
- const [expectedName, expectedType] = type.params[i];
562
+ for (let i = 0; i < t.params.length; i++) {
563
+ const field = t.params[i];
407
564
  const param = valueParams[i];
408
- if (param.name !== expectedName)
565
+ if (param.name !== field.name)
409
566
  return false;
410
- const paramType = param.type ?? { type: 'any' };
411
- if (!structuralTypeEquals(paramType, expectedType))
567
+ const paramType = param.type ?? { kind: 'any' };
568
+ if (!structureEquals(paramType, field.type))
412
569
  return false;
413
570
  }
414
571
  const retType = value.returnType.structure;
415
- if (type.ret === undefined)
572
+ if (t.ret === undefined)
416
573
  return true;
417
- return structuralTypeEquals(retType, type.ret);
574
+ return structureEquals(retType, t.ret);
418
575
  }
419
- if (type.type === 'union') {
420
- return type.members.some((member) => structuralTypeMatches(value, member));
576
+ if (type.kind === 'union') {
577
+ const t = type;
578
+ return t.members.some((member) => structureMatches(value, member));
421
579
  }
422
580
  return false;
423
581
  }
424
- /** Build a closure param tuple, omitting the optional third element when no default. */
425
- export function paramToTypeTuple(name, type, defaultValue) {
426
- return defaultValue !== undefined ? [name, type, defaultValue] : [name, type];
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;
427
590
  }
428
591
  /** Format a RillValue as a rill literal for use in type signatures. */
429
592
  function formatRillLiteral(value) {
@@ -440,75 +603,92 @@ function formatRillLiteral(value) {
440
603
  return formatValue(value);
441
604
  }
442
605
  /** Format a structural type descriptor as a human-readable string. */
443
- export function formatStructuralType(type) {
444
- if (type.type === 'any' ||
445
- type.type === 'number' ||
446
- type.type === 'string' ||
447
- type.type === 'bool' ||
448
- type.type === 'vector' ||
449
- type.type === 'type') {
450
- return type.type;
451
- }
452
- if (type.type === 'list') {
453
- if (type.element === undefined)
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)
454
618
  return 'list';
455
- return `list(${formatStructuralType(type.element)})`;
619
+ return `list(${formatStructure(t.element)})`;
456
620
  }
457
- if (type.type === 'dict') {
458
- if (type.fields === undefined)
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)
459
627
  return 'dict';
460
- const parts = Object.keys(type.fields)
628
+ const parts = Object.keys(t.fields)
461
629
  .sort()
462
630
  .map((k) => {
463
- const fieldType = type.fields[k];
464
- if (isFieldTypeWithDefault(fieldType)) {
465
- return `${k}: ${formatStructuralType(fieldType.type)} = ${formatRillLiteral(fieldType.defaultValue)}`;
466
- }
467
- return `${k}: ${formatStructuralType(fieldType)}`;
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)}`;
468
636
  });
469
637
  return `dict(${parts.join(', ')})`;
470
638
  }
471
- if (type.type === 'tuple') {
472
- if (type.elements === undefined)
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)
473
645
  return 'tuple';
474
- const parts = type.elements.map(([t, defaultVal]) => {
475
- const base = formatStructuralType(t);
476
- if (defaultVal === undefined)
646
+ const parts = t.elements.map((field) => {
647
+ const base = formatStructure(field.type);
648
+ if (field.defaultValue === undefined)
477
649
  return base;
478
- return `${base} = ${formatRillLiteral(defaultVal)}`;
650
+ return `${base} = ${formatRillLiteral(field.defaultValue)}`;
479
651
  });
480
652
  return `tuple(${parts.join(', ')})`;
481
653
  }
482
- if (type.type === 'ordered') {
483
- if (type.fields === undefined)
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)
484
660
  return 'ordered';
485
- const parts = type.fields.map(([k, t, defaultVal]) => {
486
- const base = `${k}: ${formatStructuralType(t)}`;
487
- if (defaultVal === undefined)
661
+ const parts = t.fields.map((field) => {
662
+ const base = `${field.name}: ${formatStructure(field.type)}`;
663
+ if (field.defaultValue === undefined)
488
664
  return base;
489
- return `${base} = ${formatRillLiteral(defaultVal)}`;
665
+ return `${base} = ${formatRillLiteral(field.defaultValue)}`;
490
666
  });
491
667
  return `ordered(${parts.join(', ')})`;
492
668
  }
493
- if (type.type === 'closure') {
494
- if (type.params === undefined)
669
+ if (type.kind === 'closure') {
670
+ const t = type;
671
+ if (t.params === undefined)
495
672
  return 'closure';
496
- const params = type.params
497
- .map(([name, t, defaultVal]) => {
498
- const base = `${name}: ${formatStructuralType(t)}`;
499
- if (defaultVal === undefined)
673
+ const params = t.params
674
+ .map((field) => {
675
+ const base = `${field.name}: ${formatStructure(field.type)}`;
676
+ if (field.defaultValue === undefined)
500
677
  return base;
501
- return `${base} = ${formatRillLiteral(defaultVal)}`;
678
+ return `${base} = ${formatRillLiteral(field.defaultValue)}`;
502
679
  })
503
680
  .join(', ');
504
- const ret = type.ret !== undefined ? formatStructuralType(type.ret) : 'any';
681
+ const ret = t.ret !== undefined ? formatStructure(t.ret) : 'any';
505
682
  return `|${params}| :${ret}`;
506
683
  }
507
- if (type.type === 'union') {
508
- return type.members.map(formatStructuralType).join('|');
684
+ if (type.kind === 'union') {
685
+ const t = type;
686
+ return t.members.map(formatStructure).join('|');
509
687
  }
510
688
  return 'any';
511
689
  }
690
+ /** @deprecated Use formatStructure instead. */
691
+ export const formatStructuralType = formatStructure;
512
692
  /**
513
693
  * Check if a value is of the expected type.
514
694
  * Returns true if the value matches the expected type, false otherwise.
@@ -545,88 +725,12 @@ export function isTruthy(value) {
545
725
  export function isEmpty(value) {
546
726
  return !isTruthy(value);
547
727
  }
548
- /** Format a value for display */
549
- export function formatValue(value) {
550
- if (value === null)
551
- return 'type(null)';
552
- if (typeof value === 'string')
553
- return value;
554
- if (typeof value === 'number')
555
- return String(value);
556
- if (typeof value === 'boolean')
557
- return value ? 'true' : 'false';
558
- if (isCallable(value)) {
559
- return 'type(closure)';
560
- }
561
- if (isTuple(value)) {
562
- return `tuple[${value.entries.map(formatValue).join(', ')}]`;
563
- }
564
- if (isOrdered(value)) {
565
- const parts = value.entries.map(([k, v]) => `${k}: ${formatValue(v)}`);
566
- return `ordered[${parts.join(', ')}]`;
567
- }
568
- if (isRillIterator(value)) {
569
- return 'type(iterator)';
570
- }
571
- if (Array.isArray(value)) {
572
- return `list[${value.map(formatValue).join(', ')}]`;
573
- }
574
- if (isVector(value)) {
575
- return `vector(${value.model}, ${value.data.length}d)`;
576
- }
577
- if (isTypeValue(value)) {
578
- return formatStructuralType(value.structure);
579
- }
580
- // Plain dict
581
- if (typeof value === 'object') {
582
- const dict = value;
583
- const parts = Object.entries(dict).map(([k, v]) => `${k}: ${formatValue(v)}`);
584
- return `dict[${parts.join(', ')}]`;
585
- }
586
- return String(value);
587
- }
588
- /**
589
- * Convert a RillValue to a JSON-serializable value.
590
- * @throws {Error} plain Error (not RuntimeError) for non-serializable types
591
- */
592
- export function valueToJSON(value) {
593
- if (value === null)
594
- return null;
595
- if (typeof value === 'string')
596
- return value;
597
- if (typeof value === 'number')
598
- return value;
599
- if (typeof value === 'boolean')
600
- return value;
601
- if (Array.isArray(value)) {
602
- return value.map(valueToJSON);
603
- }
604
- if (isCallable(value)) {
605
- throw new Error('closures are not JSON-serializable');
606
- }
607
- if (isTuple(value)) {
608
- throw new Error('tuples are not JSON-serializable');
609
- }
610
- if (isOrdered(value)) {
611
- throw new Error('ordered values are not JSON-serializable');
612
- }
613
- if (isVector(value)) {
614
- throw new Error('vectors are not JSON-serializable');
615
- }
616
- if (isTypeValue(value)) {
617
- throw new Error('type values are not JSON-serializable');
618
- }
619
- if (isRillIterator(value)) {
620
- throw new Error('iterators are not JSON-serializable');
621
- }
622
- // Plain dict
623
- const dict = value;
624
- const result = {};
625
- for (const [k, v] of Object.entries(dict)) {
626
- result[k] = valueToJSON(v);
627
- }
628
- return result;
629
- }
728
+ /** Format a value for display. Delegates to type-registrations. */
729
+ export const formatValue = registryFormatValue;
730
+ /** Serialize a Rill value for JSON transport. Delegates to type-registrations. */
731
+ export const serializeValue = registrySerializeValue;
732
+ /** @deprecated Use serializeValue instead. */
733
+ export const valueToJSON = serializeValue;
630
734
  /**
631
735
  * Convert a RillValue to a NativeResult for host consumption.
632
736
  * Non-representable types (closures, vectors, type values, iterators) produce descriptor objects.
@@ -634,7 +738,7 @@ export function valueToJSON(value) {
634
738
  */
635
739
  export function toNative(value) {
636
740
  const rillTypeName = inferType(value);
637
- const rillTypeSignature = formatStructuralType(inferStructuralType(value));
741
+ const rillTypeSignature = formatStructure(inferStructure(value));
638
742
  const nativeValue = toNativeValue(value);
639
743
  return { rillTypeName, rillTypeSignature, value: nativeValue };
640
744
  }
@@ -651,7 +755,7 @@ function toNativeValue(value) {
651
755
  return value.map(toNativeValue);
652
756
  }
653
757
  if (isCallable(value)) {
654
- return { signature: formatStructuralType(inferStructuralType(value)) };
758
+ return { signature: formatStructure(inferStructure(value)) };
655
759
  }
656
760
  if (isTuple(value)) {
657
761
  return value.entries.map(toNativeValue);
@@ -669,10 +773,10 @@ function toNativeValue(value) {
669
773
  if (isTypeValue(value)) {
670
774
  return {
671
775
  name: value.typeName,
672
- signature: formatStructuralType(value.structure),
776
+ signature: formatStructure(value.structure),
673
777
  };
674
778
  }
675
- if (isRillIterator(value)) {
779
+ if (isIterator(value)) {
676
780
  return { done: value.done };
677
781
  }
678
782
  // Plain dict
@@ -683,152 +787,8 @@ function toNativeValue(value) {
683
787
  }
684
788
  return result;
685
789
  }
686
- /**
687
- * Deep structural equality for all Rill values.
688
- * - Primitives: value equality
689
- * - Tuples: length + recursive element equality
690
- * - Dicts: same keys + recursive value equality (order-independent)
691
- */
692
- export function deepEquals(a, b) {
693
- // Handle primitives and null
694
- if (a === b)
695
- return true;
696
- if (a === null || b === null)
697
- return false;
698
- if (typeof a !== typeof b)
699
- return false;
700
- // Primitives (string, number, boolean) - covered by === above
701
- if (typeof a !== 'object' || typeof b !== 'object')
702
- return false;
703
- // Both are non-null objects at this point
704
- const aObj = a;
705
- const bObj = b;
706
- // Check for tuples (positional spread args)
707
- const aIsTuple = isTuple(a);
708
- const bIsTuple = isTuple(b);
709
- if (aIsTuple !== bIsTuple)
710
- return false;
711
- if (aIsTuple && bIsTuple) {
712
- if (a.entries.length !== b.entries.length)
713
- return false;
714
- for (let i = 0; i < a.entries.length; i++) {
715
- const aVal = a.entries[i];
716
- const bVal = b.entries[i];
717
- if (aVal === undefined || bVal === undefined) {
718
- if (aVal !== bVal)
719
- return false;
720
- }
721
- else if (!deepEquals(aVal, bVal)) {
722
- return false;
723
- }
724
- }
725
- return true;
726
- }
727
- // Check for ordered (named spread args)
728
- const aIsOrdered = isOrdered(a);
729
- const bIsOrdered = isOrdered(b);
730
- if (aIsOrdered !== bIsOrdered)
731
- return false;
732
- if (aIsOrdered && bIsOrdered) {
733
- if (a.entries.length !== b.entries.length)
734
- return false;
735
- for (let i = 0; i < a.entries.length; i++) {
736
- const aEntry = a.entries[i];
737
- const bEntry = b.entries[i];
738
- if (aEntry === undefined || bEntry === undefined)
739
- return false;
740
- if (aEntry[0] !== bEntry[0])
741
- return false;
742
- if (!deepEquals(aEntry[1], bEntry[1]))
743
- return false;
744
- }
745
- return true;
746
- }
747
- // Check for vectors
748
- const aIsVector = isVector(a);
749
- const bIsVector = isVector(b);
750
- if (aIsVector !== bIsVector)
751
- return false;
752
- if (aIsVector && bIsVector) {
753
- // Vectors equal when model matches AND all float elements match
754
- if (a.model !== b.model)
755
- return false;
756
- if (a.data.length !== b.data.length)
757
- return false;
758
- for (let i = 0; i < a.data.length; i++) {
759
- const aVal = a.data[i];
760
- const bVal = b.data[i];
761
- if (aVal !== bVal)
762
- return false;
763
- }
764
- return true;
765
- }
766
- // Check for type values (first-class type names)
767
- const aIsTypeValue = isTypeValue(a);
768
- const bIsTypeValue = isTypeValue(b);
769
- if (aIsTypeValue !== bIsTypeValue)
770
- return false;
771
- if (aIsTypeValue && bIsTypeValue) {
772
- return structuralTypeEquals(a.structure, b.structure);
773
- }
774
- // Check for arrays (lists)
775
- const aIsArray = Array.isArray(a);
776
- const bIsArray = Array.isArray(b);
777
- if (aIsArray !== bIsArray)
778
- return false;
779
- if (aIsArray && bIsArray) {
780
- if (a.length !== b.length)
781
- return false;
782
- for (let i = 0; i < a.length; i++) {
783
- const aElem = a[i];
784
- const bElem = b[i];
785
- if (aElem === undefined || bElem === undefined) {
786
- if (aElem !== bElem)
787
- return false;
788
- }
789
- else if (!deepEquals(aElem, bElem)) {
790
- return false;
791
- }
792
- }
793
- return true;
794
- }
795
- // Both are dicts (plain objects) or callables
796
- // For script callables, use structural equality (params + body AST + captured values)
797
- // For runtime/application callables, use reference equality
798
- if ('__type' in aObj || '__type' in bObj) {
799
- // Both must be callables to be equal
800
- if (!('__type' in aObj) || !('__type' in bObj))
801
- return false;
802
- if (aObj.__type !== 'callable' || bObj.__type !== 'callable')
803
- return false;
804
- // Script callables: structural equality
805
- if (isScriptCallable(a) && isScriptCallable(b)) {
806
- return callableEquals(a, b, deepEquals);
807
- }
808
- // Runtime/application callables: reference equality
809
- return a === b;
810
- }
811
- const aDict = a;
812
- const bDict = b;
813
- const aKeys = Object.keys(aDict);
814
- const bKeys = Object.keys(bDict);
815
- if (aKeys.length !== bKeys.length)
816
- return false;
817
- for (const key of aKeys) {
818
- if (!(key in bDict))
819
- return false;
820
- const aVal = aDict[key];
821
- const bVal = bDict[key];
822
- if (aVal === undefined || bVal === undefined) {
823
- if (aVal !== bVal)
824
- return false;
825
- }
826
- else if (!deepEquals(aVal, bVal)) {
827
- return false;
828
- }
829
- }
830
- return true;
831
- }
790
+ /** Deep structural equality for all Rill values. Delegates to type-registrations. */
791
+ export const deepEquals = registryDeepEquals;
832
792
  /** Reserved dict method names that cannot be overridden */
833
793
  export const RESERVED_DICT_METHODS = ['keys', 'values', 'entries'];
834
794
  /**
@@ -838,23 +798,54 @@ export const RESERVED_DICT_METHODS = ['keys', 'values', 'entries'];
838
798
  export const anyTypeValue = Object.freeze({
839
799
  __rill_type: true,
840
800
  typeName: 'any',
841
- structure: { type: 'any' },
801
+ structure: { kind: 'any' },
842
802
  });
843
803
  /**
844
- * Convert a RillType structural descriptor to a RillTypeValue.
845
- * Uses the RillType's `type` field as the `typeName`.
804
+ * Convert a TypeStructure descriptor to a RillTypeValue.
805
+ * Uses the TypeStructure's `kind` field as the `typeName`.
846
806
  * Falls back to 'any' for compound types that lack a direct RillTypeName mapping.
847
807
  */
848
- export function rillTypeToTypeValue(type) {
808
+ export function structureToTypeValue(type) {
849
809
  const validNames = VALID_TYPE_NAMES;
850
810
  return Object.freeze({
851
811
  __rill_type: true,
852
- typeName: (validNames.includes(type.type)
853
- ? type.type
812
+ typeName: (validNames.includes(type.kind)
813
+ ? type.kind
854
814
  : 'any'),
855
815
  structure: type,
856
816
  });
857
817
  }
818
+ /** @deprecated Use structureToTypeValue instead. */
819
+ export const rillTypeToTypeValue = structureToTypeValue;
820
+ /**
821
+ * Check if a type is a collection (dict, ordered, tuple) with defined
822
+ * fields or elements. Used to decide if an empty collection can be
823
+ * synthesized and hydrated.
824
+ */
825
+ export function hasCollectionFields(type) {
826
+ return ((type.kind === 'dict' &&
827
+ (!!type.fields ||
828
+ !!type.valueType)) ||
829
+ (type.kind === 'ordered' &&
830
+ (!!type.fields ||
831
+ !!type.valueType)) ||
832
+ (type.kind === 'tuple' &&
833
+ (!!type.elements ||
834
+ !!type.valueType)));
835
+ }
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
+ }
858
849
  /** Check if a key name is reserved */
859
850
  export function isReservedMethod(name) {
860
851
  return RESERVED_DICT_METHODS.includes(name);
@@ -866,7 +857,7 @@ export function isReservedMethod(name) {
866
857
  * - next: callable - function to get next iterator
867
858
  * - value: any (only required when not done) - current element
868
859
  */
869
- export function isRillIterator(value) {
860
+ export function isIterator(value) {
870
861
  if (!isDict(value))
871
862
  return false;
872
863
  const dict = value;
@@ -879,4 +870,9 @@ export function isRillIterator(value) {
879
870
  return false;
880
871
  return true;
881
872
  }
882
- //# sourceMappingURL=values.js.map
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;