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.
- package/README.md +4 -4
- package/dist/agentsmd.d.ts +1 -0
- package/dist/agentsmd.js +7 -28
- package/dist/agentsmd.js.map +1 -1
- package/dist/alias.js.map +1 -1
- package/dist/allow.d.ts +23 -0
- package/dist/allow.js +138 -0
- package/dist/allow.js.map +1 -0
- package/dist/aontu.d.ts +4 -2
- package/dist/aontu.js +4 -80
- package/dist/aontu.js.map +1 -1
- package/dist/aontumodel.d.ts +4 -0
- package/dist/aontumodel.js +33 -0
- package/dist/aontumodel.js.map +1 -0
- package/dist/cli.d.ts +10 -1
- package/dist/cli.js +877 -479
- package/dist/cli.js.map +1 -1
- package/dist/ctx.js +0 -48
- package/dist/ctx.js.map +1 -1
- package/dist/diff.js +0 -32
- package/dist/diff.js.map +1 -1
- package/dist/err.js +0 -40
- package/dist/err.js.map +1 -1
- package/dist/escape.js +0 -45
- package/dist/escape.js.map +1 -1
- package/dist/exactjson.d.ts +0 -35
- package/dist/exactjson.js +0 -131
- package/dist/exactjson.js.map +1 -1
- package/dist/format.js +55 -189
- package/dist/format.js.map +1 -1
- package/dist/grammar.d.ts +9 -0
- package/dist/grammar.js +54 -0
- package/dist/grammar.js.map +1 -0
- package/dist/graph.js +0 -26
- package/dist/graph.js.map +1 -1
- package/dist/hcanon.js +0 -82
- package/dist/hcanon.js.map +1 -1
- package/dist/helpdoc.d.ts +16 -0
- package/dist/helpdoc.js +59 -0
- package/dist/helpdoc.js.map +1 -0
- package/dist/hints.d.ts +0 -6
- package/dist/hints.js +59 -47
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.js +0 -114
- package/dist/jsonschema.js.map +1 -1
- package/dist/keyorder.d.ts +0 -7
- package/dist/keyorder.js +0 -41
- package/dist/keyorder.js.map +1 -1
- package/dist/lang.js +32 -877
- package/dist/lang.js.map +1 -1
- package/dist/lower.d.ts +3 -0
- package/dist/lower.js +14 -61
- package/dist/lower.js.map +1 -1
- package/dist/lsp-server.js +0 -16
- package/dist/lsp-server.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/lsp.js +12 -159
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.js +0 -26
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp.js +0 -113
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +0 -130
- package/dist/mod-tool.js.map +1 -1
- package/dist/mod.js +0 -162
- package/dist/mod.js.map +1 -1
- package/dist/patch.js +0 -217
- package/dist/patch.js.map +1 -1
- package/dist/provenance.js +0 -140
- package/dist/provenance.js.map +1 -1
- package/dist/query.js +0 -75
- package/dist/query.js.map +1 -1
- package/dist/reach.js +0 -43
- package/dist/reach.js.map +1 -1
- package/dist/relation.d.ts +2 -0
- package/dist/relation.js +3 -58
- package/dist/relation.js.map +1 -1
- package/dist/render.js +33 -143
- package/dist/render.js.map +1 -1
- package/dist/report-sarif.d.ts +0 -11
- package/dist/report-sarif.js +0 -28
- package/dist/report-sarif.js.map +1 -1
- package/dist/sig.js +0 -35
- package/dist/sig.js.map +1 -1
- package/dist/sigdecl.js +1 -1
- package/dist/sigdecl.js.map +1 -1
- package/dist/siggate.js +0 -4
- package/dist/siggate.js.map +1 -1
- package/dist/site.js +3 -29
- package/dist/site.js.map +1 -1
- package/dist/subsume.d.ts +0 -10
- package/dist/subsume.js +0 -137
- package/dist/subsume.js.map +1 -1
- package/dist/template.d.ts +2 -1
- package/dist/template.js +58 -138
- package/dist/template.js.map +1 -1
- package/dist/trim.js +0 -41
- package/dist/trim.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.js.map +1 -1
- package/dist/unify.js +12 -242
- package/dist/unify.js.map +1 -1
- package/dist/utility.js +0 -22
- package/dist/utility.js.map +1 -1
- package/dist/val/AbnfFuncVal.d.ts +18 -0
- package/dist/val/AbnfFuncVal.js +132 -0
- package/dist/val/AbnfFuncVal.js.map +1 -0
- package/dist/val/AbsentVal.d.ts +11 -0
- package/dist/val/AbsentVal.js +30 -0
- package/dist/val/AbsentVal.js.map +1 -0
- package/dist/val/AggFuncVal.d.ts +10 -1
- package/dist/val/AggFuncVal.js +104 -116
- package/dist/val/AggFuncVal.js.map +1 -1
- package/dist/val/ArithFuncVal.js +0 -12
- package/dist/val/ArithFuncVal.js.map +1 -1
- package/dist/val/BagVal.js +1 -78
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/BigDecimalVal.js +0 -16
- package/dist/val/BigDecimalVal.js.map +1 -1
- package/dist/val/BigIntegerVal.js +0 -16
- package/dist/val/BigIntegerVal.js.map +1 -1
- package/dist/val/CloseFuncVal.js +0 -9
- package/dist/val/CloseFuncVal.js.map +1 -1
- package/dist/val/CmpFuncVal.d.ts +20 -0
- package/dist/val/CmpFuncVal.js +188 -0
- package/dist/val/CmpFuncVal.js.map +1 -0
- package/dist/val/ConjunctVal.js +0 -29
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/ConstraintVal.js +0 -500
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/ContainerKindVal.js +0 -2
- package/dist/val/ContainerKindVal.js.map +1 -1
- package/dist/val/CopyFuncVal.js +0 -3
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/Decimal.js +0 -179
- package/dist/val/Decimal.js.map +1 -1
- package/dist/val/DeprecateFuncVal.js.map +1 -1
- package/dist/val/DisjunctVal.js +0 -152
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/EachFuncVal.d.ts +1 -2
- package/dist/val/EachFuncVal.js +12 -29
- package/dist/val/EachFuncVal.js.map +1 -1
- package/dist/val/EmitFuncVal.d.ts +1 -1
- package/dist/val/EmitFuncVal.js +6 -119
- package/dist/val/EmitFuncVal.js.map +1 -1
- package/dist/val/ExpectVal.js +0 -62
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FilterFuncVal.js +0 -25
- package/dist/val/FilterFuncVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +1 -0
- package/dist/val/FuncBaseVal.js +7 -127
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/GraphAtomVal.js +0 -15
- package/dist/val/GraphAtomVal.js.map +1 -1
- package/dist/val/HideFuncVal.js +0 -13
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/IntegerVal.js +0 -61
- package/dist/val/IntegerVal.js.map +1 -1
- package/dist/val/JunctionVal.js +0 -20
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.js +0 -46
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.js +0 -57
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js +11 -6
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +0 -151
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MatchFuncVal.js +0 -27
- package/dist/val/MatchFuncVal.js.map +1 -1
- package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
- package/dist/val/MaybeFuncVal.js +50 -0
- package/dist/val/MaybeFuncVal.js.map +1 -0
- package/dist/val/MoveFuncVal.js +0 -18
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.js +2 -36
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/NomFuncVal.d.ts +12 -0
- package/dist/val/NomFuncVal.js +153 -0
- package/dist/val/NomFuncVal.js.map +1 -0
- package/dist/val/NumberVal.js +0 -15
- package/dist/val/NumberVal.js.map +1 -1
- package/dist/val/OpBaseVal.d.ts +1 -0
- package/dist/val/OpBaseVal.js +3 -15
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/PackFuncVal.js +0 -34
- package/dist/val/PackFuncVal.js.map +1 -1
- package/dist/val/PathFuncVal.js +0 -6
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PathVal.js +0 -41
- package/dist/val/PathVal.js.map +1 -1
- package/dist/val/PlaceVal.js +0 -25
- package/dist/val/PlaceVal.js.map +1 -1
- package/dist/val/PlusOpVal.d.ts +1 -7
- package/dist/val/PlusOpVal.js +13 -74
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js +0 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.js +0 -167
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RecurseVal.js +0 -55
- package/dist/val/RecurseVal.js.map +1 -1
- package/dist/val/RefVal.js +0 -282
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.js +0 -232
- package/dist/val/ReferFuncVal.js.map +1 -1
- package/dist/val/ScalarKindVal.js +0 -49
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/ScalarVal.js +0 -11
- package/dist/val/ScalarVal.js.map +1 -1
- package/dist/val/StrFuncVal.js +0 -18
- package/dist/val/StrFuncVal.js.map +1 -1
- package/dist/val/SuperFuncVal.js +0 -32
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.js +0 -1
- package/dist/val/TopVal.js.map +1 -1
- package/dist/val/TranslateFuncVal.d.ts +12 -0
- package/dist/val/TranslateFuncVal.js +99 -0
- package/dist/val/TranslateFuncVal.js.map +1 -0
- package/dist/val/UpperFuncVal.js +11 -6
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/Val.d.ts +1 -0
- package/dist/val/Val.js +2 -133
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js +0 -12
- package/dist/val/VarVal.js.map +1 -1
- package/dist/val/arith.js +0 -37
- package/dist/val/arith.js.map +1 -1
- package/dist/val/caserange.d.ts +3 -0
- package/dist/val/caserange.js +49 -0
- package/dist/val/caserange.js.map +1 -0
- package/dist/val/members.js +0 -6
- package/dist/val/members.js.map +1 -1
- package/dist/val/numcmp.js +0 -11
- package/dist/val/numcmp.js.map +1 -1
- package/dist/val/numkind.js +0 -145
- package/dist/val/numkind.js.map +1 -1
- package/dist/val/valutil.js +0 -16
- package/dist/val/valutil.js.map +1 -1
- package/dist/vet.d.ts +12 -0
- package/dist/vet.js +159 -412
- package/dist/vet.js.map +1 -1
- package/dist/view.js +0 -414
- package/dist/view.js.map +1 -1
- package/dist/walk.js +0 -41
- package/dist/walk.js.map +1 -1
- package/grammar/aontu.abnf +9 -7
- package/grammar/aontu.gbnf +5 -5
- package/grammar/aontu.lark +5 -5
- package/grammar/aontu.tmLanguage.json +1 -1
- package/package.json +4 -2
- package/skill/SKILL.md +8 -0
- package/skill/init/check.sh +28 -0
- package/skill/init/data.aon +12 -0
- package/skill/init/model.aon +19 -0
- package/skill/tasks.md +151 -0
- package/src/agentsmd.ts +8 -32
- package/src/alias.ts +0 -39
- package/src/allow.ts +221 -0
- package/src/aontu.ts +10 -108
- package/src/aontumodel.ts +32 -0
- package/src/cli.ts +1009 -540
- package/src/ctx.ts +0 -103
- package/src/diff.ts +0 -40
- package/src/err.ts +0 -40
- package/src/escape.ts +0 -46
- package/src/exactjson.ts +0 -131
- package/src/format.ts +63 -234
- package/src/grammar.ts +72 -0
- package/src/graph.ts +0 -61
- package/src/hcanon.ts +0 -82
- package/src/helpdoc.ts +77 -0
- package/src/hints.ts +72 -49
- package/src/jsonschema.ts +0 -123
- package/src/keyorder.ts +0 -42
- package/src/lang.ts +39 -895
- package/src/lower.ts +15 -65
- package/src/lsp-server.ts +0 -16
- package/src/lsp.ts +12 -180
- package/src/mcp-server.ts +0 -31
- package/src/mcp.ts +0 -130
- package/src/mod-tool.ts +0 -158
- package/src/mod.ts +0 -178
- package/src/patch.ts +0 -232
- package/src/provenance.ts +0 -183
- package/src/query.ts +0 -84
- package/src/reach.ts +0 -53
- package/src/relation.ts +7 -71
- package/src/render.ts +33 -180
- package/src/report-sarif.ts +0 -48
- package/src/sig.ts +0 -35
- package/src/sigdecl.ts +1 -1
- package/src/siggate.ts +0 -30
- package/src/site.ts +3 -29
- package/src/subsume.ts +1 -161
- package/src/template.ts +69 -140
- package/src/trim.ts +0 -53
- package/src/type.ts +2 -45
- package/src/unify.ts +13 -251
- package/src/utility.ts +0 -31
- package/src/val/AbnfFuncVal.ts +181 -0
- package/src/val/AbsentVal.ts +54 -0
- package/src/val/AggFuncVal.ts +152 -188
- package/src/val/ArithFuncVal.ts +0 -20
- package/src/val/BagVal.ts +1 -78
- package/src/val/BigDecimalVal.ts +0 -16
- package/src/val/BigIntegerVal.ts +0 -16
- package/src/val/CloseFuncVal.ts +0 -9
- package/src/val/CmpFuncVal.ts +249 -0
- package/src/val/ConjunctVal.ts +0 -33
- package/src/val/ConstraintVal.ts +2 -537
- package/src/val/ContainerKindVal.ts +0 -18
- package/src/val/CopyFuncVal.ts +0 -5
- package/src/val/Decimal.ts +1 -185
- package/src/val/DeprecateFuncVal.ts +0 -10
- package/src/val/DisjunctVal.ts +0 -157
- package/src/val/EachFuncVal.ts +12 -53
- package/src/val/EmitFuncVal.ts +8 -208
- package/src/val/ExpectVal.ts +0 -62
- package/src/val/FilterFuncVal.ts +0 -55
- package/src/val/FuncBaseVal.ts +9 -130
- package/src/val/GraphAtomVal.ts +0 -42
- package/src/val/HideFuncVal.ts +0 -15
- package/src/val/IntegerVal.ts +0 -61
- package/src/val/JunctionVal.ts +0 -20
- package/src/val/KeyFuncVal.ts +0 -48
- package/src/val/ListVal.ts +0 -59
- package/src/val/LowerFuncVal.ts +12 -7
- package/src/val/MapVal.ts +0 -151
- package/src/val/MatchFuncVal.ts +0 -59
- package/src/val/MaybeFuncVal.ts +86 -0
- package/src/val/MoveFuncVal.ts +0 -20
- package/src/val/NilVal.ts +2 -36
- package/src/val/NomFuncVal.ts +200 -0
- package/src/val/NumberVal.ts +0 -16
- package/src/val/OpBaseVal.ts +4 -17
- package/src/val/PackFuncVal.ts +0 -63
- package/src/val/PathFuncVal.ts +0 -32
- package/src/val/PathVal.ts +0 -66
- package/src/val/PlaceVal.ts +0 -45
- package/src/val/PlusOpVal.ts +18 -75
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +0 -179
- package/src/val/RecurseVal.ts +0 -81
- package/src/val/RefVal.ts +1 -285
- package/src/val/ReferFuncVal.ts +0 -255
- package/src/val/ScalarKindVal.ts +0 -50
- package/src/val/ScalarVal.ts +0 -12
- package/src/val/StrFuncVal.ts +0 -44
- package/src/val/SuperFuncVal.ts +0 -42
- package/src/val/TopVal.ts +0 -1
- package/src/val/TranslateFuncVal.ts +132 -0
- package/src/val/UpperFuncVal.ts +12 -7
- package/src/val/Val.ts +3 -192
- package/src/val/VarVal.ts +0 -15
- package/src/val/arith.ts +0 -92
- package/src/val/caserange.ts +53 -0
- package/src/val/members.ts +0 -23
- package/src/val/numcmp.ts +1 -27
- package/src/val/numkind.ts +0 -149
- package/src/val/valutil.ts +0 -16
- package/src/vet.ts +209 -504
- package/src/view.ts +0 -507
- package/src/walk.ts +0 -41
- package/dist/std.d.ts +0 -3
- package/dist/std.js +0 -637
- package/dist/std.js.map +0 -1
- package/dist/val/FormFuncVal.js +0 -55
- package/dist/val/FormFuncVal.js.map +0 -1
- package/src/std.ts +0 -648
- 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
|
+
}
|
package/src/val/members.ts
CHANGED
|
@@ -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
|
|
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
|
package/src/val/numkind.ts
CHANGED
|
@@ -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,
|
package/src/val/valutil.ts
CHANGED
|
@@ -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 })
|