From dbbce60f68ada2272ef48b5ef6edec658bae3df8 Mon Sep 17 00:00:00 2001 From: Ger Hobbelt Date: Wed, 13 Dec 2017 01:57:44 +0100 Subject: [PATCH] adding and updating test cases for "lexer ES6 arrow functions in action code" issue: https://github.com/zaach/jison-lex/issues/23 --- .../001-custom-lexer-baseline.jison-ref.json5 | 2 +- ...om-lexer-extra-code-chunks.jison-ref.json5 | 2 +- .../tests/specs/003-issue-23-alt-good.js | 27 ++ .../specs/003-issue-23-alt-good.js-ref.json5 | 303 ++++++++++++++++++ .../tests/specs/003-issue-23-good.js | 27 ++ .../specs/003-issue-23-good.js-ref.json5 | 303 ++++++++++++++++++ .../tests/specs/003-issue-23-trouble.js | 27 ++ .../specs/003-issue-23-trouble.js-ref.json5 | 303 ++++++++++++++++++ 8 files changed, 992 insertions(+), 2 deletions(-) create mode 100644 packages/jison-lex/tests/specs/003-issue-23-alt-good.js create mode 100644 packages/jison-lex/tests/specs/003-issue-23-alt-good.js-ref.json5 create mode 100644 packages/jison-lex/tests/specs/003-issue-23-good.js create mode 100644 packages/jison-lex/tests/specs/003-issue-23-good.js-ref.json5 create mode 100644 packages/jison-lex/tests/specs/003-issue-23-trouble.js create mode 100644 packages/jison-lex/tests/specs/003-issue-23-trouble.js-ref.json5 diff --git a/packages/jison-lex/tests/specs/001-custom-lexer-baseline.jison-ref.json5 b/packages/jison-lex/tests/specs/001-custom-lexer-baseline.jison-ref.json5 index b87691ec6..cf331b636 100644 --- a/packages/jison-lex/tests/specs/001-custom-lexer-baseline.jison-ref.json5 +++ b/packages/jison-lex/tests/specs/001-custom-lexer-baseline.jison-ref.json5 @@ -41,7 +41,7 @@ moduleType: "commonjs", debug: false, enableDebugLogs: false, - json: false, + json: true, dumpSourceCodeOnFailure: true, throwErrorOnCompileFailure: true, defaultModuleName: "lexer", diff --git a/packages/jison-lex/tests/specs/002-custom-lexer-extra-code-chunks.jison-ref.json5 b/packages/jison-lex/tests/specs/002-custom-lexer-extra-code-chunks.jison-ref.json5 index f21ef9029..f04689d8d 100644 --- a/packages/jison-lex/tests/specs/002-custom-lexer-extra-code-chunks.jison-ref.json5 +++ b/packages/jison-lex/tests/specs/002-custom-lexer-extra-code-chunks.jison-ref.json5 @@ -50,7 +50,7 @@ moduleType: "commonjs", debug: false, enableDebugLogs: false, - json: false, + json: true, dumpSourceCodeOnFailure: true, throwErrorOnCompileFailure: true, defaultModuleName: "lexer", diff --git a/packages/jison-lex/tests/specs/003-issue-23-alt-good.js b/packages/jison-lex/tests/specs/003-issue-23-alt-good.js new file mode 100644 index 000000000..3a1722657 --- /dev/null +++ b/packages/jison-lex/tests/specs/003-issue-23-alt-good.js @@ -0,0 +1,27 @@ +// title: Parse error when using arrow function in rules +// test_input: A a B C 1 + 2 + 3 +// ... +// +// This is the SUCCESSFUL lexer spec +// + +let grammar = { + rules: [ + ['\\s+', ''], + ['\\d+', 'return "NUMBER"'], + ['\\w+', ` + if (yytext === 'a') { + return 'TOK_A'; + } else { + return 'WORD'; + } + ` + ], + ['\\+', 'return "+"'], + ['$', 'return "EOF"'], + ] +}; + +module.exports = grammar; +// export default grammar; + diff --git a/packages/jison-lex/tests/specs/003-issue-23-alt-good.js-ref.json5 b/packages/jison-lex/tests/specs/003-issue-23-alt-good.js-ref.json5 new file mode 100644 index 000000000..7d19ccebc --- /dev/null +++ b/packages/jison-lex/tests/specs/003-issue-23-alt-good.js-ref.json5 @@ -0,0 +1,303 @@ +[ + 13, + "WORD", + "A", + { + first_line: 1, + first_column: 0, + last_line: 1, + last_column: 1, + range: [ + 0, + 1 + ] + }, + "TOK_A", + "a", + { + first_line: 1, + first_column: 2, + last_line: 1, + last_column: 3, + range: [ + 2, + 3 + ] + }, + "WORD", + "B", + { + first_line: 1, + first_column: 4, + last_line: 1, + last_column: 5, + range: [ + 4, + 5 + ] + }, + "WORD", + "C", + { + first_line: 1, + first_column: 6, + last_line: 1, + last_column: 7, + range: [ + 6, + 7 + ] + }, + "NUMBER", + "1", + { + first_line: 1, + first_column: 8, + last_line: 1, + last_column: 9, + range: [ + 8, + 9 + ] + }, + "+", + "+", + { + first_line: 1, + first_column: 10, + last_line: 1, + last_column: 11, + range: [ + 10, + 11 + ] + }, + "NUMBER", + "2", + { + first_line: 1, + first_column: 12, + last_line: 1, + last_column: 13, + range: [ + 12, + 13 + ] + }, + "+", + "+", + { + first_line: 1, + first_column: 14, + last_line: 1, + last_column: 15, + range: [ + 14, + 15 + ] + }, + "NUMBER", + "3", + { + first_line: 1, + first_column: 16, + last_line: 1, + last_column: 17, + range: [ + 16, + 17 + ] + }, + "EOF", + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + { + sourceCode: "\nvar lexer = {\n/*JISON-LEX-ANALYTICS-REPORT*/EOF: 1,\n ERROR: 2,\n\n // JisonLexerError: JisonLexerError, /// <-- injected by the code generator\n\n // options: {}, /// <-- injected by the code generator\n\n // yy: ..., /// <-- injected by setInput()\n\n __currentRuleSet__: null, /// INTERNAL USE ONLY: internal rule set cache for the current lexer state\n\n __error_infos: [], /// INTERNAL USE ONLY: the set of lexErrorInfo objects created since the last cleanup\n\n __decompressed: false, /// INTERNAL USE ONLY: mark whether the lexer instance has been 'unfolded' completely and is now ready for use\n\n done: false, /// INTERNAL USE ONLY\n _backtrack: false, /// INTERNAL USE ONLY\n _input: '', /// INTERNAL USE ONLY\n _more: false, /// INTERNAL USE ONLY\n _signaled_error_token: false, /// INTERNAL USE ONLY\n\n conditionStack: [], /// INTERNAL USE ONLY; managed via `pushState()`, `popState()`, `topState()` and `stateStackSize()`\n\n match: '', /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks input which has been matched so far for the lexer token under construction. `match` is identical to `yytext` except that this one still contains the matched input string after `lexer.performAction()` has been invoked, where userland code MAY have changed/replaced the `yytext` value entirely!\n matched: '', /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks entire input which has been matched so far\n matches: false, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks RE match result for last (successful) match attempt\n yytext: '', /// ADVANCED USE ONLY: tracks input which has been matched so far for the lexer token under construction; this value is transferred to the parser as the 'token value' when the parser consumes the lexer token produced through a call to the `lex()` API.\n offset: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks the 'cursor position' in the input string, i.e. the number of characters matched so far\n yyleng: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: length of matched input for the token under construction (`yytext`)\n yylineno: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: 'line number' at which the token under construction is located\n yylloc: null, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks location info (lines + columns) for the token under construction\n\n /**\n * INTERNAL USE: construct a suitable error info hash object instance for `parseError`.\n * \n * @public\n * @this {RegExpLexer}\n */\n constructLexErrorInfo: function lexer_constructLexErrorInfo(msg, recoverable, show_input_position) {\n msg = '' + msg;\n\n // heuristic to determine if the error message already contains a (partial) source code dump\n // as produced by either `showPosition()` or `prettyPrintRange()`:\n if (show_input_position == undefined) {\n show_input_position = !(msg.indexOf('\\n') > 0 && msg.indexOf('^') > 0);\n }\n if (this.yylloc && show_input_position) {\n if (typeof this.prettyPrintRange === 'function') {\n var pretty_src = this.prettyPrintRange(this.yylloc);\n\n if (!/\\n\\s*$/.test(msg)) {\n msg += '\\n';\n }\n msg += '\\n Erroneous area:\\n' + this.prettyPrintRange(this.yylloc); \n } else if (typeof this.showPosition === 'function') {\n var pos_str = this.showPosition();\n if (pos_str) {\n if (msg.length && msg[msg.length - 1] !== '\\n' && pos_str[0] !== '\\n') {\n msg += '\\n' + pos_str;\n } else {\n msg += pos_str;\n }\n }\n }\n }\n /** @constructor */\n var pei = {\n errStr: msg,\n recoverable: !!recoverable,\n text: this.match, // This one MAY be empty; userland code should use the `upcomingInput` API to obtain more text which follows the 'lexer cursor position'...\n token: null,\n line: this.yylineno,\n loc: this.yylloc,\n yy: this.yy,\n lexer: this,\n\n /**\n * and make sure the error info doesn't stay due to potential\n * ref cycle via userland code manipulations.\n * These would otherwise all be memory leak opportunities!\n * \n * Note that only array and object references are nuked as those\n * constitute the set of elements which can produce a cyclic ref.\n * The rest of the members is kept intact as they are harmless.\n * \n * @public\n * @this {LexErrorInfo}\n */\n destroy: function destructLexErrorInfo() {\n // remove cyclic references added to error info:\n // info.yy = null;\n // info.lexer = null;\n // ...\n var rec = !!this.recoverable;\n for (var key in this) {\n if (this.hasOwnProperty(key) && typeof key === 'object') {\n this[key] = undefined;\n }\n }\n this.recoverable = rec;\n }\n };\n // track this instance so we can `destroy()` it once we deem it superfluous and ready for garbage collection!\n this.__error_infos.push(pei);\n return pei;\n },\n\n /**\n * handler which is invoked when a lexer error occurs.\n * \n * @public\n * @this {RegExpLexer}\n */\n parseError: function lexer_parseError(str, hash, ExceptionClass) {\n if (!ExceptionClass) {\n ExceptionClass = this.JisonLexerError;\n }\n if (this.yy) {\n if (this.yy.parser && typeof this.yy.parser.parseError === 'function') {\n return this.yy.parser.parseError.call(this, str, hash, ExceptionClass) || this.ERROR;\n } else if (typeof this.yy.parseError === 'function') {\n return this.yy.parseError.call(this, str, hash, ExceptionClass) || this.ERROR;\n } \n }\n throw new ExceptionClass(str, hash);\n },\n\n /**\n * method which implements `yyerror(str, ...args)` functionality for use inside lexer actions.\n * \n * @public\n * @this {RegExpLexer}\n */\n yyerror: function yyError(str /*, ...args */) {\n var lineno_msg = '';\n if (this.yylloc) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': ' + str, this.options.lexerErrorsAreRecoverable);\n\n // Add any extra args to the hash under the name `extra_error_attributes`:\n var args = Array.prototype.slice.call(arguments, 1);\n if (args.length) {\n p.extra_error_attributes = args;\n }\n\n return (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n },\n\n /**\n * final cleanup function for when we have completed lexing the input;\n * make it an API so that external code can use this one once userland\n * code has decided it's time to destroy any lingering lexer error\n * hash object instances and the like: this function helps to clean\n * up these constructs, which *may* carry cyclic references which would\n * otherwise prevent the instances from being properly and timely\n * garbage-collected, i.e. this function helps prevent memory leaks!\n * \n * @public\n * @this {RegExpLexer}\n */\n cleanupAfterLex: function lexer_cleanupAfterLex(do_not_nuke_errorinfos) {\n // prevent lingering circular references from causing memory leaks:\n this.setInput('', {});\n\n // nuke the error hash info instances created during this run.\n // Userland code must COPY any data/references\n // in the error hash instance(s) it is more permanently interested in.\n if (!do_not_nuke_errorinfos) {\n for (var i = this.__error_infos.length - 1; i >= 0; i--) {\n var el = this.__error_infos[i];\n if (el && typeof el.destroy === 'function') {\n el.destroy();\n }\n }\n this.__error_infos.length = 0;\n }\n\n return this;\n },\n\n /**\n * clear the lexer token context; intended for internal use only\n * \n * @public\n * @this {RegExpLexer}\n */\n clear: function lexer_clear() {\n this.yytext = '';\n this.yyleng = 0;\n this.match = '';\n // - DO NOT reset `this.matched`\n this.matches = false;\n this._more = false;\n this._backtrack = false;\n\n var col = (this.yylloc ? this.yylloc.last_column : 0);\n this.yylloc = {\n first_line: this.yylineno + 1,\n first_column: col,\n last_line: this.yylineno + 1,\n last_column: col,\n\n range: [this.offset, this.offset]\n };\n },\n\n /**\n * resets the lexer, sets new input\n * \n * @public\n * @this {RegExpLexer}\n */\n setInput: function lexer_setInput(input, yy) {\n this.yy = yy || this.yy || {};\n\n // also check if we've fully initialized the lexer instance,\n // including expansion work to be done to go from a loaded\n // lexer to a usable lexer:\n if (!this.__decompressed) {\n // step 1: decompress the regex list:\n var rules = this.rules;\n for (var i = 0, len = rules.length; i < len; i++) {\n var rule_re = rules[i];\n\n // compression: is the RE an xref to another RE slot in the rules[] table?\n if (typeof rule_re === 'number') {\n rules[i] = rules[rule_re];\n }\n }\n\n // step 2: unfold the conditions[] set to make these ready for use:\n var conditions = this.conditions;\n for (var k in conditions) {\n var spec = conditions[k];\n\n var rule_ids = spec.rules;\n\n var len = rule_ids.length;\n var rule_regexes = new Array(len + 1); // slot 0 is unused; we use a 1-based index approach here to keep the hottest code in `lexer_next()` fast and simple!\n var rule_new_ids = new Array(len + 1);\n\n for (var i = 0; i < len; i++) {\n var idx = rule_ids[i];\n var rule_re = rules[idx];\n rule_regexes[i + 1] = rule_re;\n rule_new_ids[i + 1] = idx;\n }\n\n spec.rules = rule_new_ids;\n spec.__rule_regexes = rule_regexes;\n spec.__rule_count = len;\n }\n\n this.__decompressed = true;\n }\n\n this._input = input || '';\n this.clear();\n this._signaled_error_token = false;\n this.done = false;\n this.yylineno = 0;\n this.matched = '';\n this.conditionStack = ['INITIAL'];\n this.__currentRuleSet__ = null;\n this.yylloc = {\n first_line: 1,\n first_column: 0,\n last_line: 1,\n last_column: 0,\n\n range: [0, 0]\n };\n this.offset = 0;\n return this;\n },\n\n /**\n * edit the remaining input via user-specified callback.\n * This can be used to forward-adjust the input-to-parse, \n * e.g. inserting macro expansions and alike in the\n * input which has yet to be lexed.\n * The behaviour of this API contrasts the `unput()` et al\n * APIs as those act on the *consumed* input, while this\n * one allows one to manipulate the future, without impacting\n * the current `yyloc` cursor location or any history. \n * \n * Use this API to help implement C-preprocessor-like\n * `#include` statements, etc.\n * \n * The provided callback must be synchronous and is\n * expected to return the edited input (string).\n *\n * The `cpsArg` argument value is passed to the callback\n * as-is.\n *\n * `callback` interface: \n * `function callback(input, cpsArg)`\n * \n * - `input` will carry the remaining-input-to-lex string\n * from the lexer.\n * - `cpsArg` is `cpsArg` passed into this API.\n * \n * The `this` reference for the callback will be set to\n * reference this lexer instance so that userland code\n * in the callback can easily and quickly access any lexer\n * API. \n *\n * When the callback returns a non-string-type falsey value,\n * we assume the callback did not edit the input and we\n * will using the input as-is.\n *\n * When the callback returns a non-string-type value, it\n * is converted to a string for lexing via the `\"\" + retval`\n * operation. (See also why: http://2ality.com/2012/03/converting-to-string.html \n * -- that way any returned object's `toValue()` and `toString()`\n * methods will be invoked in a proper/desirable order.)\n * \n * @public\n * @this {RegExpLexer}\n */\n editRemainingInput: function lexer_editRemainingInput(callback, cpsArg) {\n var rv = callback.call(this, this._input, cpsArg);\n if (typeof rv !== 'string') {\n if (rv) {\n this._input = '' + rv; \n }\n // else: keep `this._input` as is. \n } else {\n this._input = rv; \n }\n return this;\n },\n\n /**\n * consumes and returns one char from the input\n * \n * @public\n * @this {RegExpLexer}\n */\n input: function lexer_input() {\n if (!this._input) {\n //this.done = true; -- don't set `done` as we want the lex()/next() API to be able to produce one custom EOF token match after this anyhow. (lexer can match special <> tokens and perform user action code for a <> match, but only does so *once*)\n return null;\n }\n var ch = this._input[0];\n this.yytext += ch;\n this.yyleng++;\n this.offset++;\n this.match += ch;\n this.matched += ch;\n // Count the linenumber up when we hit the LF (or a stand-alone CR).\n // On CRLF, the linenumber is incremented when you fetch the CR or the CRLF combo\n // and we advance immediately past the LF as well, returning both together as if\n // it was all a single 'character' only.\n var slice_len = 1;\n var lines = false;\n if (ch === '\\n') {\n lines = true;\n } else if (ch === '\\r') {\n lines = true;\n var ch2 = this._input[1];\n if (ch2 === '\\n') {\n slice_len++;\n ch += ch2;\n this.yytext += ch2;\n this.yyleng++;\n this.offset++;\n this.match += ch2;\n this.matched += ch2;\n this.yylloc.range[1]++;\n }\n }\n if (lines) {\n this.yylineno++;\n this.yylloc.last_line++;\n this.yylloc.last_column = 0;\n } else {\n this.yylloc.last_column++;\n }\n this.yylloc.range[1]++;\n\n this._input = this._input.slice(slice_len);\n return ch;\n },\n\n /**\n * unshifts one char (or an entire string) into the input\n * \n * @public\n * @this {RegExpLexer}\n */\n unput: function lexer_unput(ch) {\n var len = ch.length;\n var lines = ch.split(/(?:\\r\\n?|\\n)/g);\n\n this._input = ch + this._input;\n this.yytext = this.yytext.substr(0, this.yytext.length - len);\n this.yyleng = this.yytext.length;\n this.offset -= len;\n this.match = this.match.substr(0, this.match.length - len);\n this.matched = this.matched.substr(0, this.matched.length - len);\n\n if (lines.length > 1) {\n this.yylineno -= lines.length - 1;\n\n this.yylloc.last_line = this.yylineno + 1;\n\n // Get last entirely matched line into the `pre_lines[]` array's\n // last index slot; we don't mind when other previously \n // matched lines end up in the array too. \n var pre = this.match;\n var pre_lines = pre.split(/(?:\\r\\n?|\\n)/g);\n if (pre_lines.length === 1) {\n pre = this.matched;\n pre_lines = pre.split(/(?:\\r\\n?|\\n)/g);\n }\n this.yylloc.last_column = pre_lines[pre_lines.length - 1].length;\n } else {\n this.yylloc.last_column -= len;\n }\n\n this.yylloc.range[1] = this.yylloc.range[0] + this.yyleng;\n\n this.done = false;\n return this;\n },\n\n /**\n * cache matched text and append it on next action\n * \n * @public\n * @this {RegExpLexer}\n */\n more: function lexer_more() {\n this._more = true;\n return this;\n },\n\n /**\n * signal the lexer that this rule fails to match the input, so the\n * next matching rule (regex) should be tested instead.\n * \n * @public\n * @this {RegExpLexer}\n */\n reject: function lexer_reject() {\n if (this.options.backtrack_lexer) {\n this._backtrack = true;\n } else {\n // when the `parseError()` call returns, we MUST ensure that the error is registered.\n // We accomplish this by signaling an 'error' token to be produced for the current\n // `.lex()` run.\n var lineno_msg = '';\n if (this.yylloc) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).', false);\n this._signaled_error_token = (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n }\n return this;\n },\n\n /**\n * retain first n characters of the match\n * \n * @public\n * @this {RegExpLexer}\n */\n less: function lexer_less(n) {\n return this.unput(this.match.slice(n));\n },\n\n /**\n * return (part of the) already matched input, i.e. for error\n * messages.\n * \n * Limit the returned string length to `maxSize` (default: 20).\n * \n * Limit the returned string to the `maxLines` number of lines of\n * input (default: 1).\n * \n * Negative limit values equal *unlimited*.\n * \n * @public\n * @this {RegExpLexer}\n */\n pastInput: function lexer_pastInput(maxSize, maxLines) {\n var past = this.matched.substring(0, this.matched.length - this.match.length);\n if (maxSize < 0)\n maxSize = past.length;\n else if (!maxSize)\n maxSize = 20;\n if (maxLines < 0)\n maxLines = past.length; // can't ever have more input lines than this!\n else if (!maxLines)\n maxLines = 1;\n // `substr` anticipation: treat \\r\\n as a single character and take a little\n // more than necessary so that we can still properly check against maxSize\n // after we've transformed and limited the newLines in here:\n past = past.substr(-maxSize * 2 - 2);\n // now that we have a significantly reduced string to process, transform the newlines\n // and chop them, then limit them:\n var a = past.replace(/\\r\\n|\\r/g, '\\n').split('\\n');\n a = a.slice(-maxLines);\n past = a.join('\\n');\n // When, after limiting to maxLines, we still have too much to return,\n // do add an ellipsis prefix...\n if (past.length > maxSize) {\n past = '...' + past.substr(-maxSize);\n }\n return past;\n },\n\n /**\n * return (part of the) upcoming input, i.e. for error messages.\n * \n * Limit the returned string length to `maxSize` (default: 20).\n * \n * Limit the returned string to the `maxLines` number of lines of input (default: 1).\n * \n * Negative limit values equal *unlimited*.\n *\n * > ### NOTE ###\n * >\n * > *\"upcoming input\"* is defined as the whole of the both\n * > the *currently lexed* input, together with any remaining input\n * > following that. *\"currently lexed\"* input is the input \n * > already recognized by the lexer but not yet returned with\n * > the lexer token. This happens when you are invoking this API\n * > from inside any lexer rule action code block. \n * >\n * \n * @public\n * @this {RegExpLexer}\n */\n upcomingInput: function lexer_upcomingInput(maxSize, maxLines) {\n var next = this.match;\n if (maxSize < 0)\n maxSize = next.length + this._input.length;\n else if (!maxSize)\n maxSize = 20;\n if (maxLines < 0)\n maxLines = maxSize; // can't ever have more input lines than this!\n else if (!maxLines)\n maxLines = 1;\n // `substring` anticipation: treat \\r\\n as a single character and take a little\n // more than necessary so that we can still properly check against maxSize\n // after we've transformed and limited the newLines in here:\n if (next.length < maxSize * 2 + 2) {\n next += this._input.substring(0, maxSize * 2 + 2); // substring is faster on Chrome/V8\n }\n // now that we have a significantly reduced string to process, transform the newlines\n // and chop them, then limit them:\n var a = next.replace(/\\r\\n|\\r/g, '\\n').split('\\n');\n a = a.slice(0, maxLines);\n next = a.join('\\n');\n // When, after limiting to maxLines, we still have too much to return,\n // do add an ellipsis postfix...\n if (next.length > maxSize) {\n next = next.substring(0, maxSize) + '...';\n }\n return next;\n },\n\n /**\n * return a string which displays the character position where the\n * lexing error occurred, i.e. for error messages\n * \n * @public\n * @this {RegExpLexer}\n */\n showPosition: function lexer_showPosition(maxPrefix, maxPostfix) {\n var pre = this.pastInput(maxPrefix).replace(/\\s/g, ' ');\n var c = new Array(pre.length + 1).join('-');\n return pre + this.upcomingInput(maxPostfix).replace(/\\s/g, ' ') + '\\n' + c + '^';\n },\n\n /**\n * return an YYLLOC info object derived off the given context (actual, preceding, following, current).\n * Use this method when the given `actual` location is not guaranteed to exist (i.e. when\n * it MAY be NULL) and you MUST have a valid location info object anyway:\n * then we take the given context of the `preceding` and `following` locations, IFF those are available,\n * and reconstruct the `actual` location info from those.\n * If this fails, the heuristic is to take the `current` location, IFF available.\n * If this fails as well, we assume the sought location is at/around the current lexer position\n * and then produce that one as a response. DO NOTE that these heuristic/derived location info\n * values MAY be inaccurate!\n *\n * NOTE: `deriveLocationInfo()` ALWAYS produces a location info object *copy* of `actual`, not just\n * a *reference* hence all input location objects can be assumed to be 'constant' (function has no side-effects).\n * \n * @public\n * @this {RegExpLexer}\n */\n deriveLocationInfo: function lexer_deriveYYLLOC(actual, preceding, following, current) {\n var loc = {\n first_line: 1,\n first_column: 0,\n last_line: 1,\n last_column: 0,\n\n range: [0, 0]\n };\n if (actual) {\n loc.first_line = actual.first_line | 0;\n loc.last_line = actual.last_line | 0;\n loc.first_column = actual.first_column | 0;\n loc.last_column = actual.last_column | 0;\n\n if (actual.range) {\n loc.range[0] = actual.range[0] | 0; \n loc.range[1] = actual.range[1] | 0;\n } \n }\n if (loc.first_line <= 0 || loc.last_line < loc.first_line) {\n // plan B: heuristic using preceding and following:\n if (loc.first_line <= 0 && preceding) {\n loc.first_line = preceding.last_line | 0;\n loc.first_column = preceding.last_column | 0;\n\n if (preceding.range) {\n loc.range[0] = actual.range[1] | 0; \n } \n }\n\n if ((loc.last_line <= 0 || loc.last_line < loc.first_line) && following) {\n loc.last_line = following.first_line | 0;\n loc.last_column = following.first_column | 0;\n\n if (following.range) {\n loc.range[1] = actual.range[0] | 0; \n } \n }\n\n // plan C?: see if the 'current' location is useful/sane too:\n if (loc.first_line <= 0 && current && (loc.last_line <= 0 || current.last_line <= loc.last_line)) {\n loc.first_line = current.first_line | 0;\n loc.first_column = current.first_column | 0;\n\n if (current.range) {\n loc.range[0] = current.range[0] | 0; \n } \n }\n\n if (loc.last_line <= 0 && current && (loc.first_line <= 0 || current.first_line >= loc.first_line)) {\n loc.last_line = current.last_line | 0;\n loc.last_column = current.last_column | 0;\n\n if (current.range) {\n loc.range[1] = current.range[1] | 0; \n } \n }\n }\n // sanitize: fix last_line BEFORE we fix first_line as we use the 'raw' value of the latter\n // or plan D heuristics to produce a 'sensible' last_line value:\n if (loc.last_line <= 0) {\n if (loc.first_line <= 0) {\n loc.first_line = this.yylloc.first_line;\n loc.last_line = this.yylloc.last_line;\n loc.first_column = this.yylloc.first_column;\n loc.last_column = this.yylloc.last_column;\n\n loc.range[0] = this.yylloc.range[0];\n loc.range[1] = this.yylloc.range[1];\n } else {\n loc.last_line = this.yylloc.last_line;\n loc.last_column = this.yylloc.last_column;\n\n loc.range[1] = this.yylloc.range[1];\n }\n }\n if (loc.first_line <= 0) {\n loc.first_line = loc.last_line;\n loc.first_column = 0; // loc.last_column;\n\n loc.range[1] = loc.range[0];\n }\n if (loc.first_column < 0) {\n loc.first_column = 0;\n }\n if (loc.last_column < 0) {\n loc.last_column = (loc.first_column > 0 ? loc.first_column : 80);\n }\n return loc;\n },\n\n /**\n * return a string which displays the lines & columns of input which are referenced \n * by the given location info range, plus a few lines of context.\n * \n * This function pretty-prints the indicated section of the input, with line numbers \n * and everything!\n * \n * This function is very useful to provide highly readable error reports, while\n * the location range may be specified in various flexible ways:\n * \n * - `loc` is the location info object which references the area which should be\n * displayed and 'marked up': these lines & columns of text are marked up by `^`\n * characters below each character in the entire input range.\n * \n * - `context_loc` is the *optional* location info object which instructs this\n * pretty-printer how much *leading* context should be displayed alongside\n * the area referenced by `loc`. This can help provide context for the displayed\n * error, etc.\n * \n * When this location info is not provided, a default context of 3 lines is\n * used.\n * \n * - `context_loc2` is another *optional* location info object, which serves\n * a similar purpose to `context_loc`: it specifies the amount of *trailing*\n * context lines to display in the pretty-print output.\n * \n * When this location info is not provided, a default context of 1 line only is\n * used.\n * \n * Special Notes:\n * \n * - when the `loc`-indicated range is very large (about 5 lines or more), then\n * only the first and last few lines of this block are printed while a\n * `...continued...` message will be printed between them.\n * \n * This serves the purpose of not printing a huge amount of text when the `loc`\n * range happens to be huge: this way a manageable & readable output results\n * for arbitrary large ranges.\n * \n * - this function can display lines of input which whave not yet been lexed.\n * `prettyPrintRange()` can access the entire input!\n * \n * @public\n * @this {RegExpLexer}\n */\n prettyPrintRange: function lexer_prettyPrintRange(loc, context_loc, context_loc2) {\n loc = this.deriveLocationInfo(loc, context_loc, context_loc2); \n const CONTEXT = 3;\n const CONTEXT_TAIL = 1;\n const MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT = 2;\n var input = this.matched + this._input;\n var lines = input.split('\\n');\n var l0 = Math.max(1, (context_loc ? context_loc.first_line : loc.first_line - CONTEXT));\n var l1 = Math.max(1, (context_loc2 ? context_loc2.last_line : loc.last_line + CONTEXT_TAIL));\n var lineno_display_width = (1 + Math.log10(l1 | 1) | 0);\n var ws_prefix = new Array(lineno_display_width).join(' ');\n var nonempty_line_indexes = [];\n var rv = lines.slice(l0 - 1, l1 + 1).map(function injectLineNumber(line, index) {\n var lno = index + l0;\n var lno_pfx = (ws_prefix + lno).substr(-lineno_display_width);\n var rv = lno_pfx + ': ' + line;\n var errpfx = (new Array(lineno_display_width + 1)).join('^');\n var offset = 2 + 1;\n var len = 0;\n\n if (lno === loc.first_line) {\n offset += loc.first_column;\n\n len = Math.max(\n 2,\n ((lno === loc.last_line ? loc.last_column : line.length)) - loc.first_column + 1\n );\n } else if (lno === loc.last_line) {\n len = Math.max(2, loc.last_column + 1);\n } else if (lno > loc.first_line && lno < loc.last_line) {\n len = Math.max(2, line.length + 1);\n }\n\n if (len) {\n var lead = new Array(offset).join('.');\n var mark = new Array(len).join('^');\n rv += '\\n' + errpfx + lead + mark;\n\n if (line.trim().length > 0) {\n nonempty_line_indexes.push(index);\n }\n }\n\n rv = rv.replace(/\\t/g, ' ');\n return rv;\n });\n\n // now make sure we don't print an overly large amount of error area: limit it \n // to the top and bottom line count:\n if (nonempty_line_indexes.length > 2 * MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT) {\n var clip_start = nonempty_line_indexes[MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT - 1] + 1;\n var clip_end = nonempty_line_indexes[nonempty_line_indexes.length - MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT] - 1;\n\n var intermediate_line = (new Array(lineno_display_width + 1)).join(' ') + ' (...continued...)';\n intermediate_line += '\\n' + (new Array(lineno_display_width + 1)).join('-') + ' (---------------)';\n rv.splice(clip_start, clip_end - clip_start + 1, intermediate_line);\n }\n return rv.join('\\n');\n },\n\n /**\n * helper function, used to produce a human readable description as a string, given\n * the input `yylloc` location object.\n * \n * Set `display_range_too` to TRUE to include the string character index position(s)\n * in the description if the `yylloc.range` is available.\n * \n * @public\n * @this {RegExpLexer}\n */\n describeYYLLOC: function lexer_describe_yylloc(yylloc, display_range_too) {\n var l1 = yylloc.first_line;\n var l2 = yylloc.last_line;\n var c1 = yylloc.first_column;\n var c2 = yylloc.last_column;\n var dl = l2 - l1;\n var dc = c2 - c1;\n var rv;\n if (dl === 0) {\n rv = 'line ' + l1 + ', ';\n if (dc <= 1) {\n rv += 'column ' + c1;\n } else {\n rv += 'columns ' + c1 + ' .. ' + c2;\n }\n } else {\n rv = 'lines ' + l1 + '(column ' + c1 + ') .. ' + l2 + '(column ' + c2 + ')';\n }\n if (yylloc.range && display_range_too) {\n var r1 = yylloc.range[0];\n var r2 = yylloc.range[1] - 1;\n if (r2 <= r1) {\n rv += ' {String Offset: ' + r1 + '}';\n } else {\n rv += ' {String Offset range: ' + r1 + ' .. ' + r2 + '}';\n }\n }\n return rv;\n },\n\n /**\n * test the lexed token: return FALSE when not a match, otherwise return token.\n * \n * `match` is supposed to be an array coming out of a regex match, i.e. `match[0]`\n * contains the actually matched text string.\n * \n * Also move the input cursor forward and update the match collectors:\n * \n * - `yytext`\n * - `yyleng`\n * - `match`\n * - `matches`\n * - `yylloc`\n * - `offset`\n * \n * @public\n * @this {RegExpLexer}\n */\n test_match: function lexer_test_match(match, indexed_rule) {\n var token,\n lines,\n backup,\n match_str,\n match_str_len;\n\n if (this.options.backtrack_lexer) {\n // save context\n backup = {\n yylineno: this.yylineno,\n yylloc: {\n first_line: this.yylloc.first_line,\n last_line: this.yylloc.last_line,\n first_column: this.yylloc.first_column,\n last_column: this.yylloc.last_column,\n\n range: this.yylloc.range.slice(0)\n },\n yytext: this.yytext,\n match: this.match,\n matches: this.matches,\n matched: this.matched,\n yyleng: this.yyleng,\n offset: this.offset,\n _more: this._more,\n _input: this._input,\n //_signaled_error_token: this._signaled_error_token,\n yy: this.yy,\n conditionStack: this.conditionStack.slice(0),\n done: this.done\n };\n }\n\n match_str = match[0];\n match_str_len = match_str.length;\n // if (match_str.indexOf('\\n') !== -1 || match_str.indexOf('\\r') !== -1) {\n lines = match_str.split(/(?:\\r\\n?|\\n)/g);\n if (lines.length > 1) {\n this.yylineno += lines.length - 1;\n\n this.yylloc.last_line = this.yylineno + 1;\n this.yylloc.last_column = lines[lines.length - 1].length;\n } else {\n this.yylloc.last_column += match_str_len;\n }\n // }\n this.yytext += match_str;\n this.match += match_str;\n this.matched += match_str;\n this.matches = match;\n this.yyleng = this.yytext.length;\n this.yylloc.range[1] += match_str_len;\n\n // previous lex rules MAY have invoked the `more()` API rather than producing a token:\n // those rules will already have moved this `offset` forward matching their match lengths,\n // hence we must only add our own match length now:\n this.offset += match_str_len;\n this._more = false;\n this._backtrack = false;\n this._input = this._input.slice(match_str_len);\n\n // calling this method:\n //\n // function lexer__performAction(yy, yyrulenumber, YY_START) {...}\n token = this.performAction.call(this, this.yy, indexed_rule, this.conditionStack[this.conditionStack.length - 1] /* = YY_START */);\n // otherwise, when the action codes are all simple return token statements:\n //token = this.simpleCaseActionClusters[indexed_rule];\n\n if (this.done && this._input) {\n this.done = false;\n }\n if (token) {\n return token;\n } else if (this._backtrack) {\n // recover context\n for (var k in backup) {\n this[k] = backup[k];\n }\n this.__currentRuleSet__ = null;\n return false; // rule action called reject() implying the next rule should be tested instead.\n } else if (this._signaled_error_token) {\n // produce one 'error' token as `.parseError()` in `reject()`\n // did not guarantee a failure signal by throwing an exception!\n token = this._signaled_error_token;\n this._signaled_error_token = false;\n return token;\n }\n return false;\n },\n\n /**\n * return next match in input\n * \n * @public\n * @this {RegExpLexer}\n */\n next: function lexer_next() {\n if (this.done) {\n this.clear();\n return this.EOF;\n }\n if (!this._input) {\n this.done = true;\n }\n\n var token,\n match,\n tempMatch,\n index;\n if (!this._more) {\n this.clear();\n }\n var spec = this.__currentRuleSet__;\n if (!spec) {\n // Update the ruleset cache as we apparently encountered a state change or just started lexing.\n // The cache is set up for fast lookup -- we assume a lexer will switch states much less often than it will\n // invoke the `lex()` token-producing API and related APIs, hence caching the set for direct access helps\n // speed up those activities a tiny bit.\n spec = this.__currentRuleSet__ = this._currentRules();\n // Check whether a *sane* condition has been pushed before: this makes the lexer robust against\n // user-programmer bugs such as https://github.com/zaach/jison-lex/issues/19\n if (!spec || !spec.rules) {\n var lineno_msg = '';\n if (this.options.trackPosition) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Internal lexer engine error' + lineno_msg + ': The lex grammar programmer pushed a non-existing condition name \"' + this.topState() + '\"; this is a fatal error and should be reported to the application programmer team!', false);\n // produce one 'error' token until this situation has been resolved, most probably by parse termination!\n return (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n }\n }\n\n var rule_ids = spec.rules;\n var regexes = spec.__rule_regexes;\n var len = spec.__rule_count;\n\n // Note: the arrays are 1-based, while `len` itself is a valid index,\n // hence the non-standard less-or-equal check in the next loop condition!\n for (var i = 1; i <= len; i++) {\n tempMatch = this._input.match(regexes[i]);\n if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {\n match = tempMatch;\n index = i;\n if (this.options.backtrack_lexer) {\n token = this.test_match(tempMatch, rule_ids[i]);\n if (token !== false) {\n return token;\n } else if (this._backtrack) {\n match = undefined;\n continue; // rule action called reject() implying a rule MISmatch.\n } else {\n // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)\n return false;\n }\n } else if (!this.options.flex) {\n break;\n }\n }\n }\n if (match) {\n token = this.test_match(match, rule_ids[index]);\n if (token !== false) {\n return token;\n }\n // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)\n return false;\n }\n if (!this._input) {\n this.done = true;\n this.clear();\n return this.EOF;\n } else {\n var lineno_msg = '';\n if (this.options.trackPosition) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': Unrecognized text.', this.options.lexerErrorsAreRecoverable);\n\n var pendingInput = this._input;\n var activeCondition = this.topState();\n var conditionStackDepth = this.conditionStack.length;\n\n token = (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n if (token === this.ERROR) {\n // we can try to recover from a lexer error that `parseError()` did not 'recover' for us\n // by moving forward at least one character at a time IFF the (user-specified?) `parseError()`\n // has not consumed/modified any pending input or changed state in the error handler:\n if (!this.matches && \n // and make sure the input has been modified/consumed ...\n pendingInput === this._input &&\n // ...or the lexer state has been modified significantly enough\n // to merit a non-consuming error handling action right now.\n activeCondition === this.topState() && \n conditionStackDepth === this.conditionStack.length\n ) {\n this.input();\n }\n }\n return token;\n }\n },\n\n /**\n * return next match that has a token\n * \n * @public\n * @this {RegExpLexer}\n */\n lex: function lexer_lex() {\n var r;\n // allow the PRE/POST handlers set/modify the return token for maximum flexibility of the generated lexer:\n if (typeof this.pre_lex === 'function') {\n r = this.pre_lex.call(this, 0);\n }\n if (typeof this.options.pre_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.options.pre_lex.call(this, r) || r;\n }\n if (this.yy && typeof this.yy.pre_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.yy.pre_lex.call(this, r) || r;\n }\n\n while (!r) {\n r = this.next();\n }\n\n if (this.yy && typeof this.yy.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.yy.post_lex.call(this, r) || r;\n }\n if (typeof this.options.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.options.post_lex.call(this, r) || r;\n }\n if (typeof this.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.post_lex.call(this, r) || r;\n }\n return r;\n },\n\n /**\n * return next match that has a token. Identical to the `lex()` API but does not invoke any of the \n * `pre_lex()` nor any of the `post_lex()` callbacks.\n * \n * @public\n * @this {RegExpLexer}\n */\n fastLex: function lexer_fastLex() {\n var r;\n\n while (!r) {\n r = this.next();\n }\n\n return r;\n },\n\n /**\n * return info about the lexer state that can help a parser or other lexer API user to use the\n * most efficient means available. This API is provided to aid run-time performance for larger\n * systems which employ this lexer.\n * \n * @public\n * @this {RegExpLexer}\n */\n canIUse: function lexer_canIUse() {\n var rv = {\n fastLex: !(\n typeof this.pre_lex === 'function' ||\n typeof this.options.pre_lex === 'function' ||\n (this.yy && typeof this.yy.pre_lex === 'function') ||\n (this.yy && typeof this.yy.post_lex === 'function') ||\n typeof this.options.post_lex === 'function' ||\n typeof this.post_lex === 'function'\n ) && typeof this.fastLex === 'function',\n };\n return rv;\n },\n\n\n /**\n * backwards compatible alias for `pushState()`;\n * the latter is symmetrical with `popState()` and we advise to use\n * those APIs in any modern lexer code, rather than `begin()`.\n * \n * @public\n * @this {RegExpLexer}\n */\n begin: function lexer_begin(condition) {\n return this.pushState(condition);\n },\n\n /**\n * activates a new lexer condition state (pushes the new lexer\n * condition state onto the condition stack)\n * \n * @public\n * @this {RegExpLexer}\n */\n pushState: function lexer_pushState(condition) {\n this.conditionStack.push(condition);\n this.__currentRuleSet__ = null;\n return this;\n },\n\n /**\n * pop the previously active lexer condition state off the condition\n * stack\n * \n * @public\n * @this {RegExpLexer}\n */\n popState: function lexer_popState() {\n var n = this.conditionStack.length - 1;\n if (n > 0) {\n this.__currentRuleSet__ = null; \n return this.conditionStack.pop();\n } else {\n return this.conditionStack[0];\n }\n },\n\n /**\n * return the currently active lexer condition state; when an index\n * argument is provided it produces the N-th previous condition state,\n * if available\n * \n * @public\n * @this {RegExpLexer}\n */\n topState: function lexer_topState(n) {\n n = this.conditionStack.length - 1 - Math.abs(n || 0);\n if (n >= 0) {\n return this.conditionStack[n];\n } else {\n return 'INITIAL';\n }\n },\n\n /**\n * (internal) determine the lexer rule set which is active for the\n * currently active lexer condition state\n * \n * @public\n * @this {RegExpLexer}\n */\n _currentRules: function lexer__currentRules() {\n if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {\n return this.conditions[this.conditionStack[this.conditionStack.length - 1]];\n } else {\n return this.conditions['INITIAL'];\n }\n },\n\n /**\n * return the number of states currently on the stack\n * \n * @public\n * @this {RegExpLexer}\n */\n stateStackSize: function lexer_stateStackSize() {\n return this.conditionStack.length;\n },\n options: {\n trackPosition: true\n},\n JisonLexerError: JisonLexerError,\n performAction: function lexer__performAction(yy, yyrulenumber, YY_START) {\n var yy_ = this;\n\n \nvar YYSTATE = YY_START;\nswitch(yyrulenumber) {\ncase 0 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\s+ */ \n \nbreak;\ncase 2 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\w+ */ \n \n if (yy_.yytext === 'a') {\n return 'TOK_A'; \n } else {\n return 'WORD'; \n }\n \nbreak;\ndefault:\n return this.simpleCaseActionClusters[yyrulenumber];\n}\n },\n simpleCaseActionClusters: {\n\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\d+ */ \n 1 : 'NUMBER',\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\+ */ \n 3 : '+',\n /*! Conditions:: INITIAL */ \n /*! Rule:: $ */ \n 4 : 'EOF'\n},\n rules: [\n /* 0: */ /^(?:\\s+)/,\n/* 1: */ /^(?:\\d+)/,\n/* 2: */ /^(?:\\w+)/,\n/* 3: */ /^(?:\\+)/,\n/* 4: */ /^(?:$)/\n ],\n conditions: {\n \"INITIAL\": {\n rules: [\n 0,\n 1,\n 2,\n 3,\n 4\n ],\n inclusive: true\n }\n}\n};\n", + options: { + lexerActionsUseYYLENG: "???", + lexerActionsUseYYLINENO: "???", + lexerActionsUseYYTEXT: "???", + lexerActionsUseYYLOC: "???", + lexerActionsUseParseError: "???", + lexerActionsUseYYERROR: "???", + lexerActionsUseLocationTracking: "???", + lexerActionsUseMore: "???", + lexerActionsUseUnput: "???", + lexerActionsUseReject: "???", + lexerActionsUseLess: "???", + lexerActionsUseDisplayAPIs: "???", + lexerActionsUseDescribeYYLOC: "???", + lex_rule_dictionary: { + rules: [ + [ + "\\s+", + "" + ], + [ + "\\d+", + "return \"NUMBER\"" + ], + [ + "\\w+", + "\n if (yytext === 'a') {\n return 'TOK_A'; \n } else {\n return 'WORD'; \n }\n " + ], + [ + "\\+", + "return \"+\"" + ], + [ + "$", + "return \"EOF\"" + ] + ] + }, + options: { + moduleType: "commonjs", + debug: false, + enableDebugLogs: false, + json: true, + dumpSourceCodeOnFailure: true, + throwErrorOnCompileFailure: true, + defaultModuleName: "lexer", + xregexp: false, + lexerErrorsAreRecoverable: false, + flex: false, + backtrack_lexer: false, + ranges: false, + trackPosition: true, + caseInsensitive: false, + exportSourceCode: false, + exportAST: false, + prettyCfg: true, + noMain: true + }, + moduleType: "commonjs", + conditions: { + INITIAL: { + rules: [ + 0, + 1, + 2, + 3, + 4 + ], + inclusive: true + } + }, + performAction: "function lexer__performAction(yy, yyrulenumber, YY_START) {\n var yy_ = this;\n\n \nvar YYSTATE = YY_START;\nswitch(yyrulenumber) {\ncase 0 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\s+ */ \n \nbreak;\ncase 2 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\w+ */ \n \n if (yy_.yytext === 'a') {\n return 'TOK_A'; \n } else {\n return 'WORD'; \n }\n \nbreak;\ndefault:\n return this.simpleCaseActionClusters[yyrulenumber];\n}\n }", + caseHelperInclude: "{\n\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\d+ */ \n 1 : 'NUMBER',\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\+ */ \n 3 : '+',\n /*! Conditions:: INITIAL */ \n /*! Rule:: $ */ \n 4 : 'EOF'\n}", + rules: [ + { + xregexp: { + captureNames: null, + source: "^(?:\\s+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\d+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\w+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:$)", + flags: "", + isNative: true + } + } + ], + macros: {}, + regular_rule_count: 2, + simple_rule_count: 3, + conditionStack: [ + "INITIAL" + ], + actionInclude: "", + moduleInclude: "", + __in_rules_failure_analysis_mode__: false, + exportSourceCode: { + enabled: false + }, + is_custom_lexer: false + } + } +] \ No newline at end of file diff --git a/packages/jison-lex/tests/specs/003-issue-23-good.js b/packages/jison-lex/tests/specs/003-issue-23-good.js new file mode 100644 index 000000000..d1690d518 --- /dev/null +++ b/packages/jison-lex/tests/specs/003-issue-23-good.js @@ -0,0 +1,27 @@ +// title: Parse error when using arrow function in rules +// test_input: A a B C 1 + 2 + 3 +// ... +// +// This is the SUCCESSFUL lexer spec +// + +let grammar = { + rules: [ + ['\\s+', ''], + ['\\d+', function () { return 'NUMBER'}], + ['\\w+', function () { + if (yytext === 'a') { + return 'TOK_A'; + } else { + return 'WORD'; + } + } + ], + ['\\+', function () { return '+' }], + ['$', function () { return 'EOF' }], + ] +}; + +module.exports = grammar; +// export default grammar; + diff --git a/packages/jison-lex/tests/specs/003-issue-23-good.js-ref.json5 b/packages/jison-lex/tests/specs/003-issue-23-good.js-ref.json5 new file mode 100644 index 000000000..1b349b076 --- /dev/null +++ b/packages/jison-lex/tests/specs/003-issue-23-good.js-ref.json5 @@ -0,0 +1,303 @@ +[ + 13, + "WORD", + "A", + { + first_line: 1, + first_column: 0, + last_line: 1, + last_column: 1, + range: [ + 0, + 1 + ] + }, + "TOK_A", + "a", + { + first_line: 1, + first_column: 2, + last_line: 1, + last_column: 3, + range: [ + 2, + 3 + ] + }, + "WORD", + "B", + { + first_line: 1, + first_column: 4, + last_line: 1, + last_column: 5, + range: [ + 4, + 5 + ] + }, + "WORD", + "C", + { + first_line: 1, + first_column: 6, + last_line: 1, + last_column: 7, + range: [ + 6, + 7 + ] + }, + "NUMBER", + "1", + { + first_line: 1, + first_column: 8, + last_line: 1, + last_column: 9, + range: [ + 8, + 9 + ] + }, + "+", + "+", + { + first_line: 1, + first_column: 10, + last_line: 1, + last_column: 11, + range: [ + 10, + 11 + ] + }, + "NUMBER", + "2", + { + first_line: 1, + first_column: 12, + last_line: 1, + last_column: 13, + range: [ + 12, + 13 + ] + }, + "+", + "+", + { + first_line: 1, + first_column: 14, + last_line: 1, + last_column: 15, + range: [ + 14, + 15 + ] + }, + "NUMBER", + "3", + { + first_line: 1, + first_column: 16, + last_line: 1, + last_column: 17, + range: [ + 16, + 17 + ] + }, + "EOF", + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + { + sourceCode: "\nvar lexer = {\n/*JISON-LEX-ANALYTICS-REPORT*/EOF: 1,\n ERROR: 2,\n\n // JisonLexerError: JisonLexerError, /// <-- injected by the code generator\n\n // options: {}, /// <-- injected by the code generator\n\n // yy: ..., /// <-- injected by setInput()\n\n __currentRuleSet__: null, /// INTERNAL USE ONLY: internal rule set cache for the current lexer state\n\n __error_infos: [], /// INTERNAL USE ONLY: the set of lexErrorInfo objects created since the last cleanup\n\n __decompressed: false, /// INTERNAL USE ONLY: mark whether the lexer instance has been 'unfolded' completely and is now ready for use\n\n done: false, /// INTERNAL USE ONLY\n _backtrack: false, /// INTERNAL USE ONLY\n _input: '', /// INTERNAL USE ONLY\n _more: false, /// INTERNAL USE ONLY\n _signaled_error_token: false, /// INTERNAL USE ONLY\n\n conditionStack: [], /// INTERNAL USE ONLY; managed via `pushState()`, `popState()`, `topState()` and `stateStackSize()`\n\n match: '', /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks input which has been matched so far for the lexer token under construction. `match` is identical to `yytext` except that this one still contains the matched input string after `lexer.performAction()` has been invoked, where userland code MAY have changed/replaced the `yytext` value entirely!\n matched: '', /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks entire input which has been matched so far\n matches: false, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks RE match result for last (successful) match attempt\n yytext: '', /// ADVANCED USE ONLY: tracks input which has been matched so far for the lexer token under construction; this value is transferred to the parser as the 'token value' when the parser consumes the lexer token produced through a call to the `lex()` API.\n offset: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks the 'cursor position' in the input string, i.e. the number of characters matched so far\n yyleng: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: length of matched input for the token under construction (`yytext`)\n yylineno: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: 'line number' at which the token under construction is located\n yylloc: null, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks location info (lines + columns) for the token under construction\n\n /**\n * INTERNAL USE: construct a suitable error info hash object instance for `parseError`.\n * \n * @public\n * @this {RegExpLexer}\n */\n constructLexErrorInfo: function lexer_constructLexErrorInfo(msg, recoverable, show_input_position) {\n msg = '' + msg;\n\n // heuristic to determine if the error message already contains a (partial) source code dump\n // as produced by either `showPosition()` or `prettyPrintRange()`:\n if (show_input_position == undefined) {\n show_input_position = !(msg.indexOf('\\n') > 0 && msg.indexOf('^') > 0);\n }\n if (this.yylloc && show_input_position) {\n if (typeof this.prettyPrintRange === 'function') {\n var pretty_src = this.prettyPrintRange(this.yylloc);\n\n if (!/\\n\\s*$/.test(msg)) {\n msg += '\\n';\n }\n msg += '\\n Erroneous area:\\n' + this.prettyPrintRange(this.yylloc); \n } else if (typeof this.showPosition === 'function') {\n var pos_str = this.showPosition();\n if (pos_str) {\n if (msg.length && msg[msg.length - 1] !== '\\n' && pos_str[0] !== '\\n') {\n msg += '\\n' + pos_str;\n } else {\n msg += pos_str;\n }\n }\n }\n }\n /** @constructor */\n var pei = {\n errStr: msg,\n recoverable: !!recoverable,\n text: this.match, // This one MAY be empty; userland code should use the `upcomingInput` API to obtain more text which follows the 'lexer cursor position'...\n token: null,\n line: this.yylineno,\n loc: this.yylloc,\n yy: this.yy,\n lexer: this,\n\n /**\n * and make sure the error info doesn't stay due to potential\n * ref cycle via userland code manipulations.\n * These would otherwise all be memory leak opportunities!\n * \n * Note that only array and object references are nuked as those\n * constitute the set of elements which can produce a cyclic ref.\n * The rest of the members is kept intact as they are harmless.\n * \n * @public\n * @this {LexErrorInfo}\n */\n destroy: function destructLexErrorInfo() {\n // remove cyclic references added to error info:\n // info.yy = null;\n // info.lexer = null;\n // ...\n var rec = !!this.recoverable;\n for (var key in this) {\n if (this.hasOwnProperty(key) && typeof key === 'object') {\n this[key] = undefined;\n }\n }\n this.recoverable = rec;\n }\n };\n // track this instance so we can `destroy()` it once we deem it superfluous and ready for garbage collection!\n this.__error_infos.push(pei);\n return pei;\n },\n\n /**\n * handler which is invoked when a lexer error occurs.\n * \n * @public\n * @this {RegExpLexer}\n */\n parseError: function lexer_parseError(str, hash, ExceptionClass) {\n if (!ExceptionClass) {\n ExceptionClass = this.JisonLexerError;\n }\n if (this.yy) {\n if (this.yy.parser && typeof this.yy.parser.parseError === 'function') {\n return this.yy.parser.parseError.call(this, str, hash, ExceptionClass) || this.ERROR;\n } else if (typeof this.yy.parseError === 'function') {\n return this.yy.parseError.call(this, str, hash, ExceptionClass) || this.ERROR;\n } \n }\n throw new ExceptionClass(str, hash);\n },\n\n /**\n * method which implements `yyerror(str, ...args)` functionality for use inside lexer actions.\n * \n * @public\n * @this {RegExpLexer}\n */\n yyerror: function yyError(str /*, ...args */) {\n var lineno_msg = '';\n if (this.yylloc) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': ' + str, this.options.lexerErrorsAreRecoverable);\n\n // Add any extra args to the hash under the name `extra_error_attributes`:\n var args = Array.prototype.slice.call(arguments, 1);\n if (args.length) {\n p.extra_error_attributes = args;\n }\n\n return (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n },\n\n /**\n * final cleanup function for when we have completed lexing the input;\n * make it an API so that external code can use this one once userland\n * code has decided it's time to destroy any lingering lexer error\n * hash object instances and the like: this function helps to clean\n * up these constructs, which *may* carry cyclic references which would\n * otherwise prevent the instances from being properly and timely\n * garbage-collected, i.e. this function helps prevent memory leaks!\n * \n * @public\n * @this {RegExpLexer}\n */\n cleanupAfterLex: function lexer_cleanupAfterLex(do_not_nuke_errorinfos) {\n // prevent lingering circular references from causing memory leaks:\n this.setInput('', {});\n\n // nuke the error hash info instances created during this run.\n // Userland code must COPY any data/references\n // in the error hash instance(s) it is more permanently interested in.\n if (!do_not_nuke_errorinfos) {\n for (var i = this.__error_infos.length - 1; i >= 0; i--) {\n var el = this.__error_infos[i];\n if (el && typeof el.destroy === 'function') {\n el.destroy();\n }\n }\n this.__error_infos.length = 0;\n }\n\n return this;\n },\n\n /**\n * clear the lexer token context; intended for internal use only\n * \n * @public\n * @this {RegExpLexer}\n */\n clear: function lexer_clear() {\n this.yytext = '';\n this.yyleng = 0;\n this.match = '';\n // - DO NOT reset `this.matched`\n this.matches = false;\n this._more = false;\n this._backtrack = false;\n\n var col = (this.yylloc ? this.yylloc.last_column : 0);\n this.yylloc = {\n first_line: this.yylineno + 1,\n first_column: col,\n last_line: this.yylineno + 1,\n last_column: col,\n\n range: [this.offset, this.offset]\n };\n },\n\n /**\n * resets the lexer, sets new input\n * \n * @public\n * @this {RegExpLexer}\n */\n setInput: function lexer_setInput(input, yy) {\n this.yy = yy || this.yy || {};\n\n // also check if we've fully initialized the lexer instance,\n // including expansion work to be done to go from a loaded\n // lexer to a usable lexer:\n if (!this.__decompressed) {\n // step 1: decompress the regex list:\n var rules = this.rules;\n for (var i = 0, len = rules.length; i < len; i++) {\n var rule_re = rules[i];\n\n // compression: is the RE an xref to another RE slot in the rules[] table?\n if (typeof rule_re === 'number') {\n rules[i] = rules[rule_re];\n }\n }\n\n // step 2: unfold the conditions[] set to make these ready for use:\n var conditions = this.conditions;\n for (var k in conditions) {\n var spec = conditions[k];\n\n var rule_ids = spec.rules;\n\n var len = rule_ids.length;\n var rule_regexes = new Array(len + 1); // slot 0 is unused; we use a 1-based index approach here to keep the hottest code in `lexer_next()` fast and simple!\n var rule_new_ids = new Array(len + 1);\n\n for (var i = 0; i < len; i++) {\n var idx = rule_ids[i];\n var rule_re = rules[idx];\n rule_regexes[i + 1] = rule_re;\n rule_new_ids[i + 1] = idx;\n }\n\n spec.rules = rule_new_ids;\n spec.__rule_regexes = rule_regexes;\n spec.__rule_count = len;\n }\n\n this.__decompressed = true;\n }\n\n this._input = input || '';\n this.clear();\n this._signaled_error_token = false;\n this.done = false;\n this.yylineno = 0;\n this.matched = '';\n this.conditionStack = ['INITIAL'];\n this.__currentRuleSet__ = null;\n this.yylloc = {\n first_line: 1,\n first_column: 0,\n last_line: 1,\n last_column: 0,\n\n range: [0, 0]\n };\n this.offset = 0;\n return this;\n },\n\n /**\n * edit the remaining input via user-specified callback.\n * This can be used to forward-adjust the input-to-parse, \n * e.g. inserting macro expansions and alike in the\n * input which has yet to be lexed.\n * The behaviour of this API contrasts the `unput()` et al\n * APIs as those act on the *consumed* input, while this\n * one allows one to manipulate the future, without impacting\n * the current `yyloc` cursor location or any history. \n * \n * Use this API to help implement C-preprocessor-like\n * `#include` statements, etc.\n * \n * The provided callback must be synchronous and is\n * expected to return the edited input (string).\n *\n * The `cpsArg` argument value is passed to the callback\n * as-is.\n *\n * `callback` interface: \n * `function callback(input, cpsArg)`\n * \n * - `input` will carry the remaining-input-to-lex string\n * from the lexer.\n * - `cpsArg` is `cpsArg` passed into this API.\n * \n * The `this` reference for the callback will be set to\n * reference this lexer instance so that userland code\n * in the callback can easily and quickly access any lexer\n * API. \n *\n * When the callback returns a non-string-type falsey value,\n * we assume the callback did not edit the input and we\n * will using the input as-is.\n *\n * When the callback returns a non-string-type value, it\n * is converted to a string for lexing via the `\"\" + retval`\n * operation. (See also why: http://2ality.com/2012/03/converting-to-string.html \n * -- that way any returned object's `toValue()` and `toString()`\n * methods will be invoked in a proper/desirable order.)\n * \n * @public\n * @this {RegExpLexer}\n */\n editRemainingInput: function lexer_editRemainingInput(callback, cpsArg) {\n var rv = callback.call(this, this._input, cpsArg);\n if (typeof rv !== 'string') {\n if (rv) {\n this._input = '' + rv; \n }\n // else: keep `this._input` as is. \n } else {\n this._input = rv; \n }\n return this;\n },\n\n /**\n * consumes and returns one char from the input\n * \n * @public\n * @this {RegExpLexer}\n */\n input: function lexer_input() {\n if (!this._input) {\n //this.done = true; -- don't set `done` as we want the lex()/next() API to be able to produce one custom EOF token match after this anyhow. (lexer can match special <> tokens and perform user action code for a <> match, but only does so *once*)\n return null;\n }\n var ch = this._input[0];\n this.yytext += ch;\n this.yyleng++;\n this.offset++;\n this.match += ch;\n this.matched += ch;\n // Count the linenumber up when we hit the LF (or a stand-alone CR).\n // On CRLF, the linenumber is incremented when you fetch the CR or the CRLF combo\n // and we advance immediately past the LF as well, returning both together as if\n // it was all a single 'character' only.\n var slice_len = 1;\n var lines = false;\n if (ch === '\\n') {\n lines = true;\n } else if (ch === '\\r') {\n lines = true;\n var ch2 = this._input[1];\n if (ch2 === '\\n') {\n slice_len++;\n ch += ch2;\n this.yytext += ch2;\n this.yyleng++;\n this.offset++;\n this.match += ch2;\n this.matched += ch2;\n this.yylloc.range[1]++;\n }\n }\n if (lines) {\n this.yylineno++;\n this.yylloc.last_line++;\n this.yylloc.last_column = 0;\n } else {\n this.yylloc.last_column++;\n }\n this.yylloc.range[1]++;\n\n this._input = this._input.slice(slice_len);\n return ch;\n },\n\n /**\n * unshifts one char (or an entire string) into the input\n * \n * @public\n * @this {RegExpLexer}\n */\n unput: function lexer_unput(ch) {\n var len = ch.length;\n var lines = ch.split(/(?:\\r\\n?|\\n)/g);\n\n this._input = ch + this._input;\n this.yytext = this.yytext.substr(0, this.yytext.length - len);\n this.yyleng = this.yytext.length;\n this.offset -= len;\n this.match = this.match.substr(0, this.match.length - len);\n this.matched = this.matched.substr(0, this.matched.length - len);\n\n if (lines.length > 1) {\n this.yylineno -= lines.length - 1;\n\n this.yylloc.last_line = this.yylineno + 1;\n\n // Get last entirely matched line into the `pre_lines[]` array's\n // last index slot; we don't mind when other previously \n // matched lines end up in the array too. \n var pre = this.match;\n var pre_lines = pre.split(/(?:\\r\\n?|\\n)/g);\n if (pre_lines.length === 1) {\n pre = this.matched;\n pre_lines = pre.split(/(?:\\r\\n?|\\n)/g);\n }\n this.yylloc.last_column = pre_lines[pre_lines.length - 1].length;\n } else {\n this.yylloc.last_column -= len;\n }\n\n this.yylloc.range[1] = this.yylloc.range[0] + this.yyleng;\n\n this.done = false;\n return this;\n },\n\n /**\n * cache matched text and append it on next action\n * \n * @public\n * @this {RegExpLexer}\n */\n more: function lexer_more() {\n this._more = true;\n return this;\n },\n\n /**\n * signal the lexer that this rule fails to match the input, so the\n * next matching rule (regex) should be tested instead.\n * \n * @public\n * @this {RegExpLexer}\n */\n reject: function lexer_reject() {\n if (this.options.backtrack_lexer) {\n this._backtrack = true;\n } else {\n // when the `parseError()` call returns, we MUST ensure that the error is registered.\n // We accomplish this by signaling an 'error' token to be produced for the current\n // `.lex()` run.\n var lineno_msg = '';\n if (this.yylloc) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).', false);\n this._signaled_error_token = (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n }\n return this;\n },\n\n /**\n * retain first n characters of the match\n * \n * @public\n * @this {RegExpLexer}\n */\n less: function lexer_less(n) {\n return this.unput(this.match.slice(n));\n },\n\n /**\n * return (part of the) already matched input, i.e. for error\n * messages.\n * \n * Limit the returned string length to `maxSize` (default: 20).\n * \n * Limit the returned string to the `maxLines` number of lines of\n * input (default: 1).\n * \n * Negative limit values equal *unlimited*.\n * \n * @public\n * @this {RegExpLexer}\n */\n pastInput: function lexer_pastInput(maxSize, maxLines) {\n var past = this.matched.substring(0, this.matched.length - this.match.length);\n if (maxSize < 0)\n maxSize = past.length;\n else if (!maxSize)\n maxSize = 20;\n if (maxLines < 0)\n maxLines = past.length; // can't ever have more input lines than this!\n else if (!maxLines)\n maxLines = 1;\n // `substr` anticipation: treat \\r\\n as a single character and take a little\n // more than necessary so that we can still properly check against maxSize\n // after we've transformed and limited the newLines in here:\n past = past.substr(-maxSize * 2 - 2);\n // now that we have a significantly reduced string to process, transform the newlines\n // and chop them, then limit them:\n var a = past.replace(/\\r\\n|\\r/g, '\\n').split('\\n');\n a = a.slice(-maxLines);\n past = a.join('\\n');\n // When, after limiting to maxLines, we still have too much to return,\n // do add an ellipsis prefix...\n if (past.length > maxSize) {\n past = '...' + past.substr(-maxSize);\n }\n return past;\n },\n\n /**\n * return (part of the) upcoming input, i.e. for error messages.\n * \n * Limit the returned string length to `maxSize` (default: 20).\n * \n * Limit the returned string to the `maxLines` number of lines of input (default: 1).\n * \n * Negative limit values equal *unlimited*.\n *\n * > ### NOTE ###\n * >\n * > *\"upcoming input\"* is defined as the whole of the both\n * > the *currently lexed* input, together with any remaining input\n * > following that. *\"currently lexed\"* input is the input \n * > already recognized by the lexer but not yet returned with\n * > the lexer token. This happens when you are invoking this API\n * > from inside any lexer rule action code block. \n * >\n * \n * @public\n * @this {RegExpLexer}\n */\n upcomingInput: function lexer_upcomingInput(maxSize, maxLines) {\n var next = this.match;\n if (maxSize < 0)\n maxSize = next.length + this._input.length;\n else if (!maxSize)\n maxSize = 20;\n if (maxLines < 0)\n maxLines = maxSize; // can't ever have more input lines than this!\n else if (!maxLines)\n maxLines = 1;\n // `substring` anticipation: treat \\r\\n as a single character and take a little\n // more than necessary so that we can still properly check against maxSize\n // after we've transformed and limited the newLines in here:\n if (next.length < maxSize * 2 + 2) {\n next += this._input.substring(0, maxSize * 2 + 2); // substring is faster on Chrome/V8\n }\n // now that we have a significantly reduced string to process, transform the newlines\n // and chop them, then limit them:\n var a = next.replace(/\\r\\n|\\r/g, '\\n').split('\\n');\n a = a.slice(0, maxLines);\n next = a.join('\\n');\n // When, after limiting to maxLines, we still have too much to return,\n // do add an ellipsis postfix...\n if (next.length > maxSize) {\n next = next.substring(0, maxSize) + '...';\n }\n return next;\n },\n\n /**\n * return a string which displays the character position where the\n * lexing error occurred, i.e. for error messages\n * \n * @public\n * @this {RegExpLexer}\n */\n showPosition: function lexer_showPosition(maxPrefix, maxPostfix) {\n var pre = this.pastInput(maxPrefix).replace(/\\s/g, ' ');\n var c = new Array(pre.length + 1).join('-');\n return pre + this.upcomingInput(maxPostfix).replace(/\\s/g, ' ') + '\\n' + c + '^';\n },\n\n /**\n * return an YYLLOC info object derived off the given context (actual, preceding, following, current).\n * Use this method when the given `actual` location is not guaranteed to exist (i.e. when\n * it MAY be NULL) and you MUST have a valid location info object anyway:\n * then we take the given context of the `preceding` and `following` locations, IFF those are available,\n * and reconstruct the `actual` location info from those.\n * If this fails, the heuristic is to take the `current` location, IFF available.\n * If this fails as well, we assume the sought location is at/around the current lexer position\n * and then produce that one as a response. DO NOTE that these heuristic/derived location info\n * values MAY be inaccurate!\n *\n * NOTE: `deriveLocationInfo()` ALWAYS produces a location info object *copy* of `actual`, not just\n * a *reference* hence all input location objects can be assumed to be 'constant' (function has no side-effects).\n * \n * @public\n * @this {RegExpLexer}\n */\n deriveLocationInfo: function lexer_deriveYYLLOC(actual, preceding, following, current) {\n var loc = {\n first_line: 1,\n first_column: 0,\n last_line: 1,\n last_column: 0,\n\n range: [0, 0]\n };\n if (actual) {\n loc.first_line = actual.first_line | 0;\n loc.last_line = actual.last_line | 0;\n loc.first_column = actual.first_column | 0;\n loc.last_column = actual.last_column | 0;\n\n if (actual.range) {\n loc.range[0] = actual.range[0] | 0; \n loc.range[1] = actual.range[1] | 0;\n } \n }\n if (loc.first_line <= 0 || loc.last_line < loc.first_line) {\n // plan B: heuristic using preceding and following:\n if (loc.first_line <= 0 && preceding) {\n loc.first_line = preceding.last_line | 0;\n loc.first_column = preceding.last_column | 0;\n\n if (preceding.range) {\n loc.range[0] = actual.range[1] | 0; \n } \n }\n\n if ((loc.last_line <= 0 || loc.last_line < loc.first_line) && following) {\n loc.last_line = following.first_line | 0;\n loc.last_column = following.first_column | 0;\n\n if (following.range) {\n loc.range[1] = actual.range[0] | 0; \n } \n }\n\n // plan C?: see if the 'current' location is useful/sane too:\n if (loc.first_line <= 0 && current && (loc.last_line <= 0 || current.last_line <= loc.last_line)) {\n loc.first_line = current.first_line | 0;\n loc.first_column = current.first_column | 0;\n\n if (current.range) {\n loc.range[0] = current.range[0] | 0; \n } \n }\n\n if (loc.last_line <= 0 && current && (loc.first_line <= 0 || current.first_line >= loc.first_line)) {\n loc.last_line = current.last_line | 0;\n loc.last_column = current.last_column | 0;\n\n if (current.range) {\n loc.range[1] = current.range[1] | 0; \n } \n }\n }\n // sanitize: fix last_line BEFORE we fix first_line as we use the 'raw' value of the latter\n // or plan D heuristics to produce a 'sensible' last_line value:\n if (loc.last_line <= 0) {\n if (loc.first_line <= 0) {\n loc.first_line = this.yylloc.first_line;\n loc.last_line = this.yylloc.last_line;\n loc.first_column = this.yylloc.first_column;\n loc.last_column = this.yylloc.last_column;\n\n loc.range[0] = this.yylloc.range[0];\n loc.range[1] = this.yylloc.range[1];\n } else {\n loc.last_line = this.yylloc.last_line;\n loc.last_column = this.yylloc.last_column;\n\n loc.range[1] = this.yylloc.range[1];\n }\n }\n if (loc.first_line <= 0) {\n loc.first_line = loc.last_line;\n loc.first_column = 0; // loc.last_column;\n\n loc.range[1] = loc.range[0];\n }\n if (loc.first_column < 0) {\n loc.first_column = 0;\n }\n if (loc.last_column < 0) {\n loc.last_column = (loc.first_column > 0 ? loc.first_column : 80);\n }\n return loc;\n },\n\n /**\n * return a string which displays the lines & columns of input which are referenced \n * by the given location info range, plus a few lines of context.\n * \n * This function pretty-prints the indicated section of the input, with line numbers \n * and everything!\n * \n * This function is very useful to provide highly readable error reports, while\n * the location range may be specified in various flexible ways:\n * \n * - `loc` is the location info object which references the area which should be\n * displayed and 'marked up': these lines & columns of text are marked up by `^`\n * characters below each character in the entire input range.\n * \n * - `context_loc` is the *optional* location info object which instructs this\n * pretty-printer how much *leading* context should be displayed alongside\n * the area referenced by `loc`. This can help provide context for the displayed\n * error, etc.\n * \n * When this location info is not provided, a default context of 3 lines is\n * used.\n * \n * - `context_loc2` is another *optional* location info object, which serves\n * a similar purpose to `context_loc`: it specifies the amount of *trailing*\n * context lines to display in the pretty-print output.\n * \n * When this location info is not provided, a default context of 1 line only is\n * used.\n * \n * Special Notes:\n * \n * - when the `loc`-indicated range is very large (about 5 lines or more), then\n * only the first and last few lines of this block are printed while a\n * `...continued...` message will be printed between them.\n * \n * This serves the purpose of not printing a huge amount of text when the `loc`\n * range happens to be huge: this way a manageable & readable output results\n * for arbitrary large ranges.\n * \n * - this function can display lines of input which whave not yet been lexed.\n * `prettyPrintRange()` can access the entire input!\n * \n * @public\n * @this {RegExpLexer}\n */\n prettyPrintRange: function lexer_prettyPrintRange(loc, context_loc, context_loc2) {\n loc = this.deriveLocationInfo(loc, context_loc, context_loc2); \n const CONTEXT = 3;\n const CONTEXT_TAIL = 1;\n const MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT = 2;\n var input = this.matched + this._input;\n var lines = input.split('\\n');\n var l0 = Math.max(1, (context_loc ? context_loc.first_line : loc.first_line - CONTEXT));\n var l1 = Math.max(1, (context_loc2 ? context_loc2.last_line : loc.last_line + CONTEXT_TAIL));\n var lineno_display_width = (1 + Math.log10(l1 | 1) | 0);\n var ws_prefix = new Array(lineno_display_width).join(' ');\n var nonempty_line_indexes = [];\n var rv = lines.slice(l0 - 1, l1 + 1).map(function injectLineNumber(line, index) {\n var lno = index + l0;\n var lno_pfx = (ws_prefix + lno).substr(-lineno_display_width);\n var rv = lno_pfx + ': ' + line;\n var errpfx = (new Array(lineno_display_width + 1)).join('^');\n var offset = 2 + 1;\n var len = 0;\n\n if (lno === loc.first_line) {\n offset += loc.first_column;\n\n len = Math.max(\n 2,\n ((lno === loc.last_line ? loc.last_column : line.length)) - loc.first_column + 1\n );\n } else if (lno === loc.last_line) {\n len = Math.max(2, loc.last_column + 1);\n } else if (lno > loc.first_line && lno < loc.last_line) {\n len = Math.max(2, line.length + 1);\n }\n\n if (len) {\n var lead = new Array(offset).join('.');\n var mark = new Array(len).join('^');\n rv += '\\n' + errpfx + lead + mark;\n\n if (line.trim().length > 0) {\n nonempty_line_indexes.push(index);\n }\n }\n\n rv = rv.replace(/\\t/g, ' ');\n return rv;\n });\n\n // now make sure we don't print an overly large amount of error area: limit it \n // to the top and bottom line count:\n if (nonempty_line_indexes.length > 2 * MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT) {\n var clip_start = nonempty_line_indexes[MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT - 1] + 1;\n var clip_end = nonempty_line_indexes[nonempty_line_indexes.length - MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT] - 1;\n\n var intermediate_line = (new Array(lineno_display_width + 1)).join(' ') + ' (...continued...)';\n intermediate_line += '\\n' + (new Array(lineno_display_width + 1)).join('-') + ' (---------------)';\n rv.splice(clip_start, clip_end - clip_start + 1, intermediate_line);\n }\n return rv.join('\\n');\n },\n\n /**\n * helper function, used to produce a human readable description as a string, given\n * the input `yylloc` location object.\n * \n * Set `display_range_too` to TRUE to include the string character index position(s)\n * in the description if the `yylloc.range` is available.\n * \n * @public\n * @this {RegExpLexer}\n */\n describeYYLLOC: function lexer_describe_yylloc(yylloc, display_range_too) {\n var l1 = yylloc.first_line;\n var l2 = yylloc.last_line;\n var c1 = yylloc.first_column;\n var c2 = yylloc.last_column;\n var dl = l2 - l1;\n var dc = c2 - c1;\n var rv;\n if (dl === 0) {\n rv = 'line ' + l1 + ', ';\n if (dc <= 1) {\n rv += 'column ' + c1;\n } else {\n rv += 'columns ' + c1 + ' .. ' + c2;\n }\n } else {\n rv = 'lines ' + l1 + '(column ' + c1 + ') .. ' + l2 + '(column ' + c2 + ')';\n }\n if (yylloc.range && display_range_too) {\n var r1 = yylloc.range[0];\n var r2 = yylloc.range[1] - 1;\n if (r2 <= r1) {\n rv += ' {String Offset: ' + r1 + '}';\n } else {\n rv += ' {String Offset range: ' + r1 + ' .. ' + r2 + '}';\n }\n }\n return rv;\n },\n\n /**\n * test the lexed token: return FALSE when not a match, otherwise return token.\n * \n * `match` is supposed to be an array coming out of a regex match, i.e. `match[0]`\n * contains the actually matched text string.\n * \n * Also move the input cursor forward and update the match collectors:\n * \n * - `yytext`\n * - `yyleng`\n * - `match`\n * - `matches`\n * - `yylloc`\n * - `offset`\n * \n * @public\n * @this {RegExpLexer}\n */\n test_match: function lexer_test_match(match, indexed_rule) {\n var token,\n lines,\n backup,\n match_str,\n match_str_len;\n\n if (this.options.backtrack_lexer) {\n // save context\n backup = {\n yylineno: this.yylineno,\n yylloc: {\n first_line: this.yylloc.first_line,\n last_line: this.yylloc.last_line,\n first_column: this.yylloc.first_column,\n last_column: this.yylloc.last_column,\n\n range: this.yylloc.range.slice(0)\n },\n yytext: this.yytext,\n match: this.match,\n matches: this.matches,\n matched: this.matched,\n yyleng: this.yyleng,\n offset: this.offset,\n _more: this._more,\n _input: this._input,\n //_signaled_error_token: this._signaled_error_token,\n yy: this.yy,\n conditionStack: this.conditionStack.slice(0),\n done: this.done\n };\n }\n\n match_str = match[0];\n match_str_len = match_str.length;\n // if (match_str.indexOf('\\n') !== -1 || match_str.indexOf('\\r') !== -1) {\n lines = match_str.split(/(?:\\r\\n?|\\n)/g);\n if (lines.length > 1) {\n this.yylineno += lines.length - 1;\n\n this.yylloc.last_line = this.yylineno + 1;\n this.yylloc.last_column = lines[lines.length - 1].length;\n } else {\n this.yylloc.last_column += match_str_len;\n }\n // }\n this.yytext += match_str;\n this.match += match_str;\n this.matched += match_str;\n this.matches = match;\n this.yyleng = this.yytext.length;\n this.yylloc.range[1] += match_str_len;\n\n // previous lex rules MAY have invoked the `more()` API rather than producing a token:\n // those rules will already have moved this `offset` forward matching their match lengths,\n // hence we must only add our own match length now:\n this.offset += match_str_len;\n this._more = false;\n this._backtrack = false;\n this._input = this._input.slice(match_str_len);\n\n // calling this method:\n //\n // function lexer__performAction(yy, yyrulenumber, YY_START) {...}\n token = this.performAction.call(this, this.yy, indexed_rule, this.conditionStack[this.conditionStack.length - 1] /* = YY_START */);\n // otherwise, when the action codes are all simple return token statements:\n //token = this.simpleCaseActionClusters[indexed_rule];\n\n if (this.done && this._input) {\n this.done = false;\n }\n if (token) {\n return token;\n } else if (this._backtrack) {\n // recover context\n for (var k in backup) {\n this[k] = backup[k];\n }\n this.__currentRuleSet__ = null;\n return false; // rule action called reject() implying the next rule should be tested instead.\n } else if (this._signaled_error_token) {\n // produce one 'error' token as `.parseError()` in `reject()`\n // did not guarantee a failure signal by throwing an exception!\n token = this._signaled_error_token;\n this._signaled_error_token = false;\n return token;\n }\n return false;\n },\n\n /**\n * return next match in input\n * \n * @public\n * @this {RegExpLexer}\n */\n next: function lexer_next() {\n if (this.done) {\n this.clear();\n return this.EOF;\n }\n if (!this._input) {\n this.done = true;\n }\n\n var token,\n match,\n tempMatch,\n index;\n if (!this._more) {\n this.clear();\n }\n var spec = this.__currentRuleSet__;\n if (!spec) {\n // Update the ruleset cache as we apparently encountered a state change or just started lexing.\n // The cache is set up for fast lookup -- we assume a lexer will switch states much less often than it will\n // invoke the `lex()` token-producing API and related APIs, hence caching the set for direct access helps\n // speed up those activities a tiny bit.\n spec = this.__currentRuleSet__ = this._currentRules();\n // Check whether a *sane* condition has been pushed before: this makes the lexer robust against\n // user-programmer bugs such as https://github.com/zaach/jison-lex/issues/19\n if (!spec || !spec.rules) {\n var lineno_msg = '';\n if (this.options.trackPosition) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Internal lexer engine error' + lineno_msg + ': The lex grammar programmer pushed a non-existing condition name \"' + this.topState() + '\"; this is a fatal error and should be reported to the application programmer team!', false);\n // produce one 'error' token until this situation has been resolved, most probably by parse termination!\n return (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n }\n }\n\n var rule_ids = spec.rules;\n var regexes = spec.__rule_regexes;\n var len = spec.__rule_count;\n\n // Note: the arrays are 1-based, while `len` itself is a valid index,\n // hence the non-standard less-or-equal check in the next loop condition!\n for (var i = 1; i <= len; i++) {\n tempMatch = this._input.match(regexes[i]);\n if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {\n match = tempMatch;\n index = i;\n if (this.options.backtrack_lexer) {\n token = this.test_match(tempMatch, rule_ids[i]);\n if (token !== false) {\n return token;\n } else if (this._backtrack) {\n match = undefined;\n continue; // rule action called reject() implying a rule MISmatch.\n } else {\n // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)\n return false;\n }\n } else if (!this.options.flex) {\n break;\n }\n }\n }\n if (match) {\n token = this.test_match(match, rule_ids[index]);\n if (token !== false) {\n return token;\n }\n // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)\n return false;\n }\n if (!this._input) {\n this.done = true;\n this.clear();\n return this.EOF;\n } else {\n var lineno_msg = '';\n if (this.options.trackPosition) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': Unrecognized text.', this.options.lexerErrorsAreRecoverable);\n\n var pendingInput = this._input;\n var activeCondition = this.topState();\n var conditionStackDepth = this.conditionStack.length;\n\n token = (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n if (token === this.ERROR) {\n // we can try to recover from a lexer error that `parseError()` did not 'recover' for us\n // by moving forward at least one character at a time IFF the (user-specified?) `parseError()`\n // has not consumed/modified any pending input or changed state in the error handler:\n if (!this.matches && \n // and make sure the input has been modified/consumed ...\n pendingInput === this._input &&\n // ...or the lexer state has been modified significantly enough\n // to merit a non-consuming error handling action right now.\n activeCondition === this.topState() && \n conditionStackDepth === this.conditionStack.length\n ) {\n this.input();\n }\n }\n return token;\n }\n },\n\n /**\n * return next match that has a token\n * \n * @public\n * @this {RegExpLexer}\n */\n lex: function lexer_lex() {\n var r;\n // allow the PRE/POST handlers set/modify the return token for maximum flexibility of the generated lexer:\n if (typeof this.pre_lex === 'function') {\n r = this.pre_lex.call(this, 0);\n }\n if (typeof this.options.pre_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.options.pre_lex.call(this, r) || r;\n }\n if (this.yy && typeof this.yy.pre_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.yy.pre_lex.call(this, r) || r;\n }\n\n while (!r) {\n r = this.next();\n }\n\n if (this.yy && typeof this.yy.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.yy.post_lex.call(this, r) || r;\n }\n if (typeof this.options.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.options.post_lex.call(this, r) || r;\n }\n if (typeof this.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.post_lex.call(this, r) || r;\n }\n return r;\n },\n\n /**\n * return next match that has a token. Identical to the `lex()` API but does not invoke any of the \n * `pre_lex()` nor any of the `post_lex()` callbacks.\n * \n * @public\n * @this {RegExpLexer}\n */\n fastLex: function lexer_fastLex() {\n var r;\n\n while (!r) {\n r = this.next();\n }\n\n return r;\n },\n\n /**\n * return info about the lexer state that can help a parser or other lexer API user to use the\n * most efficient means available. This API is provided to aid run-time performance for larger\n * systems which employ this lexer.\n * \n * @public\n * @this {RegExpLexer}\n */\n canIUse: function lexer_canIUse() {\n var rv = {\n fastLex: !(\n typeof this.pre_lex === 'function' ||\n typeof this.options.pre_lex === 'function' ||\n (this.yy && typeof this.yy.pre_lex === 'function') ||\n (this.yy && typeof this.yy.post_lex === 'function') ||\n typeof this.options.post_lex === 'function' ||\n typeof this.post_lex === 'function'\n ) && typeof this.fastLex === 'function',\n };\n return rv;\n },\n\n\n /**\n * backwards compatible alias for `pushState()`;\n * the latter is symmetrical with `popState()` and we advise to use\n * those APIs in any modern lexer code, rather than `begin()`.\n * \n * @public\n * @this {RegExpLexer}\n */\n begin: function lexer_begin(condition) {\n return this.pushState(condition);\n },\n\n /**\n * activates a new lexer condition state (pushes the new lexer\n * condition state onto the condition stack)\n * \n * @public\n * @this {RegExpLexer}\n */\n pushState: function lexer_pushState(condition) {\n this.conditionStack.push(condition);\n this.__currentRuleSet__ = null;\n return this;\n },\n\n /**\n * pop the previously active lexer condition state off the condition\n * stack\n * \n * @public\n * @this {RegExpLexer}\n */\n popState: function lexer_popState() {\n var n = this.conditionStack.length - 1;\n if (n > 0) {\n this.__currentRuleSet__ = null; \n return this.conditionStack.pop();\n } else {\n return this.conditionStack[0];\n }\n },\n\n /**\n * return the currently active lexer condition state; when an index\n * argument is provided it produces the N-th previous condition state,\n * if available\n * \n * @public\n * @this {RegExpLexer}\n */\n topState: function lexer_topState(n) {\n n = this.conditionStack.length - 1 - Math.abs(n || 0);\n if (n >= 0) {\n return this.conditionStack[n];\n } else {\n return 'INITIAL';\n }\n },\n\n /**\n * (internal) determine the lexer rule set which is active for the\n * currently active lexer condition state\n * \n * @public\n * @this {RegExpLexer}\n */\n _currentRules: function lexer__currentRules() {\n if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {\n return this.conditions[this.conditionStack[this.conditionStack.length - 1]];\n } else {\n return this.conditions['INITIAL'];\n }\n },\n\n /**\n * return the number of states currently on the stack\n * \n * @public\n * @this {RegExpLexer}\n */\n stateStackSize: function lexer_stateStackSize() {\n return this.conditionStack.length;\n },\n options: {\n trackPosition: true\n},\n JisonLexerError: JisonLexerError,\n performAction: function lexer__performAction(yy, yyrulenumber, YY_START) {\n var yy_ = this;\n\n \nvar YYSTATE = YY_START;\nswitch(yyrulenumber) {\ncase 0 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\s+ */ \n \nbreak;\ncase 2 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\w+ */ \n \n if (yy_.yytext === 'a') {\n return 'TOK_A'; \n } else {\n return 'WORD'; \n }\n \nbreak;\ndefault:\n return this.simpleCaseActionClusters[yyrulenumber];\n}\n },\n simpleCaseActionClusters: {\n\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\d+ */ \n 1 : 'NUMBER',\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\+ */ \n 3 : '+',\n /*! Conditions:: INITIAL */ \n /*! Rule:: $ */ \n 4 : 'EOF'\n},\n rules: [\n /* 0: */ /^(?:\\s+)/,\n/* 1: */ /^(?:\\d+)/,\n/* 2: */ /^(?:\\w+)/,\n/* 3: */ /^(?:\\+)/,\n/* 4: */ /^(?:$)/\n ],\n conditions: {\n \"INITIAL\": {\n rules: [\n 0,\n 1,\n 2,\n 3,\n 4\n ],\n inclusive: true\n }\n}\n};\n", + options: { + lexerActionsUseYYLENG: "???", + lexerActionsUseYYLINENO: "???", + lexerActionsUseYYTEXT: "???", + lexerActionsUseYYLOC: "???", + lexerActionsUseParseError: "???", + lexerActionsUseYYERROR: "???", + lexerActionsUseLocationTracking: "???", + lexerActionsUseMore: "???", + lexerActionsUseUnput: "???", + lexerActionsUseReject: "???", + lexerActionsUseLess: "???", + lexerActionsUseDisplayAPIs: "???", + lexerActionsUseDescribeYYLOC: "???", + lex_rule_dictionary: { + rules: [ + [ + "\\s+", + "" + ], + [ + "\\d+", + null + ], + [ + "\\w+", + null + ], + [ + "\\+", + null + ], + [ + "$", + null + ] + ] + }, + options: { + moduleType: "commonjs", + debug: false, + enableDebugLogs: false, + json: true, + dumpSourceCodeOnFailure: true, + throwErrorOnCompileFailure: true, + defaultModuleName: "lexer", + xregexp: false, + lexerErrorsAreRecoverable: false, + flex: false, + backtrack_lexer: false, + ranges: false, + trackPosition: true, + caseInsensitive: false, + exportSourceCode: false, + exportAST: false, + prettyCfg: true, + noMain: true + }, + moduleType: "commonjs", + conditions: { + INITIAL: { + rules: [ + 0, + 1, + 2, + 3, + 4 + ], + inclusive: true + } + }, + performAction: "function lexer__performAction(yy, yyrulenumber, YY_START) {\n var yy_ = this;\n\n \nvar YYSTATE = YY_START;\nswitch(yyrulenumber) {\ncase 0 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\s+ */ \n \nbreak;\ncase 2 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\w+ */ \n \n if (yy_.yytext === 'a') {\n return 'TOK_A'; \n } else {\n return 'WORD'; \n }\n \nbreak;\ndefault:\n return this.simpleCaseActionClusters[yyrulenumber];\n}\n }", + caseHelperInclude: "{\n\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\d+ */ \n 1 : 'NUMBER',\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\+ */ \n 3 : '+',\n /*! Conditions:: INITIAL */ \n /*! Rule:: $ */ \n 4 : 'EOF'\n}", + rules: [ + { + xregexp: { + captureNames: null, + source: "^(?:\\s+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\d+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\w+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:$)", + flags: "", + isNative: true + } + } + ], + macros: {}, + regular_rule_count: 2, + simple_rule_count: 3, + conditionStack: [ + "INITIAL" + ], + actionInclude: "", + moduleInclude: "", + __in_rules_failure_analysis_mode__: false, + exportSourceCode: { + enabled: false + }, + is_custom_lexer: false + } + } +] \ No newline at end of file diff --git a/packages/jison-lex/tests/specs/003-issue-23-trouble.js b/packages/jison-lex/tests/specs/003-issue-23-trouble.js new file mode 100644 index 000000000..10938c287 --- /dev/null +++ b/packages/jison-lex/tests/specs/003-issue-23-trouble.js @@ -0,0 +1,27 @@ +// title: Parse error when using arrow function in rules +// test_input: A a B C 1 + 2 + 3 +// ... +// +// This is the FAILING lexer spec +// + +let grammar = { + rules: [ + ['\\s+', ''], + ['\\d+', () => 'NUMBER'], + ['\\w+', () => { + if (yytext === 'a') { + return 'TOK_A'; + } else { + return 'WORD'; + } + } + ], + ['\\+', () => '+'], + ['$', () => 'EOF'], + ] +}; + +module.exports = grammar; +// export default grammar; + diff --git a/packages/jison-lex/tests/specs/003-issue-23-trouble.js-ref.json5 b/packages/jison-lex/tests/specs/003-issue-23-trouble.js-ref.json5 new file mode 100644 index 000000000..424471607 --- /dev/null +++ b/packages/jison-lex/tests/specs/003-issue-23-trouble.js-ref.json5 @@ -0,0 +1,303 @@ +[ + 13, + "WORD", + "A", + { + first_line: 1, + first_column: 0, + last_line: 1, + last_column: 1, + range: [ + 0, + 1 + ] + }, + "TOK_A", + "a", + { + first_line: 1, + first_column: 2, + last_line: 1, + last_column: 3, + range: [ + 2, + 3 + ] + }, + "WORD", + "B", + { + first_line: 1, + first_column: 4, + last_line: 1, + last_column: 5, + range: [ + 4, + 5 + ] + }, + "WORD", + "C", + { + first_line: 1, + first_column: 6, + last_line: 1, + last_column: 7, + range: [ + 6, + 7 + ] + }, + "NUMBER", + "1", + { + first_line: 1, + first_column: 8, + last_line: 1, + last_column: 9, + range: [ + 8, + 9 + ] + }, + "+", + "+", + { + first_line: 1, + first_column: 10, + last_line: 1, + last_column: 11, + range: [ + 10, + 11 + ] + }, + "NUMBER", + "2", + { + first_line: 1, + first_column: 12, + last_line: 1, + last_column: 13, + range: [ + 12, + 13 + ] + }, + "+", + "+", + { + first_line: 1, + first_column: 14, + last_line: 1, + last_column: 15, + range: [ + 14, + 15 + ] + }, + "NUMBER", + "3", + { + first_line: 1, + first_column: 16, + last_line: 1, + last_column: 17, + range: [ + 16, + 17 + ] + }, + "EOF", + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + 1, + "", + { + first_line: 1, + first_column: 17, + last_line: 1, + last_column: 17, + range: [ + 17, + 17 + ] + }, + { + sourceCode: "\nvar lexer = {\n/*JISON-LEX-ANALYTICS-REPORT*/EOF: 1,\n ERROR: 2,\n\n // JisonLexerError: JisonLexerError, /// <-- injected by the code generator\n\n // options: {}, /// <-- injected by the code generator\n\n // yy: ..., /// <-- injected by setInput()\n\n __currentRuleSet__: null, /// INTERNAL USE ONLY: internal rule set cache for the current lexer state\n\n __error_infos: [], /// INTERNAL USE ONLY: the set of lexErrorInfo objects created since the last cleanup\n\n __decompressed: false, /// INTERNAL USE ONLY: mark whether the lexer instance has been 'unfolded' completely and is now ready for use\n\n done: false, /// INTERNAL USE ONLY\n _backtrack: false, /// INTERNAL USE ONLY\n _input: '', /// INTERNAL USE ONLY\n _more: false, /// INTERNAL USE ONLY\n _signaled_error_token: false, /// INTERNAL USE ONLY\n\n conditionStack: [], /// INTERNAL USE ONLY; managed via `pushState()`, `popState()`, `topState()` and `stateStackSize()`\n\n match: '', /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks input which has been matched so far for the lexer token under construction. `match` is identical to `yytext` except that this one still contains the matched input string after `lexer.performAction()` has been invoked, where userland code MAY have changed/replaced the `yytext` value entirely!\n matched: '', /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks entire input which has been matched so far\n matches: false, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks RE match result for last (successful) match attempt\n yytext: '', /// ADVANCED USE ONLY: tracks input which has been matched so far for the lexer token under construction; this value is transferred to the parser as the 'token value' when the parser consumes the lexer token produced through a call to the `lex()` API.\n offset: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks the 'cursor position' in the input string, i.e. the number of characters matched so far\n yyleng: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: length of matched input for the token under construction (`yytext`)\n yylineno: 0, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: 'line number' at which the token under construction is located\n yylloc: null, /// READ-ONLY EXTERNAL ACCESS - ADVANCED USE ONLY: tracks location info (lines + columns) for the token under construction\n\n /**\n * INTERNAL USE: construct a suitable error info hash object instance for `parseError`.\n * \n * @public\n * @this {RegExpLexer}\n */\n constructLexErrorInfo: function lexer_constructLexErrorInfo(msg, recoverable, show_input_position) {\n msg = '' + msg;\n\n // heuristic to determine if the error message already contains a (partial) source code dump\n // as produced by either `showPosition()` or `prettyPrintRange()`:\n if (show_input_position == undefined) {\n show_input_position = !(msg.indexOf('\\n') > 0 && msg.indexOf('^') > 0);\n }\n if (this.yylloc && show_input_position) {\n if (typeof this.prettyPrintRange === 'function') {\n var pretty_src = this.prettyPrintRange(this.yylloc);\n\n if (!/\\n\\s*$/.test(msg)) {\n msg += '\\n';\n }\n msg += '\\n Erroneous area:\\n' + this.prettyPrintRange(this.yylloc); \n } else if (typeof this.showPosition === 'function') {\n var pos_str = this.showPosition();\n if (pos_str) {\n if (msg.length && msg[msg.length - 1] !== '\\n' && pos_str[0] !== '\\n') {\n msg += '\\n' + pos_str;\n } else {\n msg += pos_str;\n }\n }\n }\n }\n /** @constructor */\n var pei = {\n errStr: msg,\n recoverable: !!recoverable,\n text: this.match, // This one MAY be empty; userland code should use the `upcomingInput` API to obtain more text which follows the 'lexer cursor position'...\n token: null,\n line: this.yylineno,\n loc: this.yylloc,\n yy: this.yy,\n lexer: this,\n\n /**\n * and make sure the error info doesn't stay due to potential\n * ref cycle via userland code manipulations.\n * These would otherwise all be memory leak opportunities!\n * \n * Note that only array and object references are nuked as those\n * constitute the set of elements which can produce a cyclic ref.\n * The rest of the members is kept intact as they are harmless.\n * \n * @public\n * @this {LexErrorInfo}\n */\n destroy: function destructLexErrorInfo() {\n // remove cyclic references added to error info:\n // info.yy = null;\n // info.lexer = null;\n // ...\n var rec = !!this.recoverable;\n for (var key in this) {\n if (this.hasOwnProperty(key) && typeof key === 'object') {\n this[key] = undefined;\n }\n }\n this.recoverable = rec;\n }\n };\n // track this instance so we can `destroy()` it once we deem it superfluous and ready for garbage collection!\n this.__error_infos.push(pei);\n return pei;\n },\n\n /**\n * handler which is invoked when a lexer error occurs.\n * \n * @public\n * @this {RegExpLexer}\n */\n parseError: function lexer_parseError(str, hash, ExceptionClass) {\n if (!ExceptionClass) {\n ExceptionClass = this.JisonLexerError;\n }\n if (this.yy) {\n if (this.yy.parser && typeof this.yy.parser.parseError === 'function') {\n return this.yy.parser.parseError.call(this, str, hash, ExceptionClass) || this.ERROR;\n } else if (typeof this.yy.parseError === 'function') {\n return this.yy.parseError.call(this, str, hash, ExceptionClass) || this.ERROR;\n } \n }\n throw new ExceptionClass(str, hash);\n },\n\n /**\n * method which implements `yyerror(str, ...args)` functionality for use inside lexer actions.\n * \n * @public\n * @this {RegExpLexer}\n */\n yyerror: function yyError(str /*, ...args */) {\n var lineno_msg = '';\n if (this.yylloc) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': ' + str, this.options.lexerErrorsAreRecoverable);\n\n // Add any extra args to the hash under the name `extra_error_attributes`:\n var args = Array.prototype.slice.call(arguments, 1);\n if (args.length) {\n p.extra_error_attributes = args;\n }\n\n return (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n },\n\n /**\n * final cleanup function for when we have completed lexing the input;\n * make it an API so that external code can use this one once userland\n * code has decided it's time to destroy any lingering lexer error\n * hash object instances and the like: this function helps to clean\n * up these constructs, which *may* carry cyclic references which would\n * otherwise prevent the instances from being properly and timely\n * garbage-collected, i.e. this function helps prevent memory leaks!\n * \n * @public\n * @this {RegExpLexer}\n */\n cleanupAfterLex: function lexer_cleanupAfterLex(do_not_nuke_errorinfos) {\n // prevent lingering circular references from causing memory leaks:\n this.setInput('', {});\n\n // nuke the error hash info instances created during this run.\n // Userland code must COPY any data/references\n // in the error hash instance(s) it is more permanently interested in.\n if (!do_not_nuke_errorinfos) {\n for (var i = this.__error_infos.length - 1; i >= 0; i--) {\n var el = this.__error_infos[i];\n if (el && typeof el.destroy === 'function') {\n el.destroy();\n }\n }\n this.__error_infos.length = 0;\n }\n\n return this;\n },\n\n /**\n * clear the lexer token context; intended for internal use only\n * \n * @public\n * @this {RegExpLexer}\n */\n clear: function lexer_clear() {\n this.yytext = '';\n this.yyleng = 0;\n this.match = '';\n // - DO NOT reset `this.matched`\n this.matches = false;\n this._more = false;\n this._backtrack = false;\n\n var col = (this.yylloc ? this.yylloc.last_column : 0);\n this.yylloc = {\n first_line: this.yylineno + 1,\n first_column: col,\n last_line: this.yylineno + 1,\n last_column: col,\n\n range: [this.offset, this.offset]\n };\n },\n\n /**\n * resets the lexer, sets new input\n * \n * @public\n * @this {RegExpLexer}\n */\n setInput: function lexer_setInput(input, yy) {\n this.yy = yy || this.yy || {};\n\n // also check if we've fully initialized the lexer instance,\n // including expansion work to be done to go from a loaded\n // lexer to a usable lexer:\n if (!this.__decompressed) {\n // step 1: decompress the regex list:\n var rules = this.rules;\n for (var i = 0, len = rules.length; i < len; i++) {\n var rule_re = rules[i];\n\n // compression: is the RE an xref to another RE slot in the rules[] table?\n if (typeof rule_re === 'number') {\n rules[i] = rules[rule_re];\n }\n }\n\n // step 2: unfold the conditions[] set to make these ready for use:\n var conditions = this.conditions;\n for (var k in conditions) {\n var spec = conditions[k];\n\n var rule_ids = spec.rules;\n\n var len = rule_ids.length;\n var rule_regexes = new Array(len + 1); // slot 0 is unused; we use a 1-based index approach here to keep the hottest code in `lexer_next()` fast and simple!\n var rule_new_ids = new Array(len + 1);\n\n for (var i = 0; i < len; i++) {\n var idx = rule_ids[i];\n var rule_re = rules[idx];\n rule_regexes[i + 1] = rule_re;\n rule_new_ids[i + 1] = idx;\n }\n\n spec.rules = rule_new_ids;\n spec.__rule_regexes = rule_regexes;\n spec.__rule_count = len;\n }\n\n this.__decompressed = true;\n }\n\n this._input = input || '';\n this.clear();\n this._signaled_error_token = false;\n this.done = false;\n this.yylineno = 0;\n this.matched = '';\n this.conditionStack = ['INITIAL'];\n this.__currentRuleSet__ = null;\n this.yylloc = {\n first_line: 1,\n first_column: 0,\n last_line: 1,\n last_column: 0,\n\n range: [0, 0]\n };\n this.offset = 0;\n return this;\n },\n\n /**\n * edit the remaining input via user-specified callback.\n * This can be used to forward-adjust the input-to-parse, \n * e.g. inserting macro expansions and alike in the\n * input which has yet to be lexed.\n * The behaviour of this API contrasts the `unput()` et al\n * APIs as those act on the *consumed* input, while this\n * one allows one to manipulate the future, without impacting\n * the current `yyloc` cursor location or any history. \n * \n * Use this API to help implement C-preprocessor-like\n * `#include` statements, etc.\n * \n * The provided callback must be synchronous and is\n * expected to return the edited input (string).\n *\n * The `cpsArg` argument value is passed to the callback\n * as-is.\n *\n * `callback` interface: \n * `function callback(input, cpsArg)`\n * \n * - `input` will carry the remaining-input-to-lex string\n * from the lexer.\n * - `cpsArg` is `cpsArg` passed into this API.\n * \n * The `this` reference for the callback will be set to\n * reference this lexer instance so that userland code\n * in the callback can easily and quickly access any lexer\n * API. \n *\n * When the callback returns a non-string-type falsey value,\n * we assume the callback did not edit the input and we\n * will using the input as-is.\n *\n * When the callback returns a non-string-type value, it\n * is converted to a string for lexing via the `\"\" + retval`\n * operation. (See also why: http://2ality.com/2012/03/converting-to-string.html \n * -- that way any returned object's `toValue()` and `toString()`\n * methods will be invoked in a proper/desirable order.)\n * \n * @public\n * @this {RegExpLexer}\n */\n editRemainingInput: function lexer_editRemainingInput(callback, cpsArg) {\n var rv = callback.call(this, this._input, cpsArg);\n if (typeof rv !== 'string') {\n if (rv) {\n this._input = '' + rv; \n }\n // else: keep `this._input` as is. \n } else {\n this._input = rv; \n }\n return this;\n },\n\n /**\n * consumes and returns one char from the input\n * \n * @public\n * @this {RegExpLexer}\n */\n input: function lexer_input() {\n if (!this._input) {\n //this.done = true; -- don't set `done` as we want the lex()/next() API to be able to produce one custom EOF token match after this anyhow. (lexer can match special <> tokens and perform user action code for a <> match, but only does so *once*)\n return null;\n }\n var ch = this._input[0];\n this.yytext += ch;\n this.yyleng++;\n this.offset++;\n this.match += ch;\n this.matched += ch;\n // Count the linenumber up when we hit the LF (or a stand-alone CR).\n // On CRLF, the linenumber is incremented when you fetch the CR or the CRLF combo\n // and we advance immediately past the LF as well, returning both together as if\n // it was all a single 'character' only.\n var slice_len = 1;\n var lines = false;\n if (ch === '\\n') {\n lines = true;\n } else if (ch === '\\r') {\n lines = true;\n var ch2 = this._input[1];\n if (ch2 === '\\n') {\n slice_len++;\n ch += ch2;\n this.yytext += ch2;\n this.yyleng++;\n this.offset++;\n this.match += ch2;\n this.matched += ch2;\n this.yylloc.range[1]++;\n }\n }\n if (lines) {\n this.yylineno++;\n this.yylloc.last_line++;\n this.yylloc.last_column = 0;\n } else {\n this.yylloc.last_column++;\n }\n this.yylloc.range[1]++;\n\n this._input = this._input.slice(slice_len);\n return ch;\n },\n\n /**\n * unshifts one char (or an entire string) into the input\n * \n * @public\n * @this {RegExpLexer}\n */\n unput: function lexer_unput(ch) {\n var len = ch.length;\n var lines = ch.split(/(?:\\r\\n?|\\n)/g);\n\n this._input = ch + this._input;\n this.yytext = this.yytext.substr(0, this.yytext.length - len);\n this.yyleng = this.yytext.length;\n this.offset -= len;\n this.match = this.match.substr(0, this.match.length - len);\n this.matched = this.matched.substr(0, this.matched.length - len);\n\n if (lines.length > 1) {\n this.yylineno -= lines.length - 1;\n\n this.yylloc.last_line = this.yylineno + 1;\n\n // Get last entirely matched line into the `pre_lines[]` array's\n // last index slot; we don't mind when other previously \n // matched lines end up in the array too. \n var pre = this.match;\n var pre_lines = pre.split(/(?:\\r\\n?|\\n)/g);\n if (pre_lines.length === 1) {\n pre = this.matched;\n pre_lines = pre.split(/(?:\\r\\n?|\\n)/g);\n }\n this.yylloc.last_column = pre_lines[pre_lines.length - 1].length;\n } else {\n this.yylloc.last_column -= len;\n }\n\n this.yylloc.range[1] = this.yylloc.range[0] + this.yyleng;\n\n this.done = false;\n return this;\n },\n\n /**\n * cache matched text and append it on next action\n * \n * @public\n * @this {RegExpLexer}\n */\n more: function lexer_more() {\n this._more = true;\n return this;\n },\n\n /**\n * signal the lexer that this rule fails to match the input, so the\n * next matching rule (regex) should be tested instead.\n * \n * @public\n * @this {RegExpLexer}\n */\n reject: function lexer_reject() {\n if (this.options.backtrack_lexer) {\n this._backtrack = true;\n } else {\n // when the `parseError()` call returns, we MUST ensure that the error is registered.\n // We accomplish this by signaling an 'error' token to be produced for the current\n // `.lex()` run.\n var lineno_msg = '';\n if (this.yylloc) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).', false);\n this._signaled_error_token = (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n }\n return this;\n },\n\n /**\n * retain first n characters of the match\n * \n * @public\n * @this {RegExpLexer}\n */\n less: function lexer_less(n) {\n return this.unput(this.match.slice(n));\n },\n\n /**\n * return (part of the) already matched input, i.e. for error\n * messages.\n * \n * Limit the returned string length to `maxSize` (default: 20).\n * \n * Limit the returned string to the `maxLines` number of lines of\n * input (default: 1).\n * \n * Negative limit values equal *unlimited*.\n * \n * @public\n * @this {RegExpLexer}\n */\n pastInput: function lexer_pastInput(maxSize, maxLines) {\n var past = this.matched.substring(0, this.matched.length - this.match.length);\n if (maxSize < 0)\n maxSize = past.length;\n else if (!maxSize)\n maxSize = 20;\n if (maxLines < 0)\n maxLines = past.length; // can't ever have more input lines than this!\n else if (!maxLines)\n maxLines = 1;\n // `substr` anticipation: treat \\r\\n as a single character and take a little\n // more than necessary so that we can still properly check against maxSize\n // after we've transformed and limited the newLines in here:\n past = past.substr(-maxSize * 2 - 2);\n // now that we have a significantly reduced string to process, transform the newlines\n // and chop them, then limit them:\n var a = past.replace(/\\r\\n|\\r/g, '\\n').split('\\n');\n a = a.slice(-maxLines);\n past = a.join('\\n');\n // When, after limiting to maxLines, we still have too much to return,\n // do add an ellipsis prefix...\n if (past.length > maxSize) {\n past = '...' + past.substr(-maxSize);\n }\n return past;\n },\n\n /**\n * return (part of the) upcoming input, i.e. for error messages.\n * \n * Limit the returned string length to `maxSize` (default: 20).\n * \n * Limit the returned string to the `maxLines` number of lines of input (default: 1).\n * \n * Negative limit values equal *unlimited*.\n *\n * > ### NOTE ###\n * >\n * > *\"upcoming input\"* is defined as the whole of the both\n * > the *currently lexed* input, together with any remaining input\n * > following that. *\"currently lexed\"* input is the input \n * > already recognized by the lexer but not yet returned with\n * > the lexer token. This happens when you are invoking this API\n * > from inside any lexer rule action code block. \n * >\n * \n * @public\n * @this {RegExpLexer}\n */\n upcomingInput: function lexer_upcomingInput(maxSize, maxLines) {\n var next = this.match;\n if (maxSize < 0)\n maxSize = next.length + this._input.length;\n else if (!maxSize)\n maxSize = 20;\n if (maxLines < 0)\n maxLines = maxSize; // can't ever have more input lines than this!\n else if (!maxLines)\n maxLines = 1;\n // `substring` anticipation: treat \\r\\n as a single character and take a little\n // more than necessary so that we can still properly check against maxSize\n // after we've transformed and limited the newLines in here:\n if (next.length < maxSize * 2 + 2) {\n next += this._input.substring(0, maxSize * 2 + 2); // substring is faster on Chrome/V8\n }\n // now that we have a significantly reduced string to process, transform the newlines\n // and chop them, then limit them:\n var a = next.replace(/\\r\\n|\\r/g, '\\n').split('\\n');\n a = a.slice(0, maxLines);\n next = a.join('\\n');\n // When, after limiting to maxLines, we still have too much to return,\n // do add an ellipsis postfix...\n if (next.length > maxSize) {\n next = next.substring(0, maxSize) + '...';\n }\n return next;\n },\n\n /**\n * return a string which displays the character position where the\n * lexing error occurred, i.e. for error messages\n * \n * @public\n * @this {RegExpLexer}\n */\n showPosition: function lexer_showPosition(maxPrefix, maxPostfix) {\n var pre = this.pastInput(maxPrefix).replace(/\\s/g, ' ');\n var c = new Array(pre.length + 1).join('-');\n return pre + this.upcomingInput(maxPostfix).replace(/\\s/g, ' ') + '\\n' + c + '^';\n },\n\n /**\n * return an YYLLOC info object derived off the given context (actual, preceding, following, current).\n * Use this method when the given `actual` location is not guaranteed to exist (i.e. when\n * it MAY be NULL) and you MUST have a valid location info object anyway:\n * then we take the given context of the `preceding` and `following` locations, IFF those are available,\n * and reconstruct the `actual` location info from those.\n * If this fails, the heuristic is to take the `current` location, IFF available.\n * If this fails as well, we assume the sought location is at/around the current lexer position\n * and then produce that one as a response. DO NOTE that these heuristic/derived location info\n * values MAY be inaccurate!\n *\n * NOTE: `deriveLocationInfo()` ALWAYS produces a location info object *copy* of `actual`, not just\n * a *reference* hence all input location objects can be assumed to be 'constant' (function has no side-effects).\n * \n * @public\n * @this {RegExpLexer}\n */\n deriveLocationInfo: function lexer_deriveYYLLOC(actual, preceding, following, current) {\n var loc = {\n first_line: 1,\n first_column: 0,\n last_line: 1,\n last_column: 0,\n\n range: [0, 0]\n };\n if (actual) {\n loc.first_line = actual.first_line | 0;\n loc.last_line = actual.last_line | 0;\n loc.first_column = actual.first_column | 0;\n loc.last_column = actual.last_column | 0;\n\n if (actual.range) {\n loc.range[0] = actual.range[0] | 0; \n loc.range[1] = actual.range[1] | 0;\n } \n }\n if (loc.first_line <= 0 || loc.last_line < loc.first_line) {\n // plan B: heuristic using preceding and following:\n if (loc.first_line <= 0 && preceding) {\n loc.first_line = preceding.last_line | 0;\n loc.first_column = preceding.last_column | 0;\n\n if (preceding.range) {\n loc.range[0] = actual.range[1] | 0; \n } \n }\n\n if ((loc.last_line <= 0 || loc.last_line < loc.first_line) && following) {\n loc.last_line = following.first_line | 0;\n loc.last_column = following.first_column | 0;\n\n if (following.range) {\n loc.range[1] = actual.range[0] | 0; \n } \n }\n\n // plan C?: see if the 'current' location is useful/sane too:\n if (loc.first_line <= 0 && current && (loc.last_line <= 0 || current.last_line <= loc.last_line)) {\n loc.first_line = current.first_line | 0;\n loc.first_column = current.first_column | 0;\n\n if (current.range) {\n loc.range[0] = current.range[0] | 0; \n } \n }\n\n if (loc.last_line <= 0 && current && (loc.first_line <= 0 || current.first_line >= loc.first_line)) {\n loc.last_line = current.last_line | 0;\n loc.last_column = current.last_column | 0;\n\n if (current.range) {\n loc.range[1] = current.range[1] | 0; \n } \n }\n }\n // sanitize: fix last_line BEFORE we fix first_line as we use the 'raw' value of the latter\n // or plan D heuristics to produce a 'sensible' last_line value:\n if (loc.last_line <= 0) {\n if (loc.first_line <= 0) {\n loc.first_line = this.yylloc.first_line;\n loc.last_line = this.yylloc.last_line;\n loc.first_column = this.yylloc.first_column;\n loc.last_column = this.yylloc.last_column;\n\n loc.range[0] = this.yylloc.range[0];\n loc.range[1] = this.yylloc.range[1];\n } else {\n loc.last_line = this.yylloc.last_line;\n loc.last_column = this.yylloc.last_column;\n\n loc.range[1] = this.yylloc.range[1];\n }\n }\n if (loc.first_line <= 0) {\n loc.first_line = loc.last_line;\n loc.first_column = 0; // loc.last_column;\n\n loc.range[1] = loc.range[0];\n }\n if (loc.first_column < 0) {\n loc.first_column = 0;\n }\n if (loc.last_column < 0) {\n loc.last_column = (loc.first_column > 0 ? loc.first_column : 80);\n }\n return loc;\n },\n\n /**\n * return a string which displays the lines & columns of input which are referenced \n * by the given location info range, plus a few lines of context.\n * \n * This function pretty-prints the indicated section of the input, with line numbers \n * and everything!\n * \n * This function is very useful to provide highly readable error reports, while\n * the location range may be specified in various flexible ways:\n * \n * - `loc` is the location info object which references the area which should be\n * displayed and 'marked up': these lines & columns of text are marked up by `^`\n * characters below each character in the entire input range.\n * \n * - `context_loc` is the *optional* location info object which instructs this\n * pretty-printer how much *leading* context should be displayed alongside\n * the area referenced by `loc`. This can help provide context for the displayed\n * error, etc.\n * \n * When this location info is not provided, a default context of 3 lines is\n * used.\n * \n * - `context_loc2` is another *optional* location info object, which serves\n * a similar purpose to `context_loc`: it specifies the amount of *trailing*\n * context lines to display in the pretty-print output.\n * \n * When this location info is not provided, a default context of 1 line only is\n * used.\n * \n * Special Notes:\n * \n * - when the `loc`-indicated range is very large (about 5 lines or more), then\n * only the first and last few lines of this block are printed while a\n * `...continued...` message will be printed between them.\n * \n * This serves the purpose of not printing a huge amount of text when the `loc`\n * range happens to be huge: this way a manageable & readable output results\n * for arbitrary large ranges.\n * \n * - this function can display lines of input which whave not yet been lexed.\n * `prettyPrintRange()` can access the entire input!\n * \n * @public\n * @this {RegExpLexer}\n */\n prettyPrintRange: function lexer_prettyPrintRange(loc, context_loc, context_loc2) {\n loc = this.deriveLocationInfo(loc, context_loc, context_loc2); \n const CONTEXT = 3;\n const CONTEXT_TAIL = 1;\n const MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT = 2;\n var input = this.matched + this._input;\n var lines = input.split('\\n');\n var l0 = Math.max(1, (context_loc ? context_loc.first_line : loc.first_line - CONTEXT));\n var l1 = Math.max(1, (context_loc2 ? context_loc2.last_line : loc.last_line + CONTEXT_TAIL));\n var lineno_display_width = (1 + Math.log10(l1 | 1) | 0);\n var ws_prefix = new Array(lineno_display_width).join(' ');\n var nonempty_line_indexes = [];\n var rv = lines.slice(l0 - 1, l1 + 1).map(function injectLineNumber(line, index) {\n var lno = index + l0;\n var lno_pfx = (ws_prefix + lno).substr(-lineno_display_width);\n var rv = lno_pfx + ': ' + line;\n var errpfx = (new Array(lineno_display_width + 1)).join('^');\n var offset = 2 + 1;\n var len = 0;\n\n if (lno === loc.first_line) {\n offset += loc.first_column;\n\n len = Math.max(\n 2,\n ((lno === loc.last_line ? loc.last_column : line.length)) - loc.first_column + 1\n );\n } else if (lno === loc.last_line) {\n len = Math.max(2, loc.last_column + 1);\n } else if (lno > loc.first_line && lno < loc.last_line) {\n len = Math.max(2, line.length + 1);\n }\n\n if (len) {\n var lead = new Array(offset).join('.');\n var mark = new Array(len).join('^');\n rv += '\\n' + errpfx + lead + mark;\n\n if (line.trim().length > 0) {\n nonempty_line_indexes.push(index);\n }\n }\n\n rv = rv.replace(/\\t/g, ' ');\n return rv;\n });\n\n // now make sure we don't print an overly large amount of error area: limit it \n // to the top and bottom line count:\n if (nonempty_line_indexes.length > 2 * MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT) {\n var clip_start = nonempty_line_indexes[MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT - 1] + 1;\n var clip_end = nonempty_line_indexes[nonempty_line_indexes.length - MINIMUM_VISIBLE_NONEMPTY_LINE_COUNT] - 1;\n\n var intermediate_line = (new Array(lineno_display_width + 1)).join(' ') + ' (...continued...)';\n intermediate_line += '\\n' + (new Array(lineno_display_width + 1)).join('-') + ' (---------------)';\n rv.splice(clip_start, clip_end - clip_start + 1, intermediate_line);\n }\n return rv.join('\\n');\n },\n\n /**\n * helper function, used to produce a human readable description as a string, given\n * the input `yylloc` location object.\n * \n * Set `display_range_too` to TRUE to include the string character index position(s)\n * in the description if the `yylloc.range` is available.\n * \n * @public\n * @this {RegExpLexer}\n */\n describeYYLLOC: function lexer_describe_yylloc(yylloc, display_range_too) {\n var l1 = yylloc.first_line;\n var l2 = yylloc.last_line;\n var c1 = yylloc.first_column;\n var c2 = yylloc.last_column;\n var dl = l2 - l1;\n var dc = c2 - c1;\n var rv;\n if (dl === 0) {\n rv = 'line ' + l1 + ', ';\n if (dc <= 1) {\n rv += 'column ' + c1;\n } else {\n rv += 'columns ' + c1 + ' .. ' + c2;\n }\n } else {\n rv = 'lines ' + l1 + '(column ' + c1 + ') .. ' + l2 + '(column ' + c2 + ')';\n }\n if (yylloc.range && display_range_too) {\n var r1 = yylloc.range[0];\n var r2 = yylloc.range[1] - 1;\n if (r2 <= r1) {\n rv += ' {String Offset: ' + r1 + '}';\n } else {\n rv += ' {String Offset range: ' + r1 + ' .. ' + r2 + '}';\n }\n }\n return rv;\n },\n\n /**\n * test the lexed token: return FALSE when not a match, otherwise return token.\n * \n * `match` is supposed to be an array coming out of a regex match, i.e. `match[0]`\n * contains the actually matched text string.\n * \n * Also move the input cursor forward and update the match collectors:\n * \n * - `yytext`\n * - `yyleng`\n * - `match`\n * - `matches`\n * - `yylloc`\n * - `offset`\n * \n * @public\n * @this {RegExpLexer}\n */\n test_match: function lexer_test_match(match, indexed_rule) {\n var token,\n lines,\n backup,\n match_str,\n match_str_len;\n\n if (this.options.backtrack_lexer) {\n // save context\n backup = {\n yylineno: this.yylineno,\n yylloc: {\n first_line: this.yylloc.first_line,\n last_line: this.yylloc.last_line,\n first_column: this.yylloc.first_column,\n last_column: this.yylloc.last_column,\n\n range: this.yylloc.range.slice(0)\n },\n yytext: this.yytext,\n match: this.match,\n matches: this.matches,\n matched: this.matched,\n yyleng: this.yyleng,\n offset: this.offset,\n _more: this._more,\n _input: this._input,\n //_signaled_error_token: this._signaled_error_token,\n yy: this.yy,\n conditionStack: this.conditionStack.slice(0),\n done: this.done\n };\n }\n\n match_str = match[0];\n match_str_len = match_str.length;\n // if (match_str.indexOf('\\n') !== -1 || match_str.indexOf('\\r') !== -1) {\n lines = match_str.split(/(?:\\r\\n?|\\n)/g);\n if (lines.length > 1) {\n this.yylineno += lines.length - 1;\n\n this.yylloc.last_line = this.yylineno + 1;\n this.yylloc.last_column = lines[lines.length - 1].length;\n } else {\n this.yylloc.last_column += match_str_len;\n }\n // }\n this.yytext += match_str;\n this.match += match_str;\n this.matched += match_str;\n this.matches = match;\n this.yyleng = this.yytext.length;\n this.yylloc.range[1] += match_str_len;\n\n // previous lex rules MAY have invoked the `more()` API rather than producing a token:\n // those rules will already have moved this `offset` forward matching their match lengths,\n // hence we must only add our own match length now:\n this.offset += match_str_len;\n this._more = false;\n this._backtrack = false;\n this._input = this._input.slice(match_str_len);\n\n // calling this method:\n //\n // function lexer__performAction(yy, yyrulenumber, YY_START) {...}\n token = this.performAction.call(this, this.yy, indexed_rule, this.conditionStack[this.conditionStack.length - 1] /* = YY_START */);\n // otherwise, when the action codes are all simple return token statements:\n //token = this.simpleCaseActionClusters[indexed_rule];\n\n if (this.done && this._input) {\n this.done = false;\n }\n if (token) {\n return token;\n } else if (this._backtrack) {\n // recover context\n for (var k in backup) {\n this[k] = backup[k];\n }\n this.__currentRuleSet__ = null;\n return false; // rule action called reject() implying the next rule should be tested instead.\n } else if (this._signaled_error_token) {\n // produce one 'error' token as `.parseError()` in `reject()`\n // did not guarantee a failure signal by throwing an exception!\n token = this._signaled_error_token;\n this._signaled_error_token = false;\n return token;\n }\n return false;\n },\n\n /**\n * return next match in input\n * \n * @public\n * @this {RegExpLexer}\n */\n next: function lexer_next() {\n if (this.done) {\n this.clear();\n return this.EOF;\n }\n if (!this._input) {\n this.done = true;\n }\n\n var token,\n match,\n tempMatch,\n index;\n if (!this._more) {\n this.clear();\n }\n var spec = this.__currentRuleSet__;\n if (!spec) {\n // Update the ruleset cache as we apparently encountered a state change or just started lexing.\n // The cache is set up for fast lookup -- we assume a lexer will switch states much less often than it will\n // invoke the `lex()` token-producing API and related APIs, hence caching the set for direct access helps\n // speed up those activities a tiny bit.\n spec = this.__currentRuleSet__ = this._currentRules();\n // Check whether a *sane* condition has been pushed before: this makes the lexer robust against\n // user-programmer bugs such as https://github.com/zaach/jison-lex/issues/19\n if (!spec || !spec.rules) {\n var lineno_msg = '';\n if (this.options.trackPosition) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Internal lexer engine error' + lineno_msg + ': The lex grammar programmer pushed a non-existing condition name \"' + this.topState() + '\"; this is a fatal error and should be reported to the application programmer team!', false);\n // produce one 'error' token until this situation has been resolved, most probably by parse termination!\n return (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n }\n }\n\n var rule_ids = spec.rules;\n var regexes = spec.__rule_regexes;\n var len = spec.__rule_count;\n\n // Note: the arrays are 1-based, while `len` itself is a valid index,\n // hence the non-standard less-or-equal check in the next loop condition!\n for (var i = 1; i <= len; i++) {\n tempMatch = this._input.match(regexes[i]);\n if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {\n match = tempMatch;\n index = i;\n if (this.options.backtrack_lexer) {\n token = this.test_match(tempMatch, rule_ids[i]);\n if (token !== false) {\n return token;\n } else if (this._backtrack) {\n match = undefined;\n continue; // rule action called reject() implying a rule MISmatch.\n } else {\n // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)\n return false;\n }\n } else if (!this.options.flex) {\n break;\n }\n }\n }\n if (match) {\n token = this.test_match(match, rule_ids[index]);\n if (token !== false) {\n return token;\n }\n // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)\n return false;\n }\n if (!this._input) {\n this.done = true;\n this.clear();\n return this.EOF;\n } else {\n var lineno_msg = '';\n if (this.options.trackPosition) {\n lineno_msg = ' on line ' + (this.yylineno + 1);\n }\n var p = this.constructLexErrorInfo('Lexical error' + lineno_msg + ': Unrecognized text.', this.options.lexerErrorsAreRecoverable);\n\n var pendingInput = this._input;\n var activeCondition = this.topState();\n var conditionStackDepth = this.conditionStack.length;\n\n token = (this.parseError(p.errStr, p, this.JisonLexerError) || this.ERROR);\n if (token === this.ERROR) {\n // we can try to recover from a lexer error that `parseError()` did not 'recover' for us\n // by moving forward at least one character at a time IFF the (user-specified?) `parseError()`\n // has not consumed/modified any pending input or changed state in the error handler:\n if (!this.matches && \n // and make sure the input has been modified/consumed ...\n pendingInput === this._input &&\n // ...or the lexer state has been modified significantly enough\n // to merit a non-consuming error handling action right now.\n activeCondition === this.topState() && \n conditionStackDepth === this.conditionStack.length\n ) {\n this.input();\n }\n }\n return token;\n }\n },\n\n /**\n * return next match that has a token\n * \n * @public\n * @this {RegExpLexer}\n */\n lex: function lexer_lex() {\n var r;\n // allow the PRE/POST handlers set/modify the return token for maximum flexibility of the generated lexer:\n if (typeof this.pre_lex === 'function') {\n r = this.pre_lex.call(this, 0);\n }\n if (typeof this.options.pre_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.options.pre_lex.call(this, r) || r;\n }\n if (this.yy && typeof this.yy.pre_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.yy.pre_lex.call(this, r) || r;\n }\n\n while (!r) {\n r = this.next();\n }\n\n if (this.yy && typeof this.yy.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.yy.post_lex.call(this, r) || r;\n }\n if (typeof this.options.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.options.post_lex.call(this, r) || r;\n }\n if (typeof this.post_lex === 'function') {\n // (also account for a userdef function which does not return any value: keep the token as is)\n r = this.post_lex.call(this, r) || r;\n }\n return r;\n },\n\n /**\n * return next match that has a token. Identical to the `lex()` API but does not invoke any of the \n * `pre_lex()` nor any of the `post_lex()` callbacks.\n * \n * @public\n * @this {RegExpLexer}\n */\n fastLex: function lexer_fastLex() {\n var r;\n\n while (!r) {\n r = this.next();\n }\n\n return r;\n },\n\n /**\n * return info about the lexer state that can help a parser or other lexer API user to use the\n * most efficient means available. This API is provided to aid run-time performance for larger\n * systems which employ this lexer.\n * \n * @public\n * @this {RegExpLexer}\n */\n canIUse: function lexer_canIUse() {\n var rv = {\n fastLex: !(\n typeof this.pre_lex === 'function' ||\n typeof this.options.pre_lex === 'function' ||\n (this.yy && typeof this.yy.pre_lex === 'function') ||\n (this.yy && typeof this.yy.post_lex === 'function') ||\n typeof this.options.post_lex === 'function' ||\n typeof this.post_lex === 'function'\n ) && typeof this.fastLex === 'function',\n };\n return rv;\n },\n\n\n /**\n * backwards compatible alias for `pushState()`;\n * the latter is symmetrical with `popState()` and we advise to use\n * those APIs in any modern lexer code, rather than `begin()`.\n * \n * @public\n * @this {RegExpLexer}\n */\n begin: function lexer_begin(condition) {\n return this.pushState(condition);\n },\n\n /**\n * activates a new lexer condition state (pushes the new lexer\n * condition state onto the condition stack)\n * \n * @public\n * @this {RegExpLexer}\n */\n pushState: function lexer_pushState(condition) {\n this.conditionStack.push(condition);\n this.__currentRuleSet__ = null;\n return this;\n },\n\n /**\n * pop the previously active lexer condition state off the condition\n * stack\n * \n * @public\n * @this {RegExpLexer}\n */\n popState: function lexer_popState() {\n var n = this.conditionStack.length - 1;\n if (n > 0) {\n this.__currentRuleSet__ = null; \n return this.conditionStack.pop();\n } else {\n return this.conditionStack[0];\n }\n },\n\n /**\n * return the currently active lexer condition state; when an index\n * argument is provided it produces the N-th previous condition state,\n * if available\n * \n * @public\n * @this {RegExpLexer}\n */\n topState: function lexer_topState(n) {\n n = this.conditionStack.length - 1 - Math.abs(n || 0);\n if (n >= 0) {\n return this.conditionStack[n];\n } else {\n return 'INITIAL';\n }\n },\n\n /**\n * (internal) determine the lexer rule set which is active for the\n * currently active lexer condition state\n * \n * @public\n * @this {RegExpLexer}\n */\n _currentRules: function lexer__currentRules() {\n if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {\n return this.conditions[this.conditionStack[this.conditionStack.length - 1]];\n } else {\n return this.conditions['INITIAL'];\n }\n },\n\n /**\n * return the number of states currently on the stack\n * \n * @public\n * @this {RegExpLexer}\n */\n stateStackSize: function lexer_stateStackSize() {\n return this.conditionStack.length;\n },\n options: {\n trackPosition: true\n},\n JisonLexerError: JisonLexerError,\n performAction: function lexer__performAction(yy, yyrulenumber, YY_START) {\n var yy_ = this;\n\n \nvar YYSTATE = YY_START;\nswitch(yyrulenumber) {\ncase 0 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\s+ */ \n \nbreak;\ncase 2 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\w+ */ \n \n if (yy_.yytext === 'a') {\n return 'TOK_A'; \n } else {\n return 'WORD'; \n }\n \nbreak;\ndefault:\n return this.simpleCaseActionClusters[yyrulenumber];\n}\n },\n simpleCaseActionClusters: {\n\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\d+ */ \n 1 : 'NUMBER',\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\+ */ \n 3 : '+',\n /*! Conditions:: INITIAL */ \n /*! Rule:: $ */ \n 4 : 'EOF'\n},\n rules: [\n /* 0: */ /^(?:\\s+)/,\n/* 1: */ /^(?:\\d+)/,\n/* 2: */ /^(?:\\w+)/,\n/* 3: */ /^(?:\\+)/,\n/* 4: */ /^(?:$)/\n ],\n conditions: {\n \"INITIAL\": {\n rules: [\n 0,\n 1,\n 2,\n 3,\n 4\n ],\n inclusive: true\n }\n}\n};\n", + options: { + lexerActionsUseYYLENG: "???", + lexerActionsUseYYLINENO: "???", + lexerActionsUseYYTEXT: "???", + lexerActionsUseYYLOC: "???", + lexerActionsUseParseError: "???", + lexerActionsUseYYERROR: "???", + lexerActionsUseLocationTracking: "???", + lexerActionsUseMore: "???", + lexerActionsUseUnput: "???", + lexerActionsUseReject: "???", + lexerActionsUseLess: "???", + lexerActionsUseDisplayAPIs: "???", + lexerActionsUseDescribeYYLOC: "???", + lex_rule_dictionary: { + rules: [ + [ + "\\s+", + "" + ], + [ + "\\d+", + null + ], + [ + "\\w+", + null + ], + [ + "\\+", + null + ], + [ + "$", + null + ] + ] + }, + options: { + moduleType: "commonjs", + debug: false, + enableDebugLogs: false, + json: true, + dumpSourceCodeOnFailure: true, + throwErrorOnCompileFailure: true, + defaultModuleName: "lexer", + xregexp: false, + lexerErrorsAreRecoverable: false, + flex: false, + backtrack_lexer: false, + ranges: false, + trackPosition: true, + caseInsensitive: false, + exportSourceCode: false, + exportAST: false, + prettyCfg: true, + noMain: true + }, + moduleType: "commonjs", + conditions: { + INITIAL: { + rules: [ + 0, + 1, + 2, + 3, + 4 + ], + inclusive: true + } + }, + performAction: "function lexer__performAction(yy, yyrulenumber, YY_START) {\n var yy_ = this;\n\n \nvar YYSTATE = YY_START;\nswitch(yyrulenumber) {\ncase 0 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\s+ */ \n \nbreak;\ncase 2 : \n/*! Conditions:: INITIAL */ \n/*! Rule:: \\w+ */ \n \n if (yy_.yytext === 'a') {\n return 'TOK_A'; \n } else {\n return 'WORD'; \n }\n \nbreak;\ndefault:\n return this.simpleCaseActionClusters[yyrulenumber];\n}\n }", + caseHelperInclude: "{\n\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\d+ */ \n 1 : 'NUMBER',\n /*! Conditions:: INITIAL */ \n /*! Rule:: \\+ */ \n 3 : '+',\n /*! Conditions:: INITIAL */ \n /*! Rule:: $ */ \n 4 : 'EOF'\n}", + rules: [ + { + xregexp: { + captureNames: null, + source: "^(?:\\s+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\d+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\w+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:\\+)", + flags: "", + isNative: true + } + }, + { + xregexp: { + captureNames: null, + source: "^(?:$)", + flags: "", + isNative: true + } + } + ], + macros: {}, + regular_rule_count: 2, + simple_rule_count: 3, + conditionStack: [ + "INITIAL" + ], + actionInclude: "", + moduleInclude: "", + __in_rules_failure_analysis_mode__: false, + exportSourceCode: { + enabled: false + }, + is_custom_lexer: false + } + } +] \ No newline at end of file