aontu 0.61.0 → 0.63.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 (371) hide show
  1. package/README.md +4 -4
  2. package/dist/agentsmd.d.ts +1 -0
  3. package/dist/agentsmd.js +7 -28
  4. package/dist/agentsmd.js.map +1 -1
  5. package/dist/alias.js.map +1 -1
  6. package/dist/allow.d.ts +23 -0
  7. package/dist/allow.js +138 -0
  8. package/dist/allow.js.map +1 -0
  9. package/dist/aontu.d.ts +4 -2
  10. package/dist/aontu.js +4 -80
  11. package/dist/aontu.js.map +1 -1
  12. package/dist/aontumodel.d.ts +4 -0
  13. package/dist/aontumodel.js +33 -0
  14. package/dist/aontumodel.js.map +1 -0
  15. package/dist/cli.d.ts +10 -1
  16. package/dist/cli.js +877 -479
  17. package/dist/cli.js.map +1 -1
  18. package/dist/ctx.js +0 -48
  19. package/dist/ctx.js.map +1 -1
  20. package/dist/diff.js +0 -32
  21. package/dist/diff.js.map +1 -1
  22. package/dist/err.js +0 -40
  23. package/dist/err.js.map +1 -1
  24. package/dist/escape.js +0 -45
  25. package/dist/escape.js.map +1 -1
  26. package/dist/exactjson.d.ts +0 -35
  27. package/dist/exactjson.js +0 -131
  28. package/dist/exactjson.js.map +1 -1
  29. package/dist/format.js +55 -189
  30. package/dist/format.js.map +1 -1
  31. package/dist/grammar.d.ts +9 -0
  32. package/dist/grammar.js +54 -0
  33. package/dist/grammar.js.map +1 -0
  34. package/dist/graph.js +0 -26
  35. package/dist/graph.js.map +1 -1
  36. package/dist/hcanon.js +0 -82
  37. package/dist/hcanon.js.map +1 -1
  38. package/dist/helpdoc.d.ts +16 -0
  39. package/dist/helpdoc.js +59 -0
  40. package/dist/helpdoc.js.map +1 -0
  41. package/dist/hints.d.ts +0 -6
  42. package/dist/hints.js +59 -47
  43. package/dist/hints.js.map +1 -1
  44. package/dist/jsonschema.js +0 -114
  45. package/dist/jsonschema.js.map +1 -1
  46. package/dist/keyorder.d.ts +0 -7
  47. package/dist/keyorder.js +0 -41
  48. package/dist/keyorder.js.map +1 -1
  49. package/dist/lang.js +32 -877
  50. package/dist/lang.js.map +1 -1
  51. package/dist/lower.d.ts +3 -0
  52. package/dist/lower.js +14 -61
  53. package/dist/lower.js.map +1 -1
  54. package/dist/lsp-server.js +0 -16
  55. package/dist/lsp-server.js.map +1 -1
  56. package/dist/lsp.d.ts +1 -1
  57. package/dist/lsp.js +12 -159
  58. package/dist/lsp.js.map +1 -1
  59. package/dist/mcp-server.js +0 -26
  60. package/dist/mcp-server.js.map +1 -1
  61. package/dist/mcp.js +0 -113
  62. package/dist/mcp.js.map +1 -1
  63. package/dist/mod-tool.js +0 -130
  64. package/dist/mod-tool.js.map +1 -1
  65. package/dist/mod.js +0 -162
  66. package/dist/mod.js.map +1 -1
  67. package/dist/patch.js +0 -217
  68. package/dist/patch.js.map +1 -1
  69. package/dist/provenance.js +0 -140
  70. package/dist/provenance.js.map +1 -1
  71. package/dist/query.js +0 -75
  72. package/dist/query.js.map +1 -1
  73. package/dist/reach.js +0 -43
  74. package/dist/reach.js.map +1 -1
  75. package/dist/relation.d.ts +2 -0
  76. package/dist/relation.js +3 -58
  77. package/dist/relation.js.map +1 -1
  78. package/dist/render.js +33 -143
  79. package/dist/render.js.map +1 -1
  80. package/dist/report-sarif.d.ts +0 -11
  81. package/dist/report-sarif.js +0 -28
  82. package/dist/report-sarif.js.map +1 -1
  83. package/dist/sig.js +0 -35
  84. package/dist/sig.js.map +1 -1
  85. package/dist/sigdecl.js +1 -1
  86. package/dist/sigdecl.js.map +1 -1
  87. package/dist/siggate.js +0 -4
  88. package/dist/siggate.js.map +1 -1
  89. package/dist/site.js +3 -29
  90. package/dist/site.js.map +1 -1
  91. package/dist/subsume.d.ts +0 -10
  92. package/dist/subsume.js +0 -137
  93. package/dist/subsume.js.map +1 -1
  94. package/dist/template.d.ts +2 -1
  95. package/dist/template.js +58 -138
  96. package/dist/template.js.map +1 -1
  97. package/dist/trim.js +0 -41
  98. package/dist/trim.js.map +1 -1
  99. package/dist/tsconfig.tsbuildinfo +1 -1
  100. package/dist/type.js.map +1 -1
  101. package/dist/unify.js +12 -242
  102. package/dist/unify.js.map +1 -1
  103. package/dist/utility.js +0 -22
  104. package/dist/utility.js.map +1 -1
  105. package/dist/val/AbnfFuncVal.d.ts +18 -0
  106. package/dist/val/AbnfFuncVal.js +132 -0
  107. package/dist/val/AbnfFuncVal.js.map +1 -0
  108. package/dist/val/AbsentVal.d.ts +11 -0
  109. package/dist/val/AbsentVal.js +30 -0
  110. package/dist/val/AbsentVal.js.map +1 -0
  111. package/dist/val/AggFuncVal.d.ts +10 -1
  112. package/dist/val/AggFuncVal.js +104 -116
  113. package/dist/val/AggFuncVal.js.map +1 -1
  114. package/dist/val/ArithFuncVal.js +0 -12
  115. package/dist/val/ArithFuncVal.js.map +1 -1
  116. package/dist/val/BagVal.js +1 -78
  117. package/dist/val/BagVal.js.map +1 -1
  118. package/dist/val/BigDecimalVal.js +0 -16
  119. package/dist/val/BigDecimalVal.js.map +1 -1
  120. package/dist/val/BigIntegerVal.js +0 -16
  121. package/dist/val/BigIntegerVal.js.map +1 -1
  122. package/dist/val/CloseFuncVal.js +0 -9
  123. package/dist/val/CloseFuncVal.js.map +1 -1
  124. package/dist/val/CmpFuncVal.d.ts +20 -0
  125. package/dist/val/CmpFuncVal.js +188 -0
  126. package/dist/val/CmpFuncVal.js.map +1 -0
  127. package/dist/val/ConjunctVal.js +0 -29
  128. package/dist/val/ConjunctVal.js.map +1 -1
  129. package/dist/val/ConstraintVal.js +0 -500
  130. package/dist/val/ConstraintVal.js.map +1 -1
  131. package/dist/val/ContainerKindVal.js +0 -2
  132. package/dist/val/ContainerKindVal.js.map +1 -1
  133. package/dist/val/CopyFuncVal.js +0 -3
  134. package/dist/val/CopyFuncVal.js.map +1 -1
  135. package/dist/val/Decimal.js +0 -179
  136. package/dist/val/Decimal.js.map +1 -1
  137. package/dist/val/DeprecateFuncVal.js.map +1 -1
  138. package/dist/val/DisjunctVal.js +0 -152
  139. package/dist/val/DisjunctVal.js.map +1 -1
  140. package/dist/val/EachFuncVal.d.ts +1 -2
  141. package/dist/val/EachFuncVal.js +12 -29
  142. package/dist/val/EachFuncVal.js.map +1 -1
  143. package/dist/val/EmitFuncVal.d.ts +1 -1
  144. package/dist/val/EmitFuncVal.js +6 -119
  145. package/dist/val/EmitFuncVal.js.map +1 -1
  146. package/dist/val/ExpectVal.js +0 -62
  147. package/dist/val/ExpectVal.js.map +1 -1
  148. package/dist/val/FilterFuncVal.js +0 -25
  149. package/dist/val/FilterFuncVal.js.map +1 -1
  150. package/dist/val/FuncBaseVal.d.ts +1 -0
  151. package/dist/val/FuncBaseVal.js +7 -127
  152. package/dist/val/FuncBaseVal.js.map +1 -1
  153. package/dist/val/GraphAtomVal.js +0 -15
  154. package/dist/val/GraphAtomVal.js.map +1 -1
  155. package/dist/val/HideFuncVal.js +0 -13
  156. package/dist/val/HideFuncVal.js.map +1 -1
  157. package/dist/val/IntegerVal.js +0 -61
  158. package/dist/val/IntegerVal.js.map +1 -1
  159. package/dist/val/JunctionVal.js +0 -20
  160. package/dist/val/JunctionVal.js.map +1 -1
  161. package/dist/val/KeyFuncVal.js +0 -46
  162. package/dist/val/KeyFuncVal.js.map +1 -1
  163. package/dist/val/ListVal.js +0 -57
  164. package/dist/val/ListVal.js.map +1 -1
  165. package/dist/val/LowerFuncVal.js +11 -6
  166. package/dist/val/LowerFuncVal.js.map +1 -1
  167. package/dist/val/MapVal.js +0 -151
  168. package/dist/val/MapVal.js.map +1 -1
  169. package/dist/val/MatchFuncVal.js +0 -27
  170. package/dist/val/MatchFuncVal.js.map +1 -1
  171. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  172. package/dist/val/MaybeFuncVal.js +50 -0
  173. package/dist/val/MaybeFuncVal.js.map +1 -0
  174. package/dist/val/MoveFuncVal.js +0 -18
  175. package/dist/val/MoveFuncVal.js.map +1 -1
  176. package/dist/val/NilVal.js +2 -36
  177. package/dist/val/NilVal.js.map +1 -1
  178. package/dist/val/NomFuncVal.d.ts +12 -0
  179. package/dist/val/NomFuncVal.js +153 -0
  180. package/dist/val/NomFuncVal.js.map +1 -0
  181. package/dist/val/NumberVal.js +0 -15
  182. package/dist/val/NumberVal.js.map +1 -1
  183. package/dist/val/OpBaseVal.d.ts +1 -0
  184. package/dist/val/OpBaseVal.js +3 -15
  185. package/dist/val/OpBaseVal.js.map +1 -1
  186. package/dist/val/PackFuncVal.js +0 -34
  187. package/dist/val/PackFuncVal.js.map +1 -1
  188. package/dist/val/PathFuncVal.js +0 -6
  189. package/dist/val/PathFuncVal.js.map +1 -1
  190. package/dist/val/PathVal.js +0 -41
  191. package/dist/val/PathVal.js.map +1 -1
  192. package/dist/val/PlaceVal.js +0 -25
  193. package/dist/val/PlaceVal.js.map +1 -1
  194. package/dist/val/PlusOpVal.d.ts +1 -7
  195. package/dist/val/PlusOpVal.js +13 -74
  196. package/dist/val/PlusOpVal.js.map +1 -1
  197. package/dist/val/PrefFuncVal.js +0 -1
  198. package/dist/val/PrefFuncVal.js.map +1 -1
  199. package/dist/val/PrefVal.js +0 -167
  200. package/dist/val/PrefVal.js.map +1 -1
  201. package/dist/val/RecurseVal.js +0 -55
  202. package/dist/val/RecurseVal.js.map +1 -1
  203. package/dist/val/RefVal.js +0 -282
  204. package/dist/val/RefVal.js.map +1 -1
  205. package/dist/val/ReferFuncVal.js +0 -232
  206. package/dist/val/ReferFuncVal.js.map +1 -1
  207. package/dist/val/ScalarKindVal.js +0 -49
  208. package/dist/val/ScalarKindVal.js.map +1 -1
  209. package/dist/val/ScalarVal.js +0 -11
  210. package/dist/val/ScalarVal.js.map +1 -1
  211. package/dist/val/StrFuncVal.js +0 -18
  212. package/dist/val/StrFuncVal.js.map +1 -1
  213. package/dist/val/SuperFuncVal.js +0 -32
  214. package/dist/val/SuperFuncVal.js.map +1 -1
  215. package/dist/val/TopVal.js +0 -1
  216. package/dist/val/TopVal.js.map +1 -1
  217. package/dist/val/TranslateFuncVal.d.ts +12 -0
  218. package/dist/val/TranslateFuncVal.js +99 -0
  219. package/dist/val/TranslateFuncVal.js.map +1 -0
  220. package/dist/val/UpperFuncVal.js +11 -6
  221. package/dist/val/UpperFuncVal.js.map +1 -1
  222. package/dist/val/Val.d.ts +1 -0
  223. package/dist/val/Val.js +2 -133
  224. package/dist/val/Val.js.map +1 -1
  225. package/dist/val/VarVal.js +0 -12
  226. package/dist/val/VarVal.js.map +1 -1
  227. package/dist/val/arith.js +0 -37
  228. package/dist/val/arith.js.map +1 -1
  229. package/dist/val/caserange.d.ts +3 -0
  230. package/dist/val/caserange.js +49 -0
  231. package/dist/val/caserange.js.map +1 -0
  232. package/dist/val/members.js +0 -6
  233. package/dist/val/members.js.map +1 -1
  234. package/dist/val/numcmp.js +0 -11
  235. package/dist/val/numcmp.js.map +1 -1
  236. package/dist/val/numkind.js +0 -145
  237. package/dist/val/numkind.js.map +1 -1
  238. package/dist/val/valutil.js +0 -16
  239. package/dist/val/valutil.js.map +1 -1
  240. package/dist/vet.d.ts +12 -0
  241. package/dist/vet.js +159 -412
  242. package/dist/vet.js.map +1 -1
  243. package/dist/view.js +0 -414
  244. package/dist/view.js.map +1 -1
  245. package/dist/walk.js +0 -41
  246. package/dist/walk.js.map +1 -1
  247. package/grammar/aontu.abnf +9 -7
  248. package/grammar/aontu.gbnf +5 -5
  249. package/grammar/aontu.lark +5 -5
  250. package/grammar/aontu.tmLanguage.json +1 -1
  251. package/package.json +4 -2
  252. package/skill/SKILL.md +8 -0
  253. package/skill/init/check.sh +28 -0
  254. package/skill/init/data.aon +12 -0
  255. package/skill/init/model.aon +19 -0
  256. package/skill/tasks.md +151 -0
  257. package/src/agentsmd.ts +8 -32
  258. package/src/alias.ts +0 -39
  259. package/src/allow.ts +221 -0
  260. package/src/aontu.ts +10 -108
  261. package/src/aontumodel.ts +32 -0
  262. package/src/cli.ts +1009 -540
  263. package/src/ctx.ts +0 -103
  264. package/src/diff.ts +0 -40
  265. package/src/err.ts +0 -40
  266. package/src/escape.ts +0 -46
  267. package/src/exactjson.ts +0 -131
  268. package/src/format.ts +63 -234
  269. package/src/grammar.ts +72 -0
  270. package/src/graph.ts +0 -61
  271. package/src/hcanon.ts +0 -82
  272. package/src/helpdoc.ts +77 -0
  273. package/src/hints.ts +72 -49
  274. package/src/jsonschema.ts +0 -123
  275. package/src/keyorder.ts +0 -42
  276. package/src/lang.ts +39 -895
  277. package/src/lower.ts +15 -65
  278. package/src/lsp-server.ts +0 -16
  279. package/src/lsp.ts +12 -180
  280. package/src/mcp-server.ts +0 -31
  281. package/src/mcp.ts +0 -130
  282. package/src/mod-tool.ts +0 -158
  283. package/src/mod.ts +0 -178
  284. package/src/patch.ts +0 -232
  285. package/src/provenance.ts +0 -183
  286. package/src/query.ts +0 -84
  287. package/src/reach.ts +0 -53
  288. package/src/relation.ts +7 -71
  289. package/src/render.ts +33 -180
  290. package/src/report-sarif.ts +0 -48
  291. package/src/sig.ts +0 -35
  292. package/src/sigdecl.ts +1 -1
  293. package/src/siggate.ts +0 -30
  294. package/src/site.ts +3 -29
  295. package/src/subsume.ts +1 -161
  296. package/src/template.ts +69 -140
  297. package/src/trim.ts +0 -53
  298. package/src/type.ts +2 -45
  299. package/src/unify.ts +13 -251
  300. package/src/utility.ts +0 -31
  301. package/src/val/AbnfFuncVal.ts +181 -0
  302. package/src/val/AbsentVal.ts +54 -0
  303. package/src/val/AggFuncVal.ts +152 -188
  304. package/src/val/ArithFuncVal.ts +0 -20
  305. package/src/val/BagVal.ts +1 -78
  306. package/src/val/BigDecimalVal.ts +0 -16
  307. package/src/val/BigIntegerVal.ts +0 -16
  308. package/src/val/CloseFuncVal.ts +0 -9
  309. package/src/val/CmpFuncVal.ts +249 -0
  310. package/src/val/ConjunctVal.ts +0 -33
  311. package/src/val/ConstraintVal.ts +2 -537
  312. package/src/val/ContainerKindVal.ts +0 -18
  313. package/src/val/CopyFuncVal.ts +0 -5
  314. package/src/val/Decimal.ts +1 -185
  315. package/src/val/DeprecateFuncVal.ts +0 -10
  316. package/src/val/DisjunctVal.ts +0 -157
  317. package/src/val/EachFuncVal.ts +12 -53
  318. package/src/val/EmitFuncVal.ts +8 -208
  319. package/src/val/ExpectVal.ts +0 -62
  320. package/src/val/FilterFuncVal.ts +0 -55
  321. package/src/val/FuncBaseVal.ts +9 -130
  322. package/src/val/GraphAtomVal.ts +0 -42
  323. package/src/val/HideFuncVal.ts +0 -15
  324. package/src/val/IntegerVal.ts +0 -61
  325. package/src/val/JunctionVal.ts +0 -20
  326. package/src/val/KeyFuncVal.ts +0 -48
  327. package/src/val/ListVal.ts +0 -59
  328. package/src/val/LowerFuncVal.ts +12 -7
  329. package/src/val/MapVal.ts +0 -151
  330. package/src/val/MatchFuncVal.ts +0 -59
  331. package/src/val/MaybeFuncVal.ts +86 -0
  332. package/src/val/MoveFuncVal.ts +0 -20
  333. package/src/val/NilVal.ts +2 -36
  334. package/src/val/NomFuncVal.ts +200 -0
  335. package/src/val/NumberVal.ts +0 -16
  336. package/src/val/OpBaseVal.ts +4 -17
  337. package/src/val/PackFuncVal.ts +0 -63
  338. package/src/val/PathFuncVal.ts +0 -32
  339. package/src/val/PathVal.ts +0 -66
  340. package/src/val/PlaceVal.ts +0 -45
  341. package/src/val/PlusOpVal.ts +18 -75
  342. package/src/val/PrefFuncVal.ts +0 -1
  343. package/src/val/PrefVal.ts +0 -179
  344. package/src/val/RecurseVal.ts +0 -81
  345. package/src/val/RefVal.ts +1 -285
  346. package/src/val/ReferFuncVal.ts +0 -255
  347. package/src/val/ScalarKindVal.ts +0 -50
  348. package/src/val/ScalarVal.ts +0 -12
  349. package/src/val/StrFuncVal.ts +0 -44
  350. package/src/val/SuperFuncVal.ts +0 -42
  351. package/src/val/TopVal.ts +0 -1
  352. package/src/val/TranslateFuncVal.ts +132 -0
  353. package/src/val/UpperFuncVal.ts +12 -7
  354. package/src/val/Val.ts +3 -192
  355. package/src/val/VarVal.ts +0 -15
  356. package/src/val/arith.ts +0 -92
  357. package/src/val/caserange.ts +53 -0
  358. package/src/val/members.ts +0 -23
  359. package/src/val/numcmp.ts +1 -27
  360. package/src/val/numkind.ts +0 -149
  361. package/src/val/valutil.ts +0 -16
  362. package/src/vet.ts +209 -504
  363. package/src/view.ts +0 -507
  364. package/src/walk.ts +0 -41
  365. package/dist/std.d.ts +0 -3
  366. package/dist/std.js +0 -637
  367. package/dist/std.js.map +0 -1
  368. package/dist/val/FormFuncVal.js +0 -55
  369. package/dist/val/FormFuncVal.js.map +0 -1
  370. package/src/std.ts +0 -648
  371. package/src/val/FormFuncVal.ts +0 -119
