bireactive 0.3.1 → 0.3.3

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 (95) hide show
  1. package/README.md +14 -7
  2. package/dist/automerge/doc-cell.d.ts +24 -11
  3. package/dist/automerge/doc-cell.js +19 -13
  4. package/dist/automerge/index.d.ts +3 -2
  5. package/dist/automerge/index.js +6 -5
  6. package/dist/automerge/reconcile.d.ts +5 -2
  7. package/dist/automerge/reconcile.js +73 -15
  8. package/dist/core/_counts.js +5 -12
  9. package/dist/core/cell.d.ts +3 -3
  10. package/dist/core/cell.js +6 -7
  11. package/dist/core/derived-geometry.js +4 -7
  12. package/dist/core/index.d.ts +3 -1
  13. package/dist/core/index.js +3 -1
  14. package/dist/core/lenses/aggregates.d.ts +42 -52
  15. package/dist/core/lenses/aggregates.js +225 -116
  16. package/dist/core/lenses/geometry.d.ts +22 -4
  17. package/dist/core/lenses/geometry.js +59 -27
  18. package/dist/core/lenses/index.d.ts +5 -6
  19. package/dist/core/lenses/index.js +5 -6
  20. package/dist/core/lenses/memory.js +4 -17
  21. package/dist/core/lenses/numerical.d.ts +100 -0
  22. package/dist/core/lenses/{typed-factor.js → numerical.js} +136 -34
  23. package/dist/core/lenses/point-cloud.d.ts +67 -0
  24. package/dist/core/lenses/{closed-form-policies.js → point-cloud.js} +218 -81
  25. package/dist/core/lenses/snap.d.ts +1 -1
  26. package/dist/core/lenses/snap.js +3 -10
  27. package/dist/core/lenses/text.d.ts +40 -0
  28. package/dist/core/lenses/text.js +202 -0
  29. package/dist/core/lifecycle.js +3 -6
  30. package/dist/core/linalg.js +5 -11
  31. package/dist/core/optic.js +10 -15
  32. package/dist/core/optics.js +4 -8
  33. package/dist/core/store.d.ts +1 -2
  34. package/dist/core/store.js +7 -15
  35. package/dist/core/traits.d.ts +4 -7
  36. package/dist/core/traits.js +8 -12
  37. package/dist/core/values/anchor.js +0 -4
  38. package/dist/core/values/arr.d.ts +110 -0
  39. package/dist/core/values/arr.js +336 -0
  40. package/dist/core/values/audio.d.ts +8 -9
  41. package/dist/core/values/audio.js +7 -23
  42. package/dist/core/values/bool.d.ts +11 -11
  43. package/dist/core/values/bool.js +12 -22
  44. package/dist/core/values/box.d.ts +15 -20
  45. package/dist/core/values/box.js +20 -33
  46. package/dist/core/values/canvas.d.ts +18 -25
  47. package/dist/core/values/canvas.js +17 -48
  48. package/dist/core/values/color.d.ts +5 -7
  49. package/dist/core/values/color.js +5 -11
  50. package/dist/core/values/field.d.ts +6 -7
  51. package/dist/core/values/field.js +10 -35
  52. package/dist/core/values/flags.d.ts +1 -2
  53. package/dist/core/values/flags.js +1 -17
  54. package/dist/core/values/gpu.d.ts +6 -10
  55. package/dist/core/values/gpu.js +8 -22
  56. package/dist/core/values/matrix.d.ts +2 -4
  57. package/dist/core/values/matrix.js +2 -12
  58. package/dist/core/values/num.d.ts +19 -28
  59. package/dist/core/values/num.js +23 -41
  60. package/dist/core/values/pose.d.ts +2 -4
  61. package/dist/core/values/pose.js +3 -12
  62. package/dist/core/values/range.d.ts +18 -26
  63. package/dist/core/values/range.js +22 -39
  64. package/dist/core/values/reg/ambiguity.d.ts +8 -0
  65. package/dist/core/values/reg/ambiguity.js +131 -0
  66. package/dist/core/values/reg/engine.d.ts +91 -0
  67. package/dist/core/values/reg/engine.js +373 -0
  68. package/dist/core/values/reg/nfa.d.ts +42 -0
  69. package/dist/core/values/reg/nfa.js +391 -0
  70. package/dist/core/values/reg/regex.d.ts +7 -0
  71. package/dist/core/values/reg/regex.js +318 -0
  72. package/dist/core/values/reg/types.d.ts +60 -0
  73. package/dist/core/values/reg/types.js +3 -0
  74. package/dist/core/values/reg.d.ts +250 -0
  75. package/dist/core/values/reg.js +649 -0
  76. package/dist/core/values/str.d.ts +16 -60
  77. package/dist/core/values/str.js +133 -315
  78. package/dist/core/values/template.js +1 -24
  79. package/dist/core/values/transform.d.ts +3 -5
  80. package/dist/core/values/transform.js +3 -12
  81. package/dist/core/values/tri.d.ts +9 -10
  82. package/dist/core/values/tri.js +9 -15
  83. package/dist/core/values/vec.d.ts +9 -24
  84. package/dist/core/values/vec.js +9 -64
  85. package/dist/index.d.ts +0 -11
  86. package/dist/index.js +1 -11
  87. package/package.json +17 -10
  88. package/dist/coll.d.ts +0 -74
  89. package/dist/coll.js +0 -210
  90. package/dist/core/lenses/closed-form-policies.d.ts +0 -57
  91. package/dist/core/lenses/decompositions.d.ts +0 -14
  92. package/dist/core/lenses/decompositions.js +0 -224
  93. package/dist/core/lenses/domain-aggregates.d.ts +0 -42
  94. package/dist/core/lenses/domain-aggregates.js +0 -245
  95. package/dist/core/lenses/typed-factor.d.ts +0 -40
