aontu 0.51.0 → 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.
Files changed (179) hide show
  1. package/bin/aontu-lsp.js +6 -0
  2. package/bin/aontu.js +7 -0
  3. package/dist/aontu.d.ts +1 -1
  4. package/dist/aontu.js +4 -7
  5. package/dist/aontu.js.map +1 -1
  6. package/dist/cli.d.ts +0 -1
  7. package/dist/cli.js +10 -46
  8. package/dist/cli.js.map +1 -1
  9. package/dist/ctx.js +1 -1
  10. package/dist/ctx.js.map +1 -1
  11. package/dist/err.js +3 -2
  12. package/dist/err.js.map +1 -1
  13. package/dist/exactjson.js +1 -1
  14. package/dist/exactjson.js.map +1 -1
  15. package/dist/hints.d.ts +3 -1
  16. package/dist/hints.js +126 -1
  17. package/dist/hints.js.map +1 -1
  18. package/dist/keyorder.js +1 -1
  19. package/dist/keyorder.js.map +1 -1
  20. package/dist/lang.js +64 -27
  21. package/dist/lang.js.map +1 -1
  22. package/dist/lsp-server.d.ts +2 -2
  23. package/dist/lsp-server.js +10 -10
  24. package/dist/lsp-server.js.map +1 -1
  25. package/dist/lsp.js +27 -19
  26. package/dist/lsp.js.map +1 -1
  27. package/dist/site.js +1 -1
  28. package/dist/site.js.map +1 -1
  29. package/dist/tsconfig.tsbuildinfo +1 -1
  30. package/dist/unify.js +48 -1
  31. package/dist/unify.js.map +1 -1
  32. package/dist/utility.js +3 -8
  33. package/dist/utility.js.map +1 -1
  34. package/dist/val/BagVal.js +1 -1
  35. package/dist/val/BagVal.js.map +1 -1
  36. package/dist/val/BigDecimalVal.js +2 -2
  37. package/dist/val/BigDecimalVal.js.map +1 -1
  38. package/dist/val/BigIntegerVal.js +2 -2
  39. package/dist/val/BigIntegerVal.js.map +1 -1
  40. package/dist/val/BooleanVal.js +1 -1
  41. package/dist/val/BooleanVal.js.map +1 -1
  42. package/dist/val/CloseFuncVal.js +1 -1
  43. package/dist/val/CloseFuncVal.js.map +1 -1
  44. package/dist/val/ConjunctVal.js +1 -1
  45. package/dist/val/ConjunctVal.js.map +1 -1
  46. package/dist/val/ConstraintVal.d.ts +56 -0
  47. package/dist/val/ConstraintVal.js +407 -0
  48. package/dist/val/ConstraintVal.js.map +1 -0
  49. package/dist/val/CopyFuncVal.js +1 -1
  50. package/dist/val/CopyFuncVal.js.map +1 -1
  51. package/dist/val/Decimal.js +1 -1
  52. package/dist/val/Decimal.js.map +1 -1
  53. package/dist/val/DisjunctVal.js +1 -29
  54. package/dist/val/DisjunctVal.js.map +1 -1
  55. package/dist/val/ExpectVal.js +1 -1
  56. package/dist/val/ExpectVal.js.map +1 -1
  57. package/dist/val/FeatureVal.js +1 -1
  58. package/dist/val/FeatureVal.js.map +1 -1
  59. package/dist/val/FuncBaseVal.js +1 -1
  60. package/dist/val/FuncBaseVal.js.map +1 -1
  61. package/dist/val/HideFuncVal.js +1 -1
  62. package/dist/val/HideFuncVal.js.map +1 -1
  63. package/dist/val/IntegerVal.js +2 -2
  64. package/dist/val/IntegerVal.js.map +1 -1
  65. package/dist/val/JunctionVal.js +1 -1
  66. package/dist/val/JunctionVal.js.map +1 -1
  67. package/dist/val/KeyFuncVal.js +1 -1
  68. package/dist/val/KeyFuncVal.js.map +1 -1
  69. package/dist/val/ListVal.js +7 -7
  70. package/dist/val/ListVal.js.map +1 -1
  71. package/dist/val/LowerFuncVal.js +1 -1
  72. package/dist/val/LowerFuncVal.js.map +1 -1
  73. package/dist/val/MapVal.js +11 -9
  74. package/dist/val/MapVal.js.map +1 -1
  75. package/dist/val/MoveFuncVal.js +1 -1
  76. package/dist/val/MoveFuncVal.js.map +1 -1
  77. package/dist/val/NilVal.d.ts +1 -0
  78. package/dist/val/NilVal.js +10 -3
  79. package/dist/val/NilVal.js.map +1 -1
  80. package/dist/val/NullVal.js +1 -1
  81. package/dist/val/NullVal.js.map +1 -1
  82. package/dist/val/NumberVal.js +2 -2
  83. package/dist/val/NumberVal.js.map +1 -1
  84. package/dist/val/OpBaseVal.js +10 -8
  85. package/dist/val/OpBaseVal.js.map +1 -1
  86. package/dist/val/OpenFuncVal.js +1 -1
  87. package/dist/val/OpenFuncVal.js.map +1 -1
  88. package/dist/val/PathFuncVal.js +1 -1
  89. package/dist/val/PathFuncVal.js.map +1 -1
  90. package/dist/val/PlusOpVal.js +1 -1
  91. package/dist/val/PlusOpVal.js.map +1 -1
  92. package/dist/val/PrefFuncVal.js +1 -1
  93. package/dist/val/PrefFuncVal.js.map +1 -1
  94. package/dist/val/PrefVal.js +4 -3
  95. package/dist/val/PrefVal.js.map +1 -1
  96. package/dist/val/RefVal.d.ts +2 -0
  97. package/dist/val/RefVal.js +78 -9
  98. package/dist/val/RefVal.js.map +1 -1
  99. package/dist/val/ScalarKindVal.js +8 -2
  100. package/dist/val/ScalarKindVal.js.map +1 -1
  101. package/dist/val/ScalarVal.js +2 -2
  102. package/dist/val/ScalarVal.js.map +1 -1
  103. package/dist/val/StringVal.js +1 -1
  104. package/dist/val/StringVal.js.map +1 -1
  105. package/dist/val/SuperFuncVal.js +1 -1
  106. package/dist/val/SuperFuncVal.js.map +1 -1
  107. package/dist/val/TopVal.js +1 -1
  108. package/dist/val/TopVal.js.map +1 -1
  109. package/dist/val/TypeFuncVal.js +1 -1
  110. package/dist/val/TypeFuncVal.js.map +1 -1
  111. package/dist/val/UpperFuncVal.js +1 -1
  112. package/dist/val/UpperFuncVal.js.map +1 -1
  113. package/dist/val/Val.d.ts +1 -1
  114. package/dist/val/Val.js +11 -21
  115. package/dist/val/Val.js.map +1 -1
  116. package/dist/val/VarVal.js +1 -1
  117. package/dist/val/VarVal.js.map +1 -1
  118. package/dist/val/numcmp.d.ts +14 -0
  119. package/dist/val/numcmp.js +134 -0
  120. package/dist/val/numcmp.js.map +1 -0
  121. package/dist/val/numkind.js +1 -1
  122. package/dist/val/numkind.js.map +1 -1
  123. package/package.json +6 -4
  124. package/src/aontu.ts +4 -8
  125. package/src/cli.ts +12 -13
  126. package/src/ctx.ts +1 -1
  127. package/src/err.ts +3 -2
  128. package/src/exactjson.ts +1 -1
  129. package/src/hints.ts +140 -0
  130. package/src/keyorder.ts +1 -1
  131. package/src/lang.ts +75 -27
  132. package/src/lsp-server.ts +17 -15
  133. package/src/lsp.ts +27 -12
  134. package/src/site.ts +1 -1
  135. package/src/type.ts +1 -1
  136. package/src/unify.ts +52 -1
  137. package/src/utility.ts +3 -9
  138. package/src/val/BagVal.ts +1 -1
  139. package/src/val/BigDecimalVal.ts +2 -2
  140. package/src/val/BigIntegerVal.ts +2 -2
  141. package/src/val/BooleanVal.ts +1 -1
  142. package/src/val/CloseFuncVal.ts +1 -1
  143. package/src/val/ConjunctVal.ts +1 -1
  144. package/src/val/ConstraintVal.ts +561 -0
  145. package/src/val/CopyFuncVal.ts +1 -1
  146. package/src/val/Decimal.ts +1 -1
  147. package/src/val/DisjunctVal.ts +1 -37
  148. package/src/val/ExpectVal.ts +1 -1
  149. package/src/val/FeatureVal.ts +1 -1
  150. package/src/val/FuncBaseVal.ts +1 -1
  151. package/src/val/HideFuncVal.ts +1 -1
  152. package/src/val/IntegerVal.ts +2 -2
  153. package/src/val/JunctionVal.ts +1 -1
  154. package/src/val/KeyFuncVal.ts +1 -1
  155. package/src/val/ListVal.ts +3 -5
  156. package/src/val/LowerFuncVal.ts +1 -1
  157. package/src/val/MapVal.ts +7 -5
  158. package/src/val/MoveFuncVal.ts +1 -1
  159. package/src/val/NilVal.ts +13 -3
  160. package/src/val/NullVal.ts +1 -1
  161. package/src/val/NumberVal.ts +2 -2
  162. package/src/val/OpBaseVal.ts +10 -10
  163. package/src/val/OpenFuncVal.ts +1 -1
  164. package/src/val/PathFuncVal.ts +1 -1
  165. package/src/val/PlusOpVal.ts +1 -1
  166. package/src/val/PrefFuncVal.ts +1 -1
  167. package/src/val/PrefVal.ts +4 -3
  168. package/src/val/RefVal.ts +82 -9
  169. package/src/val/ScalarKindVal.ts +8 -2
  170. package/src/val/ScalarVal.ts +2 -2
  171. package/src/val/StringVal.ts +1 -1
  172. package/src/val/SuperFuncVal.ts +1 -1
  173. package/src/val/TopVal.ts +1 -1
  174. package/src/val/TypeFuncVal.ts +1 -1
  175. package/src/val/UpperFuncVal.ts +1 -1
  176. package/src/val/Val.ts +13 -8
  177. package/src/val/VarVal.ts +1 -1
  178. package/src/val/numcmp.ts +189 -0
  179. package/src/val/numkind.ts +1 -1
