libpetri 2.12.0 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-V3WTQRHC.js → chunk-7VJ5CYUU.js} +104 -2
- package/dist/chunk-7VJ5CYUU.js.map +1 -0
- package/dist/debug/index.d.ts +2 -2
- package/dist/doclet/index.d.ts +1 -1
- package/dist/{event-store-CAkN_ayv.d.ts → event-store-DKTenPbC.d.ts} +1 -1
- package/dist/export/index.d.ts +1 -1
- package/dist/index.d.ts +51 -4
- package/dist/index.js +247 -117
- package/dist/index.js.map +1 -1
- package/dist/{petri-net-B4wQwsUj.d.ts → petri-net-C3LSY-vm.d.ts} +63 -9
- package/dist/verification/index.d.ts +9 -3
- package/dist/verification/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-V3WTQRHC.js.map +0 -1
package/dist/debug/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Writable } from 'node:stream';
|
|
2
|
-
import { P as PetriNet, b as Transition, T as Token } from '../petri-net-
|
|
3
|
-
import { E as EventStore, N as NetEvent } from '../event-store-
|
|
2
|
+
import { P as PetriNet, b as Transition, T as Token } from '../petri-net-C3LSY-vm.js';
|
|
3
|
+
import { E as EventStore, N as NetEvent } from '../event-store-DKTenPbC.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Commands sent from debug UI client to server via WebSocket.
|
package/dist/doclet/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Application } from 'typedoc';
|
|
2
|
-
import { P as PetriNet, S as SubnetDef, o as Instance } from '../petri-net-
|
|
2
|
+
import { P as PetriNet, S as SubnetDef, o as Instance } from '../petri-net-C3LSY-vm.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* TypeDoc plugin for `@petrinet` and `@subnet` tags — auto-generates
|
package/dist/export/index.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PetriNet, S as SubnetDef, a as Place, T as Token, b as Transition, E as EnvironmentPlace, c as TransitionContext, O as Out } from './petri-net-
|
|
2
|
-
export { A as Arc, d as ArcInhibitor, e as ArcInput, f as ArcOutput, g as ArcRead, h as ArcReset, C as Channel, i as ComposeBindings, F as FusionSet, j as FusionSetBuilder, I as In, k as InAll, l as InAtLeast, m as InExactly, n as InOne, o as Instance, p as Interface, q as InterfaceBuilder, K as KeyFn, L as LogFn, M as MAX_DURATION_MS, r as MatchKey, s as MatchSpec, N as NameId, t as OutAnd, u as OutForwardInput, v as OutPlace, w as OutTimeout, x as OutXor, y as OutputEntry, z as PetriNetBuilder, B as Port, D as PortDirection, G as SubnetDefBuilder, H as SubnetInstance, J as Timing, Q as TimingDeadline, R as TimingDelayed, U as TimingExact, V as TimingImmediate, W as TimingWindow, X as TokenInput, Y as TokenOutput, Z as TransitionAction, _ as TransitionBuilder, $ as VerificationHarness, a0 as VerificationResult, a1 as all, a2 as allPlaces, a3 as and, a4 as andPlaces, a5 as arcPlace, a6 as atLeast, a7 as consumptionCount, a8 as deadline, a9 as delayed, aa as earliest, ab as enumerateBranches, ac as environmentPlace, ad as exact, ae as exactly, af as fork, ag as forwardInput, ah as hasDeadline, ai as hasGuard, aj as immediate, ak as inhibitorArc, al as inputArc, am as
|
|
3
|
-
import { E as EventStore } from './event-store-
|
|
4
|
-
export { A as ActionTimedOut, a as ExecutionCompleted, b as ExecutionStarted, I as InMemoryEventStore, L as LogMessage, M as MarkingSnapshot, N as NetEvent, T as TokenAdded, c as TokenRemoved, d as TransitionClockRestarted, e as TransitionCompleted, f as TransitionEnabled, g as TransitionFailed, h as TransitionStarted, i as TransitionTimedOut, j as eventTransitionName, k as eventsOfType, l as failures, m as filterEvents, n as inMemoryEventStore, o as isFailureEvent, p as noopEventStore, t as transitionEvents } from './event-store-
|
|
1
|
+
import { P as PetriNet, S as SubnetDef, a as Place, T as Token, b as Transition, E as EnvironmentPlace, c as TransitionContext, O as Out } from './petri-net-C3LSY-vm.js';
|
|
2
|
+
export { A as Arc, d as ArcInhibitor, e as ArcInput, f as ArcOutput, g as ArcRead, h as ArcReset, C as Channel, i as ComposeBindings, F as FusionSet, j as FusionSetBuilder, I as In, k as InAll, l as InAtLeast, m as InExactly, n as InOne, o as Instance, p as Interface, q as InterfaceBuilder, K as KeyFn, L as LogFn, M as MAX_DURATION_MS, r as MatchKey, s as MatchSpec, N as NameId, t as OutAnd, u as OutForwardInput, v as OutPlace, w as OutTimeout, x as OutXor, y as OutputEntry, z as PetriNetBuilder, B as Port, D as PortDirection, G as SubnetDefBuilder, H as SubnetInstance, J as Timing, Q as TimingDeadline, R as TimingDelayed, U as TimingExact, V as TimingImmediate, W as TimingWindow, X as TokenInput, Y as TokenOutput, Z as TransitionAction, _ as TransitionBuilder, $ as VerificationHarness, a0 as VerificationResult, a1 as all, a2 as allPlaces, a3 as and, a4 as andPlaces, a5 as arcPlace, a6 as atLeast, a7 as consumptionCount, a8 as deadline, a9 as delayed, aa as earliest, ab as enumerateBranches, ac as environmentPlace, ad as exact, ae as exactly, af as fork, ag as forwardInput, ah as hasDeadline, ai as hasGuard, aj as immediate, ak as inhibitorArc, al as inputArc, am as isPassthrough, an as isUnit, ao as keyForPlace, ap as latest, aq as matchCorrelates, ar as matchKey, as as matchSpec, at as matchesGuard, au as nameId, av as one, aw as outPlace, ax as outputArc, ay as passthrough, az as place, aA as produce, aB as readArc, aC as requiredCount, aD as resetArc, aE as timeout, aF as timeoutPlace, aG as tokenAt, aH as tokenOf, aI as transform, aJ as transformAsync, aK as transformFrom, aL as unitToken, aM as window, aN as withTimeout, aO as xor, aP as xorPlaces } from './petri-net-C3LSY-vm.js';
|
|
3
|
+
import { E as EventStore } from './event-store-DKTenPbC.js';
|
|
4
|
+
export { A as ActionTimedOut, a as ExecutionCompleted, b as ExecutionStarted, I as InMemoryEventStore, L as LogMessage, M as MarkingSnapshot, N as NetEvent, T as TokenAdded, c as TokenRemoved, d as TransitionClockRestarted, e as TransitionCompleted, f as TransitionEnabled, g as TransitionFailed, h as TransitionStarted, i as TransitionTimedOut, j as eventTransitionName, k as eventsOfType, l as failures, m as filterEvents, n as inMemoryEventStore, o as isFailureEvent, p as noopEventStore, t as transitionEvents } from './event-store-DKTenPbC.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Discriminated sum-type abstraction over Petri nets, distinguishing **closed**
|
|
@@ -344,6 +344,27 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
344
344
|
*/
|
|
345
345
|
private fireReadyImmediate;
|
|
346
346
|
private fireReadyGeneral;
|
|
347
|
+
/**
|
|
348
|
+
* Fires a transition, containing any synchronous throw to that one firing so it fails
|
|
349
|
+
* only that transition, not the whole run.
|
|
350
|
+
*
|
|
351
|
+
* Without this boundary an unchecked throw raised while a transition fires — a hostile
|
|
352
|
+
* EventStore.append on a token-removed or transition-started emit, or an error thrown while
|
|
353
|
+
* consuming the matched tokens — unwinds out of the orchestrator loop and kills the executor.
|
|
354
|
+
* The transition is instead failed and marked dirty for re-evaluation, the same treatment an
|
|
355
|
+
* asynchronously-reported failure gets. Enablement-phase throws (a guard or key function that
|
|
356
|
+
* throws inside canEnable, before the firing) run outside this boundary and are not contained
|
|
357
|
+
* here.
|
|
358
|
+
*
|
|
359
|
+
* fireTransition removes tokens from the marking before it reconciles the presence
|
|
360
|
+
* bitmap, so a throw inside that window would leave bits asserting tokens that are gone;
|
|
361
|
+
* the recovery re-runs updateBitmapAfterConsumption against the real marking.
|
|
362
|
+
*
|
|
363
|
+
* Unlike the Java runtime there is no VirtualMachineError/LinkageError analogue on the JS
|
|
364
|
+
* side, so every throw is contained here — there is deliberately no fatal-rethrow escape
|
|
365
|
+
* hatch.
|
|
366
|
+
*/
|
|
367
|
+
private fireTransitionContained;
|
|
347
368
|
private fireTransition;
|
|
348
369
|
private updateBitmapAfterConsumption;
|
|
349
370
|
private processCompletedTransitions;
|
|
@@ -609,6 +630,28 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
609
630
|
*/
|
|
610
631
|
private fireReadyImmediate;
|
|
611
632
|
private fireReadyGeneral;
|
|
633
|
+
/**
|
|
634
|
+
* Fires a transition, containing any synchronous throw to that one firing so it fails
|
|
635
|
+
* only that transition, not the whole run.
|
|
636
|
+
*
|
|
637
|
+
* Without this boundary an unchecked throw raised while a transition fires — a hostile
|
|
638
|
+
* EventStore.append on a token-removed or transition-started emit, or an error thrown while
|
|
639
|
+
* consuming the matched tokens — unwinds out of the orchestrator loop and kills the executor.
|
|
640
|
+
* The transition is instead failed and marked dirty for re-evaluation, the same treatment an
|
|
641
|
+
* asynchronously-reported failure gets. Enablement-phase throws (a guard or key function that
|
|
642
|
+
* throws inside canEnable, before the firing) run outside this boundary and are not contained
|
|
643
|
+
* here.
|
|
644
|
+
*
|
|
645
|
+
* fireTransition drains tokens from the queues before it reconciles the presence bitmap,
|
|
646
|
+
* so a throw inside that window would leave bits asserting tokens that are gone; the
|
|
647
|
+
* recovery re-runs updateBitmapAfterConsumption against the true queue lengths.
|
|
648
|
+
*
|
|
649
|
+
* Named to avoid colliding with the pre-existing {@link fireTransitionGuarded}
|
|
650
|
+
* guard-consume helper. Unlike the Java runtime there is no VirtualMachineError/
|
|
651
|
+
* LinkageError analogue on the JS side, so every throw is contained here — there is
|
|
652
|
+
* deliberately no fatal-rethrow escape hatch.
|
|
653
|
+
*/
|
|
654
|
+
private fireTransitionContained;
|
|
612
655
|
private fireTransition;
|
|
613
656
|
/**
|
|
614
657
|
* Consumes the name-matched tokens for a ν-net join (NU-020): correlated
|
|
@@ -677,6 +720,10 @@ declare function validateOutSpec(tName: string, spec: Out, producedPlaceNames: S
|
|
|
677
720
|
* - **AND**: recurses into all children (all branches get tokens).
|
|
678
721
|
* - **XOR**: disallowed — timeout cannot choose a branch non-deterministically.
|
|
679
722
|
* - **Timeout**: disallowed — nested timeouts would create ambiguous recovery paths.
|
|
723
|
+
*
|
|
724
|
+
* Writes through {@link TransitionContext.outputToHarvest} rather than `output(...)`:
|
|
725
|
+
* by this point the context has been detached, so the ordinary write target is closed
|
|
726
|
+
* and only the harvest collector still reaches the marking.
|
|
680
727
|
*/
|
|
681
728
|
declare function produceTimeoutOutput(context: TransitionContext, timeoutChild: Out): void;
|
|
682
729
|
|
package/dist/index.js
CHANGED
|
@@ -4,15 +4,24 @@ import {
|
|
|
4
4
|
and,
|
|
5
5
|
andPlaces,
|
|
6
6
|
enumerateBranches,
|
|
7
|
+
fork,
|
|
7
8
|
forwardInput,
|
|
9
|
+
isPassthrough,
|
|
8
10
|
isProven,
|
|
9
11
|
isViolated,
|
|
10
12
|
outPlace,
|
|
13
|
+
passthrough,
|
|
14
|
+
produce,
|
|
15
|
+
requireOutputProducingActions,
|
|
11
16
|
timeout,
|
|
12
17
|
timeoutPlace,
|
|
18
|
+
transform,
|
|
19
|
+
transformAsync,
|
|
20
|
+
transformFrom,
|
|
21
|
+
withTimeout,
|
|
13
22
|
xor,
|
|
14
23
|
xorPlaces
|
|
15
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-7VJ5CYUU.js";
|
|
16
25
|
import {
|
|
17
26
|
eventTransitionName,
|
|
18
27
|
isFailureEvent
|
|
@@ -142,83 +151,69 @@ function nameId(value) {
|
|
|
142
151
|
return value;
|
|
143
152
|
}
|
|
144
153
|
|
|
145
|
-
// src/core/
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
154
|
+
// src/core/token-output.ts
|
|
155
|
+
var TokenOutput = class {
|
|
156
|
+
_entries = [];
|
|
157
|
+
/**
|
|
158
|
+
* Once true, further writes are dropped instead of appended. Set by the executor
|
|
159
|
+
* (via {@link import('./transition-context.js').TransitionContext.detachForTimeout})
|
|
160
|
+
* when a firing times out, so the action it has stopped waiting for can no longer
|
|
161
|
+
* reach the marking. Irreversible.
|
|
162
|
+
*/
|
|
163
|
+
detached = false;
|
|
164
|
+
/** Add a value to an output place (creates token with current timestamp). */
|
|
165
|
+
add(place2, value) {
|
|
166
|
+
if (this.detached) return this;
|
|
167
|
+
this._entries.push({ place: place2, token: tokenOf(value) });
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
/** Add a pre-existing token to an output place. */
|
|
171
|
+
addToken(place2, token) {
|
|
172
|
+
if (this.detached) return this;
|
|
173
|
+
this._entries.push({ place: place2, token });
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* @internal Severs this collector: subsequent {@link add}/{@link addToken} calls are
|
|
178
|
+
* dropped. Executor machinery invoked when a firing times out — never call from an action.
|
|
179
|
+
*/
|
|
180
|
+
detach() {
|
|
181
|
+
this.detached = true;
|
|
182
|
+
}
|
|
183
|
+
/** Returns all collected outputs. */
|
|
184
|
+
entries() {
|
|
185
|
+
return this._entries;
|
|
186
|
+
}
|
|
187
|
+
/** Check if any outputs were produced. */
|
|
188
|
+
isEmpty() {
|
|
189
|
+
return this._entries.length === 0;
|
|
190
|
+
}
|
|
191
|
+
/** Returns the set of place names that received tokens. */
|
|
192
|
+
placesWithTokens() {
|
|
193
|
+
const result = /* @__PURE__ */ new Set();
|
|
194
|
+
for (const entry of this._entries) {
|
|
195
|
+
result.add(entry.place.name);
|
|
177
196
|
}
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return async (ctx) => {
|
|
182
|
-
ctx.output(place2, value);
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
function withTimeout(action, timeoutMs, timeoutPlace2, timeoutValue) {
|
|
186
|
-
return (ctx) => {
|
|
187
|
-
return new Promise((resolve2, reject) => {
|
|
188
|
-
let completed = false;
|
|
189
|
-
const timer = setTimeout(() => {
|
|
190
|
-
if (!completed) {
|
|
191
|
-
completed = true;
|
|
192
|
-
ctx.output(timeoutPlace2, timeoutValue);
|
|
193
|
-
resolve2();
|
|
194
|
-
}
|
|
195
|
-
}, timeoutMs);
|
|
196
|
-
action(ctx).then(
|
|
197
|
-
() => {
|
|
198
|
-
if (!completed) {
|
|
199
|
-
completed = true;
|
|
200
|
-
clearTimeout(timer);
|
|
201
|
-
resolve2();
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
(err) => {
|
|
205
|
-
if (!completed) {
|
|
206
|
-
completed = true;
|
|
207
|
-
clearTimeout(timer);
|
|
208
|
-
reject(err);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
);
|
|
212
|
-
});
|
|
213
|
-
};
|
|
214
|
-
}
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
215
200
|
|
|
216
201
|
// src/core/transition-context.ts
|
|
217
202
|
var EMPTY_ALIAS = /* @__PURE__ */ new Map();
|
|
218
203
|
var GLOBAL_FRESH_NAME_COUNTER = 0;
|
|
219
204
|
var TransitionContext = class {
|
|
220
205
|
rawInput;
|
|
206
|
+
/**
|
|
207
|
+
* What the executor harvests. Identical to {@link writeTarget} until
|
|
208
|
+
* {@link detachForTimeout} replaces it with a fresh collector the action cannot reach.
|
|
209
|
+
*/
|
|
221
210
|
_rawOutput;
|
|
211
|
+
/**
|
|
212
|
+
* What the action writes to. Never reassigned, so an action already inside
|
|
213
|
+
* `output(...)` cannot be redirected mid-write; severance happens by detaching this
|
|
214
|
+
* collector, not by swapping it.
|
|
215
|
+
*/
|
|
216
|
+
writeTarget;
|
|
222
217
|
allowedInputs;
|
|
223
218
|
allowedReads;
|
|
224
219
|
allowedOutputs;
|
|
@@ -234,6 +229,7 @@ var TransitionContext = class {
|
|
|
234
229
|
this._transitionName = transitionName;
|
|
235
230
|
this.rawInput = rawInput;
|
|
236
231
|
this._rawOutput = rawOutput;
|
|
232
|
+
this.writeTarget = rawOutput;
|
|
237
233
|
this._inputPlaces = inputPlaces;
|
|
238
234
|
this._readPlaces = readPlaces;
|
|
239
235
|
this._outputPlaces = outputPlaces;
|
|
@@ -340,7 +336,7 @@ var TransitionContext = class {
|
|
|
340
336
|
const actual = this.resolve(place2);
|
|
341
337
|
this.requireOutput(actual);
|
|
342
338
|
for (const value of values) {
|
|
343
|
-
this.
|
|
339
|
+
this.writeTarget.add(actual, value);
|
|
344
340
|
}
|
|
345
341
|
return this;
|
|
346
342
|
}
|
|
@@ -356,7 +352,7 @@ var TransitionContext = class {
|
|
|
356
352
|
const actual = this.resolve(place2);
|
|
357
353
|
this.requireOutput(actual);
|
|
358
354
|
for (const token of tokens) {
|
|
359
|
-
this.
|
|
355
|
+
this.writeTarget.addToken(actual, token);
|
|
360
356
|
}
|
|
361
357
|
return this;
|
|
362
358
|
}
|
|
@@ -371,6 +367,38 @@ var TransitionContext = class {
|
|
|
371
367
|
);
|
|
372
368
|
}
|
|
373
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Severs the action's output from the marking, for use when a firing times out.
|
|
372
|
+
*
|
|
373
|
+
* After this call the action's `output(...)` writes are dropped, and the executor
|
|
374
|
+
* harvests a fresh collector the action holds no reference to. Anything the action
|
|
375
|
+
* wrote *before* the timeout is discarded with it: a partial result merged with the
|
|
376
|
+
* timeout branch would violate the transition's own output spec.
|
|
377
|
+
*
|
|
378
|
+
* This is the only isolation available — libpetri does not own the promise the action
|
|
379
|
+
* runs on, so it cannot stop the work, only stop the result from landing.
|
|
380
|
+
*
|
|
381
|
+
* @internal Executor machinery — must be called by the executor, never by an action.
|
|
382
|
+
*/
|
|
383
|
+
detachForTimeout() {
|
|
384
|
+
this.writeTarget.detach();
|
|
385
|
+
this._rawOutput = new TokenOutput();
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Produces into the executor's harvest collector rather than the action's write target.
|
|
389
|
+
*
|
|
390
|
+
* Identical to {@link output} before {@link detachForTimeout}; after it, this is the
|
|
391
|
+
* only route that still reaches the marking. Used by the executor to deposit the
|
|
392
|
+
* timeout branch.
|
|
393
|
+
*
|
|
394
|
+
* @internal Executor machinery — must be called by the executor, never by an action.
|
|
395
|
+
*/
|
|
396
|
+
outputToHarvest(place2, value) {
|
|
397
|
+
const actual = this.resolve(place2);
|
|
398
|
+
this.requireOutput(actual);
|
|
399
|
+
this._rawOutput.add(actual, value);
|
|
400
|
+
return this;
|
|
401
|
+
}
|
|
374
402
|
// ==================== ν-name minting (NU-010) ====================
|
|
375
403
|
/**
|
|
376
404
|
* @internal Installs the ν-name minter. Wired by the executor at firing time
|
|
@@ -462,37 +490,6 @@ var TokenInput = class {
|
|
|
462
490
|
}
|
|
463
491
|
};
|
|
464
492
|
|
|
465
|
-
// src/core/token-output.ts
|
|
466
|
-
var TokenOutput = class {
|
|
467
|
-
_entries = [];
|
|
468
|
-
/** Add a value to an output place (creates token with current timestamp). */
|
|
469
|
-
add(place2, value) {
|
|
470
|
-
this._entries.push({ place: place2, token: tokenOf(value) });
|
|
471
|
-
return this;
|
|
472
|
-
}
|
|
473
|
-
/** Add a pre-existing token to an output place. */
|
|
474
|
-
addToken(place2, token) {
|
|
475
|
-
this._entries.push({ place: place2, token });
|
|
476
|
-
return this;
|
|
477
|
-
}
|
|
478
|
-
/** Returns all collected outputs. */
|
|
479
|
-
entries() {
|
|
480
|
-
return this._entries;
|
|
481
|
-
}
|
|
482
|
-
/** Check if any outputs were produced. */
|
|
483
|
-
isEmpty() {
|
|
484
|
-
return this._entries.length === 0;
|
|
485
|
-
}
|
|
486
|
-
/** Returns the set of place names that received tokens. */
|
|
487
|
-
placesWithTokens() {
|
|
488
|
-
const result = /* @__PURE__ */ new Set();
|
|
489
|
-
for (const entry of this._entries) {
|
|
490
|
-
result.add(entry.place.name);
|
|
491
|
-
}
|
|
492
|
-
return result;
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
|
|
496
493
|
// src/core/transition.ts
|
|
497
494
|
var TRANSITION_KEY = /* @__PURE__ */ Symbol("Transition.internal");
|
|
498
495
|
var EMPTY_PLACE_ALIAS = /* @__PURE__ */ new Map();
|
|
@@ -1267,10 +1264,6 @@ function describeTiming(t) {
|
|
|
1267
1264
|
return `Exact(atMs=${t.atMs})`;
|
|
1268
1265
|
}
|
|
1269
1266
|
}
|
|
1270
|
-
var PASSTHROUGH_REF = passthrough();
|
|
1271
|
-
function isPassthrough(action) {
|
|
1272
|
-
return action === PASSTHROUGH_REF;
|
|
1273
|
-
}
|
|
1274
1267
|
function keyOfIn(arc) {
|
|
1275
1268
|
switch (arc.type) {
|
|
1276
1269
|
case "one":
|
|
@@ -1513,6 +1506,7 @@ var SubnetDef = class _SubnetDef {
|
|
|
1513
1506
|
}
|
|
1514
1507
|
}
|
|
1515
1508
|
const syntheticNet = PetriNet.builder("verify_" + this.name).compose(sut, portMappings).build();
|
|
1509
|
+
requireOutputProducingActions(syntheticNet);
|
|
1516
1510
|
const perProperty = /* @__PURE__ */ new Map();
|
|
1517
1511
|
for (const property of properties) {
|
|
1518
1512
|
const verifier = SmtVerifier.forNet(syntheticNet).property(property);
|
|
@@ -1864,6 +1858,10 @@ var PetriNet = class _PetriNet {
|
|
|
1864
1858
|
}
|
|
1865
1859
|
/**
|
|
1866
1860
|
* Creates a new PetriNet with actions bound via a resolver function.
|
|
1861
|
+
*
|
|
1862
|
+
* The resolver is called once per transition with its name. Returning `null`
|
|
1863
|
+
* defers that transition — it keeps whatever action it already carries — which
|
|
1864
|
+
* is what makes staged binding (**MOD-024** AC7) work.
|
|
1867
1865
|
*/
|
|
1868
1866
|
bindActionsWithResolver(actionResolver) {
|
|
1869
1867
|
const boundTransitions = /* @__PURE__ */ new Set();
|
|
@@ -2497,6 +2495,7 @@ var CompiledNet = class _CompiledNet {
|
|
|
2497
2495
|
_hasMatch;
|
|
2498
2496
|
constructor(net) {
|
|
2499
2497
|
this.net = net;
|
|
2498
|
+
requireOutputProducingActions(net);
|
|
2500
2499
|
const allPlacesSet = /* @__PURE__ */ new Map();
|
|
2501
2500
|
for (const t of net.transitions) {
|
|
2502
2501
|
for (const spec of t.inputSpecs) allPlacesSet.set(spec.place.name, spec.place);
|
|
@@ -3006,6 +3005,25 @@ var OutViolationError = class extends Error {
|
|
|
3006
3005
|
};
|
|
3007
3006
|
|
|
3008
3007
|
// src/runtime/executor-support.ts
|
|
3008
|
+
function executeAction(t, context) {
|
|
3009
|
+
try {
|
|
3010
|
+
const stage = t.action(context);
|
|
3011
|
+
if (stage == null || typeof stage.then !== "function") {
|
|
3012
|
+
return Promise.reject(new Error(
|
|
3013
|
+
`'${t.name}': action returned null/non-thenable instead of a Promise`
|
|
3014
|
+
));
|
|
3015
|
+
}
|
|
3016
|
+
return Promise.resolve(stage);
|
|
3017
|
+
} catch (err) {
|
|
3018
|
+
return Promise.reject(err);
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
function swallowEventStoreFailure(when, err) {
|
|
3022
|
+
console.warn(
|
|
3023
|
+
`libpetri: EventStore.append threw while emitting ${when}; the event is dropped`,
|
|
3024
|
+
err
|
|
3025
|
+
);
|
|
3026
|
+
}
|
|
3009
3027
|
var DEADLINE_TOLERANCE_MS = 5;
|
|
3010
3028
|
function validateOutSpec(tName, spec, producedPlaceNames) {
|
|
3011
3029
|
switch (spec.type) {
|
|
@@ -3047,11 +3065,11 @@ function validateOutSpec(tName, spec, producedPlaceNames) {
|
|
|
3047
3065
|
function produceTimeoutOutput(context, timeoutChild) {
|
|
3048
3066
|
switch (timeoutChild.type) {
|
|
3049
3067
|
case "place":
|
|
3050
|
-
context.
|
|
3068
|
+
context.outputToHarvest(timeoutChild.place, null);
|
|
3051
3069
|
break;
|
|
3052
3070
|
case "forward-input": {
|
|
3053
3071
|
const value = context.input(timeoutChild.from);
|
|
3054
|
-
context.
|
|
3072
|
+
context.outputToHarvest(timeoutChild.to, value);
|
|
3055
3073
|
break;
|
|
3056
3074
|
}
|
|
3057
3075
|
case "and":
|
|
@@ -3506,7 +3524,7 @@ var BitmapNetExecutor = class {
|
|
|
3506
3524
|
for (let tid = 0; tid < this.compiled.transitionCount; tid++) {
|
|
3507
3525
|
if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
|
|
3508
3526
|
if (this.canEnable(tid, this.markedPlaces)) {
|
|
3509
|
-
this.
|
|
3527
|
+
this.fireTransitionContained(tid);
|
|
3510
3528
|
} else {
|
|
3511
3529
|
this.enabledFlags[tid] = 0;
|
|
3512
3530
|
this.enabledTransitionCount--;
|
|
@@ -3538,7 +3556,7 @@ var BitmapNetExecutor = class {
|
|
|
3538
3556
|
for (const entry of ready) {
|
|
3539
3557
|
const { tid } = entry;
|
|
3540
3558
|
if (this.enabledFlags[tid] && this.canEnable(tid, freshSnap)) {
|
|
3541
|
-
this.
|
|
3559
|
+
this.fireTransitionContained(tid);
|
|
3542
3560
|
freshSnap.set(this.markedPlaces);
|
|
3543
3561
|
} else {
|
|
3544
3562
|
this.enabledFlags[tid] = 0;
|
|
@@ -3547,6 +3565,53 @@ var BitmapNetExecutor = class {
|
|
|
3547
3565
|
}
|
|
3548
3566
|
}
|
|
3549
3567
|
}
|
|
3568
|
+
/**
|
|
3569
|
+
* Fires a transition, containing any synchronous throw to that one firing so it fails
|
|
3570
|
+
* only that transition, not the whole run.
|
|
3571
|
+
*
|
|
3572
|
+
* Without this boundary an unchecked throw raised while a transition fires — a hostile
|
|
3573
|
+
* EventStore.append on a token-removed or transition-started emit, or an error thrown while
|
|
3574
|
+
* consuming the matched tokens — unwinds out of the orchestrator loop and kills the executor.
|
|
3575
|
+
* The transition is instead failed and marked dirty for re-evaluation, the same treatment an
|
|
3576
|
+
* asynchronously-reported failure gets. Enablement-phase throws (a guard or key function that
|
|
3577
|
+
* throws inside canEnable, before the firing) run outside this boundary and are not contained
|
|
3578
|
+
* here.
|
|
3579
|
+
*
|
|
3580
|
+
* fireTransition removes tokens from the marking before it reconciles the presence
|
|
3581
|
+
* bitmap, so a throw inside that window would leave bits asserting tokens that are gone;
|
|
3582
|
+
* the recovery re-runs updateBitmapAfterConsumption against the real marking.
|
|
3583
|
+
*
|
|
3584
|
+
* Unlike the Java runtime there is no VirtualMachineError/LinkageError analogue on the JS
|
|
3585
|
+
* side, so every throw is contained here — there is deliberately no fatal-rethrow escape
|
|
3586
|
+
* hatch.
|
|
3587
|
+
*/
|
|
3588
|
+
fireTransitionContained(tid) {
|
|
3589
|
+
try {
|
|
3590
|
+
this.fireTransition(tid);
|
|
3591
|
+
} catch (e) {
|
|
3592
|
+
const t = this.compiled.transition(tid);
|
|
3593
|
+
if (this.enabledFlags[tid]) {
|
|
3594
|
+
this.enabledFlags[tid] = 0;
|
|
3595
|
+
this.enabledTransitionCount--;
|
|
3596
|
+
this.enabledAtMs[tid] = -Infinity;
|
|
3597
|
+
}
|
|
3598
|
+
if (this.inFlight.delete(t)) {
|
|
3599
|
+
this.inFlightFlags[tid] = 0;
|
|
3600
|
+
}
|
|
3601
|
+
this.updateBitmapAfterConsumption(tid);
|
|
3602
|
+
this.matchCaches[tid] = null;
|
|
3603
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
3604
|
+
this.emitEvent({
|
|
3605
|
+
type: "transition-failed",
|
|
3606
|
+
timestamp: Date.now(),
|
|
3607
|
+
transitionName: t.name,
|
|
3608
|
+
errorMessage: err.message,
|
|
3609
|
+
exceptionType: err.name,
|
|
3610
|
+
stack: err.stack
|
|
3611
|
+
});
|
|
3612
|
+
this.markTransitionDirty(tid);
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3550
3615
|
fireTransition(tid) {
|
|
3551
3616
|
const t = this.compiled.transition(tid);
|
|
3552
3617
|
const inputs = new TokenInput();
|
|
@@ -3645,7 +3710,7 @@ var BitmapNetExecutor = class {
|
|
|
3645
3710
|
);
|
|
3646
3711
|
const freshNameBase = t.name;
|
|
3647
3712
|
context.setFreshNameSupplier(() => nameId(`${freshNameBase}#${this.freshNameCounter++}`));
|
|
3648
|
-
let actionPromise = t
|
|
3713
|
+
let actionPromise = executeAction(t, context);
|
|
3649
3714
|
if (t.hasActionTimeout()) {
|
|
3650
3715
|
const timeoutSpec = t.actionTimeout;
|
|
3651
3716
|
if (timeoutSpec === null) throw new Error(`Expected actionTimeout on ${t.name}`);
|
|
@@ -3657,6 +3722,7 @@ var BitmapNetExecutor = class {
|
|
|
3657
3722
|
)
|
|
3658
3723
|
]).catch((err) => {
|
|
3659
3724
|
if (err instanceof TimeoutSentinel) {
|
|
3725
|
+
context.detachForTimeout();
|
|
3660
3726
|
produceTimeoutOutput(context, timeoutSpec.child);
|
|
3661
3727
|
this.emitEvent({
|
|
3662
3728
|
type: "action-timed-out",
|
|
@@ -3927,7 +3993,11 @@ var BitmapNetExecutor = class {
|
|
|
3927
3993
|
// ======================== Event Emission ========================
|
|
3928
3994
|
emitEvent(event) {
|
|
3929
3995
|
if (this.eventStoreEnabled) {
|
|
3930
|
-
|
|
3996
|
+
try {
|
|
3997
|
+
this.eventStore.append(event);
|
|
3998
|
+
} catch (err) {
|
|
3999
|
+
swallowEventStoreFailure(event.type, err);
|
|
4000
|
+
}
|
|
3931
4001
|
}
|
|
3932
4002
|
}
|
|
3933
4003
|
};
|
|
@@ -4764,7 +4834,7 @@ var PrecompiledNetExecutor = class {
|
|
|
4764
4834
|
for (let tid = 0; tid < tc; tid++) {
|
|
4765
4835
|
if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
|
|
4766
4836
|
if (this.canEnable(tid, this.markingBitmap)) {
|
|
4767
|
-
this.
|
|
4837
|
+
this.fireTransitionContained(tid);
|
|
4768
4838
|
} else {
|
|
4769
4839
|
this.enabledFlags[tid] = 0;
|
|
4770
4840
|
this.enabledTransitionCount--;
|
|
@@ -4795,7 +4865,7 @@ var PrecompiledNetExecutor = class {
|
|
|
4795
4865
|
for (const entry of ready) {
|
|
4796
4866
|
const { tid } = entry;
|
|
4797
4867
|
if (this.enabledFlags[tid] && this.canEnable(tid, freshSnap)) {
|
|
4798
|
-
this.
|
|
4868
|
+
this.fireTransitionContained(tid);
|
|
4799
4869
|
freshSnap.set(this.markingBitmap);
|
|
4800
4870
|
} else {
|
|
4801
4871
|
this.enabledFlags[tid] = 0;
|
|
@@ -4804,6 +4874,60 @@ var PrecompiledNetExecutor = class {
|
|
|
4804
4874
|
}
|
|
4805
4875
|
}
|
|
4806
4876
|
}
|
|
4877
|
+
/**
|
|
4878
|
+
* Fires a transition, containing any synchronous throw to that one firing so it fails
|
|
4879
|
+
* only that transition, not the whole run.
|
|
4880
|
+
*
|
|
4881
|
+
* Without this boundary an unchecked throw raised while a transition fires — a hostile
|
|
4882
|
+
* EventStore.append on a token-removed or transition-started emit, or an error thrown while
|
|
4883
|
+
* consuming the matched tokens — unwinds out of the orchestrator loop and kills the executor.
|
|
4884
|
+
* The transition is instead failed and marked dirty for re-evaluation, the same treatment an
|
|
4885
|
+
* asynchronously-reported failure gets. Enablement-phase throws (a guard or key function that
|
|
4886
|
+
* throws inside canEnable, before the firing) run outside this boundary and are not contained
|
|
4887
|
+
* here.
|
|
4888
|
+
*
|
|
4889
|
+
* fireTransition drains tokens from the queues before it reconciles the presence bitmap,
|
|
4890
|
+
* so a throw inside that window would leave bits asserting tokens that are gone; the
|
|
4891
|
+
* recovery re-runs updateBitmapAfterConsumption against the true queue lengths.
|
|
4892
|
+
*
|
|
4893
|
+
* Named to avoid colliding with the pre-existing {@link fireTransitionGuarded}
|
|
4894
|
+
* guard-consume helper. Unlike the Java runtime there is no VirtualMachineError/
|
|
4895
|
+
* LinkageError analogue on the JS side, so every throw is contained here — there is
|
|
4896
|
+
* deliberately no fatal-rethrow escape hatch.
|
|
4897
|
+
*/
|
|
4898
|
+
fireTransitionContained(tid) {
|
|
4899
|
+
try {
|
|
4900
|
+
this.fireTransition(tid);
|
|
4901
|
+
} catch (e) {
|
|
4902
|
+
const t = this.program.compiled.transition(tid);
|
|
4903
|
+
if (this.enabledFlags[tid]) {
|
|
4904
|
+
this.enabledFlags[tid] = 0;
|
|
4905
|
+
this.enabledTransitionCount--;
|
|
4906
|
+
this.enabledAtMs[tid] = -Infinity;
|
|
4907
|
+
}
|
|
4908
|
+
if (this.inFlightFlags[tid]) {
|
|
4909
|
+
this.inFlightPromises[tid] = null;
|
|
4910
|
+
this.inFlightContexts[tid] = null;
|
|
4911
|
+
this.inFlightConsumed[tid] = null;
|
|
4912
|
+
this.inFlightResolves[tid] = null;
|
|
4913
|
+
this.inFlightErrors[tid] = null;
|
|
4914
|
+
this.inFlightFlags[tid] = 0;
|
|
4915
|
+
this.inFlightCount--;
|
|
4916
|
+
}
|
|
4917
|
+
this.updateBitmapAfterConsumption(tid);
|
|
4918
|
+
this.matchCaches[tid] = null;
|
|
4919
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
4920
|
+
this.emitEvent({
|
|
4921
|
+
type: "transition-failed",
|
|
4922
|
+
timestamp: Date.now(),
|
|
4923
|
+
transitionName: t.name,
|
|
4924
|
+
errorMessage: err.message,
|
|
4925
|
+
exceptionType: err.name,
|
|
4926
|
+
stack: err.stack
|
|
4927
|
+
});
|
|
4928
|
+
this.markTransitionDirty(tid);
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4807
4931
|
fireTransition(tid) {
|
|
4808
4932
|
const prog = this.program;
|
|
4809
4933
|
const t = prog.compiled.transition(tid);
|
|
@@ -4952,7 +5076,7 @@ var PrecompiledNetExecutor = class {
|
|
|
4952
5076
|
this.freshNameSuppliers[tid] = freshNameSupplier;
|
|
4953
5077
|
}
|
|
4954
5078
|
context.setFreshNameSupplier(freshNameSupplier);
|
|
4955
|
-
let actionPromise = t
|
|
5079
|
+
let actionPromise = executeAction(t, context);
|
|
4956
5080
|
if (t.hasActionTimeout()) {
|
|
4957
5081
|
const timeoutSpec = t.actionTimeout;
|
|
4958
5082
|
if (timeoutSpec === null) throw new Error(`Expected actionTimeout on ${t.name}`);
|
|
@@ -4964,6 +5088,7 @@ var PrecompiledNetExecutor = class {
|
|
|
4964
5088
|
)
|
|
4965
5089
|
]).catch((err) => {
|
|
4966
5090
|
if (err instanceof TimeoutSentinel2) {
|
|
5091
|
+
context.detachForTimeout();
|
|
4967
5092
|
produceTimeoutOutput(context, timeoutSpec.child);
|
|
4968
5093
|
this.emitEvent({
|
|
4969
5094
|
type: "action-timed-out",
|
|
@@ -5358,7 +5483,11 @@ var PrecompiledNetExecutor = class {
|
|
|
5358
5483
|
// ======================== Event Emission ========================
|
|
5359
5484
|
emitEvent(event) {
|
|
5360
5485
|
if (this.eventStoreEnabled) {
|
|
5361
|
-
|
|
5486
|
+
try {
|
|
5487
|
+
this.eventStore.append(event);
|
|
5488
|
+
} catch (err) {
|
|
5489
|
+
swallowEventStoreFailure(event.type, err);
|
|
5490
|
+
}
|
|
5362
5491
|
}
|
|
5363
5492
|
}
|
|
5364
5493
|
};
|
|
@@ -5423,6 +5552,7 @@ export {
|
|
|
5423
5552
|
inputArc,
|
|
5424
5553
|
intersects,
|
|
5425
5554
|
isFailureEvent,
|
|
5555
|
+
isPassthrough,
|
|
5426
5556
|
isUnit,
|
|
5427
5557
|
keyForPlace,
|
|
5428
5558
|
latest,
|