@@ -12,15 +12,14 @@ export declare const sub: (a: V, b: V) => V;
12
12
  export declare const scale: (a: V, k: number) => V;
13
13
  export declare const lerp: (a: V, b: V, t: number) => V;
14
14
  export declare const equals: (a: V, b: V) => boolean;
15
- /** L2 distance over (lo, hi). Treats a range as a point in 2-space. */
15
+ /** Euclidean distance over (lo, hi). */
16
16
  export declare const metric: (a: V, b: V) => number;
17
17
  export declare const width: (r: V) => number;
18
18
  export declare const center: (r: V) => number;
19
19
  export declare const contains: (r: V, v: number) => boolean;
20
20
  export declare const clamp: (r: V, v: number) => number;
21
- /** Closest value STRICTLY outside `[lo, hi]`, displaced past the
22
- * nearest endpoint by `eps`. Used by `Range#contains` as the bwd's
23
- * false-side policy. */
21
+ /** Closest value strictly outside `[lo, hi]`, displaced past the nearest
22
+ * endpoint by `eps`. */
24
23
  export declare const eject: (r: V, v: number, eps?: number) => number;
25
24
  /** Sample at parameter `t`: `lo + t·(hi - lo)`. `t ∈ [0, 1]` stays
26
25
  * inside the range; values outside extrapolate linearly. */
