@turing-machine-js/machine 7.0.0-alpha.6 → 7.0.0-alpha.7
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/CHANGELOG.md +14 -0
- package/README.md +10 -6
- package/dist/classes/State.d.ts +48 -1
- package/dist/index.cjs +178 -65
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +178 -66
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [7.0.0-alpha.7] - 2026-05-30
|
|
8
|
+
|
|
9
|
+
Seventh v7 pre-release. Lands the `CallFrame` extraction ([#213](https://github.com/mellonis/turing-machine-js/issues/213), [PR #218](https://github.com/mellonis/turing-machine-js/pull/218)) and a `toMermaid` framed-wrapper emit fix ([#223](https://github.com/mellonis/turing-machine-js/issues/223), [PR #224](https://github.com/mellonis/turing-machine-js/pull/224)). Published under the `next` dist-tag: `npm install @turing-machine-js/machine@next`.
|
|
10
|
+
|
|
11
|
+
**Pre-release — the API surface may still shift before stable v7.0.0.** Pin to a specific alpha for reproducibility: `@turing-machine-js/machine@7.0.0-alpha.7`.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`CallFrame extends State`** ([#213](https://github.com/mellonis/turing-machine-js/issues/213)) — `withOverriddenHaltState`'s wrapper is now a first-class `State` subclass instead of a `State` instance aliasing the bare's private `#symbolToDataMap` / `#debugRef`. Transition lookups and `debug` access delegate to the bare. `instanceof State` is preserved (no breaking surface change), and `instanceof CallFrame` becomes the wrapper discriminator. `CallFrame` is exported additively from the package root.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **`toMermaid` framed-wrapper emit asymmetry** ([#223](https://github.com/mellonis/turing-machine-js/issues/223)) — `toGraph`'s reach-set previously tunneled through wrappers to their continuation but left the wrappers themselves outside the caller's frame, so framed-wrapper-continuations (e.g. `library-binary-numbers/minusOne`'s `goToNumberStart(invertNumberGoToNumberWithInversion)` inside `invertNumber`'s callable subtree) emitted at the top level, visually disconnected from their owner frame. Fix in `utilities/stateGraph.ts`'s `resolveAndPush` pushes the wrapper itself AND tunnels through `overriddenHaltStateId`, so both join the caller's frame; `utilities/graphFormats.ts` renders framed wrappers inside the owner subgraph with the same `[[…]]` shape. Unframed top-level wrappers still emit outside any subgraph. `library-binary-numbers/states.md` regenerated — only the `minusOne` diagram shape changed.
|
|
20
|
+
|
|
7
21
|
## [7.0.0-alpha.6] - 2026-05-28
|
|
8
22
|
|
|
9
23
|
Sixth v7 pre-release. Lands the debugger step controls ([#102](https://github.com/mellonis/turing-machine-js/issues/102), [PR #214](https://github.com/mellonis/turing-machine-js/pull/214)) and, in doing so, **reshapes the entire debug surface** into three clearly-separated entry points: `run()` is now pure synchronous execution (no callbacks), `runStepByStep` is the minimal pure-iteration primitive (no breakpoint detection), and a new **`DebugSession`** class owns all interactive debugging — events, step controls, throttle, and pause coordination. With #102 the **v7 milestone is feature-complete**; the stable v7.0.0 cut is the only remaining step. Published under the `next` dist-tag: `npm install @turing-machine-js/machine@next`.
|
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
A composable Turing-machine engine for JavaScript: multi-tape, subroutine composition via `withOverriddenHaltState`, Mermaid round-trip, and runtime breakpoints.
|
|
7
7
|
|
|
8
|
+
For runtime highlight + breakpoint rendering on top of the engine's `Graph`, plus a byte-identical edge-label formatter and snippet-recording artifacts, see the companion package [`@turing-machine-js/visuals`](../visuals).
|
|
9
|
+
|
|
8
10
|
<details>
|
|
9
11
|
<summary>Table of contents</summary>
|
|
10
12
|
|
|
@@ -239,7 +241,7 @@ const s = new State({
|
|
|
239
241
|
Notable members and statics:
|
|
240
242
|
|
|
241
243
|
- **`state.id`**, **`state.name`** — identity (`isHalt` is `id === 0`).
|
|
242
|
-
- **`state.withOverriddenHaltState(other)`** — returns a
|
|
244
|
+
- **`state.withOverriddenHaltState(other)`** — returns a `CallFrame` (a `State` subclass, so it flows anywhere a `State` does) whose would-be halt transitions fall through to `other`. The subroutine-call composition mechanism (see `library-binary-numbers/src/index.ts` for examples). `instanceof CallFrame` is the wrapper discriminator.
|
|
243
245
|
- **`State.toGraph(state, tapeBlock)`** — walks the reachable graph from `state` and returns a serializable `Graph` (states, transitions, alphabets).
|
|
244
246
|
- **`State.fromGraph(graph)`** — inverse of `toGraph`: rebuilds `State` instances + a fresh `TapeBlock` from a `Graph`. Round-trips together with `toMermaid` / `fromMermaid`.
|
|
245
247
|
- **`State.collectStates(state, tapeBlock)`** — walks the same graph and returns a `Map<number, {state, transitionSymbols}>` keyed by `GraphNode.id`. Use when downstream tooling holds a numeric id (e.g. a clicked node in a rendered graph) and needs the live `State` instance or the per-pattern `Symbol` for breakpoint setup. See [Setting breakpoints by graph id](#setting-breakpoints-by-graph-id).
|
|
@@ -378,7 +380,7 @@ for (const m of machine.runStepByStep({initialState})) {
|
|
|
378
380
|
|
|
379
381
|
## Subroutine composition with `withOverriddenHaltState`
|
|
380
382
|
|
|
381
|
-
`state.withOverriddenHaltState(other)` returns a
|
|
383
|
+
`state.withOverriddenHaltState(other)` returns a `CallFrame` — a `State` subclass that delegates transition lookups and `debug` to `state` (its *bare*) and whose would-be halt transitions fall through to `other` at run time. The bare is left untouched. Because a `CallFrame` is a `State`, it flows anywhere a `State` does (as a `nextState`, through `toGraph`/`fromGraph`); `instanceof CallFrame` distinguishes it from a plain state. This is the engine's only composition primitive — bigger machines are built by stacking smaller halt-on-completion subroutines.
|
|
382
384
|
|
|
383
385
|
```javascript
|
|
384
386
|
import { Alphabet, State, TapeBlock, TuringMachine, Tape, haltState, ifOtherSymbol, movements, symbolCommands } from '@turing-machine-js/machine';
|
|
@@ -447,7 +449,7 @@ flowchart TD
|
|
|
447
449
|
|
|
448
450
|
**Reading guide** — the v7 callable-subtree emit (introduced in [#174](https://github.com/mellonis/turing-machine-js/issues/174)) models `withOverriddenHaltState` as a function call: the wrapper is the call site, the bare's subtree is the callable body.
|
|
449
451
|
|
|
450
|
-
1. **`[[scanToX(eraseHere)]]` (Mermaid subroutine / double-walled-rectangle shape)** is the wrapper node
|
|
452
|
+
1. **`[[scanToX(eraseHere)]]` (Mermaid subroutine / double-walled-rectangle shape)** is the wrapper node. It's the runtime entry point — `idle -. enter .->` arrives here — and shows the composite name (`bare(override)`). Wrappers have no transitions of their own; they delegate to the bare via the `call` arrow. **Placement**: this top-level wrapper is drawn OUTSIDE any subgraph; a wrapper that participates in a caller's frame (e.g. an inner-call continuation of another wrapper, as in `library-binary-numbers/minusOne`) renders INSIDE its owner frame's subgraph with the same `[[…]]` shape (see [#223](https://github.com/mellonis/turing-machine-js/issues/223)).
|
|
451
453
|
2. **`subgraph w_1["callable subtree of scanToX"]`** is the bare's callable subtree — the scope of code that runs when the wrapper is "called." It contains the bare `s1["scanToX"]`, any body states reachable from the bare, and a local halt marker `c1(((halt)))` where the bare's halt-bound transitions land.
|
|
452
454
|
3. **The bold `==> call`** from wrapper to bare is the call arrow — visual signature of "wrapper invokes this callable subtree, pushing its override onto the runtime stack." Bold arrows are reserved for wrapper-to-bare calls; counting them in a diagram counts the wrappers in play.
|
|
453
455
|
4. **The dotted `-. return .->`** from the subtree back to the wrapper is the return arrow — fires when the bare halts (lands on `c1`) and the stack pops. The wrapper's solid `--> s2` (to `eraseHere`) is the post-return continuation; ordinary transition under the function-call mental model.
|
|
@@ -472,7 +474,7 @@ s.untag('hot');
|
|
|
472
474
|
s.tags; // readonly ['subroutine-entry']
|
|
473
475
|
```
|
|
474
476
|
|
|
475
|
-
**Scoped to the wrapper instance.** Under [`withOverriddenHaltState` memoization (#175)](https://github.com/mellonis/turing-machine-js/issues/175), `A.wohs(t1)` and `A.wohs(t2)` are distinct
|
|
477
|
+
**Scoped to the wrapper instance.** Under [`withOverriddenHaltState` memoization (#175)](https://github.com/mellonis/turing-machine-js/issues/175), `A.wohs(t1)` and `A.wohs(t2)` are distinct `CallFrame` instances even though both delegate to the same bare `A`. Tags live on the frame instance, so tagging one wrapper doesn't propagate to siblings sharing the same bare. Wrappers from `withOverriddenHaltState` start with an empty tag set (do not inherit from bare); the caller tags explicitly as needed.
|
|
476
478
|
|
|
477
479
|
**Round-trip preserved.** `state.toGraph` writes the tag set to `GraphNode.tags`; `state.fromGraph` reads it back and reapplies. `toMermaid` renders tags two ways: inline in the node label (`sN["name<br>tag1, tag2"]`, universal Mermaid line break) and as `classDef tag_<sanitized>` + `class sN tag_<sanitized>` lines for color grouping. `fromMermaid` splits the label on `<br>` as source of truth; the `class` lines are decorative and discarded on parse.
|
|
478
480
|
|
|
@@ -530,9 +532,11 @@ myState.debug = null;
|
|
|
530
532
|
|
|
531
533
|
> ⚠️ **`haltState.debug` is `boolean`-only.** Any object-shaped write (`{ before: true }`, `{ after: true }`, `{ before: true, after: true }`) throws at write time. The pause fires on the AFTER side of the iter whose transition leads to halt — `m.state` is the triggering state (not haltState), `m.pause.side === 'after'`.
|
|
532
534
|
|
|
535
|
+
> ⚠️ **An `after`-side breakpoint on the halt-triggering state collapses with `haltState.debug` into a single pause.** Both target the AFTER side of the *same* iter — the one whose transition leads to halt — and the engine fires at most one pause per iter-side, so you get one `pause` event (`side: 'after'`, `cause: 'breakpoint'`), not two. This is intentional: halt has no iteration of its own, so "after the triggering state" and "before halt" are the **same execution moment**. (Contrast two ordinary states `A → B`: `A`'s `after` and `B`'s `before` are *different* iters, so they fire as two pauses.) There is deliberately no flag to emit a second, ephemeral halt pause — one event for one real moment.
|
|
536
|
+
|
|
533
537
|
> ⚠️ **Chained-form `haltState.debug.before = true` doesn't throw in non-strict mode** — this is a JavaScript primitive quirk, not engine behavior. The getter returns the boolean `false`; assigning `.before` to that boolean is a no-op in non-strict mode (silent), a `TypeError` in strict mode. The engine setter only sees whole-object writes (`haltState.debug = X`). **Always use the whole-object form: `haltState.debug = true` / `= false` / `= null`.**
|
|
534
538
|
|
|
535
|
-
The `debug` field is mutable — toggle breakpoints at runtime without rebuilding the graph.
|
|
539
|
+
The `debug` field is mutable — toggle breakpoints at runtime without rebuilding the graph. A `CallFrame` (from `state.withOverriddenHaltState(...)`) delegates its `debug` to the bare, so an assignment on the original is visible from every wrapper and vice versa. `state.debug` is always a `DebugConfig` instance (lazy-initialized on first read); plain-object input is wrapped automatically. The instance is `Object.seal`-ed — typos like `state.debug.bofore = true` throw `TypeError` instead of silently creating a useless property.
|
|
536
540
|
|
|
537
541
|
**Filter semantics:** `true` is a wildcard (match any symbol). `[ifOtherSymbol]` is NOT a wildcard — it matches only the catch-all resolution case (same meaning as in transition keys).
|
|
538
542
|
|
|
@@ -752,7 +756,7 @@ The full reference for reading `toMermaid` output — shapes, edge styles, and t
|
|
|
752
756
|
|---|---|
|
|
753
757
|
| `s0(((halt)))` | the halt state |
|
|
754
758
|
| `sN["name"]` | a regular state (or a bare, when inside a subgraph) |
|
|
755
|
-
| `sN[["composite-name"]]` | a `withOverriddenHaltState` wrapper (call site
|
|
759
|
+
| `sN[["composite-name"]]` | a `withOverriddenHaltState` wrapper (call site; outside any subgraph when top-level, INSIDE its owner frame's subgraph when its continuation chain participates in a caller's frame — see [§Subroutine composition](#subroutine-composition-with-withoverriddenhaltstate) and [#223](https://github.com/mellonis/turing-machine-js/issues/223)) |
|
|
756
760
|
| `cN(((halt)))` inside a subgraph | halt marker (visualization aid; maps back to the singleton `haltState` at runtime) |
|
|
757
761
|
| `idle([idle])` | pre-execution sentinel (not a real state) |
|
|
758
762
|
|
package/dist/classes/State.d.ts
CHANGED
|
@@ -101,7 +101,7 @@ export default class State {
|
|
|
101
101
|
matchedSymbol: symbol;
|
|
102
102
|
ix: number;
|
|
103
103
|
};
|
|
104
|
-
withOverriddenHaltState(overriddenHaltState: State):
|
|
104
|
+
withOverriddenHaltState(overriddenHaltState: State): CallFrame;
|
|
105
105
|
/**
|
|
106
106
|
* @internal
|
|
107
107
|
*
|
|
@@ -209,4 +209,51 @@ export type HaltState = State & {
|
|
|
209
209
|
set debug(value: boolean | null);
|
|
210
210
|
};
|
|
211
211
|
export declare const haltState: HaltState;
|
|
212
|
+
/**
|
|
213
|
+
* A first-class call frame produced by `State.withOverriddenHaltState`
|
|
214
|
+
* (#213). A `CallFrame` is a `State` — `instanceof State` holds, so it flows
|
|
215
|
+
* anywhere a `State` does (as a `nextState`, through `toGraph`/`fromGraph`,
|
|
216
|
+
* etc.) — but it carries its own `bare` (the wrapped State) and `override`
|
|
217
|
+
* (the continuation pushed onto the run-stack on entry). `instanceof
|
|
218
|
+
* CallFrame` is the explicit wrapper discriminator.
|
|
219
|
+
*
|
|
220
|
+
* It owns no transitions of its own: lookups (`getSymbol`/`getCommand`/
|
|
221
|
+
* `getNextState`/`getMatchedTransition`) and `debug` DELEGATE to the bare,
|
|
222
|
+
* replacing the v6 field-aliasing (where a wrapper was a plain `State` whose
|
|
223
|
+
* private `#symbolToDataMap`/`#debugRef` were physically shared with the
|
|
224
|
+
* bare). `id`, `name` (composite `bare(override)`), and `tags` are its own
|
|
225
|
+
* (inherited State fields) — so memoized frames sharing a bare keep
|
|
226
|
+
* independent tags (#186), and the frame is never the halt singleton
|
|
227
|
+
* (fresh nonzero `#id` → `isHalt === false`).
|
|
228
|
+
*/
|
|
229
|
+
export declare class CallFrame extends State {
|
|
230
|
+
#private;
|
|
231
|
+
constructor(bare: State, override: State);
|
|
232
|
+
get bare(): State;
|
|
233
|
+
get overriddenHaltState(): State;
|
|
234
|
+
getSymbol(tapeBlock: TapeBlock): symbol;
|
|
235
|
+
getCommand(symbol: symbol): Command;
|
|
236
|
+
getNextState(symbol: symbol): State | Reference;
|
|
237
|
+
getMatchedTransition(symbol: symbol): {
|
|
238
|
+
nextState: State | Reference;
|
|
239
|
+
matchedSymbol: symbol;
|
|
240
|
+
ix: number;
|
|
241
|
+
};
|
|
242
|
+
get debug(): DebugConfig;
|
|
243
|
+
set debug(value: DebugConfig | {
|
|
244
|
+
before?: symbol[] | readonly symbol[] | true;
|
|
245
|
+
after?: symbol[] | readonly symbol[] | true;
|
|
246
|
+
} | null);
|
|
247
|
+
[STATE_INTERNAL](): {
|
|
248
|
+
readonly id: number;
|
|
249
|
+
name: string;
|
|
250
|
+
readonly bareState: State | null;
|
|
251
|
+
readonly overriddenHaltState: State | null;
|
|
252
|
+
readonly symbolToDataMap: Map<symbol, {
|
|
253
|
+
command: Command;
|
|
254
|
+
nextState: State | Reference;
|
|
255
|
+
}>;
|
|
256
|
+
readonly tags: ReadonlySet<string>;
|
|
257
|
+
};
|
|
258
|
+
}
|
|
212
259
|
export {};
|
package/dist/index.cjs
CHANGED
|
@@ -853,33 +853,70 @@ function toGraph(initialState, tapeBlock) {
|
|
|
853
853
|
};
|
|
854
854
|
}
|
|
855
855
|
// Pass 2: For each bare, compute its forward-reachable set (following
|
|
856
|
-
// transitions; stopping at halt
|
|
857
|
-
//
|
|
856
|
+
// transitions; stopping at halt; including wrappers AND tunneling through
|
|
857
|
+
// them to their `overriddenHaltStateId` continuation).
|
|
858
|
+
//
|
|
859
|
+
// Wrappers are call-site markers — semantically owned by the CALLER (the
|
|
860
|
+
// bare whose body invokes the sub-call). Both the wrapper itself and its
|
|
861
|
+
// continuation (its `--> override` arrow in the rendered diagram, sourced
|
|
862
|
+
// from `overriddenHaltStateId`) belong to the caller's frame: the wrapper
|
|
863
|
+
// visually anchors the call site inside the caller's subgraph; the
|
|
864
|
+
// continuation is the state the caller's body resumes at AFTER the inner
|
|
865
|
+
// sub-call returns. So when reach traversal hits a wrapper, we PUSH the
|
|
866
|
+
// wrapper (joining the caller's reach-set) AND tunnel through to its
|
|
867
|
+
// continuation (also joining). Wrappers carry no `transitions` of their
|
|
868
|
+
// own (Pass 1 emits `transitions: []` on wrapper nodes), so the main loop
|
|
869
|
+
// pops them and adds them to `reach` without further traversal — but the
|
|
870
|
+
// continuation already entered via the wrapper-tunnel chain in
|
|
871
|
+
// `resolveAndPush`.
|
|
872
|
+
//
|
|
873
|
+
// Halt-bound retargeting + union-find then "just work": continuation
|
|
874
|
+
// states' halt-bound transitions get retargeted to the caller's halt
|
|
875
|
+
// marker (so an in-subroutine halt returns to the caller, not the
|
|
876
|
+
// program's terminal halt); when two bares both reach the same
|
|
877
|
+
// continuation through different wrapper chains, union-find merges their
|
|
878
|
+
// frames as it already does for non-wrapper overlap.
|
|
879
|
+
//
|
|
880
|
+
// Wrapper chains (continuation IS another wrapper, e.g., nested
|
|
881
|
+
// compositions) are walked transitively by the inner while-loop in
|
|
882
|
+
// `resolveAndPush` — each tunnel hop pushes the intermediate wrapper.
|
|
858
883
|
const computeReach = (startId) => {
|
|
859
884
|
const reach = new Set();
|
|
860
|
-
const stack = [
|
|
885
|
+
const stack = [];
|
|
886
|
+
const resolveAndPush = (id) => {
|
|
887
|
+
let current = id;
|
|
888
|
+
while (true) {
|
|
889
|
+
const target = nodes[current];
|
|
890
|
+
if (!target || target.isHalt) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
if (!target.isWrapper) {
|
|
894
|
+
stack.push(current);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
// Wrapper: push it (so it joins the caller's frame) AND tunnel to
|
|
898
|
+
// its continuation. Both belong to the caller's frame.
|
|
899
|
+
stack.push(current);
|
|
900
|
+
/* c8 ignore next 3 — every wrapper emitted by Pass 1 has a
|
|
901
|
+
non-null overriddenHaltStateId (lines 76-101); this branch
|
|
902
|
+
only guards against future wrapper variants that might not. */
|
|
903
|
+
if (target.overriddenHaltStateId === null) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
current = target.overriddenHaltStateId;
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
resolveAndPush(startId);
|
|
861
910
|
while (stack.length > 0) {
|
|
862
911
|
const id = stack.pop();
|
|
863
912
|
if (reach.has(id)) {
|
|
864
913
|
continue;
|
|
865
914
|
}
|
|
866
|
-
const node = nodes[id];
|
|
867
|
-
// `nodes[id]` is always populated for `id` that the BFS reached, so
|
|
868
|
-
// a defensive `!node` check would be dead. `isHalt` / `isWrapper`
|
|
869
|
-
// are real boundaries — both stop reach-set expansion.
|
|
870
|
-
/* c8 ignore next 3 — defensive: the push site below already filters
|
|
871
|
-
halt/wrapper targets, and the initial push is always a bare, so
|
|
872
|
-
this branch is unreachable in practice. */
|
|
873
|
-
if (node.isHalt || node.isWrapper) {
|
|
874
|
-
continue;
|
|
875
|
-
}
|
|
876
915
|
reach.add(id);
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
}
|
|
882
|
-
stack.push(t.nextStateId);
|
|
916
|
+
// Wrappers have empty transitions arrays — the for-loop runs zero
|
|
917
|
+
// iterations and we proceed to the next stack entry.
|
|
918
|
+
for (const t of nodes[id].transitions) {
|
|
919
|
+
resolveAndPush(t.nextStateId);
|
|
883
920
|
}
|
|
884
921
|
}
|
|
885
922
|
return reach;
|
|
@@ -1240,7 +1277,7 @@ var __classPrivateFieldGet$2 = (undefined && undefined.__classPrivateFieldGet) |
|
|
|
1240
1277
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
1241
1278
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
1242
1279
|
};
|
|
1243
|
-
var _DebugConfig_ownerState, _DebugConfig_before, _DebugConfig_after, _State_instances, _a, _State_wrapperCache, _State_id, _State_name,
|
|
1280
|
+
var _DebugConfig_ownerState, _DebugConfig_before, _DebugConfig_after, _State_instances, _a, _State_wrapperCache, _State_id, _State_name, _State_symbolToDataMap, _State_debugRef, _State_haltDebug, _State_tags, _State_getEntry, _CallFrame_bare, _CallFrame_override;
|
|
1244
1281
|
const ifOtherSymbol = Symbol('other symbol');
|
|
1245
1282
|
// Module-private symbol used by DebugConfig setters to call State's validator
|
|
1246
1283
|
// without exposing the validator on the public surface.
|
|
@@ -1312,12 +1349,6 @@ class State {
|
|
|
1312
1349
|
// composed name on a no-arg `new State()` to bypass the constructor's
|
|
1313
1350
|
// user-facing name validation (composite names contain `(` and `)`).
|
|
1314
1351
|
_State_name.set(this, void 0);
|
|
1315
|
-
_State_overriddenHaltState.set(this, null);
|
|
1316
|
-
// For wrapper states (produced by `withOverriddenHaltState`), points at the
|
|
1317
|
-
// State whose transition map was wrapped. `null` on bare/atomic states.
|
|
1318
|
-
// `toGraph` reads this to render wrapper and bare as separate nodes linked
|
|
1319
|
-
// by a `==> call` arrow.
|
|
1320
|
-
_State_bareState.set(this, null);
|
|
1321
1352
|
_State_symbolToDataMap.set(this, new Map());
|
|
1322
1353
|
// Shared mutable cell — withOverriddenHaltState wrappers reference the same
|
|
1323
1354
|
// object so that `state.debug = ...` (and nullings) propagate across them.
|
|
@@ -1395,8 +1426,10 @@ class State {
|
|
|
1395
1426
|
get isHalt() {
|
|
1396
1427
|
return __classPrivateFieldGet$2(this, _State_id, "f") === 0;
|
|
1397
1428
|
}
|
|
1429
|
+
// Plain States never override the halt state — only a `CallFrame` (produced
|
|
1430
|
+
// by `withOverriddenHaltState`) carries an override, via its own getter.
|
|
1398
1431
|
get overriddenHaltState() {
|
|
1399
|
-
return
|
|
1432
|
+
return null;
|
|
1400
1433
|
}
|
|
1401
1434
|
get ref() {
|
|
1402
1435
|
return this;
|
|
@@ -1498,7 +1531,7 @@ class State {
|
|
|
1498
1531
|
/** @internal — invoked by DebugConfig setters via module-private symbol.
|
|
1499
1532
|
* haltState's `debug` setter rejects object writes before reaching
|
|
1500
1533
|
* DebugConfig, so this validator only sees non-halt states. */
|
|
1501
|
-
[(_State_id = new WeakMap(), _State_name = new WeakMap(),
|
|
1534
|
+
[(_State_id = new WeakMap(), _State_name = new WeakMap(), _State_symbolToDataMap = new WeakMap(), _State_debugRef = new WeakMap(), _State_haltDebug = new WeakMap(), _State_tags = new WeakMap(), _State_instances = new WeakSet(), validateDebugFilter)](fieldName, filter) {
|
|
1502
1535
|
if (filter === undefined)
|
|
1503
1536
|
return;
|
|
1504
1537
|
if (filter === true)
|
|
@@ -1557,13 +1590,13 @@ class State {
|
|
|
1557
1590
|
return { nextState: entry.nextState, matchedSymbol: symbol, ix };
|
|
1558
1591
|
}
|
|
1559
1592
|
withOverriddenHaltState(overriddenHaltState) {
|
|
1560
|
-
// Unwrap `this` if it's itself a
|
|
1593
|
+
// Unwrap `this` if it's itself a CallFrame — the chain's inner overrides
|
|
1561
1594
|
// are dead at runtime anyway (only the outermost `.wohs()`'s override is
|
|
1562
1595
|
// pushed onto the halt-stack on entry; verified empirically). Composite
|
|
1563
1596
|
// name reflects runtime behavior, not construction history. See #176.
|
|
1564
|
-
const bare =
|
|
1597
|
+
const bare = this instanceof CallFrame ? this.bare : this;
|
|
1565
1598
|
// Memoize by (bare, override) so identical args return the same instance
|
|
1566
|
-
// (#175). The cache uses WeakMaps + WeakRefs so cached
|
|
1599
|
+
// (#175). The cache uses WeakMaps + WeakRefs so cached frames can be
|
|
1567
1600
|
// GC'd when nothing else holds them. Compounds with the chain-collapse
|
|
1568
1601
|
// above: `A.wohs(t1).wohs(t2)` keys as (A, t2) after the unwrap, hitting
|
|
1569
1602
|
// the same cache slot as a direct `A.wohs(t2)`.
|
|
@@ -1581,17 +1614,9 @@ class State {
|
|
|
1581
1614
|
innerCache = new WeakMap();
|
|
1582
1615
|
__classPrivateFieldGet$2(_a, _a, "f", _State_wrapperCache).set(bare, innerCache);
|
|
1583
1616
|
}
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
const state = new _a();
|
|
1588
|
-
__classPrivateFieldSet$2(state, _State_name, `${bare.name}(${overriddenHaltState.name})`, "f");
|
|
1589
|
-
__classPrivateFieldSet$2(state, _State_symbolToDataMap, __classPrivateFieldGet$2(bare, _State_symbolToDataMap, "f"), "f");
|
|
1590
|
-
__classPrivateFieldSet$2(state, _State_overriddenHaltState, overriddenHaltState, "f");
|
|
1591
|
-
__classPrivateFieldSet$2(state, _State_debugRef, __classPrivateFieldGet$2(bare, _State_debugRef, "f"), "f");
|
|
1592
|
-
__classPrivateFieldSet$2(state, _State_bareState, bare, "f");
|
|
1593
|
-
innerCache.set(overriddenHaltState, new WeakRef(state));
|
|
1594
|
-
return state;
|
|
1617
|
+
const frame = new CallFrame(bare, overriddenHaltState);
|
|
1618
|
+
innerCache.set(overriddenHaltState, new WeakRef(frame));
|
|
1619
|
+
return frame;
|
|
1595
1620
|
}
|
|
1596
1621
|
/**
|
|
1597
1622
|
* @internal
|
|
@@ -1634,8 +1659,8 @@ class State {
|
|
|
1634
1659
|
get id() { return __classPrivateFieldGet$2(self, _State_id, "f"); },
|
|
1635
1660
|
get name() { return __classPrivateFieldGet$2(self, _State_name, "f"); },
|
|
1636
1661
|
set name(v) { __classPrivateFieldSet$2(self, _State_name, v, "f"); },
|
|
1637
|
-
get bareState() { return
|
|
1638
|
-
get overriddenHaltState() { return
|
|
1662
|
+
get bareState() { return null; },
|
|
1663
|
+
get overriddenHaltState() { return null; },
|
|
1639
1664
|
get symbolToDataMap() { return __classPrivateFieldGet$2(self, _State_symbolToDataMap, "f"); },
|
|
1640
1665
|
get tags() { return __classPrivateFieldGet$2(self, _State_tags, "f"); },
|
|
1641
1666
|
};
|
|
@@ -1646,8 +1671,13 @@ class State {
|
|
|
1646
1671
|
// Symbol patterns are returned as the raw description string from the
|
|
1647
1672
|
// interned JS Symbol (decode via decodePatternDescription if needed).
|
|
1648
1673
|
static inspect(state) {
|
|
1674
|
+
// Route through the STATE_INTERNAL view so a CallFrame reports its bare's
|
|
1675
|
+
// transitions and its own override — the view delegates those to the bare
|
|
1676
|
+
// / the frame's #override, whereas the raw private fields on a CallFrame
|
|
1677
|
+
// are empty/null.
|
|
1678
|
+
const internal = state[STATE_INTERNAL]();
|
|
1649
1679
|
const transitions = [];
|
|
1650
|
-
for (const [sym, { command, nextState }] of
|
|
1680
|
+
for (const [sym, { command, nextState }] of internal.symbolToDataMap) {
|
|
1651
1681
|
let target = null;
|
|
1652
1682
|
try {
|
|
1653
1683
|
target = nextState instanceof _a ? nextState : nextState.ref;
|
|
@@ -1664,12 +1694,13 @@ class State {
|
|
|
1664
1694
|
nextState: target ? { id: target.id, name: target.name } : null,
|
|
1665
1695
|
});
|
|
1666
1696
|
}
|
|
1697
|
+
const override = internal.overriddenHaltState;
|
|
1667
1698
|
return {
|
|
1668
|
-
id:
|
|
1669
|
-
name:
|
|
1699
|
+
id: internal.id,
|
|
1700
|
+
name: internal.name,
|
|
1670
1701
|
isHalt: state.isHalt,
|
|
1671
|
-
overriddenHaltState:
|
|
1672
|
-
? { id:
|
|
1702
|
+
overriddenHaltState: override
|
|
1703
|
+
? { id: override.id, name: override.name }
|
|
1673
1704
|
: null,
|
|
1674
1705
|
transitions,
|
|
1675
1706
|
};
|
|
@@ -1714,6 +1745,79 @@ _a = State;
|
|
|
1714
1745
|
// them, with cache misses simply reconstructing fresh wrappers.
|
|
1715
1746
|
_State_wrapperCache = { value: new WeakMap() };
|
|
1716
1747
|
const haltState = new State(null);
|
|
1748
|
+
/**
|
|
1749
|
+
* A first-class call frame produced by `State.withOverriddenHaltState`
|
|
1750
|
+
* (#213). A `CallFrame` is a `State` — `instanceof State` holds, so it flows
|
|
1751
|
+
* anywhere a `State` does (as a `nextState`, through `toGraph`/`fromGraph`,
|
|
1752
|
+
* etc.) — but it carries its own `bare` (the wrapped State) and `override`
|
|
1753
|
+
* (the continuation pushed onto the run-stack on entry). `instanceof
|
|
1754
|
+
* CallFrame` is the explicit wrapper discriminator.
|
|
1755
|
+
*
|
|
1756
|
+
* It owns no transitions of its own: lookups (`getSymbol`/`getCommand`/
|
|
1757
|
+
* `getNextState`/`getMatchedTransition`) and `debug` DELEGATE to the bare,
|
|
1758
|
+
* replacing the v6 field-aliasing (where a wrapper was a plain `State` whose
|
|
1759
|
+
* private `#symbolToDataMap`/`#debugRef` were physically shared with the
|
|
1760
|
+
* bare). `id`, `name` (composite `bare(override)`), and `tags` are its own
|
|
1761
|
+
* (inherited State fields) — so memoized frames sharing a bare keep
|
|
1762
|
+
* independent tags (#186), and the frame is never the halt singleton
|
|
1763
|
+
* (fresh nonzero `#id` → `isHalt === false`).
|
|
1764
|
+
*/
|
|
1765
|
+
class CallFrame extends State {
|
|
1766
|
+
constructor(bare, override) {
|
|
1767
|
+
super(null);
|
|
1768
|
+
_CallFrame_bare.set(this, void 0);
|
|
1769
|
+
_CallFrame_override.set(this, void 0);
|
|
1770
|
+
__classPrivateFieldSet$2(this, _CallFrame_bare, bare, "f");
|
|
1771
|
+
__classPrivateFieldSet$2(this, _CallFrame_override, override, "f");
|
|
1772
|
+
// Composite name contains `(` / `)`, which the constructor's user-facing
|
|
1773
|
+
// name validator rejects; the STATE_INTERNAL name setter bypasses it
|
|
1774
|
+
// (writes the inherited #name). `super[...]` reaches State's own view so
|
|
1775
|
+
// we don't recurse through this subclass's override below.
|
|
1776
|
+
super[STATE_INTERNAL]().name = `${bare.name}(${override.name})`;
|
|
1777
|
+
}
|
|
1778
|
+
get bare() {
|
|
1779
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f");
|
|
1780
|
+
}
|
|
1781
|
+
get overriddenHaltState() {
|
|
1782
|
+
return __classPrivateFieldGet$2(this, _CallFrame_override, "f");
|
|
1783
|
+
}
|
|
1784
|
+
getSymbol(tapeBlock) {
|
|
1785
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").getSymbol(tapeBlock);
|
|
1786
|
+
}
|
|
1787
|
+
getCommand(symbol) {
|
|
1788
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").getCommand(symbol);
|
|
1789
|
+
}
|
|
1790
|
+
getNextState(symbol) {
|
|
1791
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").getNextState(symbol);
|
|
1792
|
+
}
|
|
1793
|
+
getMatchedTransition(symbol) {
|
|
1794
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").getMatchedTransition(symbol);
|
|
1795
|
+
}
|
|
1796
|
+
get debug() {
|
|
1797
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").debug;
|
|
1798
|
+
}
|
|
1799
|
+
set debug(value) {
|
|
1800
|
+
__classPrivateFieldGet$2(this, _CallFrame_bare, "f").debug = value;
|
|
1801
|
+
}
|
|
1802
|
+
[(_CallFrame_bare = new WeakMap(), _CallFrame_override = new WeakMap(), STATE_INTERNAL)]() {
|
|
1803
|
+
// Own id / name / tags come from the inherited State fields (via super's
|
|
1804
|
+
// view); bareState / overriddenHaltState / the transition map delegate to
|
|
1805
|
+
// #bare / #override so sibling modules (stateGraph, inspect) see the
|
|
1806
|
+
// frame's true shape.
|
|
1807
|
+
const own = super[STATE_INTERNAL]();
|
|
1808
|
+
const bare = __classPrivateFieldGet$2(this, _CallFrame_bare, "f");
|
|
1809
|
+
const override = __classPrivateFieldGet$2(this, _CallFrame_override, "f");
|
|
1810
|
+
return {
|
|
1811
|
+
get id() { return own.id; },
|
|
1812
|
+
get name() { return own.name; },
|
|
1813
|
+
set name(v) { own.name = v; },
|
|
1814
|
+
get bareState() { return bare; },
|
|
1815
|
+
get overriddenHaltState() { return override; },
|
|
1816
|
+
get symbolToDataMap() { return bare[STATE_INTERNAL]().symbolToDataMap; },
|
|
1817
|
+
get tags() { return own.tags; },
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1717
1821
|
|
|
1718
1822
|
var __classPrivateFieldSet$1 = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
1719
1823
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
@@ -1810,16 +1914,10 @@ class TuringMachine {
|
|
|
1810
1914
|
const command = state.getCommand(symbol);
|
|
1811
1915
|
const matched = state.getMatchedTransition(symbol);
|
|
1812
1916
|
let nextState = matched.nextState.ref;
|
|
1813
|
-
// For wrapper-entry iters,
|
|
1814
|
-
// are empty (
|
|
1815
|
-
//
|
|
1816
|
-
|
|
1817
|
-
// is a wrapper produced by `withOverriddenHaltState`. Accessed
|
|
1818
|
-
// via the STATE_INTERNAL package-private view (same pattern
|
|
1819
|
-
// `utilities/stateGraph.ts` uses) to avoid widening the public
|
|
1820
|
-
// State API for this internal need.
|
|
1821
|
-
const stateInternal = state[STATE_INTERNAL]();
|
|
1822
|
-
const resolvableStateId = stateInternal.bareState?.id ?? state.id;
|
|
1917
|
+
// For wrapper-entry iters, a CallFrame's own transitions in `toGraph`
|
|
1918
|
+
// are empty (it delegates lookups to its bare); the resolvable
|
|
1919
|
+
// transition id lives under the bare's stateId.
|
|
1920
|
+
const resolvableStateId = state instanceof CallFrame ? state.bare.id : state.id;
|
|
1823
1921
|
const matchedTransition = {
|
|
1824
1922
|
id: `${resolvableStateId}.${matched.ix}`,
|
|
1825
1923
|
matchKinds: __classPrivateFieldGet$1(this, _TuringMachine_tapeBlock, "f").patternKinds(matched.matchedSymbol),
|
|
@@ -2321,14 +2419,20 @@ function toMermaid(graph) {
|
|
|
2321
2419
|
const nodes = Object.values(graph.nodes).slice().sort((a, b) => a.id - b.id);
|
|
2322
2420
|
// Bucket nodes for emit order.
|
|
2323
2421
|
const topLevelNodes = nodes.filter((n) => n.frameId === null && !n.isWrapper);
|
|
2422
|
+
// All wrappers — needed by the call / return / wrapper-to-override
|
|
2423
|
+
// arrow emit passes below regardless of where the wrapper renders.
|
|
2324
2424
|
const wrapperNodes = nodes.filter((n) => n.isWrapper);
|
|
2325
|
-
//
|
|
2425
|
+
// Top-level wrappers: wrappers whose caller has no frame (the caller is
|
|
2426
|
+
// the top-level program). Framed wrappers (whose caller IS a subroutine
|
|
2427
|
+
// with its own frame) render INSIDE that frame's subgraph below.
|
|
2428
|
+
const topLevelWrapperNodes = wrapperNodes.filter((w) => w.frameId === null);
|
|
2429
|
+
// Bares-bodies-and-framed-wrappers inside frames, grouped by frameId.
|
|
2326
2430
|
const nodesByFrame = new Map();
|
|
2327
2431
|
// Halt-marker per frame (kept separate so it always emits LAST inside the
|
|
2328
2432
|
// subgraph for deterministic shape).
|
|
2329
2433
|
const haltMarkerByFrame = new Map();
|
|
2330
2434
|
for (const node of nodes) {
|
|
2331
|
-
if (node.frameId === null
|
|
2435
|
+
if (node.frameId === null)
|
|
2332
2436
|
continue;
|
|
2333
2437
|
if (node.isHaltMarker) {
|
|
2334
2438
|
haltMarkerByFrame.set(node.frameId, node);
|
|
@@ -2371,8 +2475,9 @@ function toMermaid(graph) {
|
|
|
2371
2475
|
lines.push(` ${mid}["${labelOf(node)}"]`);
|
|
2372
2476
|
}
|
|
2373
2477
|
}
|
|
2374
|
-
// 2. Emit wrappers
|
|
2375
|
-
|
|
2478
|
+
// 2. Emit top-level wrappers (wrappers owned by the top-level program;
|
|
2479
|
+
// wrappers owned by a subroutine emit inside that subroutine's subgraph).
|
|
2480
|
+
for (const wrapper of topLevelWrapperNodes) {
|
|
2376
2481
|
lines.push(` ${mermaidIdFor(wrapper.id)}[["${labelOf(wrapper)}"]]`);
|
|
2377
2482
|
}
|
|
2378
2483
|
// 3. `idle` sentinel.
|
|
@@ -2389,9 +2494,16 @@ function toMermaid(graph) {
|
|
|
2389
2494
|
? `callable scope: ${frameBareNames.join(' ∪ ')}`
|
|
2390
2495
|
: `callable subtree of ${frameBareNames[0] ?? frameId}`;
|
|
2391
2496
|
lines.push(` subgraph ${frameSubgraphId(frameId)}["${label}"]`);
|
|
2392
|
-
// Inner nodes — sort by id for determinism.
|
|
2497
|
+
// Inner nodes — sort by id for determinism. Framed wrappers (call sites
|
|
2498
|
+
// owned by this frame) render with the `[[name]]` wrapper shape; bares
|
|
2499
|
+
// and body states render with the regular `["name"]` shape.
|
|
2393
2500
|
for (const node of (nodesByFrame.get(frameId) ?? []).slice().sort((a, b) => a.id - b.id)) {
|
|
2394
|
-
|
|
2501
|
+
if (node.isWrapper) {
|
|
2502
|
+
lines.push(` ${mermaidIdFor(node.id)}[["${labelOf(node)}"]]`);
|
|
2503
|
+
}
|
|
2504
|
+
else {
|
|
2505
|
+
lines.push(` ${mermaidIdFor(node.id)}["${labelOf(node)}"]`);
|
|
2506
|
+
}
|
|
2395
2507
|
}
|
|
2396
2508
|
// Every frame has a halt marker — `State.toGraph`'s frame-emit pass
|
|
2397
2509
|
// creates one for each frame. Non-null assertion is safe; a defensive
|
|
@@ -3029,6 +3141,7 @@ function runOnce(runnable, input, stepsLimit) {
|
|
|
3029
3141
|
}
|
|
3030
3142
|
|
|
3031
3143
|
exports.Alphabet = Alphabet;
|
|
3144
|
+
exports.CallFrame = CallFrame;
|
|
3032
3145
|
exports.Command = Command;
|
|
3033
3146
|
exports.DebugConfig = DebugConfig;
|
|
3034
3147
|
exports.DebugSession = DebugSession;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { default as Alphabet } from './classes/Alphabet';
|
|
2
2
|
export { default as Command } from './classes/Command';
|
|
3
3
|
export { default as Reference } from './classes/Reference';
|
|
4
|
-
export { default as State, DebugConfig, haltState, ifOtherSymbol } from './classes/State';
|
|
4
|
+
export { default as State, CallFrame, DebugConfig, haltState, ifOtherSymbol } from './classes/State';
|
|
5
5
|
export { default as Tape } from './classes/Tape';
|
|
6
6
|
export { default as TapeBlock } from './classes/TapeBlock';
|
|
7
7
|
export { default as TapeCommand, movements, symbolCommands } from './classes/TapeCommand';
|
package/dist/index.mjs
CHANGED
|
@@ -851,33 +851,70 @@ function toGraph(initialState, tapeBlock) {
|
|
|
851
851
|
};
|
|
852
852
|
}
|
|
853
853
|
// Pass 2: For each bare, compute its forward-reachable set (following
|
|
854
|
-
// transitions; stopping at halt
|
|
855
|
-
//
|
|
854
|
+
// transitions; stopping at halt; including wrappers AND tunneling through
|
|
855
|
+
// them to their `overriddenHaltStateId` continuation).
|
|
856
|
+
//
|
|
857
|
+
// Wrappers are call-site markers — semantically owned by the CALLER (the
|
|
858
|
+
// bare whose body invokes the sub-call). Both the wrapper itself and its
|
|
859
|
+
// continuation (its `--> override` arrow in the rendered diagram, sourced
|
|
860
|
+
// from `overriddenHaltStateId`) belong to the caller's frame: the wrapper
|
|
861
|
+
// visually anchors the call site inside the caller's subgraph; the
|
|
862
|
+
// continuation is the state the caller's body resumes at AFTER the inner
|
|
863
|
+
// sub-call returns. So when reach traversal hits a wrapper, we PUSH the
|
|
864
|
+
// wrapper (joining the caller's reach-set) AND tunnel through to its
|
|
865
|
+
// continuation (also joining). Wrappers carry no `transitions` of their
|
|
866
|
+
// own (Pass 1 emits `transitions: []` on wrapper nodes), so the main loop
|
|
867
|
+
// pops them and adds them to `reach` without further traversal — but the
|
|
868
|
+
// continuation already entered via the wrapper-tunnel chain in
|
|
869
|
+
// `resolveAndPush`.
|
|
870
|
+
//
|
|
871
|
+
// Halt-bound retargeting + union-find then "just work": continuation
|
|
872
|
+
// states' halt-bound transitions get retargeted to the caller's halt
|
|
873
|
+
// marker (so an in-subroutine halt returns to the caller, not the
|
|
874
|
+
// program's terminal halt); when two bares both reach the same
|
|
875
|
+
// continuation through different wrapper chains, union-find merges their
|
|
876
|
+
// frames as it already does for non-wrapper overlap.
|
|
877
|
+
//
|
|
878
|
+
// Wrapper chains (continuation IS another wrapper, e.g., nested
|
|
879
|
+
// compositions) are walked transitively by the inner while-loop in
|
|
880
|
+
// `resolveAndPush` — each tunnel hop pushes the intermediate wrapper.
|
|
856
881
|
const computeReach = (startId) => {
|
|
857
882
|
const reach = new Set();
|
|
858
|
-
const stack = [
|
|
883
|
+
const stack = [];
|
|
884
|
+
const resolveAndPush = (id) => {
|
|
885
|
+
let current = id;
|
|
886
|
+
while (true) {
|
|
887
|
+
const target = nodes[current];
|
|
888
|
+
if (!target || target.isHalt) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
if (!target.isWrapper) {
|
|
892
|
+
stack.push(current);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
// Wrapper: push it (so it joins the caller's frame) AND tunnel to
|
|
896
|
+
// its continuation. Both belong to the caller's frame.
|
|
897
|
+
stack.push(current);
|
|
898
|
+
/* c8 ignore next 3 — every wrapper emitted by Pass 1 has a
|
|
899
|
+
non-null overriddenHaltStateId (lines 76-101); this branch
|
|
900
|
+
only guards against future wrapper variants that might not. */
|
|
901
|
+
if (target.overriddenHaltStateId === null) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
current = target.overriddenHaltStateId;
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
resolveAndPush(startId);
|
|
859
908
|
while (stack.length > 0) {
|
|
860
909
|
const id = stack.pop();
|
|
861
910
|
if (reach.has(id)) {
|
|
862
911
|
continue;
|
|
863
912
|
}
|
|
864
|
-
const node = nodes[id];
|
|
865
|
-
// `nodes[id]` is always populated for `id` that the BFS reached, so
|
|
866
|
-
// a defensive `!node` check would be dead. `isHalt` / `isWrapper`
|
|
867
|
-
// are real boundaries — both stop reach-set expansion.
|
|
868
|
-
/* c8 ignore next 3 — defensive: the push site below already filters
|
|
869
|
-
halt/wrapper targets, and the initial push is always a bare, so
|
|
870
|
-
this branch is unreachable in practice. */
|
|
871
|
-
if (node.isHalt || node.isWrapper) {
|
|
872
|
-
continue;
|
|
873
|
-
}
|
|
874
913
|
reach.add(id);
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
}
|
|
880
|
-
stack.push(t.nextStateId);
|
|
914
|
+
// Wrappers have empty transitions arrays — the for-loop runs zero
|
|
915
|
+
// iterations and we proceed to the next stack entry.
|
|
916
|
+
for (const t of nodes[id].transitions) {
|
|
917
|
+
resolveAndPush(t.nextStateId);
|
|
881
918
|
}
|
|
882
919
|
}
|
|
883
920
|
return reach;
|
|
@@ -1238,7 +1275,7 @@ var __classPrivateFieldGet$2 = (undefined && undefined.__classPrivateFieldGet) |
|
|
|
1238
1275
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
1239
1276
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
1240
1277
|
};
|
|
1241
|
-
var _DebugConfig_ownerState, _DebugConfig_before, _DebugConfig_after, _State_instances, _a, _State_wrapperCache, _State_id, _State_name,
|
|
1278
|
+
var _DebugConfig_ownerState, _DebugConfig_before, _DebugConfig_after, _State_instances, _a, _State_wrapperCache, _State_id, _State_name, _State_symbolToDataMap, _State_debugRef, _State_haltDebug, _State_tags, _State_getEntry, _CallFrame_bare, _CallFrame_override;
|
|
1242
1279
|
const ifOtherSymbol = Symbol('other symbol');
|
|
1243
1280
|
// Module-private symbol used by DebugConfig setters to call State's validator
|
|
1244
1281
|
// without exposing the validator on the public surface.
|
|
@@ -1310,12 +1347,6 @@ class State {
|
|
|
1310
1347
|
// composed name on a no-arg `new State()` to bypass the constructor's
|
|
1311
1348
|
// user-facing name validation (composite names contain `(` and `)`).
|
|
1312
1349
|
_State_name.set(this, void 0);
|
|
1313
|
-
_State_overriddenHaltState.set(this, null);
|
|
1314
|
-
// For wrapper states (produced by `withOverriddenHaltState`), points at the
|
|
1315
|
-
// State whose transition map was wrapped. `null` on bare/atomic states.
|
|
1316
|
-
// `toGraph` reads this to render wrapper and bare as separate nodes linked
|
|
1317
|
-
// by a `==> call` arrow.
|
|
1318
|
-
_State_bareState.set(this, null);
|
|
1319
1350
|
_State_symbolToDataMap.set(this, new Map());
|
|
1320
1351
|
// Shared mutable cell — withOverriddenHaltState wrappers reference the same
|
|
1321
1352
|
// object so that `state.debug = ...` (and nullings) propagate across them.
|
|
@@ -1393,8 +1424,10 @@ class State {
|
|
|
1393
1424
|
get isHalt() {
|
|
1394
1425
|
return __classPrivateFieldGet$2(this, _State_id, "f") === 0;
|
|
1395
1426
|
}
|
|
1427
|
+
// Plain States never override the halt state — only a `CallFrame` (produced
|
|
1428
|
+
// by `withOverriddenHaltState`) carries an override, via its own getter.
|
|
1396
1429
|
get overriddenHaltState() {
|
|
1397
|
-
return
|
|
1430
|
+
return null;
|
|
1398
1431
|
}
|
|
1399
1432
|
get ref() {
|
|
1400
1433
|
return this;
|
|
@@ -1496,7 +1529,7 @@ class State {
|
|
|
1496
1529
|
/** @internal — invoked by DebugConfig setters via module-private symbol.
|
|
1497
1530
|
* haltState's `debug` setter rejects object writes before reaching
|
|
1498
1531
|
* DebugConfig, so this validator only sees non-halt states. */
|
|
1499
|
-
[(_State_id = new WeakMap(), _State_name = new WeakMap(),
|
|
1532
|
+
[(_State_id = new WeakMap(), _State_name = new WeakMap(), _State_symbolToDataMap = new WeakMap(), _State_debugRef = new WeakMap(), _State_haltDebug = new WeakMap(), _State_tags = new WeakMap(), _State_instances = new WeakSet(), validateDebugFilter)](fieldName, filter) {
|
|
1500
1533
|
if (filter === undefined)
|
|
1501
1534
|
return;
|
|
1502
1535
|
if (filter === true)
|
|
@@ -1555,13 +1588,13 @@ class State {
|
|
|
1555
1588
|
return { nextState: entry.nextState, matchedSymbol: symbol, ix };
|
|
1556
1589
|
}
|
|
1557
1590
|
withOverriddenHaltState(overriddenHaltState) {
|
|
1558
|
-
// Unwrap `this` if it's itself a
|
|
1591
|
+
// Unwrap `this` if it's itself a CallFrame — the chain's inner overrides
|
|
1559
1592
|
// are dead at runtime anyway (only the outermost `.wohs()`'s override is
|
|
1560
1593
|
// pushed onto the halt-stack on entry; verified empirically). Composite
|
|
1561
1594
|
// name reflects runtime behavior, not construction history. See #176.
|
|
1562
|
-
const bare =
|
|
1595
|
+
const bare = this instanceof CallFrame ? this.bare : this;
|
|
1563
1596
|
// Memoize by (bare, override) so identical args return the same instance
|
|
1564
|
-
// (#175). The cache uses WeakMaps + WeakRefs so cached
|
|
1597
|
+
// (#175). The cache uses WeakMaps + WeakRefs so cached frames can be
|
|
1565
1598
|
// GC'd when nothing else holds them. Compounds with the chain-collapse
|
|
1566
1599
|
// above: `A.wohs(t1).wohs(t2)` keys as (A, t2) after the unwrap, hitting
|
|
1567
1600
|
// the same cache slot as a direct `A.wohs(t2)`.
|
|
@@ -1579,17 +1612,9 @@ class State {
|
|
|
1579
1612
|
innerCache = new WeakMap();
|
|
1580
1613
|
__classPrivateFieldGet$2(_a, _a, "f", _State_wrapperCache).set(bare, innerCache);
|
|
1581
1614
|
}
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
const state = new _a();
|
|
1586
|
-
__classPrivateFieldSet$2(state, _State_name, `${bare.name}(${overriddenHaltState.name})`, "f");
|
|
1587
|
-
__classPrivateFieldSet$2(state, _State_symbolToDataMap, __classPrivateFieldGet$2(bare, _State_symbolToDataMap, "f"), "f");
|
|
1588
|
-
__classPrivateFieldSet$2(state, _State_overriddenHaltState, overriddenHaltState, "f");
|
|
1589
|
-
__classPrivateFieldSet$2(state, _State_debugRef, __classPrivateFieldGet$2(bare, _State_debugRef, "f"), "f");
|
|
1590
|
-
__classPrivateFieldSet$2(state, _State_bareState, bare, "f");
|
|
1591
|
-
innerCache.set(overriddenHaltState, new WeakRef(state));
|
|
1592
|
-
return state;
|
|
1615
|
+
const frame = new CallFrame(bare, overriddenHaltState);
|
|
1616
|
+
innerCache.set(overriddenHaltState, new WeakRef(frame));
|
|
1617
|
+
return frame;
|
|
1593
1618
|
}
|
|
1594
1619
|
/**
|
|
1595
1620
|
* @internal
|
|
@@ -1632,8 +1657,8 @@ class State {
|
|
|
1632
1657
|
get id() { return __classPrivateFieldGet$2(self, _State_id, "f"); },
|
|
1633
1658
|
get name() { return __classPrivateFieldGet$2(self, _State_name, "f"); },
|
|
1634
1659
|
set name(v) { __classPrivateFieldSet$2(self, _State_name, v, "f"); },
|
|
1635
|
-
get bareState() { return
|
|
1636
|
-
get overriddenHaltState() { return
|
|
1660
|
+
get bareState() { return null; },
|
|
1661
|
+
get overriddenHaltState() { return null; },
|
|
1637
1662
|
get symbolToDataMap() { return __classPrivateFieldGet$2(self, _State_symbolToDataMap, "f"); },
|
|
1638
1663
|
get tags() { return __classPrivateFieldGet$2(self, _State_tags, "f"); },
|
|
1639
1664
|
};
|
|
@@ -1644,8 +1669,13 @@ class State {
|
|
|
1644
1669
|
// Symbol patterns are returned as the raw description string from the
|
|
1645
1670
|
// interned JS Symbol (decode via decodePatternDescription if needed).
|
|
1646
1671
|
static inspect(state) {
|
|
1672
|
+
// Route through the STATE_INTERNAL view so a CallFrame reports its bare's
|
|
1673
|
+
// transitions and its own override — the view delegates those to the bare
|
|
1674
|
+
// / the frame's #override, whereas the raw private fields on a CallFrame
|
|
1675
|
+
// are empty/null.
|
|
1676
|
+
const internal = state[STATE_INTERNAL]();
|
|
1647
1677
|
const transitions = [];
|
|
1648
|
-
for (const [sym, { command, nextState }] of
|
|
1678
|
+
for (const [sym, { command, nextState }] of internal.symbolToDataMap) {
|
|
1649
1679
|
let target = null;
|
|
1650
1680
|
try {
|
|
1651
1681
|
target = nextState instanceof _a ? nextState : nextState.ref;
|
|
@@ -1662,12 +1692,13 @@ class State {
|
|
|
1662
1692
|
nextState: target ? { id: target.id, name: target.name } : null,
|
|
1663
1693
|
});
|
|
1664
1694
|
}
|
|
1695
|
+
const override = internal.overriddenHaltState;
|
|
1665
1696
|
return {
|
|
1666
|
-
id:
|
|
1667
|
-
name:
|
|
1697
|
+
id: internal.id,
|
|
1698
|
+
name: internal.name,
|
|
1668
1699
|
isHalt: state.isHalt,
|
|
1669
|
-
overriddenHaltState:
|
|
1670
|
-
? { id:
|
|
1700
|
+
overriddenHaltState: override
|
|
1701
|
+
? { id: override.id, name: override.name }
|
|
1671
1702
|
: null,
|
|
1672
1703
|
transitions,
|
|
1673
1704
|
};
|
|
@@ -1712,6 +1743,79 @@ _a = State;
|
|
|
1712
1743
|
// them, with cache misses simply reconstructing fresh wrappers.
|
|
1713
1744
|
_State_wrapperCache = { value: new WeakMap() };
|
|
1714
1745
|
const haltState = new State(null);
|
|
1746
|
+
/**
|
|
1747
|
+
* A first-class call frame produced by `State.withOverriddenHaltState`
|
|
1748
|
+
* (#213). A `CallFrame` is a `State` — `instanceof State` holds, so it flows
|
|
1749
|
+
* anywhere a `State` does (as a `nextState`, through `toGraph`/`fromGraph`,
|
|
1750
|
+
* etc.) — but it carries its own `bare` (the wrapped State) and `override`
|
|
1751
|
+
* (the continuation pushed onto the run-stack on entry). `instanceof
|
|
1752
|
+
* CallFrame` is the explicit wrapper discriminator.
|
|
1753
|
+
*
|
|
1754
|
+
* It owns no transitions of its own: lookups (`getSymbol`/`getCommand`/
|
|
1755
|
+
* `getNextState`/`getMatchedTransition`) and `debug` DELEGATE to the bare,
|
|
1756
|
+
* replacing the v6 field-aliasing (where a wrapper was a plain `State` whose
|
|
1757
|
+
* private `#symbolToDataMap`/`#debugRef` were physically shared with the
|
|
1758
|
+
* bare). `id`, `name` (composite `bare(override)`), and `tags` are its own
|
|
1759
|
+
* (inherited State fields) — so memoized frames sharing a bare keep
|
|
1760
|
+
* independent tags (#186), and the frame is never the halt singleton
|
|
1761
|
+
* (fresh nonzero `#id` → `isHalt === false`).
|
|
1762
|
+
*/
|
|
1763
|
+
class CallFrame extends State {
|
|
1764
|
+
constructor(bare, override) {
|
|
1765
|
+
super(null);
|
|
1766
|
+
_CallFrame_bare.set(this, void 0);
|
|
1767
|
+
_CallFrame_override.set(this, void 0);
|
|
1768
|
+
__classPrivateFieldSet$2(this, _CallFrame_bare, bare, "f");
|
|
1769
|
+
__classPrivateFieldSet$2(this, _CallFrame_override, override, "f");
|
|
1770
|
+
// Composite name contains `(` / `)`, which the constructor's user-facing
|
|
1771
|
+
// name validator rejects; the STATE_INTERNAL name setter bypasses it
|
|
1772
|
+
// (writes the inherited #name). `super[...]` reaches State's own view so
|
|
1773
|
+
// we don't recurse through this subclass's override below.
|
|
1774
|
+
super[STATE_INTERNAL]().name = `${bare.name}(${override.name})`;
|
|
1775
|
+
}
|
|
1776
|
+
get bare() {
|
|
1777
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f");
|
|
1778
|
+
}
|
|
1779
|
+
get overriddenHaltState() {
|
|
1780
|
+
return __classPrivateFieldGet$2(this, _CallFrame_override, "f");
|
|
1781
|
+
}
|
|
1782
|
+
getSymbol(tapeBlock) {
|
|
1783
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").getSymbol(tapeBlock);
|
|
1784
|
+
}
|
|
1785
|
+
getCommand(symbol) {
|
|
1786
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").getCommand(symbol);
|
|
1787
|
+
}
|
|
1788
|
+
getNextState(symbol) {
|
|
1789
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").getNextState(symbol);
|
|
1790
|
+
}
|
|
1791
|
+
getMatchedTransition(symbol) {
|
|
1792
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").getMatchedTransition(symbol);
|
|
1793
|
+
}
|
|
1794
|
+
get debug() {
|
|
1795
|
+
return __classPrivateFieldGet$2(this, _CallFrame_bare, "f").debug;
|
|
1796
|
+
}
|
|
1797
|
+
set debug(value) {
|
|
1798
|
+
__classPrivateFieldGet$2(this, _CallFrame_bare, "f").debug = value;
|
|
1799
|
+
}
|
|
1800
|
+
[(_CallFrame_bare = new WeakMap(), _CallFrame_override = new WeakMap(), STATE_INTERNAL)]() {
|
|
1801
|
+
// Own id / name / tags come from the inherited State fields (via super's
|
|
1802
|
+
// view); bareState / overriddenHaltState / the transition map delegate to
|
|
1803
|
+
// #bare / #override so sibling modules (stateGraph, inspect) see the
|
|
1804
|
+
// frame's true shape.
|
|
1805
|
+
const own = super[STATE_INTERNAL]();
|
|
1806
|
+
const bare = __classPrivateFieldGet$2(this, _CallFrame_bare, "f");
|
|
1807
|
+
const override = __classPrivateFieldGet$2(this, _CallFrame_override, "f");
|
|
1808
|
+
return {
|
|
1809
|
+
get id() { return own.id; },
|
|
1810
|
+
get name() { return own.name; },
|
|
1811
|
+
set name(v) { own.name = v; },
|
|
1812
|
+
get bareState() { return bare; },
|
|
1813
|
+
get overriddenHaltState() { return override; },
|
|
1814
|
+
get symbolToDataMap() { return bare[STATE_INTERNAL]().symbolToDataMap; },
|
|
1815
|
+
get tags() { return own.tags; },
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1715
1819
|
|
|
1716
1820
|
var __classPrivateFieldSet$1 = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
1717
1821
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
@@ -1808,16 +1912,10 @@ class TuringMachine {
|
|
|
1808
1912
|
const command = state.getCommand(symbol);
|
|
1809
1913
|
const matched = state.getMatchedTransition(symbol);
|
|
1810
1914
|
let nextState = matched.nextState.ref;
|
|
1811
|
-
// For wrapper-entry iters,
|
|
1812
|
-
// are empty (
|
|
1813
|
-
//
|
|
1814
|
-
|
|
1815
|
-
// is a wrapper produced by `withOverriddenHaltState`. Accessed
|
|
1816
|
-
// via the STATE_INTERNAL package-private view (same pattern
|
|
1817
|
-
// `utilities/stateGraph.ts` uses) to avoid widening the public
|
|
1818
|
-
// State API for this internal need.
|
|
1819
|
-
const stateInternal = state[STATE_INTERNAL]();
|
|
1820
|
-
const resolvableStateId = stateInternal.bareState?.id ?? state.id;
|
|
1915
|
+
// For wrapper-entry iters, a CallFrame's own transitions in `toGraph`
|
|
1916
|
+
// are empty (it delegates lookups to its bare); the resolvable
|
|
1917
|
+
// transition id lives under the bare's stateId.
|
|
1918
|
+
const resolvableStateId = state instanceof CallFrame ? state.bare.id : state.id;
|
|
1821
1919
|
const matchedTransition = {
|
|
1822
1920
|
id: `${resolvableStateId}.${matched.ix}`,
|
|
1823
1921
|
matchKinds: __classPrivateFieldGet$1(this, _TuringMachine_tapeBlock, "f").patternKinds(matched.matchedSymbol),
|
|
@@ -2319,14 +2417,20 @@ function toMermaid(graph) {
|
|
|
2319
2417
|
const nodes = Object.values(graph.nodes).slice().sort((a, b) => a.id - b.id);
|
|
2320
2418
|
// Bucket nodes for emit order.
|
|
2321
2419
|
const topLevelNodes = nodes.filter((n) => n.frameId === null && !n.isWrapper);
|
|
2420
|
+
// All wrappers — needed by the call / return / wrapper-to-override
|
|
2421
|
+
// arrow emit passes below regardless of where the wrapper renders.
|
|
2322
2422
|
const wrapperNodes = nodes.filter((n) => n.isWrapper);
|
|
2323
|
-
//
|
|
2423
|
+
// Top-level wrappers: wrappers whose caller has no frame (the caller is
|
|
2424
|
+
// the top-level program). Framed wrappers (whose caller IS a subroutine
|
|
2425
|
+
// with its own frame) render INSIDE that frame's subgraph below.
|
|
2426
|
+
const topLevelWrapperNodes = wrapperNodes.filter((w) => w.frameId === null);
|
|
2427
|
+
// Bares-bodies-and-framed-wrappers inside frames, grouped by frameId.
|
|
2324
2428
|
const nodesByFrame = new Map();
|
|
2325
2429
|
// Halt-marker per frame (kept separate so it always emits LAST inside the
|
|
2326
2430
|
// subgraph for deterministic shape).
|
|
2327
2431
|
const haltMarkerByFrame = new Map();
|
|
2328
2432
|
for (const node of nodes) {
|
|
2329
|
-
if (node.frameId === null
|
|
2433
|
+
if (node.frameId === null)
|
|
2330
2434
|
continue;
|
|
2331
2435
|
if (node.isHaltMarker) {
|
|
2332
2436
|
haltMarkerByFrame.set(node.frameId, node);
|
|
@@ -2369,8 +2473,9 @@ function toMermaid(graph) {
|
|
|
2369
2473
|
lines.push(` ${mid}["${labelOf(node)}"]`);
|
|
2370
2474
|
}
|
|
2371
2475
|
}
|
|
2372
|
-
// 2. Emit wrappers
|
|
2373
|
-
|
|
2476
|
+
// 2. Emit top-level wrappers (wrappers owned by the top-level program;
|
|
2477
|
+
// wrappers owned by a subroutine emit inside that subroutine's subgraph).
|
|
2478
|
+
for (const wrapper of topLevelWrapperNodes) {
|
|
2374
2479
|
lines.push(` ${mermaidIdFor(wrapper.id)}[["${labelOf(wrapper)}"]]`);
|
|
2375
2480
|
}
|
|
2376
2481
|
// 3. `idle` sentinel.
|
|
@@ -2387,9 +2492,16 @@ function toMermaid(graph) {
|
|
|
2387
2492
|
? `callable scope: ${frameBareNames.join(' ∪ ')}`
|
|
2388
2493
|
: `callable subtree of ${frameBareNames[0] ?? frameId}`;
|
|
2389
2494
|
lines.push(` subgraph ${frameSubgraphId(frameId)}["${label}"]`);
|
|
2390
|
-
// Inner nodes — sort by id for determinism.
|
|
2495
|
+
// Inner nodes — sort by id for determinism. Framed wrappers (call sites
|
|
2496
|
+
// owned by this frame) render with the `[[name]]` wrapper shape; bares
|
|
2497
|
+
// and body states render with the regular `["name"]` shape.
|
|
2391
2498
|
for (const node of (nodesByFrame.get(frameId) ?? []).slice().sort((a, b) => a.id - b.id)) {
|
|
2392
|
-
|
|
2499
|
+
if (node.isWrapper) {
|
|
2500
|
+
lines.push(` ${mermaidIdFor(node.id)}[["${labelOf(node)}"]]`);
|
|
2501
|
+
}
|
|
2502
|
+
else {
|
|
2503
|
+
lines.push(` ${mermaidIdFor(node.id)}["${labelOf(node)}"]`);
|
|
2504
|
+
}
|
|
2393
2505
|
}
|
|
2394
2506
|
// Every frame has a halt marker — `State.toGraph`'s frame-emit pass
|
|
2395
2507
|
// creates one for each frame. Non-null assertion is safe; a defensive
|
|
@@ -3026,4 +3138,4 @@ function runOnce(runnable, input, stepsLimit) {
|
|
|
3026
3138
|
};
|
|
3027
3139
|
}
|
|
3028
3140
|
|
|
3029
|
-
export { Alphabet, Command, DebugConfig, DebugSession, Reference, State, Tape, TapeBlock, TapeCommand, TuringMachine, equivalentOn, fromMermaid, haltState, ifOtherSymbol, movements, summarize, summarizeGraph, symbolCommands, toMermaid };
|
|
3141
|
+
export { Alphabet, CallFrame, Command, DebugConfig, DebugSession, Reference, State, Tape, TapeBlock, TapeCommand, TuringMachine, equivalentOn, fromMermaid, haltState, ifOtherSymbol, movements, summarize, summarizeGraph, symbolCommands, toMermaid };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@turing-machine-js/machine",
|
|
3
|
-
"version": "7.0.0-alpha.
|
|
3
|
+
"version": "7.0.0-alpha.7",
|
|
4
4
|
"description": "A convenient Turing machine",
|
|
5
5
|
"engines": {
|
|
6
6
|
"npm": ">=7.0.0"
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"default": "./dist/index.mjs"
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "130d4fd8b964da21a408af2986295e8000828f78"
|
|
42
42
|
}
|