@@ -20,7 +20,6 @@ import {
20
20
  explainOpen,
21
21
  ec,
22
22
  explainClose,
23
- items,
24
23
  } from '../utility'
25
24
 
26
25
  import { makeNilErr, AontuError } from '../err'
@@ -33,7 +32,6 @@ import {
33
32
  import { ConjunctVal } from './ConjunctVal'
34
33
  import { NilVal } from './NilVal'
35
34
  import { BagVal } from './BagVal'
36
- import { empty } from './Val'
37
35
 
38
36
 
39
37
  class ListVal extends BagVal {
@@ -121,9 +119,9 @@ class ListVal extends BagVal {
121
119
 
122
120
  propagateMarks(this, child)
123
121
 
122
+ // child is non-nullish: propagateMarks above dereferences it.
124
123
  out.peg[key] =
125
- undefined === child ? key_spread_cj :
126
- child.isNil ? child :
124
+ child.isNil ? child :
127
125
  key_spread_cj.isNil ? key_spread_cj :
128
126
  key_spread_cj.isTop && child.done ? child :
129
127
  child.isTop && key_spread_cj.done ? key_spread_cj :
@@ -271,7 +269,7 @@ class ListVal extends BagVal {
271
269
  this.peg[k].canon).join(',') +
272
270
  ']'
273
271
  }
274
- }
272
+ } /* node:coverage ignore next 8 */
275
273
 
