You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

92 lines
2.4 KiB

  1. 'use strict';
  2. var INITIAL_STATE = 1;
  3. var FAIL_STATE = 0;
  4. /**
  5. * A StateMachine represents a deterministic finite automaton.
  6. * It can perform matches over a sequence of values, similar to a regular expression.
  7. */
  8. class StateMachine {
  9. constructor(dfa) {
  10. this.stateTable = dfa.stateTable;
  11. this.accepting = dfa.accepting;
  12. this.tags = dfa.tags;
  13. }
  14. /**
  15. * Returns an iterable object that yields pattern matches over the input sequence.
  16. * Matches are of the form [startIndex, endIndex, tags].
  17. */
  18. match(str) {
  19. var self = this;
  20. return {
  21. *[Symbol.iterator]() {
  22. var state = INITIAL_STATE;
  23. var startRun = null;
  24. var lastAccepting = null;
  25. var lastState = null;
  26. for (var p = 0; p < str.length; p++) {
  27. var c = str[p];
  28. lastState = state;
  29. state = self.stateTable[state][c];
  30. if (state === FAIL_STATE) {
  31. // yield the last match if any
  32. if (startRun != null && lastAccepting != null && lastAccepting >= startRun) {
  33. yield [startRun, lastAccepting, self.tags[lastState]];
  34. } // reset the state as if we started over from the initial state
  35. state = self.stateTable[INITIAL_STATE][c];
  36. startRun = null;
  37. } // start a run if not in the failure state
  38. if (state !== FAIL_STATE && startRun == null) {
  39. startRun = p;
  40. } // if accepting, mark the potential match end
  41. if (self.accepting[state]) {
  42. lastAccepting = p;
  43. } // reset the state to the initial state if we get into the failure state
  44. if (state === FAIL_STATE) {
  45. state = INITIAL_STATE;
  46. }
  47. } // yield the last match if any
  48. if (startRun != null && lastAccepting != null && lastAccepting >= startRun) {
  49. yield [startRun, lastAccepting, self.tags[state]];
  50. }
  51. }
  52. };
  53. }
  54. /**
  55. * For each match over the input sequence, action functions matching
  56. * the tag definitions in the input pattern are called with the startIndex,
  57. * endIndex, and sub-match sequence.
  58. */
  59. apply(str, actions) {
  60. for (var [start, end, tags] of this.match(str)) {
  61. for (var tag of tags) {
  62. if (typeof actions[tag] === 'function') {
  63. actions[tag](start, end, str.slice(start, end + 1));
  64. }
  65. }
  66. }
  67. }
  68. }
  69. module.exports = StateMachine;
  70. //# sourceMappingURL=index.js.map