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
package/src/val/VarVal.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  /* Copyright (c) 2021-2023 Richard Rodger, MIT License */
2
2
 
3
3
 
4
-
5
4
  import type {
6
5
  Val,
7
6
  ValSpec,
@@ -22,7 +21,6 @@ import {
22
21
  } from '../ctx'
23
22
 
24
23
 
25
-
26
24
  import { StringVal } from './StringVal'
27
25
  import { FeatureVal } from './FeatureVal'
28
26
  import { NullVal } from './NullVal'
@@ -43,8 +41,6 @@ import { unite } from '../unify'
43
41
  import { top } from './top'
44
42
 
45
43
 
46
- // TODO: KEY, SELF, PARENT are reserved names - error
47
-
48
44
  class VarVal extends FeatureVal {
49
45
  isVar = true
50
46
 
@@ -64,8 +60,6 @@ class VarVal extends FeatureVal {
64
60
  let nameVal
65
61
 
66
62
  if (this.peg.isVal) {
67
- // $.a.b.c - convert path to absolute
68
- // if (this.peg instanceof RefVal) {
69
63
  if (this.peg.isRef) {
70
64
  this.peg.absolute = true
71
65
  nameVal = this.peg
@@ -80,16 +74,13 @@ class VarVal extends FeatureVal {
80
74
  }
81
75
  }
82
76
  else {
83
- // TODO: how to pass row+col?
84
77
  nameVal = new StringVal({ peg: '' + this.peg }, ctx)
85
78
  }
86
79
 
87
- // if (!(nameVal instanceof RefVal) && DONE === nameVal.dc) {
88
80
  if (!(nameVal.isRef) && DONE === nameVal.dc) {
89
81
  if (nameVal instanceof StringVal) {
90
82
  let found = ctx.vars[nameVal.peg]
91
83
 
92
- // TODO: support complex values
93
84
  const ft = typeof found
94
85
  // Single ladder: a missing var must report `unknown_var` and not
95
86
  // fall through to the `invalid_var_kind` default below.
@@ -122,10 +113,6 @@ class VarVal extends FeatureVal {
122
113
  out = makeNilErr(ctx, 'invalid_var_kind', this, peer)
123
114
  }
124
115
 
125
- // A non-TOP peer (e.g. a spread constraint unified against the
126
- // var) applies to the RESOLVED value rather than being silently
127
- // dropped (mirrors VarVal.Unify in go/varval — the resolved
128
- // value unites with the peer).
129
116
  if (!out.isNil && null != peer && !peer.isTop) {
130
117
  out = unite(te ? ctx.clone({ explain: ec(te, 'VAL') }) : ctx,
131
118
  out, peer, 'var-val')
@@ -170,7 +157,6 @@ class VarVal extends FeatureVal {
170
157
  undefined
171
158
  )
172
159
 
173
- // TODO: refactor to use Site
174
160
  nil.path = this.path
175
161
  nil.site.url = this.site.url
176
162
  nil.site.row = this.site.row
@@ -179,7 +165,6 @@ class VarVal extends FeatureVal {
179
165
  descErr(nil, ctx)
180
166
 
181
167
  if (ctx) {
182
- // ctx.err.push(nil)
183
168
  ctx.adderr(nil)
184
169
  }
185
170
  else {
package/src/val/arith.ts CHANGED
@@ -1,61 +1,6 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
3
 
4
- // THE ARITHMETIC FAMILY -- add, sub, mul, div, mod, rem.
5
- //
6
- // The review's finding I: "Arithmetic stops at `+`", so "prod gets
7
- // double the replicas" is inexpressible and Kubernetes quantity strings
8
- // silently CONCATENATE ("500m" + "500m" is "500m500m"). The design
9
- // pre-registered the semantics these functions must have
10
- // (docs/capability-review/g8-generation.md, "Arithmetic semantics,
11
- // pre-registered") and the boundary that keeps `-` `*` `/` `%`
12
- // reserved: maths arrives as functions or not at all.
13
- //
14
- // THE FAMILY IS NUMERIC, WHICH IS WHAT MAKES `add` MORE THAN A SYNONYM
15
- // FOR `+`. The operator is polymorphic -- concatenation for strings,
16
- // disjunction for booleans, addition for numbers -- and that is why the
17
- // quantity strings above concatenate instead of failing. `add("500m",
18
- // "500m")` is a located error, because a function named for a numeric
19
- // operation has no business inventing a string. So the two spellings
20
- // mean different things, and both are kept.
21
- //
22
- // Everything else here is the number tower's existing law, applied to
23
- // five more operations (docs/design/number-model.md):
24
- //
25
- // R5 CONTAGION no operation introduces a kind narrower than its
26
- // operands, so an integer result needs integer
27
- // operands.
28
- // D6 EXACT LADDER integer < biginteger < bigdecimal. A mixed exact
29
- // operation promotes to the WIDEST operand, is
30
- // computed exactly, and never demotes.
31
- // FLOAT IS OFF IT binary64 mixed with either big leaf is a hard
32
- // error in both operand orders, because promotion
33
- // either way throws away exactness the document
34
- // asked for by writing `0d`.
35
- // NO ROUNDING an exact result that will not store is refused,
36
- // never rounded to fit.
37
- //
38
- // and three refusals this file adds, which the pre-registration named:
39
- //
40
- // div/mod/rem by ZERO is a hard error in every kind. A ground-truth
41
- // language has no business manufacturing infinity, and Aontu cannot
42
- // even write one down -- an overflowing literal is a `not_number`
43
- // error nil -- so propagating one would invent a value no generated
44
- // JSON could carry.
45
- //
46
- // A NON-FINITE FLOAT RESULT is a located error. This one was already
47
- // reachable through `+` and reported as neither: `1.0e308+1.0e308`
48
- // crashed TypeScript with `[aontu/internal]` and leaked Go's raw
49
- // `json: unsupported value: +Inf` with no code at all (use-cases/
50
- // BUGS.md 39). PlusOpVal and its Go twin now go through the same
51
- // check.
52
- //
53
- // DIVISION IS NOT CLOSED OVER THE DECIMAL LEAF, so div/mod/rem refuse
54
- // a bigdecimal operand rather than rounding one third to fit. See
55
- // `inexact_divide`'s hint: scale to integers, which is the money wire
56
- // convention anyway, or accept a float.
57
-
58
-
59
4
  import type { Val } from '../type'
60
5
 
61
6
  import { AontuContext } from '../ctx'
@@ -105,9 +50,6 @@ function unpref(v: any): any {
105
50
 
106
51
 
107
52
  function arithKind(v: any): ArithKind | undefined {
108
- // Every caller hands a driven Val (an operand past the signature
109
- // gate, or a bag member from the aggregate fold), so scalarhood is
110
- // the one question -- a container member lands here.
111
53
  if (true !== v?.isScalar) {
112
54
  return undefined
113
55
  }
@@ -124,8 +66,6 @@ function arithKind(v: any): ArithKind | undefined {
124
66
  }
125
67
 
126
68
 
127
- // An exact-ladder operand as an exact integer. Only reached for the two
128
- // integral leaves; an `integer` peg is integral by construction.
129
69
  function asInteger(v: any, k: ArithKind): bigint {
130
70
  return 'biginteger' === k ? v.peg : BigInt(v.peg)
131
71
  }
@@ -136,12 +76,6 @@ function asDecimal(v: any, k: ArithKind): Decimal {
136
76
  }
137
77
 
138
78
 
139
- // The whole family, in one function, because every rule above is a rule
140
- // about ARITHMETIC and not about any one operation. `node` is the value
141
- // the error is located at -- the call, or the `+` op.
142
- // `attempt` is the name the ERROR reports, which is the operation
143
- // except when a fold borrows one: `sum` adds, but a bad member is the
144
- // author's `sum` call and must say so.
145
79
  function arith(
146
80
  ctx: AontuContext | undefined,
147
81
  op: ArithOp,
@@ -156,11 +90,6 @@ function arith(
156
90
  const ak = arithKind(av)
157
91
  const bk = arithKind(bv)
158
92
 
159
- // A non-numeric operand is not something to wait for: `resolve` is
160
- // only reached once every argument has settled, so a kind, a map, a
161
- // string or a boolean here is the author's mistake and is named as
162
- // one. (`+` differs, and must: it has answers for strings and
163
- // booleans.)
164
93
  if (undefined === ak || undefined === bk) {
165
94
  return makeNilErr(ctx, 'invalid-arg', node, undefined, name)
166
95
  }
@@ -187,9 +116,6 @@ function arith(
187
116
  }
188
117
 
189
118
 
190
- // IEEE-754 binary64, with the JSON-superset constraint still biting: an
191
- // infinite or NaN result is a located error rather than a value, because
192
- // there is no way to write one down and no JSON that could carry it.
193
119
  function floatArith(
194
120
  ctx: AontuContext | undefined,
195
121
  op: ArithOp,
@@ -210,10 +136,6 @@ function floatArith(
210
136
  // Truncated remainder, sign following the DIVIDEND, which is
211
137
  // what JavaScript's `%` and Go's math.Mod both give...
212
138
  'rem' === op ? x % y :
213
- // ...and the floored modulus, sign following the DIVISOR,
214
- // built from it. Adding the divisor back moves a remainder
215
- // whose sign disagrees into agreement, and leaves an exact
216
- // zero alone.
217
139
  flooredMod(x % y, y)
218
140
 
219
141
  return Number.isFinite(out) ?
@@ -247,11 +169,6 @@ function integerArith(
247
169
  'add' === op ? x + y :
248
170
  'sub' === op ? x - y :
249
171
  'mul' === op ? x * y :
250
- // TRUNCATION TOWARD ZERO, stated once here rather than left to
251
- // whichever host `/` each port happens to call: div(-7, 2) is
252
- // -3, not -4. BigInt division truncates, and so does Go's
253
- // big.Int.Quo (its Div floors, which is why the Go twin must
254
- // not use it).
255
172
  'div' === op ? x / y :
256
173
  'rem' === op ? x % y :
257
174
  flooredModBig(x % y, y)
@@ -262,11 +179,6 @@ function integerArith(
262
179
  return new BigIntegerVal({ peg: out })
263
180
  }
264
181
 
265
- // The result faces the SAME storage contract R1 puts on a literal --
266
- // integral, inside the int64 window, and exactly representable in
267
- // binary64 -- because Go's int64 holds results TypeScript's double
268
- // cannot, and without a shared test a document would resolve in one
269
- // port and round in the other.
270
182
  return isIntegerStorable(out) ?
271
183
  new IntegerVal({ peg: Number(out) }) :
272
184
  makeNilErr(ctx, 'inexact_integer_sum', node, undefined, name,
@@ -290,10 +202,6 @@ function decimalArith(
290
202
  y: Decimal
291
203
  ): Val {
292
204
  if (divides(op)) {
293
- // EXACT DECIMAL DIVISION IS NOT CLOSED: one third has no finite
294
- // decimal form, so a `div` over this leaf either rounds -- the one
295
- // thing the leaf exists to refuse -- or refuses. It refuses, and the
296
- // hint names both ways out.
297
205
  return makeNilErr(ctx, 'inexact_divide', node, undefined, name)
298
206
  }
299
207
 
@@ -0,0 +1,53 @@
1
+ /* Copyright (c) 2026 Richard Rodger, MIT License */
2
+
3
+
4
+ // The half-open code-point span [lo, hi) a (start, len) selects over a
5
+ // string of `n` code points.
6
+ export function caseSpan(n: number, start: number, len: number): [number, number] {
7
+ const span = len < 0 ? n : len
8
+
9
+ if (0 <= start) {
10
+ const lo = Math.min(start, n)
11
+ return [lo, Math.min(lo + span, n)]
12
+ }
13
+
14
+ const hi = Math.max(0, n + start)
15
+ return [Math.max(0, hi - span), hi]
16
+ }
17
+
18
+
19
+ // `text` with the selected run cased. Outside the run the source is
20
+ // returned verbatim, code point for code point.
21
+ export function caseRange(
22
+ text: string, start: number, len: number, up: boolean
23
+ ): string {
24
+ const cps = Array.from(text)
25
+ const [lo, hi] = caseSpan(cps.length, start, len)
26
+ if (hi <= lo) {
27
+ return text
28
+ }
29
+ const mid = cps.slice(lo, hi).join('')
30
+ return cps.slice(0, lo).join('') +
31
+ (up ? mid.toUpperCase() : mid.toLowerCase()) +
32
+ cps.slice(hi).join('')
33
+ }
34
+
35
+
36
+ export function rangeArg(v: any): number | undefined {
37
+ if (null == v) {
38
+ return undefined
39
+ }
40
+ const p = (true === v?.isScalar) ? v.peg : undefined
41
+ if ('number' === typeof p && Number.isInteger(p)) {
42
+ return p
43
+ }
44
+ // A biginteger index is an index: a position in a string is small by
45
+ // construction, or it is not an index at all.
46
+ if ('bigint' === typeof p) {
47
+ const n = Number(p)
48
+ if (Number.isSafeInteger(n)) {
49
+ return n
50
+ }
51
+ }
52
+ return NaN
53
+ }
@@ -1,23 +1,6 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
3
 
4
- // THE MEMBERS OF A BAG, as every fold and every generator over a bag
5
- // sees them (use-cases/BUGS.md §79; G9 phase 0 item 4). A member is a
6
- // child that generation would EMIT: a hide()- or type()-marked child
7
- // is not one, an alias declaration is not one, and an optional key
8
- // whose value generates nothing -- an unfilled `y?: string`, an absent
9
- // optional subtree -- is not one. `each`, `emit`, `filter`, `pick`,
10
- // `join` and the aggregates read a bag through this one function, so a
11
- // value the document withholds from its output is withheld from every
12
- // text and every total the document computes from it: a hidden field
13
- // that reached generated source through `join` is the defect this
14
- // closes, and it was one behaviour in both ports because each verb
15
- // had its own enumeration and none of them asked the mark.
16
- //
17
- // Maps list their members in code-point key order (../keyorder.ts),
18
- // lists in index order -- the one order canon, generation and the Go
19
- // port agree on (BUGS.md §62). Twin of bagMembers in go/members.go.
20
-
21
4
  import type { Val } from '../type'
22
5
  import { AontuContext } from '../ctx'
23
6
  import { cmpCodePoint } from '../keyorder'
@@ -37,12 +20,6 @@ function bagMembers(data: any, ctx: AontuContext): Member[] | undefined {
37
20
  Object.keys(data.peg).sort(cmpCodePoint) :
38
21
  (data.peg as Val[]).map((_v: Val, i: number) => '' + i)
39
22
 
40
- // A member marked while its bag is not was marked in its own right,
41
- // and is left out as generation leaves it out. Under a MARKED bag
42
- // every child carries the mark (hide() and type() mark to the
43
- // leaves), so there the mark says nothing about the member and every
44
- // child is one -- the members of a hidden bag are what the bag
45
- // holds, exactly as a reference to it lifts them.
46
23
  const lifted = true === data.mark.hide || true === data.mark.type
47
24
 
48
25
  const out: Member[] = []
package/src/val/numcmp.ts CHANGED
@@ -1,20 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- /*
4
- * Exact cross-leaf numeric comparison for the constraint algebra
5
- * (docs/reference-language.md, "The constraint algebra"): order is a
6
- * property of the number line, not the leaf, so a bound must compare an
7
- * integer, a float, a biginteger and a bigdecimal EXACTLY, with no
8
- * rounding anywhere. Every finite binary64 is exactly a rational —
9
- * mant * 2^exp — and 2^-k = 5^k * 10^-k, so every leaf converts
10
- * losslessly to a signed scaled-decimal (unscaled / 10^scale) and
11
- * comparison is bigint arithmetic. The Go mirror is numcmp.go.
12
- *
13
- * The scaled forms built here are comparison-internal: they are never
14
- * stored, never rendered, and deliberately NOT subject to the exact
15
- * leaves' 4096-digit budget (a float's exact expansion can need ~770
16
- * digits and that is fine for a compare).
17
- */
18
3
 
19
4
  import { Decimal } from './Decimal'
20
5
 
@@ -26,7 +11,7 @@ import { Decimal } from './Decimal'
26
11
  type Scaled = {
27
12
  inf?: 1 | -1
28
13
  unscaled: bigint // signed
29
- scale: number // value = unscaled / 10^scale, scale >= 0
14
+ scale: number
30
15
  }
31
16
 
32
17
 
@@ -54,8 +39,6 @@ function scaledOfFloat(f: number): Scaled {
54
39
  const expBits = Number((bits >> 52n) & 0x7ffn)
55
40
  const frac = bits & 0xfffffffffffffn
56
41
 
57
- // Normal: implicit leading bit, exponent bias 1023 plus the 52
58
- // fraction bits. Subnormal: no implicit bit, fixed exponent -1074.
59
42
  let mant: bigint
60
43
  let exp: number
61
44
  if (0 === expBits) {
@@ -94,7 +77,6 @@ function pow10(n: number): bigint {
94
77
  }
95
78
 
96
79
 
97
- // Exact three-way comparison of two scaled decimals.
98
80
  function cmpScaled(a: Scaled, b: Scaled): number {
99
81
  const ai = a.inf ?? 0
100
82
  const bi = b.inf ?? 0
@@ -113,16 +95,11 @@ function cmpScaled(a: Scaled, b: Scaled): number {
113
95
  }
114
96
 
115
97
 
116
- // Exact three-way comparison of two numeric leaf Vals, any leaves.
117
98
  function cmpNumeric(a: any, b: any): number {
118
99
  return cmpScaled(scaledOfNumeric(a), scaledOfNumeric(b))
119
100
  }
120
101
 
121
102
 
122
- // Lexical comparison by Unicode CODE POINTS — not UTF-16 code units,
123
- // which order astral-plane text differently. Go compares strings
124
- // byte-wise in UTF-8, which IS code-point order, so this is the side
125
- // that must adapt (a Phase 0 decision, docs/reference-language.md).
126
103
  function cmpCodePoints(a: string, b: string): number {
127
104
  let ai = 0
128
105
  let bi = 0
@@ -141,9 +118,6 @@ function cmpCodePoints(a: string, b: string): number {
141
118
  }
142
119
 
143
120
 
144
- // The tower order integer < float < biginteger < bigdecimal, used when
145
- // two endpoints at the SAME point meet: the survivor is the
146
- // tower-lowest spelling (docs/reference-language.md, bounds ruling 2).
147
121
  function towerRank(v: any): number {
148
122
  return v.isBigDecimal ? 3 : v.isBigInteger ? 2 :
149
123
  v.isInteger ? 0 : 1
@@ -1,154 +1,42 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- /*
4
- * Numeric kind classification, shared by every site that turns a raw
5
- * JavaScript number into an IntegerVal or a NumberVal (the aontu val
6
- * rule, rawToVal, VarVal, the `+` operator, upper()/lower()). Keeping
7
- * the test in one place stops those sites from drifting apart, and
8
- * stops them drifting from the Go port (see isIntegerKind in
9
- * go/lang.go).
10
- *
11
- * This module deliberately imports nothing: IntegerVal itself needs the
12
- * test for its constructor guard, so any import here risks a cycle.
13
- */
14
3
 
15
-
16
- // The int64 range, as exact float64 bounds. -2^63 and 2^63 are both
17
- // exactly representable; 2^63-1 is NOT (it rounds up to 2^63), which is
18
- // why the upper bound is exclusive and 0x7fffffffffffffff correctly
19
- // falls outside.
20
4
  const INT64_MIN = -9223372036854775808.0
21
5
  const INT64_LIMIT = 9223372036854775808.0
22
6
 
23
7
 
24
- // True when a numeric literal has *integer* kind. All three conditions
25
- // must hold:
26
- // (a) the source text, when there is any, contains no '.'
27
- // (b) the value is integral
28
- // (c) the value lies within the int64 range
29
- //
30
- // The range test is written against the float64 bounds rather than as
31
- // `n === Number(BigInt(n))` or Go's `n == float64(int64(n))`: converting
32
- // an out-of-range float64 to int64 is implementation-defined in Go, and
33
- // that accident is exactly what the two ports used to disagree about.
34
- //
35
- // `src` is undefined at construction sites with no source text (raw
36
- // values from an implicit top-level list, or a $var binding); there
37
- // condition (a) is vacuous and (b)+(c) decide.
38
8
  function isIntegerKind(n: number, src?: string): boolean {
39
9
  if (null != src && src.includes('.')) {
40
10
  return false
41
11
  }
42
- // Number.isInteger is false for NaN and both infinities, so a
43
- // non-finite value never reaches the range test.
44
12
  return Number.isInteger(n) && INT64_MIN <= n && n < INT64_LIMIT
45
13
  }
46
14
 
47
15
 
48
- // The same int64 window, exactly, for values that were computed as
49
- // bigints and have not been through a double yet.
50
16
  const INT64_MIN_EXACT = -9223372036854775808n
51
17
  const INT64_LIMIT_EXACT = 9223372036854775808n
52
18
 
53
19
 
54
- // D6 -- THE STORAGE CONTRACT FOR AN EXACTLY COMPUTED INTEGER.
55
- //
56
- // `integer + integer` is computed exactly (in bigint here, in checked
57
- // int64 in Go) and the exact answer is only then offered to the integer
58
- // leaf, which accepts it when it is integral (a bigint always is),
59
- // within the int64 window, AND exactly representable in binary64.
60
- //
61
- // The binary64 half is the parity-critical one. Go's int64 can hold sums
62
- // this port's double cannot -- 2^53+1 among them -- so a test written
63
- // only against the int64 window would let Go store `9007199254740993`
64
- // while TypeScript silently stored `...992`. The round-trip through
65
- // Number() is that test: it is true exactly when nothing was lost. Both
66
- // ports must refuse the same sums, which is why this is the shared
67
- // contract and not a local convenience.
68
- //
69
- // Refusal, not rounding: a sum that fails here is a located error whose
70
- // hint points at `0d` for an exact integer, per R1's own storage rule
71
- // applied to a result rather than a literal.
72
20
  function isIntegerStorable(n: bigint): boolean {
73
21
  return INT64_MIN_EXACT <= n && n < INT64_LIMIT_EXACT &&
74
22
  isExactInBinary64(n)
75
23
  }
76
24
 
77
25
 
78
- // The binary64 half of the storage contract, on its own: true when an
79
- // exact integer survives a round trip through a double unchanged.
80
- //
81
- // D7's literal rule needs exactly this half and NOT the int64 window --
82
- // 10^20 is outside int64 and is still a perfectly good float-kind value,
83
- // because it lands exactly on a binary64. THE RULE IS EXACTNESS, NOT
84
- // MAGNITUDE: `0x10000000000000000000000000000000` is 2^124, a power of
85
- // two, so it is exact and stays a value, while the very much smaller
86
- // `0x7fffffffffffffff` (2^63-1) is not and is refused.
87
- //
88
- // It is factored out rather than reimplemented so a LITERAL and a
89
- // COMPUTED SUM cannot disagree about what "exact" means: both ask this
90
- // one function, in both ports.
91
- //
92
- // The Number.isFinite guard is what makes it total. A bigint far beyond
93
- // binary64's range converts to Infinity, and BigInt(Infinity) THROWS --
94
- // so a literal like 10^400 (which the lexer already turns into a
95
- // non-finite `not_number`) would crash the test rather than fail it.
96
26
  function isExactInBinary64(n: bigint): boolean {
97
27
  const d = Number(n)
98
28
  return Number.isFinite(d) && BigInt(d) === n
99
29
  }
100
30
 
101
31
 
102
- // D7 -- LOSSY INTEGER LITERALS ARE REFUSED.
103
- //
104
- // True when `src` is an integer-source literal whose exact value cannot
105
- // be held in binary64, so storing it would silently substitute a
106
- // DIFFERENT number. Aontu refuses instead: the caller turns this into a
107
- // located parse error whose hint names the escape (`0d<digits>`).
108
- //
109
- // WHICH LITERALS ARE IN SCOPE. An integer-source literal is one that
110
- // denotes an exact integer:
111
- //
112
- // - plain decimal digits (`9007199254740993`), with the landed `_`
113
- // separator rule;
114
- // - a base-prefixed run (`0x…`, `0o…`, `0b…`);
115
- // - either of those with a NON-NEGATIVE exponent (`1e21`), which still
116
- // denotes an integer.
117
- //
118
- // Everything else is out of scope and unchanged. A `.` in the source
119
- // makes it a float literal by R1, so it is not an integer source at all;
120
- // a NEGATIVE exponent (`2e-1`, `1e-400`) denotes a fraction, and testing
121
- // those for binary64 exactness would refuse `2e-1` -- 0.2 is not exactly
122
- // representable either -- which is emphatically not what D7 is about.
123
- // The `0d` family never reaches here: it has its own matcher and its own
124
- // exact leaves.
125
- //
126
- // The value is re-derived from the SOURCE TEXT rather than read off the
127
- // lexed double `n`, because that double is the rounded value this rule
128
- // exists to detect; comparing it with itself would always agree. `n` is
129
- // passed only for the fast path, which is why the signature mirrors
130
- // isIntegerKind's.
131
32
  function isLossyIntegerLiteral(n: number, src?: string): boolean {
132
- // No source text (a raw value from an implicit top-level list, a $var
133
- // binding) means there is no literal to judge -- the same way R1's
134
- // "no `.` in the source" condition is vacuous at those sites.
135
33
  if (null == src) {
136
34
  return false
137
35
  }
138
36
 
139
- // FAST PATH, and the one every ordinary document takes: below 2^53
140
- // every integer is representable, so an integer literal whose ROUNDED
141
- // value is strictly inside that window cannot have had a different
142
- // exact value -- a different integer would be at least 1 away, and
143
- // rounding here is accurate to half a unit. This runs at every numeric
144
- // literal in every parse, so it must not allocate a bigint (2^53+1 has
145
- // rounded value 2^53 and is deliberately NOT inside the window).
146
37
  if (Number.isInteger(n) && -POW53 < n && n < POW53) {
147
38
  return false
148
39
  }
149
- // A `.` makes it a float source (R1), out of scope: checked here, and
150
- // not left to the patterns below, so the other common literal shape
151
- // also leaves without touching a regexp.
152
40
  if (-1 !== src.indexOf('.')) {
153
41
  return false
154
42
  }
@@ -163,13 +51,9 @@ function isLossyIntegerLiteral(n: number, src?: string): boolean {
163
51
  return false
164
52
  }
165
53
  const coeff = BigInt(stripSep(dec[2]))
166
- // Zero at any exponent is zero, and zero is exact -- test it before
167
- // the exponent bound, which would otherwise refuse `0e500`.
168
54
  if (0n === coeff) {
169
55
  return false
170
56
  }
171
- // Beyond this the value cannot be finite in binary64, so it cannot
172
- // be exact either -- and 10n ** BigInt(exp) must not be built.
173
57
  if (MAX_EXPONENT < exp) {
174
58
  return true
175
59
  }
@@ -183,9 +67,6 @@ function isLossyIntegerLiteral(n: number, src?: string): boolean {
183
67
  exact = BigInt('0' + base[2].toLowerCase() + stripSep(base[3]))
184
68
  }
185
69
 
186
- // The sign is irrelevant to exactness (binary64 is sign-symmetric) and
187
- // is anyway lexed as the unary prefix, but accept it so the test does
188
- // not depend on that.
189
70
  return !isExactInBinary64(exact)
190
71
  }
191
72
 
@@ -195,9 +76,6 @@ function isLossyIntegerLiteral(n: number, src?: string): boolean {
195
76
  const DEC_INT_LITERAL_RE =
196
77
  /^([-+]?)([0-9](?:_?[0-9])*)(?:[eE]([-+]?[0-9](?:_?[0-9])*))?$/
197
78
 
198
- // `[+-]? 0(x|o|b) digits`. Hex digits are the widest set, and a bad
199
- // digit for the base simply makes BigInt throw -- which cannot happen,
200
- // since the lexer only produced a token for a well-formed run.
201
79
  const BASE_INT_LITERAL_RE =
202
80
  /^([-+]?)0([xXoObB])([0-9a-fA-F](?:_?[0-9a-fA-F])*)$/
203
81
 
@@ -215,38 +93,11 @@ function stripSep(s: string): string {
215
93
  }
216
94
 
217
95
 
218
- // THE SINGLE RENDERING OF AN INTEGER-KIND PEG. Every site that turns one
219
- // into text must call this -- so that "how many rendering sites are there?"
220
- // is answerable by grepping this function's callers.
221
- //
222
- // That question has been answered wrongly twice. Issue #21 was the
223
- // divergence where TypeScript printed 2^60 as 1152921504606847000, a
224
- // DIFFERENT integer that merely rounds to the same double, because a JS
225
- // number's toString emits the shortest decimal that round-trips (at most 17
226
- // significant digits) while Go printed the exact value from its int64. It
227
- // was closed having fixed the two sites known at the time, canon and
228
- // generate. A differential audit then found a THIRD (`+`'s string
229
- // coercion) and, while fixing that, a FOURTH (a variable used as a path
230
- // segment). Both were the same one-character mistake -- `String(peg)` or
231
- // `'' + peg` on a JS number -- at a site nobody had enumerated.
232
- //
233
- // BigInt is exact here by construction: an integer-kind peg is integral and
234
- // inside the int64 window (isIntegerKind, enforced by IntegerVal's
235
- // constructor), so the conversion cannot throw or lose anything. Below 2^53
236
- // nothing moves -- BigInt(n).toString() === String(n) for every safe
237
- // integer, and both give "0" for negative zero.
238
- //
239
- // FLOAT KIND MUST NOT COME HERE. A float's shortest form IS the right
240
- // answer and is what Go prints too (1e21 -> "1e+21"), so a caller must
241
- // select on kind, not merely on the peg being a JS number.
242
96
  function integerDigits(peg: number): string {
243
97
  return BigInt(peg).toString()
244
98
  } /* node:coverage ignore next 13 */
245
99
 
246
100
 
247
- // The window bounds stay module-local: they are the rules' working
248
- // parts, not API, and every caller wants isIntegerKind or
249
- // isIntegerStorable.
250
101
  export {
251
102
  integerDigits,
252
103
  isExactInBinary64,
@@ -13,7 +13,6 @@ import { Decimal } from './Decimal'
13
13
  import { isIntegerKind } from './numkind'
14
14
 
15
15
 
16
- // TODO: move to FuncBaseVal
17
16
  export function makeScalar(scalar: any): ScalarVal {
18
17
  const st = typeof scalar
19
18
  const spec = { peg: scalar }
@@ -36,21 +35,6 @@ export function makeScalar(scalar: any): ScalarVal {
36
35
  }
37
36
 
38
37
 
39
- // Like makeScalar, but for a numeric result that must not narrow the
40
- // kind of the value it was derived from (kind contagion: upper(2) is an
41
- // integer 2, upper(1.1) is a number 2). `like` is the source Val whose
42
- // kind is being carried over; anything that is not integer kind — and
43
- // any result that has left the int64 range — yields a NumberVal.
44
- //
45
- // The two EXACT leaves need no `like`: unlike integer and float, which
46
- // share the JavaScript `number` type and so can only be told apart by
47
- // the value they came from, a bigint is a biginteger and a Decimal is a
48
- // bigdecimal. Carrying the kind is automatic because the exact result
49
- // types ARE the kinds — an exact ceiling of a bigdecimal is a Decimal,
50
- // so upper(0d1.1) is bigdecimal 0d2.0 and upper(0d5) is biginteger 0d5.
51
- //
52
- // makeScalar keeps its own contract (every number becomes a NumberVal)
53
- // for callers that have no kind to preserve.
54
38
  export function makeScalarLike(scalar: any, like: any): ScalarVal {
55
39
  if ('bigint' === typeof scalar) {
56
40
  return new BigIntegerVal({ peg: scalar })