nfa-state.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /**
  2. * The MIT License (MIT)
  3. * Copyright (c) 2017-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
  4. */
  5. 'use strict';
  6. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  7. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  8. function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
  9. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  10. var State = require('../state');
  11. var _require = require('../special-symbols'),
  12. EPSILON = _require.EPSILON;
  13. /**
  14. * NFA state.
  15. *
  16. * Allows nondeterministic transitions to several states on the
  17. * same symbol, and also epsilon-transitions.
  18. */
  19. var NFAState = function (_State) {
  20. _inherits(NFAState, _State);
  21. function NFAState() {
  22. _classCallCheck(this, NFAState);
  23. return _possibleConstructorReturn(this, (NFAState.__proto__ || Object.getPrototypeOf(NFAState)).apply(this, arguments));
  24. }
  25. _createClass(NFAState, [{
  26. key: 'matches',
  27. /**
  28. * Whether this state matches a string.
  29. *
  30. * We maintain set of visited epsilon-states to avoid infinite loops
  31. * when an epsilon-transition goes eventually to itself.
  32. *
  33. * NOTE: this function is rather "educational", since we use DFA for strings
  34. * matching. DFA is built on top of NFA, and uses fast transition table.
  35. */
  36. value: function matches(string) {
  37. var visited = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Set();
  38. // An epsilon-state has been visited, stop to avoid infinite loop.
  39. if (visited.has(this)) {
  40. return false;
  41. }
  42. visited.add(this);
  43. // No symbols left..
  44. if (string.length === 0) {
  45. // .. and we're in the accepting state.
  46. if (this.accepting) {
  47. return true;
  48. }
  49. // Check if we can reach any accepting state from
  50. // on the epsilon transitions.
  51. var _iteratorNormalCompletion = true;
  52. var _didIteratorError = false;
  53. var _iteratorError = undefined;
  54. try {
  55. for (var _iterator = this.getTransitionsOnSymbol(EPSILON)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
  56. var nextState = _step.value;
  57. if (nextState.matches('', visited)) {
  58. return true;
  59. }
  60. }
  61. } catch (err) {
  62. _didIteratorError = true;
  63. _iteratorError = err;
  64. } finally {
  65. try {
  66. if (!_iteratorNormalCompletion && _iterator.return) {
  67. _iterator.return();
  68. }
  69. } finally {
  70. if (_didIteratorError) {
  71. throw _iteratorError;
  72. }
  73. }
  74. }
  75. return false;
  76. }
  77. // Else, we get some symbols.
  78. var symbol = string[0];
  79. var rest = string.slice(1);
  80. var symbolTransitions = this.getTransitionsOnSymbol(symbol);
  81. var _iteratorNormalCompletion2 = true;
  82. var _didIteratorError2 = false;
  83. var _iteratorError2 = undefined;
  84. try {
  85. for (var _iterator2 = symbolTransitions[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
  86. var _nextState = _step2.value;
  87. if (_nextState.matches(rest)) {
  88. return true;
  89. }
  90. }
  91. // If we couldn't match on symbol, check still epsilon-transitions
  92. // without consuming the symbol (i.e. continue from `string`, not `rest`).
  93. } catch (err) {
  94. _didIteratorError2 = true;
  95. _iteratorError2 = err;
  96. } finally {
  97. try {
  98. if (!_iteratorNormalCompletion2 && _iterator2.return) {
  99. _iterator2.return();
  100. }
  101. } finally {
  102. if (_didIteratorError2) {
  103. throw _iteratorError2;
  104. }
  105. }
  106. }
  107. var _iteratorNormalCompletion3 = true;
  108. var _didIteratorError3 = false;
  109. var _iteratorError3 = undefined;
  110. try {
  111. for (var _iterator3 = this.getTransitionsOnSymbol(EPSILON)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
  112. var _nextState2 = _step3.value;
  113. if (_nextState2.matches(string, visited)) {
  114. return true;
  115. }
  116. }
  117. } catch (err) {
  118. _didIteratorError3 = true;
  119. _iteratorError3 = err;
  120. } finally {
  121. try {
  122. if (!_iteratorNormalCompletion3 && _iterator3.return) {
  123. _iterator3.return();
  124. }
  125. } finally {
  126. if (_didIteratorError3) {
  127. throw _iteratorError3;
  128. }
  129. }
  130. }
  131. return false;
  132. }
  133. /**
  134. * Returns an ε-closure for this state:
  135. * self + all states following ε-transitions.
  136. */
  137. }, {
  138. key: 'getEpsilonClosure',
  139. value: function getEpsilonClosure() {
  140. var _this2 = this;
  141. if (!this._epsilonClosure) {
  142. (function () {
  143. var epsilonTransitions = _this2.getTransitionsOnSymbol(EPSILON);
  144. var closure = _this2._epsilonClosure = new Set();
  145. closure.add(_this2);
  146. var _iteratorNormalCompletion4 = true;
  147. var _didIteratorError4 = false;
  148. var _iteratorError4 = undefined;
  149. try {
  150. for (var _iterator4 = epsilonTransitions[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
  151. var nextState = _step4.value;
  152. if (!closure.has(nextState)) {
  153. closure.add(nextState);
  154. var nextClosure = nextState.getEpsilonClosure();
  155. nextClosure.forEach(function (state) {
  156. return closure.add(state);
  157. });
  158. }
  159. }
  160. } catch (err) {
  161. _didIteratorError4 = true;
  162. _iteratorError4 = err;
  163. } finally {
  164. try {
  165. if (!_iteratorNormalCompletion4 && _iterator4.return) {
  166. _iterator4.return();
  167. }
  168. } finally {
  169. if (_didIteratorError4) {
  170. throw _iteratorError4;
  171. }
  172. }
  173. }
  174. })();
  175. }
  176. return this._epsilonClosure;
  177. }
  178. }]);
  179. return NFAState;
  180. }(State);
  181. module.exports = NFAState;