aontu 0.58.0 → 0.60.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 (52) hide show
  1. package/dist/aontu.d.ts +1 -1
  2. package/dist/aontu.js +2 -1
  3. package/dist/aontu.js.map +1 -1
  4. package/dist/cli.js +11 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/ctx.d.ts +2 -0
  7. package/dist/ctx.js +2 -0
  8. package/dist/ctx.js.map +1 -1
  9. package/dist/err.js +6 -3
  10. package/dist/err.js.map +1 -1
  11. package/dist/hcanon.js +32 -4
  12. package/dist/hcanon.js.map +1 -1
  13. package/dist/lang.js +55 -1
  14. package/dist/lang.js.map +1 -1
  15. package/dist/lsp.d.ts +1 -1
  16. package/dist/tsconfig.tsbuildinfo +1 -1
  17. package/dist/type.d.ts +2 -0
  18. package/dist/type.js.map +1 -1
  19. package/dist/val/DisjunctVal.js +33 -2
  20. package/dist/val/DisjunctVal.js.map +1 -1
  21. package/dist/val/FuncBaseVal.js +36 -13
  22. package/dist/val/FuncBaseVal.js.map +1 -1
  23. package/dist/val/ListVal.js +9 -1
  24. package/dist/val/ListVal.js.map +1 -1
  25. package/dist/val/PlaceVal.js +5 -1
  26. package/dist/val/PlaceVal.js.map +1 -1
  27. package/dist/val/RecurseVal.js +11 -0
  28. package/dist/val/RecurseVal.js.map +1 -1
  29. package/dist/val/RefVal.d.ts +1 -0
  30. package/dist/val/RefVal.js +39 -3
  31. package/dist/val/RefVal.js.map +1 -1
  32. package/dist/val/ReferFuncVal.js +24 -10
  33. package/dist/val/ReferFuncVal.js.map +1 -1
  34. package/dist/val/Val.d.ts +1 -0
  35. package/dist/val/Val.js +27 -0
  36. package/dist/val/Val.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/aontu.ts +2 -1
  39. package/src/cli.ts +11 -1
  40. package/src/ctx.ts +5 -0
  41. package/src/err.ts +6 -3
  42. package/src/hcanon.ts +32 -4
  43. package/src/lang.ts +47 -1
  44. package/src/type.ts +10 -1
  45. package/src/val/DisjunctVal.ts +33 -2
  46. package/src/val/FuncBaseVal.ts +36 -13
  47. package/src/val/ListVal.ts +9 -1
  48. package/src/val/PlaceVal.ts +5 -1
  49. package/src/val/RecurseVal.ts +11 -0
  50. package/src/val/RefVal.ts +41 -3
  51. package/src/val/ReferFuncVal.ts +24 -10
  52. package/src/val/Val.ts +33 -3