@@ -43,43 +42,36 @@ export declare class Range extends Cell<V> {
43
42
  /** End endpoint. Writes preserve `lo` (end-knob semantics). */
44
43
  get hi(): this extends WritableBrand ? Writable<Num> : Num;
45
44
  get width(): Num;
46
- /** Midpoint body-drag: read returns the center; write shifts the range
47
- * so the center matches (width preserved). `.start` is the lo-anchored
48
- * variant; `.lo` / `.hi` edit the endpoints. */
45
+ /** Midpoint body-drag: reads the center; a write shifts the range so the
46
+ * center matches (width preserved). */
49
47
  get center(): Writable<Num>;
50
- /** Translate by `by`. Reads shift the interval; writes shift back. */
48
+ /** Translate by `by`. */
51
49
  shift(by: Val<number>): this;
52
- /** Scale uniformly about the origin. Iso for `k ≠ 0`. */
50
+ /** Scale about the origin. Invertible when k ≠ 0. */
53
51
  scale(k: Val<number>): this;
54
- /** Body-drag handle: read returns `lo`; write shifts the range so `lo`
55
- * matches (width preserved). For start-knob editing use `.lo`. */
52
+ /** Body-drag handle: reads `lo`; a write shifts the range so `lo` matches
53
+ * (width preserved). */
56
54
  get start(): Writable<Num>;
57
55
  /** RO sample at `t`. `t ∈ [0, 1]` stays inside; outside extrapolates. */
58
56
  sample(t: Val<number>): Num;
59
57
  /** Bidirectional `t ↔ value` slider. Read `lo + t·(hi - lo)`; write
60
58
  * solves for `t` and updates `t` only, leaving `lo` / `hi` put. */
61
59
  slider(t: Writable<Num>): Writable<Num>;
62
- /** Membership predicate. Conditional return type: a writable `Num`
63
- * yields `Writable<Bool>` and flipping the view bumps the source
64
- * (`true` clamps into `[lo, hi]`, `false` ejects past the nearest
65
- * endpoint by `eps`). Literal / RO inputs yield a bare RO `Bool`. */
60
+ /** True when `v` is in `[lo, hi]`. A writable `Num` yields a `Writable<Bool>`:
61
+ * flipping it clamps `v` inside (`true`) or ejects it past the nearest
62
+ * endpoint (`false`). Literal/RO inputs yield a read-only `Bool`. */
66
63
  contains<P extends Val<number>>(v: P): P extends WritableBrand ? Writable<Bool> : Bool;
67
- /** RO clamp: read `v` into `[lo, hi]`. For a writable clamping lens
68
- * on a single Num, see `Num#clamp(lo, hi)`. */
64
+ /** Read-only clamp of `v` into `[lo, hi]`. */
69
65
  clampedRead(v: Val<number>): Num;
70
66
  /** Inverse of `sample`: derive the `t` that would produce `v`. */
71
67
  paramOf(v: Val<number>): Num;
72
- /** Tween-builder; animates `{lo, hi}` jointly. */
68
+ /** Tween-builder. */
73
69
  to(this: Writable<Range>, target: V, dur: Val<number>, ease?: Easing): Tween<V>;
74
70
  }
75
- /** Range over `[at, at + dur]`, parameterised by start + duration. The
76
- * timeline-clip shape: `.lo` slides the start, `.hi` the end, `.start`
77
- * body-drags (preserving width). Backed by the live `at` / `dur` Nums. */
71
+ /** Range over `[at, at + dur]`, backed by the live `at` and `dur` Nums. */
78
72
  export declare function span(at: Writable<Num>, dur: Writable<Num>): Writable<Range>;
79
- /** Writable `Range` over `[lo, hi]`. Each endpoint is a literal `number`
80
- * (lifted to a fresh seed) or an existing `Writable<Num>` (identity
81
- * passthrough). RO sources are rejected at the type level — use
82
- * `Range.derive(...)` for reactive RO tracking, or `cell.value` to
83
- * snapshot. Lock an endpoint with `Num.pin(c)`. */
73
+ /** Writable `Range` over `[lo, hi]`. Each endpoint is a literal (new cell) or
74
+ * existing writable (passed through); for read-only sources use `Range.derive`.
75
+ * Lock an endpoint with `Num.pin`. */
84
76
  export declare function range(lo?: Init<Num>, hi?: Init<Num>): Writable<Range>;
85
77
  export {};
@@ -1,10 +1,3 @@
1
- // range.ts — reactive numeric interval `[lo, hi]`.
2
- //
3
- // Home for sliders, scrollbars, and timeline clip spans. Field lenses
4
- // give start-knob (`.lo`) and end-knob (`.hi`) drag; `.start` / `.center`
5
- // are body-drags (shift both, preserving width — anchored at lo / midpoint
6
- // respectively); `.slider(t)` is the bidirectional `t ↔ lo + t·(hi - lo)`
7
- // iso. Traits: `linear`, `lerp`, `equals`, `pack` (scalar-only).
8
1
  import { tween } from "../../animation/index.js";
