aontu 0.50.1 → 0.52.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/bin/aontu-lsp.js +6 -0
- package/bin/aontu.js +7 -0
- package/dist/aontu.d.ts +4 -2
- package/dist/aontu.js +21 -8
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +43 -53
- package/dist/cli.js.map +1 -1
- package/dist/ctx.js +1 -1
- package/dist/ctx.js.map +1 -1
- package/dist/err.js +3 -2
- package/dist/err.js.map +1 -1
- package/dist/exactjson.d.ts +37 -0
- package/dist/exactjson.js +228 -0
- package/dist/exactjson.js.map +1 -0
- package/dist/hints.d.ts +3 -1
- package/dist/hints.js +187 -5
- package/dist/hints.js.map +1 -1
- package/dist/keyorder.d.ts +9 -0
- package/dist/keyorder.js +65 -0
- package/dist/keyorder.js.map +1 -0
- package/dist/lang.js +263 -30
- package/dist/lang.js.map +1 -1
- package/dist/lsp-server.d.ts +2 -2
- package/dist/lsp-server.js +10 -10
- package/dist/lsp-server.js.map +1 -1
- package/dist/lsp.js +39 -21
- package/dist/lsp.js.map +1 -1
- package/dist/site.js +1 -1
- package/dist/site.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/unify.js +48 -1
- package/dist/unify.js.map +1 -1
- package/dist/utility.js +3 -8
- package/dist/utility.js.map +1 -1
- package/dist/val/BagVal.js +9 -6
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/BigDecimalVal.d.ts +13 -0
- package/dist/val/BigDecimalVal.js +80 -0
- package/dist/val/BigDecimalVal.js.map +1 -0
- package/dist/val/BigIntegerVal.d.ts +11 -0
- package/dist/val/BigIntegerVal.js +75 -0
- package/dist/val/BigIntegerVal.js.map +1 -0
- package/dist/val/BooleanVal.js +1 -1
- package/dist/val/BooleanVal.js.map +1 -1
- package/dist/val/CloseFuncVal.js +1 -1
- package/dist/val/CloseFuncVal.js.map +1 -1
- package/dist/val/ConjunctVal.js +1 -1
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/ConstraintVal.d.ts +56 -0
- package/dist/val/ConstraintVal.js +407 -0
- package/dist/val/ConstraintVal.js.map +1 -0
- package/dist/val/CopyFuncVal.js +1 -1
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/Decimal.d.ts +32 -0
- package/dist/val/Decimal.js +318 -0
- package/dist/val/Decimal.js.map +1 -0
- package/dist/val/DisjunctVal.js +1 -29
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/ExpectVal.js +1 -1
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FeatureVal.js +1 -1
- package/dist/val/FeatureVal.js.map +1 -1
- package/dist/val/FuncBaseVal.js +1 -1
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/HideFuncVal.js +1 -1
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/IntegerVal.d.ts +2 -0
- package/dist/val/IntegerVal.js +77 -5
- package/dist/val/IntegerVal.js.map +1 -1
- package/dist/val/JunctionVal.js +1 -1
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.d.ts +1 -1
- package/dist/val/KeyFuncVal.js +34 -4
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.js +7 -7
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js +21 -4
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +17 -13
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MoveFuncVal.js +26 -9
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.d.ts +1 -0
- package/dist/val/NilVal.js +10 -3
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/NullVal.js +1 -1
- package/dist/val/NullVal.js.map +1 -1
- package/dist/val/NumberVal.d.ts +1 -0
- package/dist/val/NumberVal.js +25 -4
- package/dist/val/NumberVal.js.map +1 -1
- package/dist/val/OpBaseVal.js +10 -8
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/OpenFuncVal.js +1 -1
- package/dist/val/OpenFuncVal.js.map +1 -1
- package/dist/val/PathFuncVal.js +10 -2
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PlusOpVal.d.ts +3 -1
- package/dist/val/PlusOpVal.js +140 -29
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js +1 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.d.ts +2 -0
- package/dist/val/PrefVal.js +44 -7
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RefVal.d.ts +2 -0
- package/dist/val/RefVal.js +135 -11
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ScalarKindVal.d.ts +12 -2
- package/dist/val/ScalarKindVal.js +108 -13
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/ScalarVal.d.ts +1 -0
- package/dist/val/ScalarVal.js +18 -3
- package/dist/val/ScalarVal.js.map +1 -1
- package/dist/val/StringVal.js +1 -1
- package/dist/val/StringVal.js.map +1 -1
- package/dist/val/SuperFuncVal.d.ts +1 -1
- package/dist/val/SuperFuncVal.js +15 -2
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.js +1 -1
- package/dist/val/TopVal.js.map +1 -1
- package/dist/val/TypeFuncVal.js +1 -1
- package/dist/val/TypeFuncVal.js.map +1 -1
- package/dist/val/UpperFuncVal.js +21 -4
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/Val.d.ts +1 -1
- package/dist/val/Val.js +11 -21
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js +8 -2
- package/dist/val/VarVal.js.map +1 -1
- package/dist/val/numcmp.d.ts +14 -0
- package/dist/val/numcmp.js +134 -0
- package/dist/val/numcmp.js.map +1 -0
- package/dist/val/numkind.d.ts +6 -0
- package/dist/val/numkind.js +224 -0
- package/dist/val/numkind.js.map +1 -0
- package/dist/val/valutil.d.ts +1 -0
- package/dist/val/valutil.js +35 -0
- package/dist/val/valutil.js.map +1 -1
- package/package.json +7 -5
- package/src/aontu.ts +26 -9
- package/src/cli.ts +48 -21
- package/src/ctx.ts +1 -1
- package/src/err.ts +3 -2
- package/src/exactjson.ts +254 -0
- package/src/hints.ts +213 -4
- package/src/keyorder.ts +73 -0
- package/src/lang.ts +303 -31
- package/src/lsp-server.ts +17 -15
- package/src/lsp.ts +37 -14
- package/src/site.ts +1 -1
- package/src/type.ts +1 -1
- package/src/unify.ts +52 -1
- package/src/utility.ts +3 -9
- package/src/val/BagVal.ts +9 -6
- package/src/val/BigDecimalVal.ts +117 -0
- package/src/val/BigIntegerVal.ts +110 -0
- package/src/val/BooleanVal.ts +1 -1
- package/src/val/CloseFuncVal.ts +1 -1
- package/src/val/ConjunctVal.ts +1 -1
- package/src/val/ConstraintVal.ts +561 -0
- package/src/val/CopyFuncVal.ts +1 -1
- package/src/val/Decimal.ts +385 -0
- package/src/val/DisjunctVal.ts +1 -37
- package/src/val/ExpectVal.ts +1 -1
- package/src/val/FeatureVal.ts +1 -1
- package/src/val/FuncBaseVal.ts +1 -1
- package/src/val/HideFuncVal.ts +1 -1
- package/src/val/IntegerVal.ts +81 -5
- package/src/val/JunctionVal.ts +1 -1
- package/src/val/KeyFuncVal.ts +36 -4
- package/src/val/ListVal.ts +3 -5
- package/src/val/LowerFuncVal.ts +22 -5
- package/src/val/MapVal.ts +13 -9
- package/src/val/MoveFuncVal.ts +27 -10
- package/src/val/NilVal.ts +13 -3
- package/src/val/NullVal.ts +1 -1
- package/src/val/NumberVal.ts +27 -4
- package/src/val/OpBaseVal.ts +10 -10
- package/src/val/OpenFuncVal.ts +1 -1
- package/src/val/PathFuncVal.ts +10 -2
- package/src/val/PlusOpVal.ts +168 -32
- package/src/val/PrefFuncVal.ts +1 -1
- package/src/val/PrefVal.ts +70 -8
- package/src/val/RefVal.ts +143 -11
- package/src/val/ScalarKindVal.ts +123 -12
- package/src/val/ScalarVal.ts +20 -3
- package/src/val/StringVal.ts +1 -1
- package/src/val/SuperFuncVal.ts +15 -2
- package/src/val/TopVal.ts +1 -1
- package/src/val/TypeFuncVal.ts +1 -1
- package/src/val/UpperFuncVal.ts +22 -5
- package/src/val/Val.ts +13 -8
- package/src/val/VarVal.ts +8 -2
- package/src/val/numcmp.ts +189 -0
- package/src/val/numkind.ts +256 -0
- package/src/val/valutil.ts +36 -0
package/src/val/PrefVal.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { top } from './top'
|
|
24
24
|
|
|
25
25
|
import { FeatureVal } from './FeatureVal'
|
|
26
|
+
import { ScalarKindVal, kindFamily } from './ScalarKindVal'
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class PrefVal extends FeatureVal {
|
|
@@ -30,7 +31,26 @@ class PrefVal extends FeatureVal {
|
|
|
30
31
|
isGenable = true
|
|
31
32
|
cjo = 30000
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
// The preferred value's own type: the yardstick for "did the peer say
|
|
35
|
+
// anything I did not already say?". A peer that resolves to this (or
|
|
36
|
+
// to the family gate below) leaves the preference standing.
|
|
37
|
+
// Both are assigned by resuper(), called from the constructor.
|
|
38
|
+
superpeg!: Val
|
|
39
|
+
|
|
40
|
+
// The gate an overriding peer must pass. A preference is a DEFAULT, so
|
|
41
|
+
// a concrete peer replaces it -- but only within the preferred value's
|
|
42
|
+
// FAMILY: `*lower(1.1) & a` is a conflict, not an override.
|
|
43
|
+
//
|
|
44
|
+
// Family and not leaf, because the number tower made `integer` and
|
|
45
|
+
// `float` disjoint siblings under `number`. Gating on the leaf would
|
|
46
|
+
// turn `*lower(2.2) & 3` (a float default overridden by an integer)
|
|
47
|
+
// into an error, which is a tightening no document asked for; gating
|
|
48
|
+
// on the family keeps it working and makes the mirror case
|
|
49
|
+
// (`*2 & 3.0`, an error before the tower) work too. For every
|
|
50
|
+
// non-numeric value the family root IS the leaf, so this is the
|
|
51
|
+
// preferred value's type as before.
|
|
52
|
+
familypeg!: Val
|
|
53
|
+
|
|
34
54
|
rank: number = 0
|
|
35
55
|
|
|
36
56
|
constructor(
|
|
@@ -46,18 +66,54 @@ class PrefVal extends FeatureVal {
|
|
|
46
66
|
this.rank = 1 + spec.peg.rank
|
|
47
67
|
}
|
|
48
68
|
|
|
49
|
-
this.
|
|
69
|
+
this.resuper()
|
|
50
70
|
// console.log('PVC', this.peg.canon, this.superpeg.canon)
|
|
51
71
|
}
|
|
52
72
|
|
|
53
73
|
|
|
74
|
+
// Recompute the type yardstick and the override gate from the current
|
|
75
|
+
// peg. Called again whenever the peg resolves (e.g. a ref).
|
|
76
|
+
private resuper() {
|
|
77
|
+
const peg: any = this.peg
|
|
78
|
+
|
|
79
|
+
// A preference whose peg is ITSELF a kind (`*integer`) constrains
|
|
80
|
+
// nothing: there is no type-of-a-type in this lattice, so any peer
|
|
81
|
+
// wins. (Pinned by test/spec/var.tsv:var-pref-kind-narrow. Before
|
|
82
|
+
// the tower this fell out of a ScalarKindVal's superior being top;
|
|
83
|
+
// now that a leaf kind lifts to `number`, it has to be said.)
|
|
84
|
+
if (true === peg.isScalarKind) {
|
|
85
|
+
this.superpeg = top()
|
|
86
|
+
this.familypeg = this.superpeg
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const sup: any = peg.superior()
|
|
91
|
+
this.superpeg = sup
|
|
92
|
+
|
|
93
|
+
// No optional chain: superior() is contractually non-null (every
|
|
94
|
+
// Val returns one, a NilVal returning itself), so guarding against
|
|
95
|
+
// nullish here would claim a possibility the type does not have.
|
|
96
|
+
if (true === sup.isScalarKind) {
|
|
97
|
+
const family = kindFamily(sup.peg)
|
|
98
|
+
// The gate stands in for the preferred value in any conflict it
|
|
99
|
+
// reports, so it must carry the same site and path as the type it
|
|
100
|
+
// widens -- otherwise NilVal.make picks a different primary and
|
|
101
|
+
// the error moves to the wrong path.
|
|
102
|
+
this.familypeg = family === sup.peg ?
|
|
103
|
+
sup : sup.place(new ScalarKindVal({ peg: family, path: sup.path }))
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
this.familypeg = sup
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
54
111
|
// PrefVal unify always returns a PrefVal
|
|
55
112
|
// PrefVals can only be removed by becoming Nil in a Disjunct
|
|
56
113
|
unify(peer: Val, ctx: AontuContext): Val {
|
|
57
114
|
peer = peer ?? top()
|
|
58
115
|
|
|
59
116
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Pref', this, peer)
|
|
60
|
-
let done = true
|
|
61
117
|
let out: Val = this
|
|
62
118
|
let why = ''
|
|
63
119
|
|
|
@@ -66,7 +122,7 @@ class PrefVal extends FeatureVal {
|
|
|
66
122
|
this.peg, top(), 'pref/resolve')
|
|
67
123
|
// console.log('PREF-RESOLVED', this.peg.canon, '->', resolved)
|
|
68
124
|
this.peg = resolved
|
|
69
|
-
this.
|
|
125
|
+
this.resuper()
|
|
70
126
|
}
|
|
71
127
|
|
|
72
128
|
if (peer instanceof PrefVal) {
|
|
@@ -107,8 +163,12 @@ class PrefVal extends FeatureVal {
|
|
|
107
163
|
why += 'super-'
|
|
108
164
|
|
|
109
165
|
out = unite(te ? ctx.clone({ explain: ec(te, 'SUPER') }) : ctx,
|
|
110
|
-
this.
|
|
111
|
-
|
|
166
|
+
this.familypeg, peer, 'pref-super/' + this.id)
|
|
167
|
+
|
|
168
|
+
// The peer added nothing beyond a type the preferred value already
|
|
169
|
+
// satisfies (`*1 & integer`, `*1 & number`), so the preference
|
|
170
|
+
// stands. Anything else is a concrete override and wins.
|
|
171
|
+
if (out.same(this.superpeg) || out.same(this.familypeg)) {
|
|
112
172
|
out = this.peg
|
|
113
173
|
why += 'same'
|
|
114
174
|
}
|
|
@@ -119,7 +179,9 @@ class PrefVal extends FeatureVal {
|
|
|
119
179
|
why += 'none'
|
|
120
180
|
}
|
|
121
181
|
|
|
122
|
-
|
|
182
|
+
// Every pref result is DONE, including a stuck conjunct from the
|
|
183
|
+
// superior-unify (mirrored by PrefVal.Unify in go/pref.go).
|
|
184
|
+
out.dc = DONE
|
|
123
185
|
|
|
124
186
|
// console.log('PREFVAL-OUT', why, this.canon, peer.canon, '->', out.canon, out.done)
|
|
125
187
|
|
|
@@ -165,7 +227,7 @@ class PrefVal extends FeatureVal {
|
|
|
165
227
|
|
|
166
228
|
return val.gen(ctx)
|
|
167
229
|
}
|
|
168
|
-
}
|
|
230
|
+
} /* node:coverage ignore next 6 */
|
|
169
231
|
|
|
170
232
|
|
|
171
233
|
export {
|
package/src/val/RefVal.ts
CHANGED
|
@@ -37,9 +37,18 @@ import { NumberVal } from './NumberVal'
|
|
|
37
37
|
import { ConjunctVal } from './ConjunctVal'
|
|
38
38
|
import { VarVal } from './VarVal'
|
|
39
39
|
import { FeatureVal } from './FeatureVal'
|
|
40
|
+
import { integerDigits } from './numkind'
|
|
41
|
+
import { BigIntegerVal } from './BigIntegerVal'
|
|
42
|
+
import { BigDecimalVal } from './BigDecimalVal'
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
|
|
46
|
+
// A path segment no spelling can produce, used when append meets a Val
|
|
47
|
+
// class it has no rule for. A key cannot contain a NUL, so this can never
|
|
48
|
+
// match, which turns a silent path-shortening bug into a visible miss.
|
|
49
|
+
const UNSPELLABLE_SEGMENT = '\u0000unspellable'
|
|
50
|
+
|
|
51
|
+
|
|
43
52
|
class RefVal extends FeatureVal {
|
|
44
53
|
isRef = true
|
|
45
54
|
isGenable = true
|
|
@@ -59,8 +68,9 @@ class RefVal extends FeatureVal {
|
|
|
59
68
|
super(spec, ctx)
|
|
60
69
|
this.peg = []
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
// The field initialiser (absolute = false) has just run, so only
|
|
72
|
+
// the spec can carry absoluteness in (RefVal.clone re-passes it).
|
|
73
|
+
this.absolute = true === spec.absolute
|
|
64
74
|
|
|
65
75
|
this.prefix = true === spec.prefix
|
|
66
76
|
|
|
@@ -102,6 +112,22 @@ class RefVal extends FeatureVal {
|
|
|
102
112
|
this.peg.push(...partvals)
|
|
103
113
|
}
|
|
104
114
|
|
|
115
|
+
// THE EXACT LEAVES ARE PATH TEXT LIKE ANY OTHER SPELLING. `0d1` as a
|
|
116
|
+
// segment addresses the key literally spelled `0d1` -- the same key
|
|
117
|
+
// `a:{0d1:7}` creates -- and is NOT the number 1, so it neither
|
|
118
|
+
// indexes a list nor reaches a key spelled `1`.
|
|
119
|
+
//
|
|
120
|
+
// Without these branches the part fell off the end of the chain and
|
|
121
|
+
// was SILENTLY DROPPED, so `$.a.0d0` resolved to `$.a` and handed back
|
|
122
|
+
// the CONTAINER. That is a wrong value, not a miss -- strictly worse
|
|
123
|
+
// than an error -- and it made `$.a.0d0` and `$.a.0d1` denote the same
|
|
124
|
+
// location.
|
|
125
|
+
else if (part instanceof BigIntegerVal || part instanceof BigDecimalVal) {
|
|
126
|
+
// A bigdecimal splits on its point exactly as a float does, so
|
|
127
|
+
// `$.x.0d1.5` addresses two levels.
|
|
128
|
+
this.peg.push(...part.src.split('.'))
|
|
129
|
+
}
|
|
130
|
+
|
|
105
131
|
else if (part instanceof VarVal) {
|
|
106
132
|
partval = part
|
|
107
133
|
this.peg.push(partval)
|
|
@@ -131,6 +157,16 @@ class RefVal extends FeatureVal {
|
|
|
131
157
|
|
|
132
158
|
this.peg.push(...part.peg)
|
|
133
159
|
}
|
|
160
|
+
|
|
161
|
+
// A closed chain, deliberately. Every branch above ends in a push, so
|
|
162
|
+
// an unhandled Val class used to fall through in SILENCE and shorten
|
|
163
|
+
// the path by one segment -- which is how the two exact leaves, added
|
|
164
|
+
// by the number tower, made references resolve to their own container.
|
|
165
|
+
// A segment that cannot be spelled is pushed as one that cannot match,
|
|
166
|
+
// so the reference misses loudly instead of succeeding wrongly.
|
|
167
|
+
else {
|
|
168
|
+
this.peg.push(UNSPELLABLE_SEGMENT)
|
|
169
|
+
}
|
|
134
170
|
}
|
|
135
171
|
|
|
136
172
|
|
|
@@ -146,14 +182,13 @@ class RefVal extends FeatureVal {
|
|
|
146
182
|
// TODO: not resolved when all Vals in path are done is an error
|
|
147
183
|
// as path cannot be found
|
|
148
184
|
// let resolved: Val | undefined = null == ctx ? this : ctx.find(this)
|
|
149
|
-
let found: Val | undefined =
|
|
185
|
+
let found: Val | undefined = this.find(ctx)
|
|
150
186
|
|
|
187
|
+
// `?? this` makes resolved non-nullish, so an unresolved reference
|
|
188
|
+
// takes the RefVal arm below rather than a separate null arm.
|
|
151
189
|
const resolved = found ?? this
|
|
152
190
|
|
|
153
|
-
if (
|
|
154
|
-
out = this
|
|
155
|
-
}
|
|
156
|
-
else if (resolved instanceof RefVal) {
|
|
191
|
+
if (resolved instanceof RefVal) {
|
|
157
192
|
if (peer.isTop) {
|
|
158
193
|
out = this
|
|
159
194
|
why = 'pt'
|
|
@@ -272,7 +307,19 @@ class RefVal extends FeatureVal {
|
|
|
272
307
|
// The resolved variable IS a path segment: $seg.r with
|
|
273
308
|
// seg="x" reads ...x.r (previously the coerced value was
|
|
274
309
|
// dropped, silently reading the path without it).
|
|
275
|
-
|
|
310
|
+
//
|
|
311
|
+
// Integer kind renders its EXACT digits -- the FOURTH site
|
|
312
|
+
// to get this wrong (see integerDigits and #21). `'' + peg`
|
|
313
|
+
// on a JS number gives the shortest round-tripping form, so
|
|
314
|
+
// a variable bound to 2^60 addressed the key
|
|
315
|
+
// "1152921504606847000" and missed the real one. Go's
|
|
316
|
+
// ref.go dispatches on kind here and was already correct.
|
|
317
|
+
//
|
|
318
|
+
// Every other kind is already right under `'' +`: a bigint
|
|
319
|
+
// and a Decimal stringify to exact digits, and a float must
|
|
320
|
+
// keep JS parity.
|
|
321
|
+
parts.push(part.isInteger ?
|
|
322
|
+
integerDigits(part.peg as number) : '' + part.peg)
|
|
276
323
|
}
|
|
277
324
|
}
|
|
278
325
|
}
|
|
@@ -302,8 +349,20 @@ class RefVal extends FeatureVal {
|
|
|
302
349
|
(p === sep ? a.length = a.length - 1 : a.push(p), a)), [])
|
|
303
350
|
|
|
304
351
|
if (modes.includes('KEY')) {
|
|
352
|
+
// STRINGIFY. A LIST index arrives here as a JS NUMBER (jsonic puts
|
|
353
|
+
// it in the path as one, and lang.ts copies the path wholesale),
|
|
354
|
+
// so `.$KEY` inside a list built a StringVal whose peg was the
|
|
355
|
+
// number 0 -- an ill-formed value, not a design choice: it canoned
|
|
356
|
+
// as a bare 0, generated a JSON number, satisfied `number` and
|
|
357
|
+
// failed `string`. Go stringifies, and key() already agreed with
|
|
358
|
+
// Go, so this port disagreed with itself.
|
|
359
|
+
//
|
|
360
|
+
// Coerced HERE, at the consumption site, rather than by
|
|
361
|
+
// normalising Val.path: the numeric segment originates in jsonic's
|
|
362
|
+
// own r.k.path and every other path consumer (find's descent,
|
|
363
|
+
// key(), the clone/spread machinery) already handles it.
|
|
305
364
|
let key = this.path[this.path.length - 2]
|
|
306
|
-
let sv = new StringVal({ peg: null == key ? '' : key }, ctx)
|
|
365
|
+
let sv = new StringVal({ peg: null == key ? '' : '' + key }, ctx)
|
|
307
366
|
|
|
308
367
|
// TODO: other props?
|
|
309
368
|
sv.dc = DONE
|
|
@@ -354,8 +413,16 @@ class RefVal extends FeatureVal {
|
|
|
354
413
|
else if (pI === refpath.length) {
|
|
355
414
|
out = node
|
|
356
415
|
|
|
416
|
+
// A reference landing on another reference may be a PROVEN
|
|
417
|
+
// mutual cycle (a: $.b, b: $.a) -- follow the plain-ref chain
|
|
418
|
+
// and, if it revisits a node, report path_cycle now instead of
|
|
419
|
+
// deferring every pass and dying later as a generic ref error.
|
|
420
|
+
// No proof (chain leaves plain refs, or ends) defers as before.
|
|
421
|
+
if (null != out && (out as any).isRef && this.detectRefCycle(ctx)) {
|
|
422
|
+
out = makeNilErr(ctx, 'path_cycle', this)
|
|
423
|
+
}
|
|
357
424
|
// Types and hidden values are cloned and made concrete
|
|
358
|
-
if (null != out) { // && (out.mark.type || out.mark.hide)) {
|
|
425
|
+
else if (null != out) { // && (out.mark.type || out.mark.hide)) {
|
|
359
426
|
|
|
360
427
|
// console.log('FOUND-A', out)
|
|
361
428
|
|
|
@@ -397,6 +464,71 @@ class RefVal extends FeatureVal {
|
|
|
397
464
|
}
|
|
398
465
|
|
|
399
466
|
|
|
467
|
+
// Follow the chain of plain references from this node; true iff the
|
|
468
|
+
// chain revisits a node -- a PROVEN reference cycle, distinct from a
|
|
469
|
+
// merely unresolved reference. Detection is only on the resolution
|
|
470
|
+
// chain revisiting a node, never on syntactic shape: a chain that
|
|
471
|
+
// passes through a variable segment, a conjunct, a function, or any
|
|
472
|
+
// non-ref value yields no proof and the ref defers as before.
|
|
473
|
+
detectRefCycle(ctx: AontuContext): boolean {
|
|
474
|
+
const seen = new Set<number>()
|
|
475
|
+
let cur: RefVal = this
|
|
476
|
+
// No hop cap: every iteration either returns or adds a NEW ref to
|
|
477
|
+
// `seen`, and the tree holds finitely many refs, so the chase
|
|
478
|
+
// terminates at the first repetition or the first non-ref — a cap
|
|
479
|
+
// would just make cycles longer than it invisible.
|
|
480
|
+
for (; ;) {
|
|
481
|
+
if (seen.has(cur.id)) {
|
|
482
|
+
return true
|
|
483
|
+
}
|
|
484
|
+
seen.add(cur.id)
|
|
485
|
+
const rp = cur.plainRefPath()
|
|
486
|
+
if (null == rp) {
|
|
487
|
+
return false
|
|
488
|
+
}
|
|
489
|
+
let node: any = ctx.root
|
|
490
|
+
for (let i = 0; i < rp.length && null != node; i++) {
|
|
491
|
+
node = (node.isMap || node.isList) ? node.peg[rp[i]] : undefined
|
|
492
|
+
}
|
|
493
|
+
if (null == node || !node.isRef) {
|
|
494
|
+
return false
|
|
495
|
+
}
|
|
496
|
+
cur = node
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
// The resolved absolute path of a reference whose segments are all
|
|
502
|
+
// plain strings; undefined when the ref has variable segments (no
|
|
503
|
+
// cycle proof is attempted for those). Mirrors find's refpath
|
|
504
|
+
// computation for the plain case, including the `.` prefix reduction.
|
|
505
|
+
plainRefPath(): string[] | undefined {
|
|
506
|
+
const parts: string[] = []
|
|
507
|
+
for (const p of this.peg) {
|
|
508
|
+
if ('string' !== typeof p) {
|
|
509
|
+
return undefined
|
|
510
|
+
}
|
|
511
|
+
parts.push(p)
|
|
512
|
+
}
|
|
513
|
+
const refpath = this.absolute ? parts :
|
|
514
|
+
this.path.slice(0, -1).concat(parts)
|
|
515
|
+
const reduced: string[] = []
|
|
516
|
+
for (const p of refpath) {
|
|
517
|
+
if ('.' === p) {
|
|
518
|
+
// A parent step off the top of the path proves nothing.
|
|
519
|
+
if (0 === reduced.length) {
|
|
520
|
+
return undefined
|
|
521
|
+
}
|
|
522
|
+
reduced.length = reduced.length - 1
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
reduced.push(p)
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return reduced
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
|
|
400
532
|
same(peer: Val): boolean {
|
|
401
533
|
return null == peer ? false : this.peg === peer.peg
|
|
402
534
|
}
|
|
@@ -450,7 +582,7 @@ class RefVal extends FeatureVal {
|
|
|
450
582
|
].filter(p => '' != p).join(',')
|
|
451
583
|
}
|
|
452
584
|
|
|
453
|
-
}
|
|
585
|
+
} /* node:coverage ignore next 6 */
|
|
454
586
|
|
|
455
587
|
|
|
456
588
|
export {
|
package/src/val/ScalarKindVal.ts
CHANGED
|
@@ -24,17 +24,101 @@ import { makeNilErr, AontuError } from '../err'
|
|
|
24
24
|
import { FeatureVal } from './FeatureVal'
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
//
|
|
27
|
+
// Kind markers.
|
|
28
|
+
//
|
|
29
|
+
// A ScalarKindVal's canon is its marker's constructor name, lowercased,
|
|
30
|
+
// so these class names are load-bearing language surface: `Integer` is
|
|
31
|
+
// the keyword `integer`, `Float` is the keyword `float`.
|
|
32
|
+
//
|
|
33
|
+
// The numeric part of the lattice is a pure supertype over disjoint
|
|
34
|
+
// leaves:
|
|
35
|
+
//
|
|
36
|
+
// number (the global Number constructor)
|
|
37
|
+
// |- integer Integer int64-window exact
|
|
38
|
+
// |- float Float IEEE-754 binary64
|
|
39
|
+
// |- biginteger BigInteger exact, opt-in via 0d
|
|
40
|
+
// |- bigdecimal BigDecimal exact, opt-in via 0d
|
|
41
|
+
//
|
|
42
|
+
// The global `Number` constructor is the marker for the SUPERTYPE only:
|
|
43
|
+
// no concrete ScalarVal ever carries it. A binary64 value is FLOAT kind
|
|
44
|
+
// (NumberVal is the binary64 leaf; the class name is historical).
|
|
45
|
+
//
|
|
46
|
+
// A ScalarKindVal for `number` matches a concrete value of any numeric
|
|
47
|
+
// leaf, and meeting it with a leaf yields that leaf. Two distinct leaves
|
|
48
|
+
// are disjoint sets with no common lower bound, so they do not unify.
|
|
49
|
+
|
|
50
|
+
// A ScalarKind for the int64-window exact integers.
|
|
28
51
|
class Integer { }
|
|
29
52
|
|
|
53
|
+
// A ScalarKind for IEEE-754 binary64 values.
|
|
54
|
+
class Float { }
|
|
55
|
+
|
|
56
|
+
// A ScalarKind for the unbounded exact integers, reached only by a `0d`
|
|
57
|
+
// literal with no fraction and no exponent.
|
|
58
|
+
class BigInteger { }
|
|
59
|
+
|
|
60
|
+
// A ScalarKind for the exact base-10 decimals, reached only by a `0d`
|
|
61
|
+
// literal carrying a `.` or an exponent.
|
|
62
|
+
class BigDecimal { }
|
|
63
|
+
|
|
30
64
|
// A ScalarKind for null.
|
|
31
65
|
class Null { }
|
|
32
66
|
|
|
33
67
|
|
|
68
|
+
// The immediate lattice parent of each kind marker. A marker absent from
|
|
69
|
+
// this table sits directly under top (string, boolean, null -- and
|
|
70
|
+
// `number` itself, which is the root of the numeric family).
|
|
71
|
+
//
|
|
72
|
+
// Adding a leaf is one row.
|
|
73
|
+
const KIND_PARENT = new Map<any, any>([
|
|
74
|
+
[Integer, Number],
|
|
75
|
+
[Float, Number],
|
|
76
|
+
[BigInteger, Number],
|
|
77
|
+
[BigDecimal, Number],
|
|
78
|
+
])
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// The immediate lattice superior of a kind marker, or undefined when the
|
|
82
|
+
// marker's superior is top.
|
|
83
|
+
function kindParent(kind: any): any {
|
|
84
|
+
return KIND_PARENT.get(kind)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
// The root of a kind marker's family: the highest ancestor below top.
|
|
89
|
+
// Every numeric leaf answers `number`; a kind with no parent is its own
|
|
90
|
+
// family root (string, boolean, null).
|
|
91
|
+
function kindFamily(kind: any): any {
|
|
92
|
+
let root = kind
|
|
93
|
+
for (let k = KIND_PARENT.get(kind); null != k; k = KIND_PARENT.get(k)) {
|
|
94
|
+
root = k
|
|
95
|
+
}
|
|
96
|
+
return root
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
// True when `sub` is `sup`, or sits anywhere below it. The numeric
|
|
101
|
+
// lattice is two deep today; walking the chain keeps this correct if it
|
|
102
|
+
// ever deepens.
|
|
103
|
+
function kindSubsumes(sup: any, sub: any): boolean {
|
|
104
|
+
for (let k = sub; null != k; k = KIND_PARENT.get(k)) {
|
|
105
|
+
if (k === sup) {
|
|
106
|
+
return true
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
34
113
|
type ScalarConstructor =
|
|
35
114
|
StringConstructor |
|
|
36
115
|
NumberConstructor |
|
|
37
116
|
BooleanConstructor |
|
|
117
|
+
(typeof Integer) |
|
|
118
|
+
(typeof Float) |
|
|
119
|
+
(typeof BigInteger) |
|
|
120
|
+
(typeof BigDecimal) |
|
|
121
|
+
(typeof Null) |
|
|
38
122
|
(typeof Integer.constructor)
|
|
39
123
|
|
|
40
124
|
|
|
@@ -64,13 +148,19 @@ class ScalarKindVal extends FeatureVal {
|
|
|
64
148
|
|
|
65
149
|
let out: Val = this
|
|
66
150
|
|
|
67
|
-
if (
|
|
151
|
+
if ((peer as any).isConstraint) {
|
|
152
|
+
// The constraint algebra owns the kind-meets-constraint rules
|
|
153
|
+
// (narrowing, domain checks) -- delegate, so disjunct trials and
|
|
154
|
+
// direct drives agree with the sorted conjunct fold.
|
|
155
|
+
out = (peer as any).unify(this, ctx)
|
|
156
|
+
}
|
|
157
|
+
else if (peerIsScalarVal) {
|
|
68
158
|
let peerKind = (peer as any).kind
|
|
69
159
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
160
|
+
// A kind admits a concrete value of that kind, or of any kind
|
|
161
|
+
// below it: `float & 1.5` is 1.5, and `number & 1` is 1 because
|
|
162
|
+
// integer sits under number.
|
|
163
|
+
if (kindSubsumes(this.peg, peerKind)) {
|
|
74
164
|
out = peer
|
|
75
165
|
}
|
|
76
166
|
else {
|
|
@@ -78,13 +168,16 @@ class ScalarKindVal extends FeatureVal {
|
|
|
78
168
|
}
|
|
79
169
|
}
|
|
80
170
|
else if (peerIsScalarKind) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
171
|
+
// The meet of two kinds is the narrower one when they are
|
|
172
|
+
// comparable. Distinct leaves (float & integer) are disjoint sets
|
|
173
|
+
// of values, so they have no common lower bound and fail.
|
|
174
|
+
if (this.peg === peer.peg) {
|
|
85
175
|
out = this
|
|
86
176
|
}
|
|
87
|
-
else if (this.peg
|
|
177
|
+
else if (kindSubsumes(this.peg, peer.peg)) {
|
|
178
|
+
out = peer
|
|
179
|
+
}
|
|
180
|
+
else if (kindSubsumes(peer.peg, this.peg)) {
|
|
88
181
|
out = this
|
|
89
182
|
}
|
|
90
183
|
else {
|
|
@@ -108,18 +201,36 @@ class ScalarKindVal extends FeatureVal {
|
|
|
108
201
|
}
|
|
109
202
|
|
|
110
203
|
|
|
204
|
+
// The super() ladder: a leaf kind lifts to its parent kind
|
|
205
|
+
// (super(integer) -> number, super(float) -> number), and a kind with
|
|
206
|
+
// no parent lifts to top (super(number) -> top). A concrete value
|
|
207
|
+
// lifts to its own leaf via ScalarVal.superior.
|
|
208
|
+
superior(): Val {
|
|
209
|
+
const parent = kindParent(this.peg)
|
|
210
|
+
return null == parent ?
|
|
211
|
+
super.superior() :
|
|
212
|
+
this.place(new ScalarKindVal({ peg: parent }))
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
|
|
111
216
|
same(peer: any): boolean {
|
|
112
217
|
let out = peer?.isScalarKind ? this.peg === peer?.peg : super.same(peer)
|
|
113
218
|
return out
|
|
114
219
|
}
|
|
115
220
|
|
|
116
221
|
|
|
117
|
-
}
|
|
222
|
+
} /* node:coverage ignore next 15 */
|
|
118
223
|
|
|
119
224
|
|
|
120
225
|
export {
|
|
226
|
+
BigDecimal,
|
|
227
|
+
BigInteger,
|
|
228
|
+
Float,
|
|
121
229
|
Integer,
|
|
122
230
|
Null,
|
|
123
231
|
ScalarConstructor,
|
|
124
232
|
ScalarKindVal,
|
|
233
|
+
kindFamily,
|
|
234
|
+
kindParent,
|
|
235
|
+
kindSubsumes,
|
|
125
236
|
}
|
package/src/val/ScalarVal.ts
CHANGED
|
@@ -60,7 +60,7 @@ class ScalarVal extends Val {
|
|
|
60
60
|
let out: Val
|
|
61
61
|
|
|
62
62
|
// Exactly equal scalars are handled in unify.unite
|
|
63
|
-
if (peer.isScalarKind) {
|
|
63
|
+
if (peer.isScalarKind || (peer as any).isConstraint) {
|
|
64
64
|
out = peer.unify(this, ctx)
|
|
65
65
|
}
|
|
66
66
|
else if (peer.isTop) {
|
|
@@ -87,7 +87,24 @@ class ScalarVal extends Val {
|
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
same(peer: any): boolean {
|
|
90
|
-
|
|
90
|
+
// Two concrete scalars are the same only when KIND and value both
|
|
91
|
+
// match. Comparing peg alone is a leftover from before integer and
|
|
92
|
+
// number were distinct kinds; without the kind test `1|1.0` would
|
|
93
|
+
// collapse to a single alternative and `(1|1.0) & 1.0` could pick
|
|
94
|
+
// the integer.
|
|
95
|
+
return peer?.isScalar ?
|
|
96
|
+
(peer.kind === this.kind && this.samePeg(peer.peg)) :
|
|
97
|
+
super.same(peer)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
// Value comparison for this leaf's peg (D2: identity is kind AND
|
|
102
|
+
// value, NEVER the identity of the object holding the value). `===` is
|
|
103
|
+
// right for every peg that is a primitive -- including a bigint, where
|
|
104
|
+
// two separately built copies of the same number compare equal -- and
|
|
105
|
+
// wrong for a peg that is an object, so BigDecimalVal overrides it.
|
|
106
|
+
samePeg(peg: any): boolean {
|
|
107
|
+
return peg === this.peg
|
|
91
108
|
}
|
|
92
109
|
|
|
93
110
|
|
|
@@ -104,7 +121,7 @@ class ScalarVal extends Val {
|
|
|
104
121
|
}))
|
|
105
122
|
}
|
|
106
123
|
|
|
107
|
-
}
|
|
124
|
+
} /* node:coverage ignore next 6 */
|
|
108
125
|
|
|
109
126
|
|
|
110
127
|
export {
|
package/src/val/StringVal.ts
CHANGED
package/src/val/SuperFuncVal.ts
CHANGED
|
@@ -34,11 +34,24 @@ class SuperFuncVal extends FuncBaseVal {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
resolve(_ctx: AontuContext,
|
|
37
|
+
resolve(_ctx: AontuContext, args: Val[]) {
|
|
38
|
+
// super(x) is the lattice-superior of its ARGUMENT, not of the
|
|
39
|
+
// super() call itself: super(1) -> integer, super(1.5) -> number,
|
|
40
|
+
// super(a) -> string, super(true) -> boolean. Returning the
|
|
41
|
+
// function's own superior (top) is what made super() inert.
|
|
42
|
+
const arg: any = args?.[0]
|
|
43
|
+
if (arg?.isVal) {
|
|
44
|
+
const sup = arg.superior()
|
|
45
|
+
// Where the argument has no meaningful superior (superior()
|
|
46
|
+
// defaults to top), fall back to the previous behaviour.
|
|
47
|
+
if (null != sup && true !== sup.isTop) {
|
|
48
|
+
return this.place(sup)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
38
51
|
return this.place(this.superior())
|
|
39
52
|
}
|
|
40
53
|
|
|
41
|
-
}
|
|
54
|
+
} /* node:coverage ignore next 6 */
|
|
42
55
|
|
|
43
56
|
|
|
44
57
|
export {
|
package/src/val/TopVal.ts
CHANGED