@turing-machine-js/machine 2.0.2 → 3.0.1
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 +54 -0
- package/README.md +256 -12
- package/dist/classes/State.d.ts +27 -0
- package/dist/index.cjs +775 -173
- package/dist/index.d.ts +5 -1
- package/dist/index.mjs +771 -174
- package/dist/utilities/equivalence.d.ts +31 -0
- package/dist/utilities/graph.d.ts +29 -0
- package/dist/utilities/graphFormats.d.ts +3 -0
- package/dist/utilities/introspection.d.ts +15 -0
- package/package.json +2 -8
- package/dist/classes/Alphabet.js +0 -50
- package/dist/classes/Command.js +0 -38
- package/dist/classes/Lock.js +0 -34
- package/dist/classes/Reference.js +0 -31
- package/dist/classes/State.js +0 -113
- package/dist/classes/Tape.js +0 -95
- package/dist/classes/TapeBlock.js +0 -198
- package/dist/classes/TapeCommand.js +0 -46
- package/dist/classes/TuringMachine.js +0 -102
- package/dist/index.js +0 -8
- package/dist/utilities/functions.js +0 -13
- package/tsconfig.tsbuildinfo +0 -1
package/dist/index.mjs
CHANGED
|
@@ -173,121 +173,13 @@ class Reference {
|
|
|
173
173
|
}
|
|
174
174
|
_Reference_referenceBinding = new WeakMap();
|
|
175
175
|
|
|
176
|
-
var __classPrivateFieldGet$4 = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
177
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
178
|
-
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");
|
|
179
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
180
|
-
};
|
|
181
176
|
var __classPrivateFieldSet$4 = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
182
177
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
183
178
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
184
179
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
185
180
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
186
181
|
};
|
|
187
|
-
var
|
|
188
|
-
const ifOtherSymbol = Symbol('other symbol');
|
|
189
|
-
class State {
|
|
190
|
-
constructor(stateDefinition = null, name) {
|
|
191
|
-
_State_id.set(this, id(this));
|
|
192
|
-
_State_name.set(this, void 0);
|
|
193
|
-
_State_overrodeHaltState.set(this, null);
|
|
194
|
-
_State_symbolToDataMap.set(this, new Map());
|
|
195
|
-
if (stateDefinition) {
|
|
196
|
-
const keys = Object.getOwnPropertyNames(stateDefinition);
|
|
197
|
-
if (keys.length) {
|
|
198
|
-
throw new Error(`invalid state definition while constructing state #${__classPrivateFieldGet$4(this, _State_id, "f")}`);
|
|
199
|
-
}
|
|
200
|
-
const symbols = Object.getOwnPropertySymbols(stateDefinition);
|
|
201
|
-
if (symbols.length === 0) {
|
|
202
|
-
throw new Error(`invalid state definition while constructing state #${__classPrivateFieldGet$4(this, _State_id, "f")}`);
|
|
203
|
-
}
|
|
204
|
-
symbols.forEach((symbol) => {
|
|
205
|
-
const { nextState } = stateDefinition[symbol];
|
|
206
|
-
const nextStateLocal = nextState !== null && nextState !== void 0 ? nextState : this;
|
|
207
|
-
if (!(nextStateLocal instanceof State) && !(nextStateLocal instanceof Reference)) {
|
|
208
|
-
throw new Error('invalid nextState');
|
|
209
|
-
}
|
|
210
|
-
let { command } = stateDefinition[symbol];
|
|
211
|
-
if (command == null) {
|
|
212
|
-
command = new Command([
|
|
213
|
-
new TapeCommand({}),
|
|
214
|
-
]);
|
|
215
|
-
}
|
|
216
|
-
if (!(command instanceof Command) && !Array.isArray(command)) {
|
|
217
|
-
command = [command];
|
|
218
|
-
}
|
|
219
|
-
let commandLocal = command;
|
|
220
|
-
if (Array.isArray(command)) {
|
|
221
|
-
try {
|
|
222
|
-
commandLocal = new Command(command);
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (!(commandLocal instanceof Command)) {
|
|
228
|
-
throw new Error('invalid command');
|
|
229
|
-
}
|
|
230
|
-
__classPrivateFieldGet$4(this, _State_symbolToDataMap, "f").set(symbol, {
|
|
231
|
-
command: commandLocal,
|
|
232
|
-
nextState: nextStateLocal,
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
__classPrivateFieldSet$4(this, _State_name, name !== null && name !== void 0 ? name : `id:${__classPrivateFieldGet$4(this, _State_id, "f")}`, "f");
|
|
237
|
-
}
|
|
238
|
-
get id() {
|
|
239
|
-
return __classPrivateFieldGet$4(this, _State_id, "f");
|
|
240
|
-
}
|
|
241
|
-
get name() {
|
|
242
|
-
return __classPrivateFieldGet$4(this, _State_name, "f");
|
|
243
|
-
}
|
|
244
|
-
get isHalt() {
|
|
245
|
-
return __classPrivateFieldGet$4(this, _State_id, "f") === 0;
|
|
246
|
-
}
|
|
247
|
-
get overrodeHaltState() {
|
|
248
|
-
return __classPrivateFieldGet$4(this, _State_overrodeHaltState, "f");
|
|
249
|
-
}
|
|
250
|
-
get ref() {
|
|
251
|
-
return this;
|
|
252
|
-
}
|
|
253
|
-
getSymbol(tapeBlock) {
|
|
254
|
-
const symbol = [...__classPrivateFieldGet$4(this, _State_symbolToDataMap, "f").keys()].find((currentSymbol) => tapeBlock.isMatched({
|
|
255
|
-
symbol: currentSymbol,
|
|
256
|
-
}));
|
|
257
|
-
if (symbol) {
|
|
258
|
-
return symbol;
|
|
259
|
-
}
|
|
260
|
-
return ifOtherSymbol;
|
|
261
|
-
}
|
|
262
|
-
getCommand(symbol) {
|
|
263
|
-
if (__classPrivateFieldGet$4(this, _State_symbolToDataMap, "f").has(symbol)) {
|
|
264
|
-
return __classPrivateFieldGet$4(this, _State_symbolToDataMap, "f").get(symbol).command;
|
|
265
|
-
}
|
|
266
|
-
throw new Error(`No command for symbol at state named ${__classPrivateFieldGet$4(this, _State_name, "f")}`);
|
|
267
|
-
}
|
|
268
|
-
getNextState(symbol) {
|
|
269
|
-
if (__classPrivateFieldGet$4(this, _State_symbolToDataMap, "f").has(symbol)) {
|
|
270
|
-
return __classPrivateFieldGet$4(this, _State_symbolToDataMap, "f").get(symbol).nextState;
|
|
271
|
-
}
|
|
272
|
-
throw new Error(`No nextState for symbol at state named ${__classPrivateFieldGet$4(this, _State_id, "f")}`);
|
|
273
|
-
}
|
|
274
|
-
withOverrodeHaltState(overrodeHaltState) {
|
|
275
|
-
const state = new State(null, `${this.name}>${overrodeHaltState.name}`);
|
|
276
|
-
__classPrivateFieldSet$4(state, _State_symbolToDataMap, __classPrivateFieldGet$4(this, _State_symbolToDataMap, "f"), "f");
|
|
277
|
-
__classPrivateFieldSet$4(state, _State_overrodeHaltState, overrodeHaltState, "f");
|
|
278
|
-
return state;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
_State_id = new WeakMap(), _State_name = new WeakMap(), _State_overrodeHaltState = new WeakMap(), _State_symbolToDataMap = new WeakMap();
|
|
282
|
-
const haltState = new State(null);
|
|
283
|
-
|
|
284
|
-
var __classPrivateFieldSet$3 = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
285
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
286
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
287
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
288
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
289
|
-
};
|
|
290
|
-
var __classPrivateFieldGet$3 = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
182
|
+
var __classPrivateFieldGet$4 = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
291
183
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
292
184
|
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");
|
|
293
185
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
@@ -303,46 +195,46 @@ class Tape {
|
|
|
303
195
|
if (!isSymbolsValid) {
|
|
304
196
|
throw new Error('symbolList contains invalid symbol');
|
|
305
197
|
}
|
|
306
|
-
__classPrivateFieldSet$
|
|
307
|
-
__classPrivateFieldSet$
|
|
308
|
-
__classPrivateFieldSet$
|
|
198
|
+
__classPrivateFieldSet$4(this, _Tape_alphabet, new Alphabet(alphabet), "f");
|
|
199
|
+
__classPrivateFieldSet$4(this, _Tape_position, position, "f");
|
|
200
|
+
__classPrivateFieldSet$4(this, _Tape_viewportWidth, viewportWidth, "f");
|
|
309
201
|
const symbolsCopy = Array.from(symbols);
|
|
310
202
|
if (symbolsCopy.length === 0) {
|
|
311
|
-
symbolsCopy.push(__classPrivateFieldGet$
|
|
203
|
+
symbolsCopy.push(__classPrivateFieldGet$4(this, _Tape_alphabet, "f").blankSymbol);
|
|
312
204
|
}
|
|
313
|
-
__classPrivateFieldSet$
|
|
205
|
+
__classPrivateFieldSet$4(this, _Tape_symbols, symbolsCopy.map((symbol) => __classPrivateFieldGet$4(this, _Tape_alphabet, "f").index(symbol)), "f");
|
|
314
206
|
}
|
|
315
207
|
get alphabet() {
|
|
316
|
-
return __classPrivateFieldGet$
|
|
208
|
+
return __classPrivateFieldGet$4(this, _Tape_alphabet, "f");
|
|
317
209
|
}
|
|
318
210
|
get extraCellsCount() {
|
|
319
|
-
return (__classPrivateFieldGet$
|
|
211
|
+
return (__classPrivateFieldGet$4(this, _Tape_viewportWidth, "f") - 1) / 2;
|
|
320
212
|
}
|
|
321
213
|
get position() {
|
|
322
|
-
return __classPrivateFieldGet$
|
|
214
|
+
return __classPrivateFieldGet$4(this, _Tape_position, "f");
|
|
323
215
|
}
|
|
324
216
|
get symbol() {
|
|
325
|
-
return __classPrivateFieldGet$
|
|
217
|
+
return __classPrivateFieldGet$4(this, _Tape_alphabet, "f").get(__classPrivateFieldGet$4(this, _Tape_symbols, "f")[__classPrivateFieldGet$4(this, _Tape_position, "f")]);
|
|
326
218
|
}
|
|
327
219
|
set symbol(symbol) {
|
|
328
|
-
if (!__classPrivateFieldGet$
|
|
220
|
+
if (!__classPrivateFieldGet$4(this, _Tape_alphabet, "f").has(symbol)) {
|
|
329
221
|
throw new Error('Invalid symbol');
|
|
330
222
|
}
|
|
331
|
-
__classPrivateFieldGet$
|
|
223
|
+
__classPrivateFieldGet$4(this, _Tape_symbols, "f")[__classPrivateFieldGet$4(this, _Tape_position, "f")] = __classPrivateFieldGet$4(this, _Tape_alphabet, "f").index(symbol);
|
|
332
224
|
}
|
|
333
225
|
get symbols() {
|
|
334
|
-
return __classPrivateFieldGet$
|
|
335
|
-
.map((index) => __classPrivateFieldGet$
|
|
226
|
+
return __classPrivateFieldGet$4(this, _Tape_symbols, "f")
|
|
227
|
+
.map((index) => __classPrivateFieldGet$4(this, _Tape_alphabet, "f").get(index));
|
|
336
228
|
}
|
|
337
229
|
get viewport() {
|
|
338
|
-
const startIx = __classPrivateFieldGet$
|
|
339
|
-
const endIx = __classPrivateFieldGet$
|
|
340
|
-
return __classPrivateFieldGet$
|
|
230
|
+
const startIx = __classPrivateFieldGet$4(this, _Tape_position, "f") - this.extraCellsCount;
|
|
231
|
+
const endIx = __classPrivateFieldGet$4(this, _Tape_position, "f") + this.extraCellsCount + 1;
|
|
232
|
+
return __classPrivateFieldGet$4(this, _Tape_symbols, "f")
|
|
341
233
|
.slice(startIx, endIx)
|
|
342
|
-
.map((index) => __classPrivateFieldGet$
|
|
234
|
+
.map((index) => __classPrivateFieldGet$4(this, _Tape_alphabet, "f").get(index));
|
|
343
235
|
}
|
|
344
236
|
get viewportWidth() {
|
|
345
|
-
return __classPrivateFieldGet$
|
|
237
|
+
return __classPrivateFieldGet$4(this, _Tape_viewportWidth, "f");
|
|
346
238
|
}
|
|
347
239
|
set viewportWidth(width) {
|
|
348
240
|
let finalWidth = width;
|
|
@@ -352,35 +244,35 @@ class Tape {
|
|
|
352
244
|
if (finalWidth % 2 === 0) {
|
|
353
245
|
finalWidth += 1;
|
|
354
246
|
}
|
|
355
|
-
__classPrivateFieldSet$
|
|
247
|
+
__classPrivateFieldSet$4(this, _Tape_viewportWidth, finalWidth, "f");
|
|
356
248
|
this.normalise();
|
|
357
249
|
}
|
|
358
250
|
left() {
|
|
359
|
-
__classPrivateFieldSet$
|
|
251
|
+
__classPrivateFieldSet$4(this, _Tape_position, __classPrivateFieldGet$4(this, _Tape_position, "f") - 1, "f");
|
|
360
252
|
this.normalise();
|
|
361
253
|
}
|
|
362
254
|
normalise() {
|
|
363
|
-
while (__classPrivateFieldGet$
|
|
364
|
-
__classPrivateFieldGet$
|
|
365
|
-
__classPrivateFieldSet$
|
|
255
|
+
while (__classPrivateFieldGet$4(this, _Tape_position, "f") - this.extraCellsCount < 0) {
|
|
256
|
+
__classPrivateFieldGet$4(this, _Tape_symbols, "f").unshift(0);
|
|
257
|
+
__classPrivateFieldSet$4(this, _Tape_position, __classPrivateFieldGet$4(this, _Tape_position, "f") + 1, "f");
|
|
366
258
|
}
|
|
367
|
-
while (__classPrivateFieldGet$
|
|
368
|
-
__classPrivateFieldGet$
|
|
259
|
+
while (__classPrivateFieldGet$4(this, _Tape_position, "f") + this.extraCellsCount >= __classPrivateFieldGet$4(this, _Tape_symbols, "f").length) {
|
|
260
|
+
__classPrivateFieldGet$4(this, _Tape_symbols, "f").push(0);
|
|
369
261
|
}
|
|
370
262
|
}
|
|
371
263
|
right() {
|
|
372
|
-
__classPrivateFieldSet$
|
|
264
|
+
__classPrivateFieldSet$4(this, _Tape_position, __classPrivateFieldGet$4(this, _Tape_position, "f") + 1, "f");
|
|
373
265
|
this.normalise();
|
|
374
266
|
}
|
|
375
267
|
}
|
|
376
268
|
_Tape_alphabet = new WeakMap(), _Tape_symbols = new WeakMap(), _Tape_position = new WeakMap(), _Tape_viewportWidth = new WeakMap();
|
|
377
269
|
|
|
378
|
-
var __classPrivateFieldGet$
|
|
270
|
+
var __classPrivateFieldGet$3 = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
379
271
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
380
272
|
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");
|
|
381
273
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
382
274
|
};
|
|
383
|
-
var __classPrivateFieldSet$
|
|
275
|
+
var __classPrivateFieldSet$3 = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
384
276
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
385
277
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
386
278
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
@@ -392,30 +284,30 @@ class Lock {
|
|
|
392
284
|
_Lock_lockSymbol.set(this, null);
|
|
393
285
|
}
|
|
394
286
|
lock(symbol) {
|
|
395
|
-
if (__classPrivateFieldGet$
|
|
396
|
-
__classPrivateFieldSet$
|
|
287
|
+
if (__classPrivateFieldGet$3(this, _Lock_lockSymbol, "f") === null) {
|
|
288
|
+
__classPrivateFieldSet$3(this, _Lock_lockSymbol, symbol, "f");
|
|
397
289
|
}
|
|
398
290
|
}
|
|
399
291
|
unlock(symbol) {
|
|
400
|
-
if (__classPrivateFieldGet$
|
|
401
|
-
__classPrivateFieldSet$
|
|
292
|
+
if (__classPrivateFieldGet$3(this, _Lock_lockSymbol, "f") === symbol) {
|
|
293
|
+
__classPrivateFieldSet$3(this, _Lock_lockSymbol, null, "f");
|
|
402
294
|
}
|
|
403
295
|
}
|
|
404
296
|
check(symbol) {
|
|
405
|
-
if (__classPrivateFieldGet$
|
|
297
|
+
if (__classPrivateFieldGet$3(this, _Lock_lockSymbol, "f") && __classPrivateFieldGet$3(this, _Lock_lockSymbol, "f") !== symbol) {
|
|
406
298
|
throw new Error('Lock check failed');
|
|
407
299
|
}
|
|
408
300
|
}
|
|
409
301
|
}
|
|
410
302
|
_Lock_lockSymbol = new WeakMap();
|
|
411
303
|
|
|
412
|
-
var __classPrivateFieldSet$
|
|
304
|
+
var __classPrivateFieldSet$2 = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
413
305
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
414
306
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
415
307
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
416
308
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
417
309
|
};
|
|
418
|
-
var __classPrivateFieldGet$
|
|
310
|
+
var __classPrivateFieldGet$2 = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
419
311
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
420
312
|
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");
|
|
421
313
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
@@ -429,7 +321,7 @@ class TapeBlock {
|
|
|
429
321
|
_TapeBlock_lock.set(this, new Lock());
|
|
430
322
|
_TapeBlock_tapes.set(this, void 0);
|
|
431
323
|
_TapeBlock_buildPatternList.set(this, (symbolList) => symbolList.reduce((result, symbol, ix) => {
|
|
432
|
-
const row = Math.floor(ix / __classPrivateFieldGet$
|
|
324
|
+
const row = Math.floor(ix / __classPrivateFieldGet$2(this, _TapeBlock_tapes, "f").length);
|
|
433
325
|
if (!Array.isArray(result[row])) {
|
|
434
326
|
result[row] = [];
|
|
435
327
|
}
|
|
@@ -445,7 +337,7 @@ class TapeBlock {
|
|
|
445
337
|
if (patternList.some((pattern) => pattern.every((symbol) => symbol === ifOtherSymbol))) {
|
|
446
338
|
return ifOtherSymbol;
|
|
447
339
|
}
|
|
448
|
-
const [storedPatternListSymbol] = [...__classPrivateFieldGet$
|
|
340
|
+
const [storedPatternListSymbol] = [...__classPrivateFieldGet$2(this, _TapeBlock_symbolToPatternListMap, "f").entries()]
|
|
449
341
|
.find(([, storedPatternList]) => {
|
|
450
342
|
if (storedPatternList.length !== patternList.length) {
|
|
451
343
|
return false;
|
|
@@ -459,8 +351,8 @@ class TapeBlock {
|
|
|
459
351
|
symbol = storedPatternListSymbol;
|
|
460
352
|
}
|
|
461
353
|
else {
|
|
462
|
-
symbol = Symbol(__classPrivateFieldGet$
|
|
463
|
-
__classPrivateFieldGet$
|
|
354
|
+
symbol = Symbol(__classPrivateFieldGet$2(_a, _a, "f", _TapeBlock_generateSymbolHint).call(_a, patternList));
|
|
355
|
+
__classPrivateFieldGet$2(this, _TapeBlock_symbolToPatternListMap, "f").set(symbol, patternList);
|
|
464
356
|
}
|
|
465
357
|
return symbol;
|
|
466
358
|
});
|
|
@@ -475,60 +367,60 @@ class TapeBlock {
|
|
|
475
367
|
else if (Array.isArray(symbols)) {
|
|
476
368
|
localSymbols = [...symbols];
|
|
477
369
|
}
|
|
478
|
-
if (localSymbols.length === 0 || localSymbols.length % __classPrivateFieldGet$
|
|
370
|
+
if (localSymbols.length === 0 || localSymbols.length % __classPrivateFieldGet$2(this, _TapeBlock_tapes, "f").length > 0) {
|
|
479
371
|
throw new Error('invalid symbol parameter');
|
|
480
372
|
}
|
|
481
373
|
const invalidSymbolIndex = localSymbols.findIndex((symbol, ix) => (symbol !== ifOtherSymbol
|
|
482
|
-
&& !__classPrivateFieldGet$
|
|
374
|
+
&& !__classPrivateFieldGet$2(this, _TapeBlock_tapes, "f")[ix % __classPrivateFieldGet$2(this, _TapeBlock_tapes, "f").length].alphabet.has(symbol)));
|
|
483
375
|
if (invalidSymbolIndex >= 0) {
|
|
484
376
|
throw new Error('invalid symbol parameter');
|
|
485
377
|
}
|
|
486
378
|
if (localSymbols.every((symbol) => symbol === ifOtherSymbol)) {
|
|
487
379
|
return ifOtherSymbol;
|
|
488
380
|
}
|
|
489
|
-
return __classPrivateFieldGet$
|
|
381
|
+
return __classPrivateFieldGet$2(this, _TapeBlock_getSymbolForPatternList, "f").call(this, __classPrivateFieldGet$2(this, _TapeBlock_buildPatternList, "f").call(this, localSymbols));
|
|
490
382
|
});
|
|
491
|
-
__classPrivateFieldSet$
|
|
383
|
+
__classPrivateFieldSet$2(this, _TapeBlock_tapes, [], "f");
|
|
492
384
|
if ('alphabets' in argument) {
|
|
493
385
|
const { alphabets } = argument;
|
|
494
386
|
if (alphabets.length === 0) {
|
|
495
387
|
throw new Error('empty alphabet list');
|
|
496
388
|
}
|
|
497
|
-
__classPrivateFieldSet$
|
|
389
|
+
__classPrivateFieldSet$2(this, _TapeBlock_tapes, alphabets.map((alphabet) => new Tape({
|
|
498
390
|
alphabet,
|
|
499
391
|
})), "f");
|
|
500
392
|
}
|
|
501
393
|
else if ('tapes' in argument) {
|
|
502
|
-
__classPrivateFieldSet$
|
|
394
|
+
__classPrivateFieldSet$2(this, _TapeBlock_tapes, argument.tapes, "f");
|
|
503
395
|
}
|
|
504
|
-
if (__classPrivateFieldGet$
|
|
396
|
+
if (__classPrivateFieldGet$2(this, _TapeBlock_tapes, "f").length === 0) {
|
|
505
397
|
throw new Error('empty tape list');
|
|
506
398
|
}
|
|
507
399
|
}
|
|
508
400
|
get alphabets() {
|
|
509
|
-
return [...__classPrivateFieldGet$
|
|
401
|
+
return [...__classPrivateFieldGet$2(this, _TapeBlock_tapes, "f").map((tape) => tape.alphabet)];
|
|
510
402
|
}
|
|
511
403
|
get currentSymbols() {
|
|
512
|
-
return __classPrivateFieldGet$
|
|
404
|
+
return __classPrivateFieldGet$2(this, _TapeBlock_tapes, "f").map((tape) => tape.symbol);
|
|
513
405
|
}
|
|
514
406
|
get [(_TapeBlock_symbolToPatternListMap = new WeakMap(), _TapeBlock_lock = new WeakMap(), _TapeBlock_tapes = new WeakMap(), _TapeBlock_buildPatternList = new WeakMap(), _TapeBlock_getSymbolForPatternList = new WeakMap(), _TapeBlock_symbol = new WeakMap(), lockSymbol)]() {
|
|
515
|
-
return __classPrivateFieldGet$
|
|
407
|
+
return __classPrivateFieldGet$2(this, _TapeBlock_lock, "f");
|
|
516
408
|
}
|
|
517
409
|
get symbol() {
|
|
518
|
-
return __classPrivateFieldGet$
|
|
410
|
+
return __classPrivateFieldGet$2(this, _TapeBlock_symbol, "f").bind(this);
|
|
519
411
|
}
|
|
520
412
|
get tapes() {
|
|
521
|
-
return [...__classPrivateFieldGet$
|
|
413
|
+
return [...__classPrivateFieldGet$2(this, _TapeBlock_tapes, "f")];
|
|
522
414
|
}
|
|
523
415
|
set [symbolToPatternListMapSymbol](symbolToPatternListMap) {
|
|
524
|
-
__classPrivateFieldSet$
|
|
416
|
+
__classPrivateFieldSet$2(this, _TapeBlock_symbolToPatternListMap, new Map(symbolToPatternListMap), "f");
|
|
525
417
|
}
|
|
526
418
|
applyCommand(command, executionSymbol = null) {
|
|
527
|
-
__classPrivateFieldGet$
|
|
528
|
-
if (__classPrivateFieldGet$
|
|
419
|
+
__classPrivateFieldGet$2(this, _TapeBlock_lock, "f").check(executionSymbol);
|
|
420
|
+
if (__classPrivateFieldGet$2(this, _TapeBlock_tapes, "f").length !== command.tapesCommands.length) {
|
|
529
421
|
throw new Error('invalid command');
|
|
530
422
|
}
|
|
531
|
-
__classPrivateFieldGet$
|
|
423
|
+
__classPrivateFieldGet$2(this, _TapeBlock_tapes, "f").forEach((tape, ix) => {
|
|
532
424
|
const { movement, symbol } = command.tapesCommands[ix];
|
|
533
425
|
if (typeof symbol === 'string') {
|
|
534
426
|
tape.symbol = symbol;
|
|
@@ -564,28 +456,27 @@ class TapeBlock {
|
|
|
564
456
|
else {
|
|
565
457
|
tapeBlock = _a.fromAlphabets(this.alphabets);
|
|
566
458
|
}
|
|
567
|
-
tapeBlock[symbolToPatternListMapSymbol] = __classPrivateFieldGet$
|
|
459
|
+
tapeBlock[symbolToPatternListMapSymbol] = __classPrivateFieldGet$2(this, _TapeBlock_symbolToPatternListMap, "f");
|
|
568
460
|
return tapeBlock;
|
|
569
461
|
}
|
|
570
462
|
isMatched({ currentSymbols = this.currentSymbols, symbol }) {
|
|
571
|
-
var _b;
|
|
572
463
|
if (symbol === ifOtherSymbol) {
|
|
573
464
|
return true;
|
|
574
465
|
}
|
|
575
|
-
if (!__classPrivateFieldGet$
|
|
466
|
+
if (!__classPrivateFieldGet$2(this, _TapeBlock_symbolToPatternListMap, "f").has(symbol)) {
|
|
576
467
|
throw new Error('invalid symbol');
|
|
577
468
|
}
|
|
578
|
-
const patternList = __classPrivateFieldGet$
|
|
579
|
-
return
|
|
469
|
+
const patternList = __classPrivateFieldGet$2(this, _TapeBlock_symbolToPatternListMap, "f").get(symbol);
|
|
470
|
+
return patternList?.some((pattern) => (pattern
|
|
580
471
|
.every((everySymbol, ix) => (everySymbol === ifOtherSymbol
|
|
581
|
-
|| everySymbol === currentSymbols[ix]))))
|
|
472
|
+
|| everySymbol === currentSymbols[ix])))) ?? false;
|
|
582
473
|
}
|
|
583
474
|
replaceTape(tape, tapeIx = 0) {
|
|
584
|
-
if (__classPrivateFieldGet$
|
|
475
|
+
if (__classPrivateFieldGet$2(this, _TapeBlock_tapes, "f")[tapeIx] == null) {
|
|
585
476
|
throw new Error('invalid tapeIx');
|
|
586
477
|
}
|
|
587
|
-
if (tape.alphabet.symbols.join('') === __classPrivateFieldGet$
|
|
588
|
-
__classPrivateFieldGet$
|
|
478
|
+
if (tape.alphabet.symbols.join('') === __classPrivateFieldGet$2(this, _TapeBlock_tapes, "f")[tapeIx].alphabet.symbols.join('')) {
|
|
479
|
+
__classPrivateFieldGet$2(this, _TapeBlock_tapes, "f")[tapeIx] = tape;
|
|
589
480
|
}
|
|
590
481
|
else {
|
|
591
482
|
throw new Error('invalid tape');
|
|
@@ -603,6 +494,408 @@ _TapeBlock_generateSymbolHint = { value: (patternList) => JSON.stringify(pattern
|
|
|
603
494
|
.map((pattern) => pattern
|
|
604
495
|
.map((symbol) => (symbol === ifOtherSymbol ? null : symbol)))) };
|
|
605
496
|
|
|
497
|
+
const movementDescriptionToLabel = {
|
|
498
|
+
'move caret left command': 'L',
|
|
499
|
+
'move caret right command': 'R',
|
|
500
|
+
'do not move carer': 'S',
|
|
501
|
+
};
|
|
502
|
+
const symbolCommandDescriptionToLabel = {
|
|
503
|
+
'keep symbol command': '·',
|
|
504
|
+
'erase symbol command': '⌫',
|
|
505
|
+
};
|
|
506
|
+
// Reserved characters in the encoded pattern string:
|
|
507
|
+
// '*' per-cell ifOtherSymbol (matches any symbol on that tape)
|
|
508
|
+
// '-' the tape's blank symbol
|
|
509
|
+
// ',' separates per-tape cells inside one pattern
|
|
510
|
+
// '|' separates alternative patterns
|
|
511
|
+
// '\\' escape prefix — to represent any of '*', '-', ',', '|', or '\\' as a
|
|
512
|
+
// *literal* alphabet symbol, prefix it with '\\' (e.g. '\\*' for literal '*').
|
|
513
|
+
function escapeAlphabetSymbol(s) {
|
|
514
|
+
return s
|
|
515
|
+
.replace(/\\/g, '\\\\')
|
|
516
|
+
.replace(/\*/g, '\\*')
|
|
517
|
+
.replace(/-/g, '\\-')
|
|
518
|
+
.replace(/,/g, '\\,')
|
|
519
|
+
.replace(/\|/g, '\\|');
|
|
520
|
+
}
|
|
521
|
+
function decodePatternDescription(description, alphabets) {
|
|
522
|
+
if (!description) {
|
|
523
|
+
return '?';
|
|
524
|
+
}
|
|
525
|
+
if (description === 'other symbol') {
|
|
526
|
+
return '*';
|
|
527
|
+
}
|
|
528
|
+
try {
|
|
529
|
+
const patternList = JSON.parse(description);
|
|
530
|
+
return patternList
|
|
531
|
+
.map((pattern) => pattern
|
|
532
|
+
.map((s, tapeIx) => {
|
|
533
|
+
if (s === null) {
|
|
534
|
+
return '*';
|
|
535
|
+
}
|
|
536
|
+
if (s === alphabets[tapeIx]?.[0]) {
|
|
537
|
+
return '-';
|
|
538
|
+
}
|
|
539
|
+
return escapeAlphabetSymbol(s);
|
|
540
|
+
})
|
|
541
|
+
.join(','))
|
|
542
|
+
.join('|');
|
|
543
|
+
}
|
|
544
|
+
catch {
|
|
545
|
+
return description;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function decodeMovement(description) {
|
|
549
|
+
if (!description) {
|
|
550
|
+
return '?';
|
|
551
|
+
}
|
|
552
|
+
return movementDescriptionToLabel[description] ?? description;
|
|
553
|
+
}
|
|
554
|
+
function splitUnescaped(s, sep) {
|
|
555
|
+
const parts = [];
|
|
556
|
+
let current = '';
|
|
557
|
+
let i = 0;
|
|
558
|
+
while (i < s.length) {
|
|
559
|
+
if (s[i] === '\\' && i + 1 < s.length) {
|
|
560
|
+
current += s[i + 1];
|
|
561
|
+
i += 2;
|
|
562
|
+
}
|
|
563
|
+
else if (s[i] === sep) {
|
|
564
|
+
parts.push(current);
|
|
565
|
+
current = '';
|
|
566
|
+
i += 1;
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
current += s[i];
|
|
570
|
+
i += 1;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
parts.push(current);
|
|
574
|
+
return parts;
|
|
575
|
+
}
|
|
576
|
+
function parsePatternString(s, alphabets) {
|
|
577
|
+
if (s === '*') {
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
const alternatives = splitUnescaped(s, '|');
|
|
581
|
+
return alternatives.map((alt) => {
|
|
582
|
+
const cells = splitUnescaped(alt, ',');
|
|
583
|
+
return cells.map((cell, tapeIx) => {
|
|
584
|
+
if (cell === '*') {
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
if (cell === '-') {
|
|
588
|
+
return alphabets[tapeIx]?.[0] ?? cell;
|
|
589
|
+
}
|
|
590
|
+
return cell;
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
const movementLabelToSymbol = {
|
|
595
|
+
L: movements.left,
|
|
596
|
+
R: movements.right,
|
|
597
|
+
S: movements.stay,
|
|
598
|
+
};
|
|
599
|
+
function parseMovementLabel(label) {
|
|
600
|
+
const m = movementLabelToSymbol[label];
|
|
601
|
+
if (!m) {
|
|
602
|
+
throw new Error(`unknown movement label: ${label}`);
|
|
603
|
+
}
|
|
604
|
+
return m;
|
|
605
|
+
}
|
|
606
|
+
function parseWriteSymbolLabel(label) {
|
|
607
|
+
if (label === '·') {
|
|
608
|
+
return symbolCommands.keep;
|
|
609
|
+
}
|
|
610
|
+
if (label === '⌫') {
|
|
611
|
+
return symbolCommands.erase;
|
|
612
|
+
}
|
|
613
|
+
return label;
|
|
614
|
+
}
|
|
615
|
+
function decodeWriteSymbol(symbol) {
|
|
616
|
+
if (typeof symbol === 'symbol') {
|
|
617
|
+
const description = symbol.description ?? '?';
|
|
618
|
+
return symbolCommandDescriptionToLabel[description] ?? description;
|
|
619
|
+
}
|
|
620
|
+
return symbol;
|
|
621
|
+
}
|
|
622
|
+
// Format converters (toMermaid / fromMermaid) live in ./graphFormats.
|
|
623
|
+
|
|
624
|
+
var __classPrivateFieldGet$1 = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
625
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
626
|
+
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");
|
|
627
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
628
|
+
};
|
|
629
|
+
var __classPrivateFieldSet$1 = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
630
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
631
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
632
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
633
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
634
|
+
};
|
|
635
|
+
var _State_id, _State_name, _State_overrodeHaltState, _State_symbolToDataMap;
|
|
636
|
+
const ifOtherSymbol = Symbol('other symbol');
|
|
637
|
+
class State {
|
|
638
|
+
constructor(stateDefinition = null, name) {
|
|
639
|
+
_State_id.set(this, id(this));
|
|
640
|
+
_State_name.set(this, void 0);
|
|
641
|
+
_State_overrodeHaltState.set(this, null);
|
|
642
|
+
_State_symbolToDataMap.set(this, new Map());
|
|
643
|
+
if (stateDefinition) {
|
|
644
|
+
const keys = Object.getOwnPropertyNames(stateDefinition);
|
|
645
|
+
if (keys.length) {
|
|
646
|
+
throw new Error(`invalid state definition while constructing state #${__classPrivateFieldGet$1(this, _State_id, "f")}`);
|
|
647
|
+
}
|
|
648
|
+
const symbols = Object.getOwnPropertySymbols(stateDefinition);
|
|
649
|
+
if (symbols.length === 0) {
|
|
650
|
+
throw new Error(`invalid state definition while constructing state #${__classPrivateFieldGet$1(this, _State_id, "f")}`);
|
|
651
|
+
}
|
|
652
|
+
symbols.forEach((symbol) => {
|
|
653
|
+
const { nextState } = stateDefinition[symbol];
|
|
654
|
+
const nextStateLocal = nextState ?? this;
|
|
655
|
+
if (!(nextStateLocal instanceof State) && !(nextStateLocal instanceof Reference)) {
|
|
656
|
+
throw new Error('invalid nextState');
|
|
657
|
+
}
|
|
658
|
+
let { command } = stateDefinition[symbol];
|
|
659
|
+
if (command == null) {
|
|
660
|
+
command = new Command([
|
|
661
|
+
new TapeCommand({}),
|
|
662
|
+
]);
|
|
663
|
+
}
|
|
664
|
+
if (!(command instanceof Command) && !Array.isArray(command)) {
|
|
665
|
+
command = [command];
|
|
666
|
+
}
|
|
667
|
+
let commandLocal = command;
|
|
668
|
+
if (Array.isArray(command)) {
|
|
669
|
+
try {
|
|
670
|
+
commandLocal = new Command(command);
|
|
671
|
+
}
|
|
672
|
+
catch (error) {
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (!(commandLocal instanceof Command)) {
|
|
676
|
+
throw new Error('invalid command');
|
|
677
|
+
}
|
|
678
|
+
__classPrivateFieldGet$1(this, _State_symbolToDataMap, "f").set(symbol, {
|
|
679
|
+
command: commandLocal,
|
|
680
|
+
nextState: nextStateLocal,
|
|
681
|
+
});
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
__classPrivateFieldSet$1(this, _State_name, name ?? `id:${__classPrivateFieldGet$1(this, _State_id, "f")}`, "f");
|
|
685
|
+
}
|
|
686
|
+
get id() {
|
|
687
|
+
return __classPrivateFieldGet$1(this, _State_id, "f");
|
|
688
|
+
}
|
|
689
|
+
get name() {
|
|
690
|
+
return __classPrivateFieldGet$1(this, _State_name, "f");
|
|
691
|
+
}
|
|
692
|
+
get isHalt() {
|
|
693
|
+
return __classPrivateFieldGet$1(this, _State_id, "f") === 0;
|
|
694
|
+
}
|
|
695
|
+
get overrodeHaltState() {
|
|
696
|
+
return __classPrivateFieldGet$1(this, _State_overrodeHaltState, "f");
|
|
697
|
+
}
|
|
698
|
+
get ref() {
|
|
699
|
+
return this;
|
|
700
|
+
}
|
|
701
|
+
getSymbol(tapeBlock) {
|
|
702
|
+
const symbol = [...__classPrivateFieldGet$1(this, _State_symbolToDataMap, "f").keys()].find((currentSymbol) => tapeBlock.isMatched({
|
|
703
|
+
symbol: currentSymbol,
|
|
704
|
+
}));
|
|
705
|
+
if (symbol) {
|
|
706
|
+
return symbol;
|
|
707
|
+
}
|
|
708
|
+
return ifOtherSymbol;
|
|
709
|
+
}
|
|
710
|
+
getCommand(symbol) {
|
|
711
|
+
if (__classPrivateFieldGet$1(this, _State_symbolToDataMap, "f").has(symbol)) {
|
|
712
|
+
return __classPrivateFieldGet$1(this, _State_symbolToDataMap, "f").get(symbol).command;
|
|
713
|
+
}
|
|
714
|
+
throw new Error(`No command for symbol at state named ${__classPrivateFieldGet$1(this, _State_name, "f")}`);
|
|
715
|
+
}
|
|
716
|
+
getNextState(symbol) {
|
|
717
|
+
if (__classPrivateFieldGet$1(this, _State_symbolToDataMap, "f").has(symbol)) {
|
|
718
|
+
return __classPrivateFieldGet$1(this, _State_symbolToDataMap, "f").get(symbol).nextState;
|
|
719
|
+
}
|
|
720
|
+
throw new Error(`No nextState for symbol at state named ${__classPrivateFieldGet$1(this, _State_id, "f")}`);
|
|
721
|
+
}
|
|
722
|
+
withOverrodeHaltState(overrodeHaltState) {
|
|
723
|
+
const state = new State(null, `${this.name}>${overrodeHaltState.name}`);
|
|
724
|
+
__classPrivateFieldSet$1(state, _State_symbolToDataMap, __classPrivateFieldGet$1(this, _State_symbolToDataMap, "f"), "f");
|
|
725
|
+
__classPrivateFieldSet$1(state, _State_overrodeHaltState, overrodeHaltState, "f");
|
|
726
|
+
return state;
|
|
727
|
+
}
|
|
728
|
+
// Single-state introspection — no traversal, no tapeBlock required.
|
|
729
|
+
// Returns id, name, halt-status, override-halt target, and the list of
|
|
730
|
+
// transitions out of this state with decoded write/movement labels.
|
|
731
|
+
// Symbol patterns are returned as the raw description string from the
|
|
732
|
+
// interned JS Symbol (decode via decodePatternDescription if needed).
|
|
733
|
+
static inspect(state) {
|
|
734
|
+
const transitions = [];
|
|
735
|
+
for (const [sym, { command, nextState }] of __classPrivateFieldGet$1(state, _State_symbolToDataMap, "f")) {
|
|
736
|
+
let target = null;
|
|
737
|
+
try {
|
|
738
|
+
target = nextState instanceof State ? nextState : nextState.ref;
|
|
739
|
+
}
|
|
740
|
+
catch {
|
|
741
|
+
target = null; // unbound Reference
|
|
742
|
+
}
|
|
743
|
+
transitions.push({
|
|
744
|
+
rawPatternDescription: sym.description,
|
|
745
|
+
command: command.tapesCommands.map((tc) => ({
|
|
746
|
+
symbol: decodeWriteSymbol(tc.symbol),
|
|
747
|
+
movement: decodeMovement(tc.movement.description),
|
|
748
|
+
})),
|
|
749
|
+
nextState: target ? { id: target.id, name: target.name } : null,
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
return {
|
|
753
|
+
id: __classPrivateFieldGet$1(state, _State_id, "f"),
|
|
754
|
+
name: __classPrivateFieldGet$1(state, _State_name, "f"),
|
|
755
|
+
isHalt: state.isHalt,
|
|
756
|
+
overrodeHaltState: __classPrivateFieldGet$1(state, _State_overrodeHaltState, "f")
|
|
757
|
+
? { id: __classPrivateFieldGet$1(state, _State_overrodeHaltState, "f").id, name: __classPrivateFieldGet$1(state, _State_overrodeHaltState, "f").name }
|
|
758
|
+
: null,
|
|
759
|
+
transitions,
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
static toGraph(initialState, tapeBlock) {
|
|
763
|
+
const nodes = {};
|
|
764
|
+
const queue = [initialState];
|
|
765
|
+
const alphabets = tapeBlock.alphabets.map((alphabet) => alphabet.symbols);
|
|
766
|
+
while (queue.length > 0) {
|
|
767
|
+
const current = queue.shift();
|
|
768
|
+
if (__classPrivateFieldGet$1(current, _State_id, "f") in nodes) {
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
const node = {
|
|
772
|
+
id: __classPrivateFieldGet$1(current, _State_id, "f"),
|
|
773
|
+
name: __classPrivateFieldGet$1(current, _State_name, "f"),
|
|
774
|
+
isHalt: current.isHalt,
|
|
775
|
+
transitions: [],
|
|
776
|
+
overrodeHaltStateId: __classPrivateFieldGet$1(current, _State_overrodeHaltState, "f")?.id ?? null,
|
|
777
|
+
};
|
|
778
|
+
nodes[__classPrivateFieldGet$1(current, _State_id, "f")] = node;
|
|
779
|
+
if (__classPrivateFieldGet$1(current, _State_overrodeHaltState, "f")) {
|
|
780
|
+
queue.push(__classPrivateFieldGet$1(current, _State_overrodeHaltState, "f"));
|
|
781
|
+
}
|
|
782
|
+
for (const [sym, { command, nextState }] of __classPrivateFieldGet$1(current, _State_symbolToDataMap, "f")) {
|
|
783
|
+
let target;
|
|
784
|
+
try {
|
|
785
|
+
target = nextState instanceof State ? nextState : nextState.ref;
|
|
786
|
+
}
|
|
787
|
+
catch {
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
node.transitions.push({
|
|
791
|
+
pattern: decodePatternDescription(sym.description, alphabets),
|
|
792
|
+
command: command.tapesCommands.map((tc) => ({
|
|
793
|
+
symbol: decodeWriteSymbol(tc.symbol),
|
|
794
|
+
movement: decodeMovement(tc.movement.description),
|
|
795
|
+
})),
|
|
796
|
+
nextStateId: target.id,
|
|
797
|
+
});
|
|
798
|
+
queue.push(target);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return { initialId: __classPrivateFieldGet$1(initialState, _State_id, "f"), alphabets, nodes };
|
|
802
|
+
}
|
|
803
|
+
// Inverse of toGraph: rebuilds a State graph (and a fresh TapeBlock with the
|
|
804
|
+
// graph's alphabets) from a serialized Graph. Round-trips with toGraph in
|
|
805
|
+
// the sense that running the rebuilt machine on the same input gives the
|
|
806
|
+
// same output, but the rebuilt State instances have *new* internal IDs.
|
|
807
|
+
static fromGraph(graph) {
|
|
808
|
+
const alphabetObjs = graph.alphabets.map((syms) => new Alphabet(syms));
|
|
809
|
+
const tapeBlock = TapeBlock.fromAlphabets(alphabetObjs);
|
|
810
|
+
const ids = Object.keys(graph.nodes).map(Number);
|
|
811
|
+
// Pass 1: pre-create a Reference for each non-halt node so transitions can
|
|
812
|
+
// forward-declare their targets.
|
|
813
|
+
const refs = {};
|
|
814
|
+
for (const nodeId of ids) {
|
|
815
|
+
if (!graph.nodes[nodeId].isHalt) {
|
|
816
|
+
refs[nodeId] = new Reference();
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
// Convert a parsed pattern back to the symbol key the State expects.
|
|
820
|
+
const patternToKey = (parsed) => {
|
|
821
|
+
if (parsed === null) {
|
|
822
|
+
return ifOtherSymbol;
|
|
823
|
+
}
|
|
824
|
+
const flat = [];
|
|
825
|
+
for (const row of parsed) {
|
|
826
|
+
for (const cell of row) {
|
|
827
|
+
flat.push(cell === null ? ifOtherSymbol : cell);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
return tapeBlock.symbol(flat);
|
|
831
|
+
};
|
|
832
|
+
// Pass 2: build a "bare" State for each non-halt node (no override yet).
|
|
833
|
+
// nextState entries point at refs so cycles work; haltState is used directly.
|
|
834
|
+
const bareStates = {};
|
|
835
|
+
for (const nodeId of ids) {
|
|
836
|
+
const node = graph.nodes[nodeId];
|
|
837
|
+
if (node.isHalt) {
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
const stateDefinition = {};
|
|
841
|
+
for (const t of node.transitions) {
|
|
842
|
+
const key = patternToKey(parsePatternString(t.pattern, graph.alphabets));
|
|
843
|
+
const target = graph.nodes[t.nextStateId];
|
|
844
|
+
const nextState = target.isHalt ? haltState : refs[t.nextStateId];
|
|
845
|
+
stateDefinition[key] = {
|
|
846
|
+
command: t.command.map((c) => ({
|
|
847
|
+
symbol: parseWriteSymbolLabel(c.symbol),
|
|
848
|
+
movement: parseMovementLabel(c.movement),
|
|
849
|
+
})),
|
|
850
|
+
nextState,
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
bareStates[nodeId] = new State(stateDefinition, node.name);
|
|
854
|
+
}
|
|
855
|
+
// Pass 3: apply overrideHaltStates transitively.
|
|
856
|
+
const finalStates = {};
|
|
857
|
+
const inProgress = new Set();
|
|
858
|
+
const getFinal = (nodeId) => {
|
|
859
|
+
if (finalStates[nodeId]) {
|
|
860
|
+
return finalStates[nodeId];
|
|
861
|
+
}
|
|
862
|
+
const node = graph.nodes[nodeId];
|
|
863
|
+
if (node.isHalt) {
|
|
864
|
+
finalStates[nodeId] = haltState;
|
|
865
|
+
return haltState;
|
|
866
|
+
}
|
|
867
|
+
if (inProgress.has(nodeId)) {
|
|
868
|
+
throw new Error(`override-halt cycle at state #${nodeId}`);
|
|
869
|
+
}
|
|
870
|
+
inProgress.add(nodeId);
|
|
871
|
+
let state = bareStates[nodeId];
|
|
872
|
+
if (node.overrodeHaltStateId !== null) {
|
|
873
|
+
state = bareStates[nodeId].withOverrodeHaltState(getFinal(node.overrodeHaltStateId));
|
|
874
|
+
}
|
|
875
|
+
inProgress.delete(nodeId);
|
|
876
|
+
finalStates[nodeId] = state;
|
|
877
|
+
return state;
|
|
878
|
+
};
|
|
879
|
+
for (const nodeId of ids) {
|
|
880
|
+
getFinal(nodeId);
|
|
881
|
+
}
|
|
882
|
+
// Pass 4: bind each ref to the FINAL (possibly wrapped) state so transitions
|
|
883
|
+
// resolve to the version that has its override-halt set.
|
|
884
|
+
for (const nodeId of ids) {
|
|
885
|
+
if (!graph.nodes[nodeId].isHalt) {
|
|
886
|
+
refs[nodeId].bind(finalStates[nodeId]);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
return {
|
|
890
|
+
start: finalStates[graph.initialId],
|
|
891
|
+
tapeBlock,
|
|
892
|
+
states: finalStates,
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
_State_id = new WeakMap(), _State_name = new WeakMap(), _State_overrodeHaltState = new WeakMap(), _State_symbolToDataMap = new WeakMap();
|
|
897
|
+
const haltState = new State(null);
|
|
898
|
+
|
|
606
899
|
var __classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
607
900
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
608
901
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
@@ -702,4 +995,308 @@ class TuringMachine {
|
|
|
702
995
|
}
|
|
703
996
|
_TuringMachine_tapeBlock = new WeakMap(), _TuringMachine_stack = new WeakMap();
|
|
704
997
|
|
|
705
|
-
|
|
998
|
+
// Format converters between a Graph (the data model produced by State.toGraph
|
|
999
|
+
// and consumed by State.fromGraph) and external string representations.
|
|
1000
|
+
//
|
|
1001
|
+
// Currently only Mermaid flowchart syntax is supported. Future formats
|
|
1002
|
+
// (Graphviz, JSON-LD, custom DSL) belong here too.
|
|
1003
|
+
function toMermaid(graph) {
|
|
1004
|
+
const lines = [
|
|
1005
|
+
'flowchart TD',
|
|
1006
|
+
`%% alphabets: ${JSON.stringify(graph.alphabets)}`,
|
|
1007
|
+
];
|
|
1008
|
+
for (const node of Object.values(graph.nodes)) {
|
|
1009
|
+
const id = `s${node.id}`;
|
|
1010
|
+
if (node.isHalt) {
|
|
1011
|
+
lines.push(` ${id}(((halt)))`);
|
|
1012
|
+
}
|
|
1013
|
+
else if (node.id === graph.initialId) {
|
|
1014
|
+
lines.push(` ${id}(("${node.name}"))`);
|
|
1015
|
+
}
|
|
1016
|
+
else {
|
|
1017
|
+
lines.push(` ${id}["${node.name}"]`);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
for (const node of Object.values(graph.nodes)) {
|
|
1021
|
+
for (const t of node.transitions) {
|
|
1022
|
+
// Per-tape commands separated with ',' to mirror the pattern syntax.
|
|
1023
|
+
const cmd = t.command.map((c) => `${c.symbol}/${c.movement}`).join(',');
|
|
1024
|
+
const label = `${t.pattern} → ${cmd}`;
|
|
1025
|
+
lines.push(` s${node.id} -- "${label}" --> s${t.nextStateId}`);
|
|
1026
|
+
}
|
|
1027
|
+
if (node.overrodeHaltStateId !== null) {
|
|
1028
|
+
lines.push(` s${node.id} -. onHalt .-> s${node.overrodeHaltStateId}`);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return lines.join('\n');
|
|
1032
|
+
}
|
|
1033
|
+
// Inverse of toMermaid: parses the Mermaid output produced by toMermaid back
|
|
1034
|
+
// into a Graph. The parser is strict to the dialect toMermaid emits — it
|
|
1035
|
+
// recognises the specific node/edge shapes and the leading
|
|
1036
|
+
// `%% alphabets: [...]` comment. Hand-edited Mermaid that uses different
|
|
1037
|
+
// arrow styles or shapes will not parse.
|
|
1038
|
+
//
|
|
1039
|
+
// Caveats:
|
|
1040
|
+
// - Write-symbol cells in commands are split on '/' (last occurrence) and
|
|
1041
|
+
// per-tape segments are split on ','. If your alphabet contains '/' or ','
|
|
1042
|
+
// as literal symbols, the parser cannot disambiguate. Stick to alphabets
|
|
1043
|
+
// without those characters when round-tripping through Mermaid.
|
|
1044
|
+
const haltNodeRegex = /^s(\d+)\(\(\(halt\)\)\)$/;
|
|
1045
|
+
const initialNodeRegex = /^s(\d+)\(\("([^"]*)"\)\)$/;
|
|
1046
|
+
const regularNodeRegex = /^s(\d+)\["([^"]*)"\]$/;
|
|
1047
|
+
const transitionRegex = /^s(\d+)\s+--\s+"(.*)"\s+-->\s+s(\d+)$/;
|
|
1048
|
+
const onHaltRegex = /^s(\d+)\s+-\.\s+onHalt\s+\.->\s+s(\d+)$/;
|
|
1049
|
+
// First capture char anchored as \S to avoid polynomial backtracking between
|
|
1050
|
+
// the preceding \s* and a permissive (.+); see CodeQL js/polynomial-redos.
|
|
1051
|
+
const alphabetsRegex = /^%%\s*alphabets:\s*(\S.*)$/;
|
|
1052
|
+
function fromMermaid(text) {
|
|
1053
|
+
const lines = text.split('\n').map((l) => l.trim()).filter(Boolean);
|
|
1054
|
+
let alphabets = [];
|
|
1055
|
+
let initialId = null;
|
|
1056
|
+
const nodes = {};
|
|
1057
|
+
const ensureNode = (id, opts = {}) => {
|
|
1058
|
+
if (!nodes[id]) {
|
|
1059
|
+
nodes[id] = {
|
|
1060
|
+
id,
|
|
1061
|
+
name: opts.name ?? `s${id}`,
|
|
1062
|
+
isHalt: opts.isHalt ?? false,
|
|
1063
|
+
transitions: [],
|
|
1064
|
+
overrodeHaltStateId: null,
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
else {
|
|
1068
|
+
if (opts.name !== undefined) {
|
|
1069
|
+
nodes[id].name = opts.name;
|
|
1070
|
+
}
|
|
1071
|
+
if (opts.isHalt !== undefined) {
|
|
1072
|
+
nodes[id].isHalt = opts.isHalt;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
return nodes[id];
|
|
1076
|
+
};
|
|
1077
|
+
// First pass: alphabets + nodes.
|
|
1078
|
+
for (const line of lines) {
|
|
1079
|
+
if (line === 'flowchart TD') {
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
const am = line.match(alphabetsRegex);
|
|
1083
|
+
if (am) {
|
|
1084
|
+
alphabets = JSON.parse(am[1]);
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
const hm = line.match(haltNodeRegex);
|
|
1088
|
+
if (hm) {
|
|
1089
|
+
ensureNode(Number(hm[1]), { name: 'halt', isHalt: true });
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
const im = line.match(initialNodeRegex);
|
|
1093
|
+
if (im) {
|
|
1094
|
+
const id = Number(im[1]);
|
|
1095
|
+
initialId = id;
|
|
1096
|
+
ensureNode(id, { name: im[2] });
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
const rm = line.match(regularNodeRegex);
|
|
1100
|
+
if (rm) {
|
|
1101
|
+
ensureNode(Number(rm[1]), { name: rm[2] });
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
// Second pass: edges.
|
|
1106
|
+
for (const line of lines) {
|
|
1107
|
+
const om = line.match(onHaltRegex);
|
|
1108
|
+
if (om) {
|
|
1109
|
+
ensureNode(Number(om[1])).overrodeHaltStateId = Number(om[2]);
|
|
1110
|
+
continue;
|
|
1111
|
+
}
|
|
1112
|
+
const tm = line.match(transitionRegex);
|
|
1113
|
+
if (tm) {
|
|
1114
|
+
const fromId = Number(tm[1]);
|
|
1115
|
+
const label = tm[2];
|
|
1116
|
+
const toId = Number(tm[3]);
|
|
1117
|
+
const arrowIx = label.indexOf(' → ');
|
|
1118
|
+
if (arrowIx === -1) {
|
|
1119
|
+
throw new Error(`fromMermaid: malformed edge label: "${label}"`);
|
|
1120
|
+
}
|
|
1121
|
+
const pattern = label.slice(0, arrowIx);
|
|
1122
|
+
const commandStr = label.slice(arrowIx + ' → '.length);
|
|
1123
|
+
const command = commandStr.split(',').map((part) => {
|
|
1124
|
+
const slashIx = part.lastIndexOf('/');
|
|
1125
|
+
if (slashIx === -1) {
|
|
1126
|
+
throw new Error(`fromMermaid: malformed command part: "${part}"`);
|
|
1127
|
+
}
|
|
1128
|
+
return {
|
|
1129
|
+
symbol: part.slice(0, slashIx),
|
|
1130
|
+
movement: part.slice(slashIx + 1),
|
|
1131
|
+
};
|
|
1132
|
+
});
|
|
1133
|
+
ensureNode(fromId).transitions.push({ pattern, command, nextStateId: toId });
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
if (initialId === null) {
|
|
1137
|
+
throw new Error('fromMermaid: no initial state (double-paren node) found');
|
|
1138
|
+
}
|
|
1139
|
+
return { initialId, alphabets, nodes };
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
function summarizeGraph(graph) {
|
|
1143
|
+
const nodes = Object.values(graph.nodes);
|
|
1144
|
+
let transitionCount = 0;
|
|
1145
|
+
let compositionEdgeCount = 0;
|
|
1146
|
+
let selfLoopCount = 0;
|
|
1147
|
+
for (const node of nodes) {
|
|
1148
|
+
transitionCount += node.transitions.length;
|
|
1149
|
+
if (node.overrodeHaltStateId !== null) {
|
|
1150
|
+
compositionEdgeCount += 1;
|
|
1151
|
+
}
|
|
1152
|
+
for (const t of node.transitions) {
|
|
1153
|
+
if (t.nextStateId === node.id) {
|
|
1154
|
+
selfLoopCount += 1;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
// Longest withOverrodeHaltState chain. Walks node → overrodeHaltState recursively;
|
|
1159
|
+
// a Set guards against cycles in the override graph (which throw at construction
|
|
1160
|
+
// time anyway, but being defensive costs little).
|
|
1161
|
+
const overrideDepthFrom = (id, visited) => {
|
|
1162
|
+
if (visited.has(id)) {
|
|
1163
|
+
return 0;
|
|
1164
|
+
}
|
|
1165
|
+
visited.add(id);
|
|
1166
|
+
const node = graph.nodes[id];
|
|
1167
|
+
if (!node || node.overrodeHaltStateId === null) {
|
|
1168
|
+
return 0;
|
|
1169
|
+
}
|
|
1170
|
+
return 1 + overrideDepthFrom(node.overrodeHaltStateId, visited);
|
|
1171
|
+
};
|
|
1172
|
+
const maxCompositionDepth = nodes.reduce((max, node) => Math.max(max, overrideDepthFrom(node.id, new Set())), 0);
|
|
1173
|
+
// Cycle detection: tri-color DFS over the transition graph.
|
|
1174
|
+
const WHITE = 0;
|
|
1175
|
+
const GREY = 1;
|
|
1176
|
+
const BLACK = 2;
|
|
1177
|
+
const color = new Map();
|
|
1178
|
+
for (const node of nodes) {
|
|
1179
|
+
color.set(node.id, WHITE);
|
|
1180
|
+
}
|
|
1181
|
+
let hasCycles = false;
|
|
1182
|
+
const visit = (id) => {
|
|
1183
|
+
// No `if (hasCycles) return` guard at function entry: the recursive call
|
|
1184
|
+
// pattern (outer for-loop checks before calling, inner loop checks after
|
|
1185
|
+
// each recursive call) ensures visit() is never invoked when hasCycles
|
|
1186
|
+
// is already true. Static analysis confirmed the guard was unreachable.
|
|
1187
|
+
if (color.get(id) === GREY) {
|
|
1188
|
+
hasCycles = true;
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
if (color.get(id) === BLACK) {
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
color.set(id, GREY);
|
|
1195
|
+
const node = graph.nodes[id];
|
|
1196
|
+
if (node) {
|
|
1197
|
+
for (const t of node.transitions) {
|
|
1198
|
+
visit(t.nextStateId);
|
|
1199
|
+
if (hasCycles) {
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
color.set(id, BLACK);
|
|
1205
|
+
};
|
|
1206
|
+
for (const node of nodes) {
|
|
1207
|
+
if (hasCycles) {
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
visit(node.id);
|
|
1211
|
+
}
|
|
1212
|
+
return {
|
|
1213
|
+
stateCount: nodes.length,
|
|
1214
|
+
transitionCount,
|
|
1215
|
+
compositionEdgeCount,
|
|
1216
|
+
maxCompositionDepth,
|
|
1217
|
+
selfLoopCount,
|
|
1218
|
+
hasCycles,
|
|
1219
|
+
tapeCount: graph.alphabets.length,
|
|
1220
|
+
alphabetCardinalities: graph.alphabets.map((a) => a.length),
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
// Convenience: build the graph and summarize in one step.
|
|
1224
|
+
function summarize(state, tapeBlock) {
|
|
1225
|
+
return summarizeGraph(State.toGraph(state, tapeBlock));
|
|
1226
|
+
}
|
|
1227
|
+
// Behavioral equivalence checking (the testing-tool counterpart to introspection)
|
|
1228
|
+
// lives in ./equivalence — kept separate because it runs machines and compares
|
|
1229
|
+
// outputs rather than examining structure.
|
|
1230
|
+
|
|
1231
|
+
const defaultCompare = (a, b) => a === b;
|
|
1232
|
+
function equivalentOn(reference, candidate, cases, options = {}) {
|
|
1233
|
+
const compareOutputs = options.compareOutputs ?? defaultCompare;
|
|
1234
|
+
const compareSnapshots = options.compareSnapshots === undefined
|
|
1235
|
+
? defaultCompare
|
|
1236
|
+
: options.compareSnapshots;
|
|
1237
|
+
const stepsLimit = options.stepsLimit ?? 1e5;
|
|
1238
|
+
const results = cases.map((c) => {
|
|
1239
|
+
const pair = typeof c === 'string' ? { reference: c, candidate: c } : c;
|
|
1240
|
+
const refRun = runOnce(reference, pair.reference, stepsLimit);
|
|
1241
|
+
const candRun = runOnce(candidate, pair.candidate, stepsLimit);
|
|
1242
|
+
const agree = compareOutputs(refRun.finalOutput, candRun.finalOutput);
|
|
1243
|
+
let firstDivergenceStep = null;
|
|
1244
|
+
if (!agree && compareSnapshots !== null) {
|
|
1245
|
+
const minLen = Math.min(refRun.snapshots.length, candRun.snapshots.length);
|
|
1246
|
+
for (let i = 0; i < minLen; i += 1) {
|
|
1247
|
+
if (!compareSnapshots(refRun.snapshots[i], candRun.snapshots[i])) {
|
|
1248
|
+
firstDivergenceStep = i;
|
|
1249
|
+
break;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
if (firstDivergenceStep === null && refRun.snapshots.length !== candRun.snapshots.length) {
|
|
1253
|
+
firstDivergenceStep = minLen;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
return {
|
|
1257
|
+
case: pair,
|
|
1258
|
+
agree,
|
|
1259
|
+
referenceOutput: refRun.finalOutput,
|
|
1260
|
+
candidateOutput: candRun.finalOutput,
|
|
1261
|
+
referenceSteps: refRun.stepCount,
|
|
1262
|
+
candidateSteps: candRun.stepCount,
|
|
1263
|
+
firstDivergenceStep,
|
|
1264
|
+
};
|
|
1265
|
+
});
|
|
1266
|
+
return {
|
|
1267
|
+
results,
|
|
1268
|
+
allAgree: results.every((r) => r.agree),
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
// Single-machine runner: snapshots the tape after each step and returns the
|
|
1272
|
+
// final output, the snapshot list, and the step count.
|
|
1273
|
+
function runOnce(runnable, input, stepsLimit) {
|
|
1274
|
+
const tapeBlock = runnable.getTapeBlock();
|
|
1275
|
+
const tape = new Tape({
|
|
1276
|
+
alphabet: tapeBlock.tapes[0].alphabet,
|
|
1277
|
+
symbols: input.split(''),
|
|
1278
|
+
});
|
|
1279
|
+
tapeBlock.replaceTape(tape);
|
|
1280
|
+
const machine = new TuringMachine({ tapeBlock });
|
|
1281
|
+
const snapshots = [];
|
|
1282
|
+
let stepCount = 0;
|
|
1283
|
+
// Iterate the generator manually (the yielded MachineState isn't needed —
|
|
1284
|
+
// we only care about the side effects on the tape). At each yield the tape
|
|
1285
|
+
// reflects the state BEFORE the current step's command; after the loop
|
|
1286
|
+
// exits the tape has had every command applied.
|
|
1287
|
+
const generator = machine.runStepByStep({ initialState: runnable.state, stepsLimit });
|
|
1288
|
+
let result = generator.next();
|
|
1289
|
+
while (!result.done) {
|
|
1290
|
+
snapshots.push(tape.symbols.join(''));
|
|
1291
|
+
stepCount += 1;
|
|
1292
|
+
result = generator.next();
|
|
1293
|
+
}
|
|
1294
|
+
snapshots.push(tape.symbols.join(''));
|
|
1295
|
+
return {
|
|
1296
|
+
finalOutput: tape.symbols.join('').trim(),
|
|
1297
|
+
snapshots,
|
|
1298
|
+
stepCount,
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
export { Alphabet, Command, Reference, State, Tape, TapeBlock, TapeCommand, TuringMachine, equivalentOn, fromMermaid, haltState, ifOtherSymbol, movements, summarize, summarizeGraph, symbolCommands, toMermaid };
|