@@ -1,47 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- // AGGREGATION, PROJECTION AND THE STRING FOLD: `sum(d)`, `least(d)`,
4
- // `greatest(d)`, `pick(d, k)` and `join(d, sep?)`.
5
- //
6
- // The review's finding I: "No aggregation. `length()` counts but
7
- // nothing sums: an invoice total, a fleet-wide resource budget, a quota
8
- // roll-up -- all inexpressible." Use case 10 had to write totals by
9
- // hand and spot-check them with `must()`, which is a model asserting
10
- // what it should be able to COMPUTE.
11
- //
12
- // total: sum($.lines) # an invoice total
13
- // cheapest: least($.quotes) # ... and the extremes
14
- // peak: greatest($.hourly)
15
- //
16
- // A FOLD OVER A FINITE, SETTLED BAG IS AS TOTAL AS `each`. There is no
17
- // recursion here and no user-supplied step: the bag is the one the
18
- // model already holds, the operation is fixed, and the walk visits each
19
- // child exactly once. That is the whole reason these are built-ins
20
- // rather than a `fold` combinator -- a fold takes a function, and a
21
- // language with no user functions has none to take.
22
- //
23
- // THE NAMES ARE `least` AND `greatest`, NOT `min` AND `max`, because
24
- // those two are already the constraint atoms for a LOWER and UPPER
25
- // BOUND (`min(3)` means "at least 3"). An aggregate over a bag and a
26
- // bound on a value are different things and must not share a spelling;
27
- // least and greatest are the lattice's own words for the extremes of a
28
- // set, which is exactly what these compute.
29
- //
30
- // `sum` FOLDS WITH `add`, so the number tower's whole law comes with it
31
- // (arith.ts): the exact ladder, R5 contagion, the refusal to mix a
32
- // binary float with an exact leaf, and the refusal to store a result
33
- // that will not fit. A bag of integers sums to an integer; one integer
34
- // float among them makes the total a float; `0d` operands keep it
35
- // exact. And `sum([])` is `0` -- addition has an identity, which is
36
- // what makes the empty case answerable.
37
- //
38
- // `least`/`greatest` have NO identity to answer an empty bag with: the
39
- // least element of nothing is not a value, it is a question with no
40
- // answer, so an empty bag is a located `aggregate_empty` rather than an
41
- // invented zero or infinity. They compare with the tower's EXACT
42
- // comparator (numcmp), so an integer and a bigdecimal in one bag order
43
- // correctly rather than through binary64, and the winner is returned
44
- // with its own kind intact.
45
3
 