9
2
  import { Cell, cachedDerive, fieldLens, isReadonly, reader, readNow, SKIP, } from "../cell.js";
10
3
  import { Bool } from "./bool.js";
@@ -17,15 +10,14 @@ export const lerp = (a, b, t) => ({
17
10
  hi: a.hi + (b.hi - a.hi) * t,
18
11
  });
19
12
  export const equals = (a, b) => a === b || (a.lo === b.lo && a.hi === b.hi);
20
- /** L2 distance over (lo, hi). Treats a range as a point in 2-space. */
13
+ /** Euclidean distance over (lo, hi). */
21
14
  export const metric = (a, b) => Math.hypot(a.lo - b.lo, a.hi - b.hi);
22
15
  export const width = (r) => r.hi - r.lo;
23
16
  export const center = (r) => (r.lo + r.hi) / 2;
24
17
  export const contains = (r, v) => v >= r.lo && v <= r.hi;
25
18
  export const clamp = (r, v) => (v < r.lo ? r.lo : v > r.hi ? r.hi : v);
26
- /** Closest value STRICTLY outside `[lo, hi]`, displaced past the
27
- * nearest endpoint by `eps`. Used by `Range#contains` as the bwd's
28
- * false-side policy. */
19
+ /** Closest value strictly outside `[lo, hi]`, displaced past the nearest
20
+ * endpoint by `eps`. */
29
21
  export const eject = (r, v, eps = 1e-6) => {
30
22
  if (!contains(r, v))
31
23
  return v;
@@ -71,21 +63,20 @@ export class Range extends Cell {
71
63
  get width() {
72
64
  return cachedDerive(this, "width", Num, width);
73
65
  }
74
- /** Midpoint body-drag: read returns the center; write shifts the range
75
- * so the center matches (width preserved). `.start` is the lo-anchored
76
- * variant; `.lo` / `.hi` edit the endpoints. */
66
+ /** Midpoint body-drag: reads the center; a write shifts the range so the
67
+ * center matches (width preserved). */
77
68
  get center() {
78
69
  return Num.lens(this, center, (c, src) => {
79
70
  const half = (src.hi - src.lo) / 2;
80
71
  return { lo: c - half, hi: c + half };
81
72
  });
82
73
  }
83
- /** Translate by `by`. Reads shift the interval; writes shift back. */
74
+ /** Translate by `by`. */
84
75
  shift(by) {
85
76
  const f = reader(by);
86
77
  return this.lens(v => ({ lo: v.lo + f(), hi: v.hi + f() }), n => ({ lo: n.lo - f(), hi: n.hi - f() }));
87
78
  }
88
- /** Scale uniformly about the origin. Iso for `k ≠ 0`. */
79
+ /** Scale about the origin. Invertible when k ≠ 0. */
89
80
  scale(k) {
90
81
  const kf = reader(k);
91
82
  return this.lens(v => {
@@ -96,8 +87,8 @@ export class Range extends Cell {
96
87
  return { lo: n.lo / k, hi: n.hi / k };
97
88
  });
98
89
  }
99
- /** Body-drag handle: read returns `lo`; write shifts the range so `lo`
100
- * matches (width preserved). For start-knob editing use `.lo`. */
90
+ /** Body-drag handle: reads `lo`; a write shifts the range so `lo` matches
91
+ * (width preserved). */
101
92
  get start() {
102
93
  return Num.lens(this, v => v.lo, (newLo, src) => ({ lo: newLo, hi: newLo + (src.hi - src.lo) }));
103
94
  }
@@ -108,21 +99,19 @@ export class Range extends Cell {
108
99
  /** Bidirectional `t ↔ value` slider. Read `lo + t·(hi - lo)`; write
109
100
  * solves for `t` and updates `t` only, leaving `lo` / `hi` put. */
110
101
  slider(t) {
111
- // `this as Range` pins the tuple element type (polymorphic `this`
112
- // defeats the mapped-tuple inference on `[this, t]`).
102
+ // `this as Range` pins the tuple element type; polymorphic `this` breaks
103
+ // the mapped-tuple inference.
113
104
  return Num.lens([this, t], ([r, tv]) => sample(r, tv), (v, [r]) => {
114
105
  const w = r.hi - r.lo;
115
106
  return [SKIP, w === 0 ? 0 : (v - r.lo) / w];
116
107
  });
117
108
  }
118
- /** Membership predicate. Conditional return type: a writable `Num`
119
- * yields `Writable<Bool>` and flipping the view bumps the source
120
- * (`true` clamps into `[lo, hi]`, `false` ejects past the nearest
121
- * endpoint by `eps`). Literal / RO inputs yield a bare RO `Bool`. */
109
+ /** True when `v` is in `[lo, hi]`. A writable `Num` yields a `Writable<Bool>`:
110
+ * flipping it clamps `v` inside (`true`) or ejects it past the nearest
111
+ * endpoint (`false`). Literal/RO inputs yield a read-only `Bool`. */
122
112
  contains(v) {
123
113
  if (v instanceof Num) {
124
- // RO Num has no backward path RO branch. Sources and
125
- // writable lenses both accept write-back.
114
+ // RO Num has no backward path; only writable Nums accept write-back.
126
115
  if (!isReadonly(v)) {
127
116
  return Bool.lens([this, v], (vals) => contains(vals[0], vals[1]), (target, vals) => {
128
117
  const [r, n] = vals;
@@ -134,8 +123,7 @@ export class Range extends Cell {
134
123
  }
135
124
  return Bool.derive(() => contains(this.value, readNow(v)));
136
125
  }
137
- /** RO clamp: read `v` into `[lo, hi]`. For a writable clamping lens
138
- * on a single Num, see `Num#clamp(lo, hi)`. */
126
+ /** Read-only clamp of `v` into `[lo, hi]`. */
139
127
  clampedRead(v) {
140
128
  return Num.derive(() => clamp(this.value, readNow(v)));
141
129
  }
@@ -143,27 +131,22 @@ export class Range extends Cell {
143
131
  paramOf(v) {
144
132
  return Num.derive(() => paramOf(this.value, readNow(v)));
145
133
  }
146
- /** Tween-builder; animates `{lo, hi}` jointly. */
134
+ /** Tween-builder. */
147
135
  to(target, dur, ease) {
148
136
  return tween(this, target, dur, ease);
149
137
  }
150
138
  }
151
- /** @internal 2-input lens over two writable `Num`s; `range()` delegates
152
- * here after lifting literals. */
139
+ /** Lens combining two writable `Num`s into a `Range`. */
153
140
  function ends(lo, hi) {
154
141
  return Range.lens([lo, hi], (vals) => ({ lo: vals[0], hi: vals[1] }), (target) => [target.lo, target.hi]);
155
142
  }
156
- /** Range over `[at, at + dur]`, parameterised by start + duration. The
157
- * timeline-clip shape: `.lo` slides the start, `.hi` the end, `.start`
158
- * body-drags (preserving width). Backed by the live `at` / `dur` Nums. */
143
+ /** Range over `[at, at + dur]`, backed by the live `at` and `dur` Nums. */
159
144
  export function span(at, dur) {
160
145
  return Range.lens([at, dur], (vals) => ({ lo: vals[0], hi: vals[0] + vals[1] }), (target) => [target.lo, target.hi - target.lo]);
161
146
  }
162
- /** Writable `Range` over `[lo, hi]`. Each endpoint is a literal `number`
163
- * (lifted to a fresh seed) or an existing `Writable<Num>` (identity
164
- * passthrough). RO sources are rejected at the type level — use
165
- * `Range.derive(...)` for reactive RO tracking, or `cell.value` to
166
- * snapshot. Lock an endpoint with `Num.pin(c)`. */
147
+ /** Writable `Range` over `[lo, hi]`. Each endpoint is a literal (new cell) or
148
+ * existing writable (passed through); for read-only sources use `Range.derive`.
149
+ * Lock an endpoint with `Num.pin`. */
167
150
  export function range(lo = 0, hi = 1) {
168
151
  if (typeof lo === "number" && typeof hi === "number") {
169
152
  return new Range({ lo, hi });
@@ -0,0 +1,8 @@
1
+ import { type Re } from "./engine.js";
2
+ /** A witness in `L(a) ∩ L(b)` (shortest), or `null` if the languages are
3
+ * disjoint. Product BFS over derivative pairs. */
4
+ export declare function intersects(a: Re, b: Re): string | null;
5
+ /** A witness string that `a · b` factors two distinct ways, or `null` if the
6
+ * concatenation is unambiguous. Ambiguous iff some nonempty bridge `t` can
7
+ * both extend a word of `L(a)` and be absorbed into `L(b)`. */
8
+ export declare function concatAmbiguity(a: Re, b: Re): string | null;
@@ -0,0 +1,131 @@
1
+ import { alphabetOf, der, nullable, reKey } from "./engine.js";
2
+ const cp = (c) => String.fromCharCode(c);
3
+ /** Representative code units that distinguish every transition in `a` and `b`
4
+ * (the range endpoints of every char class). Sufficient to realize every
5
+ * reachable derivative pair. */
6
+ function alphaUnion(a, b) {
7
+ const set = alphabetOf(a);
8
+ alphabetOf(b, set);
9
+ return [...set];
10
+ }
11
+ /** Fold the derivative across a string. */
12
+ function applyStr(r, s) {
13
+ let cur = r;
14
+ for (let i = 0; i < s.length && cur.k !== "emp"; i++)
15
+ cur = der(cur, s.charCodeAt(i));
16
+ return cur;
17
+ }
18
+ /** A witness in `L(a) ∩ L(b)` (shortest), or `null` if the languages are
19
+ * disjoint. Product BFS over derivative pairs. */
20
+ export function intersects(a, b) {
21
+ const alpha = alphaUnion(a, b);
22
+ const seen = new Set([`${reKey(a)}|${reKey(b)}`]);
23
+ const queue = [{ a, b, w: "" }];
24
+ for (let head = 0; head < queue.length; head++) {
25
+ const { a: da, b: db, w } = queue[head];
26
+ if (nullable(da) && nullable(db))
27
+ return w;
28
+ for (const c of alpha) {
29
+ const na = der(da, c);
30
+ if (na.k === "emp")
31
+ continue;
32
+ const nb = der(db, c);
33
+ if (nb.k === "emp")
34
+ continue;
35
+ const key = `${reKey(na)}|${reKey(nb)}`;
36
+ if (seen.has(key))
37
+ continue;
38
+ seen.add(key);
39
+ queue.push({ a: na, b: nb, w: w + cp(c) });
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ /** All reachable derivative states of `r`, each with a shortest word reaching
45
+ * it (BFS over the derivative automaton). */
46
+ function reachableStates(r) {
47
+ const alpha = [...alphabetOf(r)];
48
+ const out = new Map([[reKey(r), { re: r, word: "" }]]);
49
+ const queue = [{ re: r, word: "" }];
50
+ for (let head = 0; head < queue.length; head++) {
51
+ const { re, word } = queue[head];
52
+ for (const c of alpha) {
53
+ const d = der(re, c);
54
+ if (d.k === "emp")
55
+ continue;
56
+ const k = reKey(d);
57
+ if (out.has(k))
58
+ continue;
59
+ const w = word + cp(c);
60
+ out.set(k, { re: d, word: w });
61
+ queue.push({ re: d, word: w });
62
+ }
63
+ }
64
+ return out;
65
+ }
66
+ const SET_KEY = (states) => states.map(reKey).sort().join(",");
67
+ const dedup = (states) => {
68
+ const seen = new Set();
69
+ const out = [];
70
+ for (const s of states) {
71
+ const k = reKey(s);
72
+ if (!seen.has(k)) {
73
+ seen.add(k);
74
+ out.push(s);
75
+ }
76
+ }
77
+ return out;
78
+ };
79
+ // A generous bound: if the product search explodes past this, refuse to certify
80
+ // (sound — we reject rather than risk admitting an ambiguous grammar).
81
+ const MAX_STATES = 200000;
82
+ /** A witness string that `a · b` factors two distinct ways, or `null` if the
83
+ * concatenation is unambiguous. Ambiguous iff some nonempty bridge `t` can
84
+ * both extend a word of `L(a)` and be absorbed into `L(b)`. */
85
+ export function concatAmbiguity(a, b) {
86
+ const statesA = reachableStates(a);
87
+ const accepting = [];
88
+ for (const st of statesA.values())
89
+ if (nullable(st.re))
90
+ accepting.push(st);
91
+ if (accepting.length === 0)
92
+ return null; // L(a) = ∅: nothing to split
93
+ const alpha = alphaUnion(a, b);
94
+ // Search for a nonempty bridge `t`: state = (set of A-derivatives reached
95
+ // from A's accepting states by `t`, der(b, t)).
96
+ const start = dedup(accepting.map(s => s.re));
97
+ const seen = new Set([`${SET_KEY(start)}|${reKey(b)}`]);
98
+ const queue = [{ sa: start, db: b, t: "" }];
99
+ for (let head = 0; head < queue.length; head++) {
100
+ if (seen.size > MAX_STATES)
101
+ throw new Error("reg: grammar too complex to verify");
102
+ const { sa, db, t } = queue[head];
103
+ if (t.length > 0 && sa.some(nullable)) {
104
+ const v = intersects(db, b); // v ∈ L(b) with t·v ∈ L(b)
105
+ if (v !== null)
106
+ return witnessFor(accepting, t, v);
107
+ }
108
+ for (const c of alpha) {
109
+ const db2 = der(db, c);
110
+ if (db2.k === "emp")
111
+ continue; // t·… can no longer be a prefix of L(b)
112
+ const sa2 = dedup(sa.map(s => der(s, c)).filter(s => s.k !== "emp"));
113
+ if (sa2.length === 0)
114
+ continue; // no accepting continuation on the left
115
+ const key = `${SET_KEY(sa2)}|${reKey(db2)}`;
116
+ if (seen.has(key))
117
+ continue;
118
+ seen.add(key);
119
+ queue.push({ sa: sa2, db: db2, t: t + cp(c) });
120
+ }
121
+ }
122
+ return null;
123
+ }
124
+ /** Assemble the full doubly-parsing string `u·t·v`: pick an accepting `u ∈ L(a)`
125
+ * (shortest known) with `u·t ∈ L(a)`; falls back to `t·v` if none is found. */
126
+ function witnessFor(accepting, t, v) {
127
+ for (const s of accepting)
128
+ if (nullable(applyStr(s.re, t)))
129
+ return s.word + t + v;
130
+ return t + v;
131
+ }
@@ -0,0 +1,91 @@
1
+ /** A set of UTF-16 code units as sorted, merged, inclusive ranges. Negation is
2
+ * resolved at construction, so a set is always a positive union of ranges. */
3
+ export declare class CharSet {
4
+ readonly ranges: ReadonlyArray<readonly [number, number]>;
5
+ private constructor();
6
+ /** Build from arbitrary (possibly overlapping/unsorted) ranges. */
7
+ static of(ranges: ReadonlyArray<readonly [number, number]>): CharSet;
8
+ static char(cp: number): CharSet;
9
+ static range(lo: number, hi: number): CharSet;
10
+ /** The full code-unit alphabet. */
11
+ static full(): CharSet;
12
+ static empty(): CharSet;
13
+ has(cp: number): boolean;
14
+ isEmpty(): boolean;
15
+ union(other: CharSet): CharSet;
16
+ /** Do the two sets share any code unit? (Both are sorted/normalized.) */
17
+ overlaps(other: CharSet): boolean;
18
+ /** Complement against the full code-unit alphabet. */
19
+ complement(): CharSet;
20
+ /** Case-fold (ASCII + via `toUpperCase`/`toLowerCase`) for the `i` flag.
21
+ * Conservative: adds the upper/lower variant of every unit in range. */
22
+ ignoreCase(): CharSet;
23
+ }
24
+ /** A regular expression over code units. `emp` = ∅ (matches nothing), `eps` =
25
+ * ε (matches the empty string). Built only through the smart constructors
26
+ * below so that derivatives stay simplified. */
27
+ export type Re = {
28
+ readonly k: "emp";
29
+ } | {
30
+ readonly k: "eps";
31
+ } | {
32
+ readonly k: "chr";
33
+ readonly set: CharSet;
34
+ } | {
35
+ readonly k: "seq";
36
+ readonly a: Re;
37
+ readonly b: Re;
38
+ } | {
39
+ readonly k: "alt";
40
+ readonly a: Re;
41
+ readonly b: Re;
42
+ } | {
43
+ readonly k: "star";
44
+ readonly r: Re;
45
+ };
46
+ export declare const EMP: Re;
47
+ export declare const EPS: Re;
48
+ export declare function chr(set: CharSet): Re;
49
+ /** Concatenation, simplified: `∅·_ = _·∅ = ∅`, `ε·b = b`, `a·ε = a`. */
50
+ export declare function seq(a: Re, b: Re): Re;
51
+ /** Union, normalized modulo ACI: flatten nested alts and drop duplicate
52
+ * branches, preserving first-occurrence order. The derivative-state set is
53
+ * finite only modulo ACI, so this keeps `der` bounded. Order is preserved (not
54
+ * sorted) to keep greedy/backtracking semantics. */
55
+ export declare function alt(a: Re, b: Re): Re;
56
+ /** Kleene star, simplified: `∅* = ε* = ε`, `(r*)* = r*`. */
57
+ export declare function star(r: Re): Re;
58
+ /** N-ary concatenation (right-nested). */
59
+ export declare function seqAll(parts: readonly Re[]): Re;
60
+ /** N-ary union. */
61
+ export declare function altAll(branches: readonly Re[]): Re;
62
+ /** Bounded repetition `r{lo,hi}` (hi `undefined` = unbounded). */
63
+ export declare function repeat(r: Re, lo: number, hi: number | undefined): Re;
64
+ /** A canonical structural key, used both for ACI dedup in `alt` and for
65
+ * derivative-state dedup during language enumeration. */
66
+ export declare function reKey(r: Re): string;
67
+ /** Does `r` match the empty string? */
68
+ export declare function nullable(r: Re): boolean;
69
+ /** Brzozowski derivative of `r` with respect to code unit `cp`. */
70
+ export declare function der(r: Re, cp: number): Re;
71
+ /** Does `r` match exactly `s[from..to)`? */
72
+ export declare function accepts(r: Re, s: string, from?: number, to?: number): boolean;
73
+ /** Every prefix length `k ≥ 0` such that `r` matches `s[pos..pos+k)`, ascending.
74
+ * This is the backtracking lexer primitive: a leaf can accept several lengths
75
+ * (`\d+` over "123" accepts 1, 2, 3) and the value parser tries them
76
+ * greedily (longest first) with proper fallback. */
77
+ export declare function matchLengths(r: Re, s: string, pos: number): number[];
78
+ /** Characters that can begin a word in `L(r)`. */
79
+ export declare function firstSet(r: Re): CharSet;
80
+ /** Characters that can extend an already-complete match of `r` (the union of
81
+ * the first-sets of every reachable accepting derivative state). Finite and
82
+ * terminating because the derivative-state set is finite modulo ACI. */
83
+ export declare function followLast(r: Re): CharSet;
84
+ /** Representative code units that exercise every char-set boundary in `r`
85
+ * (each range's low/high endpoint). Enough to drive structural exploration
86
+ * without iterating the whole alphabet. */
87
+ export declare function alphabetOf(r: Re, out?: Set<number>): Set<number>;
88
+ /** Enumerate strings in `L(r)` over `alphabet`, shortest-first, up to `maxLen`
89
+ * and `cap` results. Used by the ambiguity oracle to find minimal
90
+ * counterexamples; bounded so it always terminates. */
91
+ export declare function language(r: Re, alphabet: readonly number[], maxLen: number, cap: number): Generator<string>;