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