if (typeof module === "object" && typeof module.exports === "object") module.exports = Lexer; Lexer.defunct = function (chr) { throw new Error("Unexpected character at index " + (this.index - 1) + ": " + chr); }; try { Lexer.engineHasStickySupport = typeof /(?:)/.sticky == 'boolean'; } catch (ignored) { Lexer.engineHasStickySupport = false; } try { Lexer.engineHasUnicodeSupport = typeof /(?:)/.unicode == 'boolean'; } catch (ignored) { Lexer.engineHasUnicodeSupport = false; } function Lexer(defunct) { if (typeof defunct !== "function") defunct = Lexer.defunct; var tokens = []; var rules = []; var remove = 0; this.state = 0; this.index = 0; this.input = ""; this.addRule = function (pattern, action, start) { var global = pattern.global; if (!global || Lexer.engineHasStickySupport && !pattern.sticky) { var flags = Lexer.engineHasStickySupport ? "gy" : "g"; if (pattern.multiline) flags += "m"; if (pattern.ignoreCase) flags += "i"; if (Lexer.engineHasUnicodeSupport && pattern.unicode) flags += "u"; pattern = new RegExp(pattern.source, flags); } if (Object.prototype.toString.call(start) !== "[object Array]") start = [0]; rules.push({ pattern: pattern, global: global, action: action, start: start }); return this; }; this.setInput = function (input) { remove = 0; this.state = 0; this.index = 0; tokens.length = 0; this.input = input; return this; }; this.lex = function () { if (tokens.length) return tokens.shift(); this.reject = true; while (this.index <= this.input.length) { var matches = scan.call(this).splice(remove); var index = this.index; while (matches.length) { if (this.reject) { var match = matches.shift(); var result = match.result; var length = match.length; this.index += length; this.reject = false; remove++; var token = match.action.apply(this, result); if (this.reject) this.index = result.index; else if (typeof token !== "undefined") { switch (Object.prototype.toString.call(token)) { case "[object Array]": tokens = token.slice(1); token = token[0]; default: if (length) remove = 0; return token; } } } else break; } var input = this.input; if (index < input.length) { if (this.reject) { remove = 0; var token = defunct.call(this, input.charAt(this.index++)); if (typeof token !== "undefined") { if (Object.prototype.toString.call(token) === "[object Array]") { tokens = token.slice(1); return token[0]; } else return token; } } else { if (this.index !== index) remove = 0; this.reject = true; } } else if (matches.length) this.reject = true; else break; } }; function scan() { var matches = []; var index = 0; var state = this.state; var lastIndex = this.index; var input = this.input; for (var i = 0, length = rules.length; i < length; i++) { var rule = rules[i]; var start = rule.start; var states = start.length; if ((!states || start.indexOf(state) >= 0) || (state % 2 && states === 1 && !start[0])) { var pattern = rule.pattern; pattern.lastIndex = lastIndex; var result = pattern.exec(input); if (result && result.index === lastIndex) { var j = matches.push({ result: result, action: rule.action, length: result[0].length }); if (rule.global) index = j; while (--j > index) { var k = j - 1; if (matches[j].length > matches[k].length) { var temple = matches[j]; matches[j] = matches[k]; matches[k] = temple; } } } } } return matches; } }