46
4
  import type {
47
5
  Val,
@@ -59,6 +17,7 @@ import { StringVal } from './StringVal'
59
17
  import { FuncBaseVal } from './FuncBaseVal'
60
18
  import { arith } from './arith'
61
19
  import { cmpNumeric } from './numcmp'
20
+ import { cmpCodePoint } from '../keyorder'
62
21
  import { memberVals } from './members'
63
22
  import { plusText } from './PlusOpVal'
64
23
 
@@ -66,12 +25,6 @@ import { plusText } from './PlusOpVal'
66
25
  type AggOp = 'sum' | 'least' | 'greatest'
67
26
 
68
27
 
69
- // The children of a bag, in the order the aggregate sees them: source
70
- // order for a list, sorted-key order for a map -- `each`'s order, and
71
- // for the same reason (a map has no order of its own, so the language
72
- // picks one and states it).
73
- // The members of the bag a fold reads: what generation would emit
74
- // (./members.ts, BUGS.md §79), in the one map-key order (BUGS.md §62).
75
28
  function bagChildren(data: any, ctx: AontuContext): Val[] | undefined {
76
29
  return memberVals(data, ctx)
77
30
  }
@@ -80,9 +33,6 @@ function bagChildren(data: any, ctx: AontuContext): Val[] | undefined {
80
33
  class AggFuncVal extends FuncBaseVal {
81
34
  isAggFunc = true
82
35
 
83
- // THE STAGING RULE (G8 phase 0). A total over a bag that is still
84
- // being merged into is a total of the wrong bag -- the same reason
85
- // `filter` and `each` wait.
86
36
  staged = true
87
37
 
88
38
  op: AggOp
@@ -97,21 +47,11 @@ class AggFuncVal extends FuncBaseVal {
97
47
  }
98
48
 
99
49
 
100
- // NO `make` OVERRIDE, matching the other STAGED funcs (pack, each,
101
- // filter, match): a staged call returns `residuate` before `unify`
102
- // ever reaches the rebuild branch, so an override there would be
103
- // unreachable code pretending to be a contract. The base's `make`
104
- // raises `func:<name>` if that ever stops being true, which is the
105
- // loud answer rather than a value that silently lost its operation.
106
-
107
50
  funcname() {
108
51
  return this.op
109
52
  }
110
53
 
111
54
 
112
- // The base does not drive the argument: `unify` drives it by hand,
113
- // because a staged func must advance what it is waiting on every
114
- // pass rather than only on the pass it fires.
115
55
  prepare(_ctx: AontuContext, _args: Val[]) {
116
56
  return null
117
57
  }
@@ -137,9 +77,6 @@ class AggFuncVal extends FuncBaseVal {
137
77
  }
138
78
 
139
79
  if ('sum' === this.op) {
140
- // Zero is addition's identity, so an empty bag has an answer and
141
- // it is an integer -- the narrowest kind, which the first real
142
- // operand then widens under R5 exactly as `add(0, x)` would.
143
80
  let total: Val = new IntegerVal({ peg: 0 })
144
81
  for (const child of children) {
145
82
  total = arith(ctx, 'add', this, total, child, this.op)
@@ -192,28 +129,6 @@ function unpref(v: any): any {
192
129
  }
193
130
 
194
131
 
195
- // PROJECTION: `pick(d, k)` -- one element per child of `d`, being that
196
- // child's `k`.
197
- //
198
- // The other half of the review's finding I: "`_.field` is unspellable,
199
- // `filter` cannot see into lists, `unique()`-by-field is reserved but
200
- // absent -- so 'no two services share a port' and 'unique event ids'
201
- // cannot be said." Without it the aggregates above cannot reach the
202
- // case that motivated them, because `sum` needs a bag of NUMBERS and a
203
- // model holds a bag of RECORDS:
204
- //
205
- // total: sum(pick($.lines, amountCents))
206
- //
207
- // IT IS NOT `each` WITH A CLEVER TEMPLATE. `each(d, t)` MEETS each
208
- // child with `t`, and a meet cannot select: `each($.lines, _.amount)`
209
- // asks for a child that is simultaneously the whole record and one of
210
- // its fields, which is why every spelling of it answers `no_path`.
211
- // Selection is a different operation and gets its own verb.
212
- //
213
- // A CHILD MISSING THE KEY IS AN ERROR, not a silently shorter list.
214
- // Skipping would make `sum(pick(...))` quietly total the wrong set of
215
- // records -- the failure mode an aggregate exists to prevent -- so the
216
- // refusal names the child (`pick_key`).
217
132
  class PickFuncVal extends FuncBaseVal {
218
133
  isPickFunc = true
219
134
 
@@ -293,56 +208,159 @@ class PickFuncVal extends FuncBaseVal {
293
208
  }
294
209
 
295
210
 
211
+ // `pick`'s rule, plus: the empty string is the member itself, which is
212
+ // how a keyless descending sort is spelled.
213
+ function projectorName(key: any): [string, boolean] {
214
+ if (null == key || null == key.peg) {
215
+ return ['', true]
216
+ }
217
+ if ('string' === typeof key.peg) {
218
+ return [key.peg, true]
219
+ }
220
+ if ('number' === typeof key.peg && key.isInteger) {
221
+ return [String(key.peg), true]
222
+ }
223
+ return ['', false]
224
+ }
225
+
226
+
227
+ function fieldOf(child: any, name: string): Val | undefined {
228
+ return true === child?.isMap ? child.peg[name] :
229
+ true === child?.isList ? child.peg[Number(name)] :
230
+ undefined
231
+ }
232
+
233
+
234
+ const SORT_DIRECTIONS: Record<string, number> = { asc: 1, desc: -1 }
235
+
236
+
237
+ function directionOf(v: any): number | undefined {
238
+ if (null == v || null == v.peg) {
239
+ return 1
240
+ }
241
+ return 'string' === typeof v.peg ? SORT_DIRECTIONS[v.peg] : undefined
242
+ }
243
+
244
+
245
+ // Text by code point, numbers by the exact comparator, nothing else.
246
+ function sortDomain(u: any): 'text' | 'number' | undefined {
247
+ if (true !== u?.isVal || true !== u.isScalar || true === u.isNull) {
248
+ return undefined
249
+ }
250
+ if ('string' === typeof u.peg) {
251
+ return 'text'
252
+ }
253
+ return 'boolean' === typeof u.peg ? undefined : 'number'
254
+ }
255
+
256
+
257
+ type SortRow = { idx: number, val: Val, key: any }
258
+
259
+
260
+ class SortFuncVal extends FuncBaseVal {
261
+ isSortFunc = true
262
+
263
+ // The bag must settle before it is ordered, exactly as it must
264
+ // before it is projected.
265
+ staged = true
266
+
267
+ constructor(
268
+ spec: ValSpec,
269
+ ctx?: AontuContext
270
+ ) {
271
+ super(spec, ctx)
272
+ }
273
+
274
+
275
+ funcname() {
276
+ return 'sort'
277
+ }
278
+
279
+
280
+ // The base drives no argument: the DATA is driven by hand below, and
281
+ // the projector is a bare word the parser has already made a string.
282
+ prepare(_ctx: AontuContext, _args: Val[]) {
283
+ return null
284
+ }
285
+
286
+
287
+ unify(peer: Val, ctx: AontuContext): Val {
288
+ const ready = this.driveStagedArgs(ctx, 1)
289
+
290
+ if (!ready || !ctx.settle) {
291
+ return this.residuate(peer, ctx)
292
+ }
293
+
294
+ return super.unify(peer, ctx)
295
+ }
296
+
297
+
298
+ resolve(ctx: AontuContext, args: Val[]) {
299
+ const children = bagChildren(args?.[0], ctx)
300
+
301
+ if (undefined === children) {
302
+ return this.place(makeNilErr(ctx, 'aggregate_data', this, undefined,
303
+ 'sort'))
304
+ }
305
+
306
+ const [name, nameok] = projectorName(args?.[1])
307
+
308
+ if (!nameok) {
309
+ return this.place(makeNilErr(ctx, 'invalid-arg', this, undefined,
310
+ 'sort'))
311
+ }
312
+
313
+ const dir = directionOf(args?.[2])
314
+
315
+ if (undefined === dir) {
316
+ return this.place(makeNilErr(ctx, 'sort_dir', this, undefined, 'sort',
317
+ { dir: (args[2] as any).canon }))
318
+ }
319
+
320
+ const rows: SortRow[] = []
321
+ let domain: 'text' | 'number' | undefined = undefined
322
+
323
+ for (const child of children) {
324
+ const at: any = '' === name ? child : fieldOf(child, name)
325
+
326
+ if (null == at) {
327
+ return this.place(makeNilErr(ctx, 'sort_key', this, undefined, 'sort',
328
+ { key: name }))
329
+ }
330
+
331
+ const u = unpref(at)
332
+ const found = sortDomain(u)
333
+
334
+ if (undefined === found ||
335
+ (undefined !== domain && found !== domain)) {
336
+ return this.place(makeNilErr(ctx, 'sort_domain', this, undefined,
337
+ 'sort', { member: u.canon }))
338
+ }
339
+
340
+ domain = found
341
+ rows.push({ idx: rows.length, val: child, key: u })
342
+ }
343
+
344
+ // The source index breaks every tie, so the order is TOTAL and
345
+ // neither port's sort algorithm can reorder equals.
346
+ rows.sort((a, b) => {
347
+ const c = 'text' === domain ?
348
+ cmpCodePoint(a.key.peg as string, b.key.peg as string) :
349
+ cmpNumeric(a.key, b.key)
350
+ return 0 === c ? a.idx - b.idx : dir * c
351
+ })
352
+
353
+ const peg: Val[] = rows.map(
354
+ (r, i) => r.val.clone(ctx.descend(String(i))))
355
+
356
+ return this.place(new ListVal({ peg }, ctx))
357
+ }
358
+ }
359
+
296
360
 
297
- // THE FOLD TO A STRING: `join(coll, sep?)` -- G9 phase 2.
298
- //
299
- // The one primitive between a model and a generated file. A spread can
300
- // put a separator AFTER each element; putting one BETWEEN N elements is
301
- // a reduction over strings, and the language had none: `sum` is numeric,
302
- // `+` does not reduce a list, and indexed concatenation needs the arity
303
- // known in advance. So a generated SQL column list carried a trailing
304
- // comma and did not parse (use-cases/15-code-generation).
305
- //
306
- // IT FOLDS WITH `+` SEEDED WITH `""`, exactly as `sum` folds with `add`
307
- // seeded with `0`. That is not a figure of speech: the members are
308
- // rendered by `plusText`, which IS the function `+`'s string branch
309
- // calls, so the language keeps exactly one answer to "how does a number
310
- // become text" and the two cannot drift. `join(coll)` is therefore
311
- // concatenation and no `concat` is needed; `join(coll, "\n")` is lines
312
- // and no `lines` is needed. ONE BUILTIN, NOT A FAMILY.
313
- //
314
- // `split`/`words` is the inverse -- an input-PARSING operation with no
315
- // generation use -- and is deliberately absent.
316
- //
317
- // EMPTY IS `""`, concatenation's identity, the exact parallel of
318
- // `sum([]) == 0` and the opposite of `least([])`: a fold with an
319
- // identity can answer the empty bag, and one without has to refuse it.
320
- //
321
- // MEMBERS ARE VALIDATED BEFORE THE FOLD, which is the whole reason this
322
- // is not three lines. `+` with a string on the left RESIDUATES on a
323
- // container or a null rather than refusing (`"" + {b:1}` and `"x" +
324
- // null` both reach generation as `mapval_no_gen`), so folding blindly
325
- // would turn a bad member into a useless late error pointing at the
326
- // wrong thing. The three verdicts below are that check.
327
361
  type MemberVerdict = 'text' | 'never' | 'notyet'
328
362
 
329
363
 
330
- // Which of the three a value is.
331
- //
332
- // `text` -- `+` would take it, so the fold can.
333
- //
334
- // `never` -- a SETTLED value that will never become text: a map, a
335
- // list, a null. This is `join_member`, class `conflict`, and it names
336
- // the member rather than the call, because "one of these is not a
337
- // string" is only actionable if you are told which.
338
- //
339
- // `notyet` -- an unresolved kind, a top, a stable residue. NOT a join
340
- // failure at all: the call stays residual and generation reports
341
- // `mapval_no_gen`, class `incomplete`, exactly as docs/trust.md
342
- // requires ("a stable residue ... is ordinary incompleteness"). Getting
343
- // this split wrong in either direction is the defect that matters here:
344
- // refusing a residue makes `join` unusable inside a schema, and
345
- // deferring on a map makes a real error arrive as a shrug.
346
364
  function memberVerdict(v: any): MemberVerdict {
347
365
  const u = unpref(v)
348
366
  if (undefined !== plusText(u)) {
@@ -355,15 +373,6 @@ function memberVerdict(v: any): MemberVerdict {
355
373
  }
356
374
 
357
375
 
358
- // The separator is a STRING or it is nothing.
359
- //
360
- // A number would render perfectly well through `+`, and is still
361
- // refused: the separator is not a member of the fold, it is the
362
- // parameter naming the text between members, and `join(x, 5)` is far
363
- // likelier a mistake than an intent to separate with "5". `pick`'s key
364
- // argument draws the same line for the same reason. This is the
365
- // direction that can be loosened later without breaking a document;
366
- // the other direction cannot.
367
376
  function sepVerdict(v: any): MemberVerdict {
368
377
  const u = unpref(v)
369
378
  if (u?.isVal && u.isScalar) {
@@ -391,22 +400,6 @@ class JoinFuncVal extends FuncBaseVal {
391
400
  }
392
401
 
393
402
 
394
- // A `make` OVERRIDE, WHERE ITS AggFuncVal SIBLINGS HAVE NONE, and the
395
- // difference is worth stating because it is not arbitrary. `sum`,
396
- // `pick` and the rest are staged and nothing more: they residuate
397
- // before `unify` reaches the rebuild branch, so a `make` there would
398
- // be unreachable code pretending to be a contract, and the base's
399
- // `func:<name>` refusal is the loud answer if that ever changes.
400
- //
401
- // `join` is the first builtin that is BOTH staged AND defers its
402
- // resolution (see `deferResolve`). A deferred call has settled
403
- // arguments, so it does reach the rebuild branch, and without this it
404
- // raised `func:join` on the first document with an unresolved member
405
- // — where the Go port residuated and reported `mapval_no_gen`.
406
- // Opposite answers on `join($.m, ",")` with `m: [string]`, caught by
407
- // running both engines rather than by either test suite. `super` and
408
- // bare `id`, the two other deferring calls, each carry the same
409
- // override for the same reason.
410
403
  make(_ctx: AontuContext, spec: ValSpec): Val {
411
404
  return new JoinFuncVal(spec)
412
405
  }
@@ -426,10 +419,6 @@ class JoinFuncVal extends FuncBaseVal {
426
419
 
427
420
 
428
421
  unify(peer: Val, ctx: AontuContext): Val {
429
- // BOTH arguments, unlike `pick`, which drives only its bag: `pick`'s
430
- // key is a bare word the parser has already made a string, while a
431
- // separator is an ordinary expression and `join($.rows, $.sep)` has
432
- // to wait for it.
433
422
  const ready = this.driveStagedArgs(ctx, 2)
434
423
 
435
424
  if (!ready || !ctx.settle) {
@@ -440,10 +429,6 @@ class JoinFuncVal extends FuncBaseVal {
440
429
  }
441
430
 
442
431
 
443
- // The `notyet` half of the verdict, taken before `resolve` runs: with
444
- // arguments settled but a member still a kind, the call rides the
445
- // ordinary args-not-done path and residuates, which is what makes an
446
- // unresolved member ordinary incompleteness rather than a refusal.
447
432
  deferResolve(ctx: AontuContext, args?: Val[]): boolean {
448
433
  const children = bagChildren(args?.[0], ctx)
449
434
  if (undefined === children) {
@@ -467,28 +452,11 @@ class JoinFuncVal extends FuncBaseVal {
467
452
  'join'))
468
453
  }
469
454
 
470
- // Arity is [1,2], so a second argument is present or the separator
471
- // is the empty string -- which makes `join(coll)` concatenation.
472
- // The separator's SHAPE is settled before resolve runs: the
473
- // signature gate refuses every concrete non-string
474
- // (docs/design/SIGNATURES.0.md; join(d: map|list, sep?: string)),
475
- // and deferResolve holds the call while sepVerdict answers notyet
476
- // -- so a present separator here is text.
477
455
  let sep = ''
478
456
  if (1 < args.length) {
479
457
  sep = unpref(args[1]).peg
480
458
  }
481
459
 
482
- // NO NIL-MEMBER GUARD, WHERE `sum` HAS ONE, and the difference is
483
- // the fold's shape rather than an oversight. `sum` folds with
484
- // `arith`, which MINTS a nil part-way through — a non-numeric child
485
- // or an overflow — so it has to stop and return it. `join` folds
486
- // already-unified values, and a nil among a list's elements
487
- // collapses the list before this call resolves: `join([least([])],
488
- // ",")` reports `aggregate_empty` at the member's own path,
489
- // `$.o.0`, and never reaches here. A guard was written, the
490
- // ADR-002 gate found it unexecuted, and probing confirmed no
491
- // spelling reaches it, so it is removed rather than excused.
492
460
  const parts: string[] = []
493
461
  for (const child of children) {
494
462
  const u: any = unpref(child)
@@ -500,16 +468,11 @@ class JoinFuncVal extends FuncBaseVal {
500
468
  parts.push(text)
501
469
  }
502
470
 
503
- // Every part is already a string, so this IS the `+` fold seeded
504
- // with `""` -- written as one concatenation because a loop of `+`
505
- // over settled strings cannot differ from it, and because the Go
506
- // twin's strings.Join must produce the same bytes.
507
471
  return this.place(new StringVal({ peg: parts.join(sep) }))
508
472
  }
509
473
  }
510
474
 
511
475
 
512
- // The three the registry names. Each is its operation and nothing else.
513
476
  class SumFuncVal extends AggFuncVal {
514
477
  constructor(spec: ValSpec, ctx?: AontuContext) { super(spec, ctx, 'sum') }
515
478
  }
@@ -522,13 +485,14 @@ class GreatestFuncVal extends AggFuncVal {
522
485
  constructor(spec: ValSpec, ctx?: AontuContext) {
523
486
  super(spec, ctx, 'greatest')
524
487
  }
525
- } /* node:coverage ignore next 10 */
488
+ } /* node:coverage ignore next 11 */
526
489
 
527
490
 
528
491
  export {
529
492
  AggFuncVal,
530
493
  JoinFuncVal,
531
494
  PickFuncVal,
495
+ SortFuncVal,
532
496
  SumFuncVal,
533
497
  LeastFuncVal,
534
498
  GreatestFuncVal,
@@ -15,17 +15,6 @@ import { arith } from './arith'
15
15
  import type { ArithOp } from './arith'
16
16
 
17
17
 
18
- // ONE CLASS FOR SIX FUNCTIONS, because every rule they obey is a rule
19
- // about arithmetic rather than about any one operation (see arith.ts).
20
- // Six near-identical classes would be six places for the exact ladder,
21
- // the zero divisor and the storage contract to drift apart, and the
22
- // number tower's whole point is that they cannot.
23
- //
24
- // The op is carried on the instance and answered by `funcname()`, which
25
- // is what canon renders and what an error names. The six one-line
26
- // subclasses below exist only because the parser's registry constructs
27
- // with `new funcval({peg: args})` and has nowhere to put a name; every
28
- // line of behaviour is here.
29
18
  class ArithFuncVal extends FuncBaseVal {
30
19
  isArithFunc = true
31
20
 
@@ -60,18 +49,9 @@ class ArithFuncVal extends FuncBaseVal {
60
49
  }
61
50
 
62
51
 
63
- // NO superior() OVERRIDE, deliberately. An arithmetic call could only
64
- // advertise a kind once both its operands were concrete scalars -- and
65
- // at that point it has RESOLVED, so what `super()` sees is the result,
66
- // whose own superior is already the right answer:
67
- // `super(mul(2,3))` is `integer` and `super(mul(2,1.5))` is `float`,
68
- // through the value rather than through a promise about it. The
69
- // override was written and then removed as unreachable; the same is
70
- // true of FuncVal.superior in the Go port.
71
52
  }
72
53
 
73
54
 
74
- // The six the registry names. Each is its operation and nothing else.
75
55
  class AddFuncVal extends ArithFuncVal {
76
56
  constructor(spec: ValSpec, ctx?: AontuContext) { super(spec, ctx, 'add') }
77
57
  }
package/src/val/BagVal.ts CHANGED
@@ -30,15 +30,6 @@ abstract class BagVal extends FeatureVal {
30
30
  closed: boolean = false
31
31
  optionalKeys: string[] = []
32
32
 
33
- // ALIAS DECLARATIONS, by key. `%uint8 = …` binds a name for this file
34
- // and is not a field of the document: it does not generate and does
35
- // not appear in canon, so a document using aliases and its expanded
36
- // twin are the SAME document and hash identically
37
- // (docs/design/ALIASES.0.md §4).
38
- //
39
- // Keyed on the map rather than marked on the value, because a
40
- // reference copies the value it resolves to -- a mark riding the
41
- // value would erase the referring field along with the declaration.
42
33
  aliasKeys: string[] = []
43
34
 
44
35
  spread = {
@@ -60,30 +51,9 @@ abstract class BagVal extends FeatureVal {
60
51
 
61
52
 
62
53
  handleExpectedVal(key: string, val: Val, parent: Val, ctx: AontuContext): Val {
63
- // A MARKED value is carried, never expected (ADR-005 era, BUGS.md
64
- // §12's include form): a type()/hide()-marked child legitimately
65
- // participates in unification without ever generating — that is
66
- // the marks contract — so wrapping one as an expectation turned a
67
- // schema field arriving through an include's map meet into a
68
- // bogus `mapval_spread_required` naming a spread that exists in
69
- // neither file. The bag's gen already skips marked children.
70
- //
71
- // An OPERATOR is carried too (BUGS.md §36): an expression is a
72
- // computation that resolves by itself once its operands do — the
73
- // bag's own-key loop drives it every pass — so `m:{y:.x+1}`
74
- // arriving as a peer key must keep computing exactly as it does
75
- // written inline. Wrapping it froze the op (an expectation only
76
- // advances when a peer arrives) and the residue then reported the
77
- // phantom `mapval_spread_required` naming a spread that exists
78
- // nowhere. An op that truly never resolves is honest *_no_gen
79
- // residue naming the expression itself.
80
54
  if (val.isGenable || val.isOp || val.mark.type || val.mark.hide) {
81
55
  return val
82
56
  }
83
- // An expectation baked into a combined spread template (the
84
- // 'map-self' meet of two unequal templates) is re-wrapped FRESH, so
85
- // key/parent name THIS bag and the template's own node is never
86
- // stored at a destination.
87
57
  const expectVal = new ExpectVal({ peg: val.isExpect ? val.peg : val }, ctx)
88
58
  expectVal.key = key
89
59
  expectVal.parent = parent
@@ -91,20 +61,6 @@ abstract class BagVal extends FeatureVal {
91
61
  }
92
62
 
93
63
 
94
- // TWO BAGS ARE THE SAME VALUE WHEN THEY HAVE THE SAME SHAPE. Val.same
95
- // falls back to object IDENTITY, which no two separately built maps
96
- // share -- so `x:*{a:1}|{a:number}` met by `x:{a:2}` left
97
- // `{"a":2}|{"a":2}`, a disjunction of one value spelled twice, past
98
- // the DisjunctVal dedup. Generation's old member FOLD hid that
99
- // (folding a value with itself is that value); ADR-007 does not, and
100
- // a disjunction whose alternatives are all the SAME value is
101
- // resolved, not ambiguous. Canon prints the collapse too, which is
102
- // the more honest text.
103
- //
104
- // Structural, and deliberately strict: container kind, closedness,
105
- // the marks, the optional keys and the key set must all agree before
106
- // the children are compared pairwise. Recursion terminates because a
107
- // reference is not a bag -- RefVal keeps the identity comparison.
108
64
  same(peer: any): boolean {
109
65
  if (this === peer) {
110
66
  return true
@@ -118,11 +74,6 @@ abstract class BagVal extends FeatureVal {
118
74
  this.mark.hide !== peer.mark.hide) {
119
75
  return false
120
76
  }
121
- // The SPREAD is part of the shape (BUGS.md §52 regime 4): `[]`
122
- // and `[&: T]` share an empty key set, and calling them the same
123
- // value collapsed the disjunction to its first arm before any
124
- // data could pick -- the vacuous-schema hole. Two spreads are the
125
- // same when their canons are.
126
77
  const scj: any = (this as any).spread?.cj
127
78
  const pcj: any = peer.spread?.cj
128
79
  if ((null == scj) !== (null == pcj) ||
@@ -158,12 +109,6 @@ abstract class BagVal extends FeatureVal {
158
109
  return undefined
159
110
  }
160
111
 
161
- // Maps emit their keys in CODE POINT order so the generated output
162
- // is independent of insertion/unification order and matches the Go
163
- // port. Lists keep their numeric index order.
164
- //
165
- // The keys are String()-coerced because a list entry carries a
166
- // numeric index here; the coercion is a no-op for every map key.
167
112
  let entries = items(this.peg)
168
113
  if (this.isMap) {
169
114
  entries = entries
@@ -214,22 +159,7 @@ abstract class BagVal extends FeatureVal {
214
159
  put(cval)
215
160
  }
216
161
 
217
- // A CONJUNCT IS GENERABLE WHEN IT IS A SETTLED SIZING RESIDUE
218
- // (the review's finding C, use-cases/BUGS.md §16). `length` and
219
- // `unique` over a container keep the readings more members could
220
- // still change, so `a: length(3) a:[1,2,3]` is a conjunct of the
221
- // atom and the list right up to generation -- which is where the
222
- // atom decides, in ConjunctVal.gen. Any OTHER conjunct is
223
- // unresolved and falls through to the residue error below,
224
- // exactly as before.
225
162
  else if (bagGenable(child)) {
226
- // An optional child is generated in an isolated collect context so an
227
- // unresolved inner value (a bare type that survived unification, e.g.
228
- // an absent optional sub-map's `field: string`) is dropped rather than
229
- // raised: the optional subtree is simply omitted. Without isolation
230
- // such inner errors pollute the shared ctx.err and make generate()
231
- // throw even though the key is skipped below. Mirrors the
232
- // optional-disjunct path above.
233
163
  const cctx = optional ? ctx.clone({ err: [], collect: true }) : ctx
234
164
 
235
165
  let cval = child.gen(cctx)
@@ -273,7 +203,6 @@ abstract class BagVal extends FeatureVal {
273
203
  break
274
204
  }
275
205
 
276
- // else optional so we can ignore it
277
206
  }
278
207
 
279
208
  return out
@@ -304,13 +233,6 @@ export function sizingResidue(v: any): { con: any, bag: any } | undefined {
304
233
  { con, bag } : undefined
305
234
  }
306
235
 
307
- // bagGenable is the bag's generability whitelist. A graph atom
308
- // (RELATIONS P2) is exactly as generable as the value it carries: the
309
- // atom is transparent at generation, so wrapping a field's value in
310
- // acyclic() must not change whether the bag accepts it -- an unmet
311
- // rel() refuses required generation with or without the atom, and a
312
- // BARE atom generates nothing and is dropped, exactly as an unmet
313
- // rel() under an optional key is.
314
236
  export function bagGenable(child: any): boolean {
315
237
  if (true === child.isGraphAtom) {
316
238
  return undefined === child.held || bagGenable(child.held)
@@ -322,6 +244,7 @@ export function bagGenable(child: any): boolean {
322
244
  return true
323
245
  }
324
246
  return true === child.isScalar
247
+ || true === child.isAbsent
325
248
  || true === child.isMap
326
249
  || true === child.isList
327
250
  || true === child.isPref
@@ -22,15 +22,6 @@ import {
22
22
  } from '../utility'
23
23
 
24
24
 
25
- // The exact base-10 decimal leaf of the number tower, reached only by a
26
- // `0d` literal carrying a `.` or an exponent (`0d1.5`, `0d1e3`) or by
27
- // direct construction.
28
- //
29
- // Its peg is a Decimal -- an OBJECT, so unlike every other scalar leaf
30
- // its identity cannot be `===` on the peg. Two bigdecimals are the same
31
- // value when their NUMBERS are equal (D2), which normalisation at
32
- // construction reduces to a two-field comparison; `samePeg` and `unify`
33
- // below are the two places that must not forget it.
34
25
  class BigDecimalVal extends ScalarVal {
35
26
  isBigDecimal = true
36
27
 
@@ -40,10 +31,6 @@ class BigDecimalVal extends ScalarVal {
40
31
  spec: ValSpec,
41
32
  ctx?: AontuContext
42
33
  ) {
43
- // Exact-input construction (D8): a Decimal, or a decimal literal as
44
- // text (`'1.5'`, `'0d1e3'`). A JS `number` is deliberately NOT
45
- // accepted -- binary64 has already rounded it, so `0.1` could never
46
- // arrive exact.
47
34
  let peg = spec.peg
48
35
  if ('string' === typeof peg) {
49
36
  try {
@@ -78,9 +65,6 @@ class BigDecimalVal extends ScalarVal {
78
65
  peer.kind === this.kind &&
79
66
  this.peg.equals(peer.peg)
80
67
  ) {
81
- // Same kind and equal NUMBER. Never `peer.peg === this.peg`:
82
- // that is object identity, and `0d0.10 & 0d0.1` (two Decimals
83
- // holding one value) has to succeed.
84
68
  out = this
85
69
  }
86
70
  else if (peer.isTop) {