276
274
 
277
275
 
@@ -82,7 +82,7 @@ class LowerFuncVal extends FuncBaseVal {
82
82
  super.superior()
83
83
  }
84
84
 
85
- }
85
+ } /* node:coverage ignore next 6 */
86
86
 
87
87
 
88
88
  export {
package/src/val/MapVal.ts CHANGED
@@ -42,7 +42,7 @@ import { cmpCodePoint } from '../keyorder'
42
42
  // pass. The map lives on the unify root ctx (see Unify), so it persists
43
43
  // across fixpoint passes and is GC'd with the run.
44
44
  function spreadSnapKey(cj: any): string {
45
- return cj.canon + '~' + (cj.site?.row ?? -1) + ':' + (cj.site?.col ?? -1)
45
+ return cj.canon + '~' + cj.site.row + ':' + cj.site.col
46
46
  }
47
47
 
48
48
  // Snapshot a path-dependent ref spread to its structural target once,
@@ -229,7 +229,9 @@ class MapVal extends BagVal {
229
229
  // but costs O(keys) deep template clones per pass on large
230
230
  // models — the dominant cost on generated-SDK model trees.
231
231
  let oval: Val
232
- if (undefined !== child && !spread_cj.isTop
232
+ // No `undefined !== child` here: propagateMarks above already
233
+ // dereferenced it, so a missing child would have thrown there.
234
+ if (!spread_cj.isTop
233
235
  && (child as any)._spr === (spread_cj as any).id) {
234
236
  oval = child.done ? child :
235
237
  unite(te ? keyctx.clone({ explain: ec(te, 'KEY:' + key) }) : keyctx,
@@ -239,9 +241,9 @@ class MapVal extends BagVal {
239
241
  else {
240
242
  const key_spread_cj = spread_cj.spreadClone(keyctx)
241
243
 
244
+ // child is non-nullish: propagateMarks above dereferences it.
242
245
  oval =
243
- undefined === child ? key_spread_cj :
244
- child.isNil ? child :
246
+ child.isNil ? child :
245
247
  key_spread_cj.isNil ? key_spread_cj :
246
248
  key_spread_cj.isTop && child.done ? child :
247
249
  child.isTop && key_spread_cj.done ? key_spread_cj :
@@ -449,7 +451,7 @@ class MapVal extends BagVal {
449
451
  return this.spread.cj ? '&:' + this.spread.cj.inspect(null == d ? 0 : d + 1) : ''
450
452
  }
451
453
 
452
- }
454
+ } /* node:coverage ignore next 6 */
453
455
 
454
456
 
455
457
  export {
@@ -92,7 +92,7 @@ class MoveFuncVal extends FuncBaseVal {
92
92
 
93
93
  return out
94
94
  }
95
- }
95
+ } /* node:coverage ignore next 6 */
96
96
 
97
97
 
98
98
  export {
package/src/val/NilVal.ts CHANGED
@@ -18,6 +18,8 @@ import { Val, EMPTY_ERR } from './Val'
18
18
 
19
19
  import { AontuError, descErr } from '../err'
20
20
 
21
+ import { codeClass } from '../hints'
22
+
21
23
 
22
24
  class NilVal extends Val {
23
25
  isNil = true
@@ -98,10 +100,10 @@ class NilVal extends Val {
98
100
  if (spec && 'object' === typeof spec) {
99
101
  this.why = spec?.why
100
102
  this.msg = 'string' === typeof spec?.msg ? spec.msg : this.msg
101
- this.err = spec ?
103
+ this.err =
102
104
  Array.isArray(spec.err) ? [...spec.err] :
103
105
  null != spec.err ? [spec.err] :
104
- EMPTY_ERR : EMPTY_ERR
106
+ EMPTY_ERR
105
107
  }
106
108
 
107
109
  // Nil is always DONE, by definition.
@@ -135,6 +137,14 @@ class NilVal extends Val {
135
137
  }
136
138
 
137
139
 
140
+ // The code's class from the shared registry (test/spec/errcodes.tsv):
141
+ // conflict | incomplete | reference | parse | budget | internal.
142
+ // A why-less nil classifies as its eventual gen-time code, nil_gen.
143
+ get class(): string {
144
+ return codeClass(null == this.why ? 'nil_gen' : String(this.why))
145
+ }
146
+
147
+
138
148
  gen(ctx: AontuContext) {
139
149
  // Unresolved nil cannot be generated, so always an error.
140
150
 
@@ -174,7 +184,7 @@ class NilVal extends Val {
174
184
  //
175
185
  // Do NOT use this sentinel for errors that may surface: those need
176
186
  // real NilVals with proper site/path info for descErr formatting.
177
- const TRIAL_NIL = new NilVal({ why: '|:trial-nil' })
187
+ const TRIAL_NIL = new NilVal({ why: '|:trial-nil' }) /* node:coverage ignore next 7 */
178
188
 
179
189
 
180
190
  export {
@@ -29,7 +29,7 @@ class NullVal extends ScalarVal {
29
29
  unify(peer: Val, ctx: AontuContext): Val {
30
30
  return super.unify(peer, ctx)
31
31
  }
32
- }
32
+ } /* node:coverage ignore next 7 */
33
33
 
34
34
 
35
35
  export {
@@ -49,7 +49,7 @@ class NumberVal extends ScalarVal {
49
49
  let out: Val = this
50
50
 
51
51
  if (null != peer) {
52
- if (peer.isScalarKind) {
52
+ if (peer.isScalarKind || (peer as any).isConstraint) {
53
53
  out = peer.unify(this, ctx)
54
54
  }
55
55
  else if (
@@ -95,7 +95,7 @@ class NumberVal extends ScalarVal {
95
95
  s.includes('N') ||
96
96
  s.includes('I')) ? s : s + '.0'
97
97
  }
98
- }
98
+ } /* node:coverage ignore next 6 */
99
99
 
100
100
 
101
101
  export {
@@ -67,7 +67,11 @@ class OpBaseVal extends FeatureVal {
67
67
 
68
68
  unify(peer: Val, ctx: AontuContext): Val {
69
69
  const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Op:' + this.opname(), this, peer)
70
- let out: Val = this
70
+ // Declared without an initial value: every arm below assigns it, and
71
+ // seeding it with `this` made the two arms that stand the op read as
72
+ // redundant self-assignments. The arms themselves stay as they are —
73
+ // they mirror the dispatch switch in go/op.go arm for arm (ADR-001).
74
+ let out: Val
71
75
 
72
76
  if (this.id == peer.id) {
73
77
  return this
@@ -88,16 +92,12 @@ class OpBaseVal extends FeatureVal {
88
92
  // console.log('OPVAL', this.id, this.opname(), pegdone, newpeg.map(p => p.canon))
89
93
 
90
94
  if (pegdone) {
91
- let result: Val | undefined = null == ctx ? this : this.operate(ctx, newpeg)
92
-
93
- result = result || this
94
-
95
- if (null == result && this.canon === peer.canon) {
96
- out = this
97
- }
95
+ // `|| this` makes result truthy, so an op that cannot compute yet
96
+ // takes the OpBaseVal arm below rather than a separate null arm.
97
+ let result: Val = this.operate(ctx, newpeg) || this
98
98
 
99
99
  // TODO: should be result.isOp
100
- else if (result instanceof OpBaseVal) {
100
+ if (result instanceof OpBaseVal) {
101
101
  if (peer.isTop) {
102
102
  out = this
103
103
  }
@@ -223,7 +223,7 @@ class OpBaseVal extends FeatureVal {
223
223
 
224
224
  return undefined
225
225
  }
226
- }
226
+ } /* node:coverage ignore next 6 */
227
227
 
228
228
 
229
229
  export {
@@ -52,7 +52,7 @@ class OpenFuncVal extends FuncBaseVal {
52
52
  return argval
53
53
  }
54
54
 
55
- }
55
+ } /* node:coverage ignore next 6 */
56
56
 
57
57
 
58
58
  export {
@@ -75,7 +75,7 @@ class PathFuncVal extends FuncBaseVal {
75
75
  return out
76
76
  }
77
77
 
78
- }
78
+ } /* node:coverage ignore next 6 */
79
79
 
80
80
 
81
81
  export {
@@ -237,7 +237,7 @@ function integer(v: any, k: OpKind): bigint {
237
237
  // Scale 0 normalises to the one decimal place the leaf keeps.
238
238
  function decimal(v: any, k: OpKind): Decimal {
239
239
  return 'bigdecimal' === k ? v.peg : new Decimal(integer(v, k), 0)
240
- }
240
+ } /* node:coverage ignore next 6 */
241
241
 
242
242
 
243
243
  export {
@@ -65,7 +65,7 @@ class PrefFuncVal extends FuncBaseVal {
65
65
  return out
66
66
  }
67
67
 
68
- }
68
+ } /* node:coverage ignore next 6 */
69
69
 
70
70
 
71
71
  export {
@@ -114,7 +114,6 @@ class PrefVal extends FeatureVal {
114
114
  peer = peer ?? top()
115
115
 
116
116
  const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Pref', this, peer)
117
- let done = true
118
117
  let out: Val = this
119
118
  let why = ''
120
119
 
@@ -180,7 +179,9 @@ class PrefVal extends FeatureVal {
180
179
  why += 'none'
181
180
  }
182
181
 
183
- out.dc = done ? DONE : this.dc + 1
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
184
185
 
185
186
  // console.log('PREFVAL-OUT', why, this.canon, peer.canon, '->', out.canon, out.done)
186
187
 
@@ -226,7 +227,7 @@ class PrefVal extends FeatureVal {
226
227
 
227
228
  return val.gen(ctx)
228
229
  }
229
- }
230
+ } /* node:coverage ignore next 6 */
230
231
 
231
232
 
232
233
  export {
package/src/val/RefVal.ts CHANGED
@@ -68,8 +68,9 @@ class RefVal extends FeatureVal {
68
68
  super(spec, ctx)
69
69
  this.peg = []
70
70
 
71
- this.absolute = true === this.absolute ? true : // absolute sticks
72
- true === spec.absolute ? true : false
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
73
74
 
74
75
  this.prefix = true === spec.prefix
75
76
 
@@ -181,14 +182,13 @@ class RefVal extends FeatureVal {
181
182
  // TODO: not resolved when all Vals in path are done is an error
182
183
  // as path cannot be found
183
184
  // let resolved: Val | undefined = null == ctx ? this : ctx.find(this)
184
- let found: Val | undefined = null == ctx ? this : this.find(ctx)
185
+ let found: Val | undefined = this.find(ctx)
185
186
 
187
+ // `?? this` makes resolved non-nullish, so an unresolved reference
188
+ // takes the RefVal arm below rather than a separate null arm.
186
189
  const resolved = found ?? this
187
190
 
188
- if (null == resolved && this.canon === peer.canon) {
189
- out = this
190
- }
191
- else if (resolved instanceof RefVal) {
191
+ if (resolved instanceof RefVal) {
192
192
  if (peer.isTop) {
193
193
  out = this
194
194
  why = 'pt'
@@ -413,8 +413,16 @@ class RefVal extends FeatureVal {
413
413
  else if (pI === refpath.length) {
414
414
  out = node
415
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
+ }
416
424
  // Types and hidden values are cloned and made concrete
417
- if (null != out) { // && (out.mark.type || out.mark.hide)) {
425
+ else if (null != out) { // && (out.mark.type || out.mark.hide)) {
418
426
 
419
427
  // console.log('FOUND-A', out)
420
428
 
@@ -456,6 +464,71 @@ class RefVal extends FeatureVal {
456
464
  }
457
465
 
458
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
+
459
532
  same(peer: Val): boolean {
460
533
  return null == peer ? false : this.peg === peer.peg
461
534
  }
@@ -509,7 +582,7 @@ class RefVal extends FeatureVal {
509
582
  ].filter(p => '' != p).join(',')
510
583
  }
511
584
 
512
- }
585
+ } /* node:coverage ignore next 6 */
513
586
 
514
587
 
515
588
  export {
@@ -148,7 +148,13 @@ class ScalarKindVal extends FeatureVal {
148
148
 
149
149
  let out: Val = this
150
150
 
151
- if (peerIsScalarVal) {
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) {
152
158
  let peerKind = (peer as any).kind
153
159
 
154
160
  // A kind admits a concrete value of that kind, or of any kind
@@ -213,7 +219,7 @@ class ScalarKindVal extends FeatureVal {
213
219
  }
214
220
 
215
221
 
216
- }
222
+ } /* node:coverage ignore next 15 */
217
223
 
218
224
 
219
225
  export {
@@ -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) {
@@ -121,7 +121,7 @@ class ScalarVal extends Val {
121
121
  }))
122
122
  }
123
123
 
124
- }
124
+ } /* node:coverage ignore next 6 */
125
125
 
126
126
 
127
127
  export {
@@ -30,7 +30,7 @@ class StringVal extends ScalarVal {
30
30
  return JSON.stringify(this.peg)
31
31
  }
32
32
 
33
- }
33
+ } /* node:coverage ignore next 5 */
34
34
 
35
35
  export {
36
36
  StringVal,
@@ -51,7 +51,7 @@ class SuperFuncVal extends FuncBaseVal {
51
51
  return this.place(this.superior())
52
52
  }
53
53
 
54
- }
54
+ } /* node:coverage ignore next 6 */
55
55
 
56
56
 
57
57
  export {
package/src/val/TopVal.ts CHANGED
@@ -61,7 +61,7 @@ class TopVal extends Val {
61
61
  return undefined
62
62
  }
63
63
 
64
- }
64
+ } /* node:coverage ignore next 6 */
65
65
 
66
66
 
67
67
  export {
@@ -61,7 +61,7 @@ class TypeFuncVal extends FuncBaseVal {
61
61
 
62
62
  return out
63
63
  }
64
- }
64
+ } /* node:coverage ignore next 6 */
65
65
 
66
66
 
67
67
  export {
@@ -81,7 +81,7 @@ class UpperFuncVal extends FuncBaseVal {
81
81
  })) :
82
82
  super.superior()
83
83
  }
84
- }
84
+ } /* node:coverage ignore next 6 */
85
85
 
86
86
 
87
87
  export {
package/src/val/Val.ts CHANGED
@@ -148,11 +148,13 @@ abstract class Val {
148
148
 
149
149
  deps?: any
150
150
 
151
- #ctx: any
151
+ // TS-private (as _site above): the `#` form emits downlevel helper
152
+ // functions whose branches no supported Node can execute.
153
+ private _ctx: any
152
154
 
153
155
  // TODO: Site needed in ctor
154
156
  constructor(spec: ValSpec, ctx?: AontuContext) {
155
- this.#ctx = ctx
157
+ this._ctx = ctx
156
158
 
157
159
  this.peg = spec?.peg
158
160
 
@@ -179,7 +181,7 @@ abstract class Val {
179
181
 
180
182
 
181
183
  ctx() {
182
- return this.#ctx
184
+ return this._ctx
183
185
  }
184
186
 
185
187
 
@@ -217,9 +219,12 @@ abstract class Val {
217
219
 
218
220
  out.dc = this.done ? DONE : out.dc
219
221
 
220
- out.site.row = spec?.row ?? this.site.row ?? -1
221
- out.site.col = spec?.col ?? this.site.col ?? -1
222
- out.site.url = spec?.url ?? this.site.url ?? ''
222
+ // this.site is a lazy getter that always yields a Site, and Site's
223
+ // constructor coerces row/col to numbers and url to a string, so the
224
+ // spec value is the only one that can be absent.
225
+ out.site.row = spec?.row ?? this.site.row
226
+ out.site.col = spec?.col ?? this.site.col
227
+ out.site.url = spec?.url ?? this.site.url
223
228
 
224
229
  out.mark = Object.assign({}, this.mark, fullspec.mark ?? {})
225
230
  out.mark.type = this.mark.type && (fullspec.mark?.type ?? true)
@@ -427,7 +432,7 @@ function inspectpeg(peg: any, d: number) {
427
432
  ('{' +
428
433
  Object.entries(peg).map((n: any) =>
429
434
  '\n ' + indent + n[0] + ': ' + // n[1].inspect(d)
430
- (n[1].inspect(d) ?? '' + n[1])
435
+ n[1].inspect(d)
431
436
  ).join(',') +
432
437
  '\n' + indent + '}')
433
438
  )
@@ -448,7 +453,7 @@ function empty(o: any) {
448
453
  || (null != o && 'object' === typeof o && 0 === Object.keys(o).length)
449
454
  || false
450
455
  )
451
- }
456
+ } /* node:coverage ignore next 16 */
452
457
 
453
458
 
454
459
 
package/src/val/VarVal.ts CHANGED
@@ -189,7 +189,7 @@ class VarVal extends FeatureVal {
189
189
 
190
190
  return undefined
191
191
  }
192
- }
192
+ } /* node:coverage ignore next 6 */
193
193
 
194
194
 
195
195
  export {