1 | import { reduce as reduce_to_639 } from 'reduce-to-639-1';
|
2 | import { seq, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key, array_box_if_string } from './jssm_util';
|
3 | import { parse } from './jssm-dot';
|
4 | import { version } from './version';
|
5 | function arrow_direction(arrow) {
|
6 | switch (String(arrow)) {
|
7 | case '->':
|
8 | case '→':
|
9 | case '=>':
|
10 | case '⇒':
|
11 | case '~>':
|
12 | case '↛':
|
13 | return 'right';
|
14 | case '<-':
|
15 | case '←':
|
16 | case '<=':
|
17 | case '⇐':
|
18 | case '<~':
|
19 | case '↚':
|
20 | return 'left';
|
21 | case '<->':
|
22 | case '↔':
|
23 | case '<-=>':
|
24 | case '←⇒':
|
25 | case '←=>':
|
26 | case '<-⇒':
|
27 | case '<-~>':
|
28 | case '←↛':
|
29 | case '←~>':
|
30 | case '<-↛':
|
31 | case '<=>':
|
32 | case '⇔':
|
33 | case '<=->':
|
34 | case '⇐→':
|
35 | case '⇐->':
|
36 | case '<=→':
|
37 | case '<=~>':
|
38 | case '⇐↛':
|
39 | case '⇐~>':
|
40 | case '<=↛':
|
41 | case '<~>':
|
42 | case '↮':
|
43 | case '<~->':
|
44 | case '↚→':
|
45 | case '↚->':
|
46 | case '<~→':
|
47 | case '<~=>':
|
48 | case '↚⇒':
|
49 | case '↚=>':
|
50 | case '<~⇒':
|
51 | return 'both';
|
52 | default:
|
53 | throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
|
54 | }
|
55 | }
|
56 | function arrow_left_kind(arrow) {
|
57 | switch (String(arrow)) {
|
58 | case '->':
|
59 | case '→':
|
60 | case '=>':
|
61 | case '⇒':
|
62 | case '~>':
|
63 | case '↛':
|
64 | return 'none';
|
65 | case '<-':
|
66 | case '←':
|
67 | case '<->':
|
68 | case '↔':
|
69 | case '<-=>':
|
70 | case '←⇒':
|
71 | case '<-~>':
|
72 | case '←↛':
|
73 | return 'legal';
|
74 | case '<=':
|
75 | case '⇐':
|
76 | case '<=>':
|
77 | case '⇔':
|
78 | case '<=->':
|
79 | case '⇐→':
|
80 | case '<=~>':
|
81 | case '⇐↛':
|
82 | return 'main';
|
83 | case '<~':
|
84 | case '↚':
|
85 | case '<~>':
|
86 | case '↮':
|
87 | case '<~->':
|
88 | case '↚→':
|
89 | case '<~=>':
|
90 | case '↚⇒':
|
91 | return 'forced';
|
92 | default:
|
93 | throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
|
94 | }
|
95 | }
|
96 | function arrow_right_kind(arrow) {
|
97 | switch (String(arrow)) {
|
98 | case '<-':
|
99 | case '←':
|
100 | case '<=':
|
101 | case '⇐':
|
102 | case '<~':
|
103 | case '↚':
|
104 | return 'none';
|
105 | case '->':
|
106 | case '→':
|
107 | case '<->':
|
108 | case '↔':
|
109 | case '<=->':
|
110 | case '⇐→':
|
111 | case '<~->':
|
112 | case '↚→':
|
113 | return 'legal';
|
114 | case '=>':
|
115 | case '⇒':
|
116 | case '<=>':
|
117 | case '⇔':
|
118 | case '<-=>':
|
119 | case '←⇒':
|
120 | case '<~=>':
|
121 | case '↚⇒':
|
122 | return 'main';
|
123 | case '~>':
|
124 | case '↛':
|
125 | case '<~>':
|
126 | case '↮':
|
127 | case '<-~>':
|
128 | case '←↛':
|
129 | case '<=~>':
|
130 | case '⇐↛':
|
131 | return 'forced';
|
132 | default:
|
133 | throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
|
134 | }
|
135 | }
|
136 | function makeTransition(this_se, from, to, isRight, _wasList, _wasIndex) {
|
137 | const kind = isRight ? arrow_right_kind(this_se.kind) : arrow_left_kind(this_se.kind), edge = {
|
138 | from,
|
139 | to,
|
140 | kind,
|
141 | forced_only: kind === 'forced',
|
142 | main_path: kind === 'main'
|
143 | };
|
144 | const action = isRight ? 'r_action' : 'l_action', probability = isRight ? 'r_probability' : 'l_probability';
|
145 | if (this_se[action]) {
|
146 | edge.action = this_se[action];
|
147 | }
|
148 | if (this_se[probability]) {
|
149 | edge.probability = this_se[probability];
|
150 | }
|
151 | return edge;
|
152 | }
|
153 | function compile_rule_transition_step(acc, from, to, this_se, next_se) {
|
154 | const edges = [];
|
155 | const uFrom = (Array.isArray(from) ? from : [from]), uTo = (Array.isArray(to) ? to : [to]);
|
156 | uFrom.map((f) => {
|
157 | uTo.map((t) => {
|
158 | const right = makeTransition(this_se, f, t, true);
|
159 | if (right.kind !== 'none') {
|
160 | edges.push(right);
|
161 | }
|
162 | const left = makeTransition(this_se, t, f, false);
|
163 | if (left.kind !== 'none') {
|
164 | edges.push(left);
|
165 | }
|
166 | });
|
167 | });
|
168 | const new_acc = acc.concat(edges);
|
169 | if (next_se) {
|
170 | return compile_rule_transition_step(new_acc, to, next_se.to, next_se, next_se.se);
|
171 | }
|
172 | else {
|
173 | return new_acc;
|
174 | }
|
175 | }
|
176 | function compile_rule_handle_transition(rule) {
|
177 | return compile_rule_transition_step([], rule.from, rule.se.to, rule.se, rule.se.se);
|
178 | }
|
179 | function compile_rule_handler(rule) {
|
180 | if (rule.key === 'transition') {
|
181 | return { agg_as: 'transition', val: compile_rule_handle_transition(rule) };
|
182 | }
|
183 | if (rule.key === 'machine_language') {
|
184 | return { agg_as: 'machine_language', val: reduce_to_639(rule.value) };
|
185 | }
|
186 | if (rule.key === 'state_declaration') {
|
187 | if (!rule.name) {
|
188 | throw new Error('State declarations must have a name');
|
189 | }
|
190 | return { agg_as: 'state_declaration', val: { state: rule.name, declarations: rule.value } };
|
191 | }
|
192 | if (['arrange_declaration', 'arrange_start_declaration',
|
193 | 'arrange_end_declaration'].includes(rule.key)) {
|
194 | return { agg_as: rule.key, val: [rule.value] };
|
195 | }
|
196 | const tautologies = [
|
197 | 'graph_layout', 'start_states', 'end_states', 'machine_name', 'machine_version',
|
198 | 'machine_comment', 'machine_author', 'machine_contributor', 'machine_definition',
|
199 | 'machine_reference', 'machine_license', 'fsl_version', 'state_config', 'theme',
|
200 | 'flow', 'dot_preamble'
|
201 | ];
|
202 | if (tautologies.includes(rule.key)) {
|
203 | return { agg_as: rule.key, val: rule.value };
|
204 | }
|
205 | throw new Error(`compile_rule_handler: Unknown rule: ${JSON.stringify(rule)}`);
|
206 | }
|
207 | function compile(tree) {
|
208 | const results = {
|
209 | graph_layout: [],
|
210 | transition: [],
|
211 | start_states: [],
|
212 | end_states: [],
|
213 | state_config: [],
|
214 | state_declaration: [],
|
215 | fsl_version: [],
|
216 | machine_author: [],
|
217 | machine_comment: [],
|
218 | machine_contributor: [],
|
219 | machine_definition: [],
|
220 | machine_language: [],
|
221 | machine_license: [],
|
222 | machine_name: [],
|
223 | machine_reference: [],
|
224 | theme: [],
|
225 | flow: [],
|
226 | dot_preamble: [],
|
227 | arrange_declaration: [],
|
228 | arrange_start_declaration: [],
|
229 | arrange_end_declaration: [],
|
230 | machine_version: []
|
231 | };
|
232 | tree.map((tr) => {
|
233 | const rule = compile_rule_handler(tr), agg_as = rule.agg_as, val = rule.val;
|
234 | results[agg_as] = results[agg_as].concat(val);
|
235 | });
|
236 | const assembled_transitions = [].concat(...results['transition']);
|
237 | const result_cfg = {
|
238 | start_states: results.start_states.length ? results.start_states : [assembled_transitions[0].from],
|
239 | transitions: assembled_transitions
|
240 | };
|
241 | const oneOnlyKeys = [
|
242 | 'graph_layout', 'machine_name', 'machine_version', 'machine_comment',
|
243 | 'fsl_version', 'machine_license', 'machine_definition', 'machine_language',
|
244 | 'theme', 'flow', 'dot_preamble'
|
245 | ];
|
246 | oneOnlyKeys.map((oneOnlyKey) => {
|
247 | if (results[oneOnlyKey].length > 1) {
|
248 | throw new Error(`May only have one ${oneOnlyKey} statement maximum: ${JSON.stringify(results[oneOnlyKey])}`);
|
249 | }
|
250 | else {
|
251 | if (results[oneOnlyKey].length) {
|
252 | result_cfg[oneOnlyKey] = results[oneOnlyKey][0];
|
253 | }
|
254 | }
|
255 | });
|
256 | ['arrange_declaration', 'arrange_start_declaration', 'arrange_end_declaration',
|
257 | 'machine_author', 'machine_contributor', 'machine_reference', 'state_declaration'].map((multiKey) => {
|
258 | if (results[multiKey].length) {
|
259 | result_cfg[multiKey] = results[multiKey];
|
260 | }
|
261 | });
|
262 | return result_cfg;
|
263 | }
|
264 | function make(plan) {
|
265 | return compile(parse(plan, {}));
|
266 | }
|
267 | function transfer_state_properties(state_decl) {
|
268 | state_decl.declarations.map((d) => {
|
269 | switch (d.key) {
|
270 | case 'shape':
|
271 | state_decl.shape = d.value;
|
272 | break;
|
273 | case 'color':
|
274 | state_decl.color = d.value;
|
275 | break;
|
276 | case 'corners':
|
277 | state_decl.corners = d.value;
|
278 | break;
|
279 | case 'linestyle':
|
280 | state_decl.linestyle = d.value;
|
281 | break;
|
282 | case 'text-color':
|
283 | state_decl.textColor = d.value;
|
284 | break;
|
285 | case 'background-color':
|
286 | state_decl.backgroundColor = d.value;
|
287 | break;
|
288 | case 'border-color':
|
289 | state_decl.borderColor = d.value;
|
290 | break;
|
291 | default: throw new Error(`Unknown state property: '${JSON.stringify(d)}'`);
|
292 | }
|
293 | });
|
294 | return state_decl;
|
295 | }
|
296 | class Machine {
|
297 | constructor({ start_states, complete = [], transitions, machine_author, machine_comment, machine_contributor, machine_definition, machine_language, machine_license, machine_name, machine_version, state_declaration, fsl_version, dot_preamble = undefined, arrange_declaration = [], arrange_start_declaration = [], arrange_end_declaration = [], theme = 'default', flow = 'down', graph_layout = 'dot' }) {
|
298 | this._state = start_states[0];
|
299 | this._states = new Map();
|
300 | this._state_declarations = new Map();
|
301 | this._edges = [];
|
302 | this._edge_map = new Map();
|
303 | this._named_transitions = new Map();
|
304 | this._actions = new Map();
|
305 | this._reverse_actions = new Map();
|
306 | this._reverse_action_targets = new Map();
|
307 | this._machine_author = array_box_if_string(machine_author);
|
308 | this._machine_comment = machine_comment;
|
309 | this._machine_contributor = array_box_if_string(machine_contributor);
|
310 | this._machine_definition = machine_definition;
|
311 | this._machine_language = machine_language;
|
312 | this._machine_license = machine_license;
|
313 | this._machine_name = machine_name;
|
314 | this._machine_version = machine_version;
|
315 | this._raw_state_declaration = state_declaration || [];
|
316 | this._fsl_version = fsl_version;
|
317 | this._arrange_declaration = arrange_declaration;
|
318 | this._arrange_start_declaration = arrange_start_declaration;
|
319 | this._arrange_end_declaration = arrange_end_declaration;
|
320 | this._dot_preamble = dot_preamble;
|
321 | this._theme = theme;
|
322 | this._flow = flow;
|
323 | this._graph_layout = graph_layout;
|
324 | if (state_declaration) {
|
325 | state_declaration.map((state_decl) => {
|
326 | if (this._state_declarations.has(state_decl.state)) {
|
327 | throw new Error(`Added the same state declaration twice: ${JSON.stringify(state_decl.state)}`);
|
328 | }
|
329 | this._state_declarations.set(state_decl.state, transfer_state_properties(state_decl));
|
330 | });
|
331 | }
|
332 | transitions.map((tr) => {
|
333 | if (tr.from === undefined) {
|
334 | throw new Error(`transition must define 'from': ${JSON.stringify(tr)}`);
|
335 | }
|
336 | if (tr.to === undefined) {
|
337 | throw new Error(`transition must define 'to': ${JSON.stringify(tr)}`);
|
338 | }
|
339 | const cursor_from = this._states.get(tr.from)
|
340 | || { name: tr.from, from: [], to: [], complete: complete.includes(tr.from) };
|
341 | if (!(this._states.has(tr.from))) {
|
342 | this._new_state(cursor_from);
|
343 | }
|
344 | const cursor_to = this._states.get(tr.to)
|
345 | || { name: tr.to, from: [], to: [], complete: complete.includes(tr.to) };
|
346 | if (!(this._states.has(tr.to))) {
|
347 | this._new_state(cursor_to);
|
348 | }
|
349 | if (cursor_from.to.includes(tr.to)) {
|
350 | throw new Error(`already has ${JSON.stringify(tr.from)} to ${JSON.stringify(tr.to)}`);
|
351 | }
|
352 | else {
|
353 | cursor_from.to.push(tr.to);
|
354 | cursor_to.from.push(tr.from);
|
355 | }
|
356 | this._edges.push(tr);
|
357 | const thisEdgeId = this._edges.length - 1;
|
358 | if (tr.name) {
|
359 | if (this._named_transitions.has(tr.name)) {
|
360 | throw new Error(`named transition "${JSON.stringify(tr.name)}" already created`);
|
361 | }
|
362 | else {
|
363 | this._named_transitions.set(tr.name, thisEdgeId);
|
364 | }
|
365 | }
|
366 | const from_mapping = this._edge_map.get(tr.from) || new Map();
|
367 | if (!(this._edge_map.has(tr.from))) {
|
368 | this._edge_map.set(tr.from, from_mapping);
|
369 | }
|
370 | from_mapping.set(tr.to, thisEdgeId);
|
371 | if (tr.action) {
|
372 | let actionMap = this._actions.get(tr.action);
|
373 | if (!(actionMap)) {
|
374 | actionMap = new Map();
|
375 | this._actions.set(tr.action, actionMap);
|
376 | }
|
377 | if (actionMap.has(tr.from)) {
|
378 | throw new Error(`action ${JSON.stringify(tr.action)} already attached to origin ${JSON.stringify(tr.from)}`);
|
379 | }
|
380 | else {
|
381 | actionMap.set(tr.from, thisEdgeId);
|
382 | }
|
383 | let rActionMap = this._reverse_actions.get(tr.from);
|
384 | if (!(rActionMap)) {
|
385 | rActionMap = new Map();
|
386 | this._reverse_actions.set(tr.from, rActionMap);
|
387 | }
|
388 | rActionMap.set(tr.action, thisEdgeId);
|
389 | if (!(this._reverse_action_targets.has(tr.to))) {
|
390 | this._reverse_action_targets.set(tr.to, new Map());
|
391 | }
|
392 | }
|
393 | });
|
394 | }
|
395 | _new_state(state_config) {
|
396 | if (this._states.has(state_config.name)) {
|
397 | throw new Error(`state ${JSON.stringify(state_config.name)} already exists`);
|
398 | }
|
399 | this._states.set(state_config.name, state_config);
|
400 | return state_config.name;
|
401 | }
|
402 | state() {
|
403 | return this._state;
|
404 | }
|
405 | state_is_final(whichState) {
|
406 | return ((this.state_is_terminal(whichState)) && (this.state_is_complete(whichState)));
|
407 | }
|
408 | is_final() {
|
409 | return this.state_is_final(this.state());
|
410 | }
|
411 | graph_layout() {
|
412 | return this._graph_layout;
|
413 | }
|
414 | dot_preamble() {
|
415 | return this._dot_preamble;
|
416 | }
|
417 | machine_author() {
|
418 | return this._machine_author;
|
419 | }
|
420 | machine_comment() {
|
421 | return this._machine_comment;
|
422 | }
|
423 | machine_contributor() {
|
424 | return this._machine_contributor;
|
425 | }
|
426 | machine_definition() {
|
427 | return this._machine_definition;
|
428 | }
|
429 | machine_language() {
|
430 | return this._machine_language;
|
431 | }
|
432 | machine_license() {
|
433 | return this._machine_license;
|
434 | }
|
435 | machine_name() {
|
436 | return this._machine_name;
|
437 | }
|
438 | machine_version() {
|
439 | return this._machine_version;
|
440 | }
|
441 | raw_state_declarations() {
|
442 | return this._raw_state_declaration;
|
443 | }
|
444 | state_declaration(which) {
|
445 | return this._state_declarations.get(which);
|
446 | }
|
447 | state_declarations() {
|
448 | return this._state_declarations;
|
449 | }
|
450 | fsl_version() {
|
451 | return this._fsl_version;
|
452 | }
|
453 | machine_state() {
|
454 | return {
|
455 | internal_state_impl_version: 1,
|
456 | actions: this._actions,
|
457 | edge_map: this._edge_map,
|
458 | edges: this._edges,
|
459 | named_transitions: this._named_transitions,
|
460 | reverse_actions: this._reverse_actions,
|
461 | state: this._state,
|
462 | states: this._states
|
463 | };
|
464 | }
|
465 | states() {
|
466 | return Array.from(this._states.keys());
|
467 | }
|
468 | state_for(whichState) {
|
469 | const state = this._states.get(whichState);
|
470 | if (state) {
|
471 | return state;
|
472 | }
|
473 | else {
|
474 | throw new Error(`no such state ${JSON.stringify(state)}`);
|
475 | }
|
476 | }
|
477 | has_state(whichState) {
|
478 | return this._states.get(whichState) !== undefined;
|
479 | }
|
480 | list_edges() {
|
481 | return this._edges;
|
482 | }
|
483 | list_named_transitions() {
|
484 | return this._named_transitions;
|
485 | }
|
486 | list_actions() {
|
487 | return Array.from(this._actions.keys());
|
488 | }
|
489 | theme() {
|
490 | return this._theme;
|
491 | }
|
492 | flow() {
|
493 | return this._flow;
|
494 | }
|
495 | get_transition_by_state_names(from, to) {
|
496 | const emg = this._edge_map.get(from);
|
497 | if (emg) {
|
498 | return emg.get(to);
|
499 | }
|
500 | else {
|
501 | return undefined;
|
502 | }
|
503 | }
|
504 | lookup_transition_for(from, to) {
|
505 | const id = this.get_transition_by_state_names(from, to);
|
506 | return ((id === undefined) || (id === null)) ? undefined : this._edges[id];
|
507 | }
|
508 | list_transitions(whichState = this.state()) {
|
509 | return { entrances: this.list_entrances(whichState), exits: this.list_exits(whichState) };
|
510 | }
|
511 | list_entrances(whichState = this.state()) {
|
512 | return (this._states.get(whichState)
|
513 | || { from: undefined }).from
|
514 | || [];
|
515 | }
|
516 | list_exits(whichState = this.state()) {
|
517 | return (this._states.get(whichState)
|
518 | || { to: undefined }).to
|
519 | || [];
|
520 | }
|
521 | probable_exits_for(whichState) {
|
522 | const wstate = this._states.get(whichState);
|
523 | if (!(wstate)) {
|
524 | throw new Error(`No such state ${JSON.stringify(whichState)} in probable_exits_for`);
|
525 | }
|
526 | const wstate_to = wstate.to, wtf = wstate_to
|
527 | .map((ws) => this.lookup_transition_for(this.state(), ws))
|
528 | .filter(Boolean);
|
529 | return wtf;
|
530 | }
|
531 | probabilistic_transition() {
|
532 | const selected = weighted_rand_select(this.probable_exits_for(this.state()));
|
533 | return this.transition(selected.to);
|
534 | }
|
535 | probabilistic_walk(n) {
|
536 | return seq(n)
|
537 | .map(() => {
|
538 | const state_was = this.state();
|
539 | this.probabilistic_transition();
|
540 | return state_was;
|
541 | })
|
542 | .concat([this.state()]);
|
543 | }
|
544 | probabilistic_histo_walk(n) {
|
545 | return histograph(this.probabilistic_walk(n));
|
546 | }
|
547 | actions(whichState = this.state()) {
|
548 | const wstate = this._reverse_actions.get(whichState);
|
549 | if (wstate) {
|
550 | return Array.from(wstate.keys());
|
551 | }
|
552 | else {
|
553 | throw new Error(`No such state ${JSON.stringify(whichState)}`);
|
554 | }
|
555 | }
|
556 | list_states_having_action(whichState) {
|
557 | const wstate = this._actions.get(whichState);
|
558 | if (wstate) {
|
559 | return Array.from(wstate.keys());
|
560 | }
|
561 | else {
|
562 | throw new Error(`No such state ${JSON.stringify(whichState)}`);
|
563 | }
|
564 | }
|
565 | list_exit_actions(whichState = this.state()) {
|
566 | const ra_base = this._reverse_actions.get(whichState);
|
567 | if (!(ra_base)) {
|
568 | throw new Error(`No such state ${JSON.stringify(whichState)}`);
|
569 | }
|
570 | return Array.from(ra_base.values())
|
571 | .map((edgeId) => this._edges[edgeId])
|
572 | .filter((o) => o.from === whichState)
|
573 | .map((filtered) => filtered.action);
|
574 | }
|
575 | probable_action_exits(whichState = this.state()) {
|
576 | const ra_base = this._reverse_actions.get(whichState);
|
577 | if (!(ra_base)) {
|
578 | throw new Error(`No such state ${JSON.stringify(whichState)}`);
|
579 | }
|
580 | return Array.from(ra_base.values())
|
581 | .map((edgeId) => this._edges[edgeId])
|
582 | .filter((o) => o.from === whichState)
|
583 | .map((filtered) => ({ action: filtered.action,
|
584 | probability: filtered.probability
|
585 | }));
|
586 | }
|
587 | is_unenterable(whichState) {
|
588 | if (!(this.has_state(whichState))) {
|
589 | throw new Error(`No such state ${whichState}`);
|
590 | }
|
591 | return this.list_entrances(whichState).length === 0;
|
592 | }
|
593 | has_unenterables() {
|
594 | return this.states().some((x) => this.is_unenterable(x));
|
595 | }
|
596 | is_terminal() {
|
597 | return this.state_is_terminal(this.state());
|
598 | }
|
599 | state_is_terminal(whichState) {
|
600 | if (!(this.has_state(whichState))) {
|
601 | throw new Error(`No such state ${whichState}`);
|
602 | }
|
603 | return this.list_exits(whichState).length === 0;
|
604 | }
|
605 | has_terminals() {
|
606 | return this.states().some((x) => this.state_is_terminal(x));
|
607 | }
|
608 | is_complete() {
|
609 | return this.state_is_complete(this.state());
|
610 | }
|
611 | state_is_complete(whichState) {
|
612 | const wstate = this._states.get(whichState);
|
613 | if (wstate) {
|
614 | return wstate.complete;
|
615 | }
|
616 | else {
|
617 | throw new Error(`No such state ${JSON.stringify(whichState)}`);
|
618 | }
|
619 | }
|
620 | has_completes() {
|
621 | return this.states().some((x) => this.state_is_complete(x));
|
622 | }
|
623 | action(name, newData) {
|
624 | if (this.valid_action(name, newData)) {
|
625 | const edge = this.current_action_edge_for(name);
|
626 | this._state = edge.to;
|
627 | return true;
|
628 | }
|
629 | else {
|
630 | return false;
|
631 | }
|
632 | }
|
633 | transition(newState, newData) {
|
634 | if (this.valid_transition(newState, newData)) {
|
635 | this._state = newState;
|
636 | return true;
|
637 | }
|
638 | else {
|
639 | return false;
|
640 | }
|
641 | }
|
642 | force_transition(newState, newData) {
|
643 | if (this.valid_force_transition(newState, newData)) {
|
644 | this._state = newState;
|
645 | return true;
|
646 | }
|
647 | else {
|
648 | return false;
|
649 | }
|
650 | }
|
651 | current_action_for(action) {
|
652 | const action_base = this._actions.get(action);
|
653 | return action_base ? action_base.get(this.state()) : undefined;
|
654 | }
|
655 | current_action_edge_for(action) {
|
656 | const idx = this.current_action_for(action);
|
657 | if ((idx === undefined) || (idx === null)) {
|
658 | throw new Error(`No such action ${JSON.stringify(action)}`);
|
659 | }
|
660 | return this._edges[idx];
|
661 | }
|
662 | valid_action(action, _newData) {
|
663 | return this.current_action_for(action) !== undefined;
|
664 | }
|
665 | valid_transition(newState, _newData) {
|
666 | const transition_for = this.lookup_transition_for(this.state(), newState);
|
667 | if (!(transition_for)) {
|
668 | return false;
|
669 | }
|
670 | if (transition_for.forced_only) {
|
671 | return false;
|
672 | }
|
673 | return true;
|
674 | }
|
675 | valid_force_transition(newState, _newData) {
|
676 | return (this.lookup_transition_for(this.state(), newState) !== undefined);
|
677 | }
|
678 | sm(template_strings, ...remainder) {
|
679 | return sm(template_strings, ...remainder);
|
680 | }
|
681 | }
|
682 | function sm(template_strings, ...remainder) {
|
683 | return new Machine(make(template_strings.reduce((acc, val, idx) => `${acc}${remainder[idx - 1]}${val}`)));
|
684 | }
|
685 | export { version, transfer_state_properties, Machine, make, parse, compile, sm, arrow_direction, arrow_left_kind, arrow_right_kind, seq, weighted_rand_select, histograph, weighted_sample_select, weighted_histo_key };
|