@@ -335,7 +335,15 @@ class ListVal extends BagVal {
335
335
  { mark: spec?.mark, dup: spec?.dup } : {}
336
336
  for (let entry of Object.entries(this.peg)) {
337
337
  out.peg[entry[0]] =
338
- (entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx, childspec) : entry[1]
338
+ (entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx, {
339
+ ...childspec,
340
+ // AN ELEMENT IS A POSITION, exactly as a map's child is
341
+ // (MapVal.clone). Without this an explicitly pathed clone
342
+ // rebased the list and left every element at its source
343
+ // path -- the Go twin descends by index (go/clone.go, the
344
+ // *ListVal arm of clonePathKind).
345
+ path: [...out.path, entry[0]],
346
+ }) : entry[1]
339
347
  }
340
348
  if (this.spread.cj) {
341
349
  out.spread.cj = this.spread.cj.clone(ctx, childspec)
@@ -133,7 +133,11 @@ function hasPlace(v: Val): boolean {
133
133
  // generator's to fill with its OWN source children when it fires.
134
134
  function fillPlace(v: Val, fill: Val, ctx: AontuContext): Val {
135
135
  if (true === (v as any).isPlace) {
136
- return fill
136
+ // A FILL IS A POSITION. The hole knows where it sits in the
137
+ // instance; the datum arriving in it does not, and inserted as it
138
+ // stands it keeps the paths it had at its SOURCE, so every finding
139
+ // under it names a path that does not exist.
140
+ return fill.clone(ctx, { path: [...(v as any).path] })
137
141
  }
138
142
 
139
143
  const peg: any = (v as any).peg
@@ -204,6 +204,17 @@ function bumpRecurse(v: any, xc: number): void {
204
204
  v.xc = Math.max(v.xc, xc)
205
205
  return
206
206
  }
207
+ // A RAW REFERENCE TO A RECURSIVE TARGET IS THE RECURSION, minted or
208
+ // not -- the same reading containsRecurseOf already takes, and the
209
+ // reason bound 2 was inert. A freshly cloned level holds the
210
+ // definition's references UNRESOLVED, so this walk found no
211
+ // residual to stamp and `xc` read 0 at every expansion, in the
212
+ // healthy form too. The seed rides on the reference and the
213
+ // residual minted from it starts there (ts/src/val/RefVal.ts).
214
+ if (true === v.isRef) {
215
+ v.rxc = Math.max(v.rxc ?? 0, xc)
216
+ return
217
+ }
207
218
  const peg: any = v.peg
208
219
  if (true === v.isMap && null != peg) {
209
220
  for (const k of Object.keys(peg)) {
package/src/val/RefVal.ts CHANGED
@@ -107,6 +107,15 @@ class RefVal extends FeatureVal {
107
107
  // after unification (see `canon` below). Not a ValSpec field: it is
108
108
  // a rendering of the settled tree, never a parse-time property.
109
109
  expansion: Val | undefined = undefined
110
+
111
+ // THE RECURSION SEED (use-cases/BUGS.md §57). A reference that names
112
+ // a recursive definition IS the fixpoint reference; it mints a
113
+ // RecurseVal when it resolves. bumpRecurse stamps the expansion
114
+ // depth here, because a freshly cloned level holds the definition's
115
+ // references UNRESOLVED and so has no residual to stamp -- which is
116
+ // why the design's second termination bound read 0 at every
117
+ // expansion. The minted residual starts from this.
118
+ rxc: number = 0
110
119
  prefix: boolean = false
111
120
 
112
121
  constructor(
@@ -329,7 +338,7 @@ class RefVal extends FeatureVal {
329
338
  out = makeNilErr(ctx, 'path_cycle', this)
330
339
  }
331
340
  else {
332
- const rec: any = new RecurseVal({ target } as any, ctx)
341
+ const rec: any = new RecurseVal({ target, xc: this.rxc } as any, ctx)
333
342
  rec.site = this.site
334
343
  rec.path = [...this.path]
335
344
  out = rec
@@ -610,7 +619,8 @@ class RefVal extends FeatureVal {
610
619
  // residual is the resolved form, exactly as at the prefix
611
620
  // positions inside the definition.
612
621
  else if (null != out && !snap && containsRecurseOf(out, this.peg as any)) {
613
- const rec: any = new RecurseVal({ target: [...this.peg] } as any, ctx)
622
+ const rec: any = new RecurseVal(
623
+ { target: [...this.peg], xc: this.rxc } as any, ctx)
614
624
  rec.site = this.site
615
625
  rec.path = [...this.path]
616
626
  out = rec
@@ -653,7 +663,31 @@ class RefVal extends FeatureVal {
653
663
  const lifted = true !== (ctx as any).argsnap
654
664
  || true === out.mark.type || true === out.mark.hide
655
665
 
656
- out = out.clone(ctx)
666
+ // A REFERENCE'S COPY OWNS ITS ARGUMENTS (ADR-025). The copy
667
+ // is a per-destination instance exactly as a spread's or a
668
+ // generator's is, so ADR-005's rule holds here too: nothing
669
+ // path-dependent may be shared between two destinations, or
670
+ // the first destination's resolution answers for them all.
671
+ // The shallow clone shared a call's ARGUMENTS -- so
672
+ // `items: [&: $.entities.User]` over a `close({...})` target
673
+ // gave every element the one inner map, whose path each
674
+ // element rebased in turn, and the constraint that failed at
675
+ // element 2 reported element 0's path (use-cases GAP 8).
676
+ //
677
+ // A STAGED CALL IS THE EXCEPTION, because it has not decided
678
+ // yet. Its arguments are still being driven AT ITS OWN SITE
679
+ // (the staging rule, G8 phase 0), and a copy that owned them
680
+ // would drive its own set at the referring position instead:
681
+ // the relative `.side_effect` in a `match()` would read the
682
+ // referring field's siblings (use-cases/09-agent-tools), and
683
+ // an alias naming an `emit` rule table -- a template, which
684
+ // is exactly a value copied before it resolves -- would read
685
+ // its recursive `%w` as a self-reference. A staged call
686
+ // ANYWHERE in the target counts: what is referenced is
687
+ // usually the conjunct the call sits in, not the call.
688
+ // The copy shares what the source is still settling, and
689
+ // owns the rest.
690
+ out = out.clone(ctx, { dup: !out.holdsStaged })
657
691
 
658
692
  if (lifted) {
659
693
  walk(out, (_key: string | number | undefined, val: Val) => {
@@ -805,6 +839,10 @@ class RefVal extends FeatureVal {
805
839
  ...(spec || {})
806
840
  }) as RefVal)
807
841
  out.expansion = this.expansion
842
+ // The recursion seed travels with the clone: a spread template is
843
+ // cloned per destination, and each clone's residual must start
844
+ // where the level it came from left off.
845
+ out.rxc = this.rxc
808
846
  return out
809
847
  }
810
848
 
@@ -290,13 +290,25 @@ class ReferVal extends FeatureVal {
290
290
  // resolved string should take.
291
291
  settle(ctx: AontuContext, site: Val): Val {
292
292
  if (undefined === this.addr) {
293
- // NOT DONE, unlike `string` or `min(1)`. A refer without an
294
- // address has not done its work — it exists to check one — and
295
- // the pass loop must keep offering it the chance. The cost is
296
- // that a SCHEMA mentioning a link never resolves either, so
297
- // `type({from: refer($.std.Port)})` is not expressible today;
298
- // G4 phase 4 records why, and what it would take.
299
- this.dc = 0
293
+ // DONE while unmet, as `string` and `min(1)` are, and as RelVal
294
+ // has been since it was written (see its constructor). An
295
+ // ADDRESS-LESS refer has nothing to check yet and nothing to
296
+ // refuse: it is its own settled residual, and the meet
297
+ // re-activates it the moment a value arrives, because map
298
+ // merges build the conjunct regardless.
299
+ //
300
+ // NOT-DONE here used to be justified as keeping the pass loop
301
+ // offering the refer a chance -- but that is the job of the
302
+ // OTHER pending branch below, where an address exists and its
303
+ // target has not appeared. This branch has no address to
304
+ // resolve, so staying not-done bought nothing and cost the
305
+ // schema idiom: a `type()` body holding a link never settled,
306
+ // so its mark never transferred, so generation could not skip
307
+ // the marked subtree and raised `mapval_no_gen` naming the
308
+ // definition. `type({p: integer})`, `type({p: path()})` and
309
+ // `type({p: min(1)})` all settled; only a link did not
310
+ // (aontu-lang/aontu#172, G4 phase 4's recorded cost).
311
+ this.dc = DONE
300
312
  return this
301
313
  }
302
314
  // The address is a TREE PATH, resolved from the link's own
@@ -477,11 +489,13 @@ class RelVal extends FeatureVal {
477
489
  super(spec, ctx)
478
490
  this.tval = (spec as any).tval ?? top()
479
491
  this.held = (spec as any).held
480
- // DONE while unmet, deliberately -- the property refer() lacks and
481
- // G4 phase 4 records the cost of: a type() body holding a rel()
492
+ // DONE while unmet, deliberately: a type() body holding a rel()
482
493
  // must SETTLE, or the schema idiom (`dependsOn?: rel($.T)` inside
483
494
  // a vocabulary) leaves the type unresolved and every reference to
484
- // it deferring forever. An unmet rel is its own settled residual,
495
+ // it deferring forever. This was the property refer() lacked --
496
+ // G4 phase 4 recorded the cost -- until 2026-09-07, when an
497
+ // address-less refer was given it too (#172); the two now settle
498
+ // by the same rule, which is what the shared reasoning below is. An unmet rel is its own settled residual,
485
499
  // like `min(1)`; the meet re-activates it whenever a value
486
500
  // arrives, because map merges build the conjunct regardless.
487
501
  this.dc = DONE
package/src/val/Val.ts CHANGED
@@ -44,9 +44,12 @@ type ValSpec = {
44
44
  // depth explicitly: `dup: true` makes FuncBaseVal, PrefVal and
45
45
  // OpBaseVal clone their inner Vals too, and the bag/junction clones
46
46
  // carry the flag down. Set by pack/each template instantiation,
47
- // filter condition testing, and spread application (MapVal/
48
- // ListVal.spreadClone) — never by the residuation or ref-resolution
49
- // clones, whose sharing is pinned behaviour.
47
+ // filter condition testing, spread application (MapVal/
48
+ // ListVal.spreadClone), and REFERENCE RESOLUTION of a target that
49
+ // holds no staged call, whose copy is a per-destination instance
50
+ // too (ADR-025) — never by the residuation clone, whose sharing is
51
+ // pinned behaviour, and never by a copy of something still being
52
+ // settled at its own site, which is what keeps the ghost rows.
50
53
  dup?: boolean,
51
54
 
52
55
 
@@ -440,6 +443,33 @@ abstract class Val {
440
443
  }
441
444
 
442
445
 
446
+ // A STAGED CALL STANDING ANYWHERE IN THIS VALUE (the `staged` flag,
447
+ // G8 phase 0). Such a call has not decided: its arguments are still
448
+ // being driven AT ITS OWN SITE, so a REFERENCE's copy shares it
449
+ // rather than owning a set of arguments it would drive at the
450
+ // referring position instead (RefVal.find, ADR-025). Not cached:
451
+ // unlike isPathDependent this is a fact about the value's current
452
+ // state, and the whole point is that it stops being true.
453
+ get holdsStaged(): boolean {
454
+ if (true === (this as any).staged) {
455
+ return true
456
+ }
457
+ const peg: any = this.peg
458
+ if (Array.isArray(peg)) {
459
+ for (let i = 0; i < peg.length; i++) {
460
+ if (true === peg[i]?.isVal && peg[i].holdsStaged) return true
461
+ }
462
+ }
463
+ else if (null != peg && 'object' === typeof peg) {
464
+ for (const k in peg) {
465
+ if (true === peg[k]?.isVal && peg[k].holdsStaged) return true
466
+ }
467
+ }
468
+ const spreadCj = (this as any).spread?.cj as Val | undefined
469
+ return true === spreadCj?.isVal && (spreadCj as any).holdsStaged
470
+ }
471
+
472
+
443
473
  // PUT A MINTED VALUE WHERE THIS ONE STANDS: the site travels, and so
444
474
  // does provenance, because the two answer one question. A narrowed
445
475
  // disjunction, a lifted kind, a resolved reference -- each is a