# HG changeset patch # User Mike Pavone # Date 1332097384 25200 # Node ID 3d1b8e96f5dc7ed51fb25215d228ac873772c973 Initial commit diff -r 000000000000 -r 3d1b8e96f5dc editor.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor.css Sun Mar 18 12:03:04 2012 -0700 @@ -0,0 +1,75 @@ + +body, html +{ + width: 100%; + height: 100%; + margin: 0; +} + +body > div +{ + margin: 0; +} + +.controls +{ + width: 15%; + height: 100%; + display: inline-block; + padding: 0; + margin: 0; + vertical-align: top; +} + +#src +{ + width: 70%; + display: inline-block; + padding: 0; + margin: 0; +} + +ul +{ + border-style: solid; + border-color: black; + border-width: 1px; + display: block; + padding: 2px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + height: 50%; + margin: 0; + overflow: auto; +} + +ul:first-child +{ + border-bottom-width: 0px; +} + +#operators, .showops > #builtin +{ + display: none; +} + +.showops > #operators +{ + display: block; +} + +li +{ + display: inline-block; + border-style: solid; + border-color: lightgrey; + border-width: 1px; + padding: 2px; + margin: 4px; + min-width: 9mm; + min-height: 9mm; + cursor: pointer; +} + + diff -r 000000000000 -r 3d1b8e96f5dc editor.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor.js Sun Mar 18 12:03:04 2012 -0700 @@ -0,0 +1,15 @@ + + +onReady(function() { + each(qall('li'), function (idx,el) { + el.onclick = function (event) { + q('#src').innerHTML += el.innerHTML; + }; + }); + q('#ops_button').onclick = function (event) { + addClass(this.parentNode.parentNode, 'showops'); + }; + q('#builtin_button').onclick = function (event) { + removeClass(this.parentNode.parentNode, 'showops'); + }; +}); diff -r 000000000000 -r 3d1b8e96f5dc index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/index.html Sun Mar 18 12:03:04 2012 -0700 @@ -0,0 +1,35 @@ + + + + Awesome! + + + + + +
+ + + +
+ + +
+ + diff -r 000000000000 -r 3d1b8e96f5dc mquery.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mquery.js Sun Mar 18 12:03:04 2012 -0700 @@ -0,0 +1,70 @@ +function each(container, fun) +{ + if (container instanceof Array) { + for (var i = 0; i < container.length; i++) { + fun(i, conatiner[i]); + } + } else { + for (var i in container) { + if (container.hasOwnProperty(i)) { + fun(i, container[i]); + } + } + } +} + +function q(query) +{ + return document.querySelector(query); +} +function qall(query) +{ + return document.querySelectorAll(query); +} + +function hide(el) +{ + el.style.display = 'none'; +} + +function show(el, dtype) +{ + if (dtype === undefined) { + dtype = 'block'; + } + el.style.display +} + +function onReady(fun) +{ + if (document.readyState == 'complete') { + fun(); + } else { + document.onreadystatechange = function() { + if (document.readyState == 'complete') { + fun(); + document.onreadystatechange = null; + } + } + } +} + +function addClass(el, classname) +{ + var classes = el.className.split(' '); + if (classes.indexOf(classname) == -1) { + classes.push(classname); + el.className = classes.join(' '); + } +} + +function removeClass(el, classname) +{ + var classes = el.className.split(' '); + var idx = classes.indexOf(classname); + if (idx > -1) { + classes.splice(idx, 1); + el.className = classes.join(' '); + } +} + diff -r 000000000000 -r 3d1b8e96f5dc parser.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parser.js Sun Mar 18 12:03:04 2012 -0700 @@ -0,0 +1,30 @@ +var grammar = +'start = addsub;' + +'addsub = left:muldiv " "* op:("+"/"-") " "* right:addsub [ \\n\\r]* { return {type: "op", left: left, op: op, right: right }; } / muldiv;'+ +'muldiv = left:primlitsym " "* op:("*"/"/") " "* right:muldiv { return {type: "op", left: left, op: op, right: right }; } / primlitsym;'+ +'primlitsym = [ \\n\\r]* val:(float / int / string / symbol / object / lambda / "(" expr:addsub " "* ")" { return expr; }) { return val; };' + +'symbol = chars:[a-zA-Z_!?@]+ middle:[a-zA-Z_!?@0-9:]* trailing:[a-zA-Z_!?@0-9]* { return {type: "symbol", name: chars.join("") + middle.join("") + trailing.join("")}; };' + +'float = digits:[0-9]+ "." decimals:[0-9]+ { return {type: "floatlit", value: parseFloat(digits.join("") + "." + decimals.join("")) }; };' + +'int = digits:[0-9]+ { return {type: "intlit", value: parseInt(digits.join(""), 10)}; };' + +'string = "\\"" text:[^\\"]* "\\"" { return {type: "strlit", value: text.join("")}; };' + +'object = "#{" messages:assignment* "}" { return {type: "object", messages: messages}; };' + +'assignment = [ \\n\\r]* sym:symbol " "* "<-" expr:addsub { return {type: "assignment", symbol: sym, expression: expr}; }' + +'lambda = args:((& ":") argname+ )? "{" exprs:(assignment / addsub)* [ \\n\\r]* "}" { return {type: "lambda", args: args[1], expressions: exprs}; };' + +'argname = chars:[a-zA-Z_!?@:]+ trailing:[a-zA-Z_!?@0-9]* " "* { return {type: "symbol", name: chars.join("") + trailing.join("")}; };'; +var parser = PEG.buildParser(grammar); + +//var parser = PEG.buildParser('start = expr; expr = int; int = digits:[0-9]+ { return parseInt(digits.join(""), 10); }'); + +onReady(function() { + q('input[type=button]').onclick = function() { + var text = q('textarea').value; + try { + var parsed = parser.parse(text); + q('div').innerHTML = text + "

" + JSON.stringify(parsed); + console.log(parsed); + } catch(e) { + q('div').innerHTML = e.message + '
Line: ' + e.line + '
Col: ' + e.column; + } + } +}); + diff -r 000000000000 -r 3d1b8e96f5dc peg.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/peg.js Sun Mar 18 12:03:04 2012 -0700 @@ -0,0 +1,5141 @@ +/* PEG.js 0.6.2 (http://pegjs.majda.cz/) */ + +(function() { + +var undefined; + +var PEG = { + /* PEG.js version. */ + VERSION: "0.6.2", + + /* + * Generates a parser from a specified grammar and returns it. + * + * The grammar must be a string in the format described by the metagramar in + * the parser.pegjs file. + * + * Throws |PEG.parser.SyntaxError| if the grammar contains a syntax error or + * |PEG.GrammarError| if it contains a semantic error. Note that not all + * errors are detected during the generation and some may protrude to the + * generated parser and cause its malfunction. + */ + buildParser: function(grammar) { + return PEG.compiler.compile(PEG.parser.parse(grammar)); + } +}; + +/* Thrown when the grammar contains an error. */ + +PEG.GrammarError = function(message) { + this.name = "PEG.GrammarError"; + this.message = message; +}; + +PEG.GrammarError.prototype = Error.prototype; + +function contains(array, value) { + /* + * Stupid IE does not have Array.prototype.indexOf, otherwise this function + * would be a one-liner. + */ + var length = array.length; + for (var i = 0; i < length; i++) { + if (array[i] === value) { + return true; + } + } + return false; +} + +function each(array, callback) { + var length = array.length; + for (var i = 0; i < length; i++) { + callback(array[i]); + } +} + +function map(array, callback) { + var result = []; + var length = array.length; + for (var i = 0; i < length; i++) { + result[i] = callback(array[i]); + } + return result; +} + +/* + * Returns a string padded on the left to a desired length with a character. + * + * The code needs to be in sync with th code template in the compilation + * function for "action" nodes. + */ +function padLeft(input, padding, length) { + var result = input; + + var padLength = length - input.length; + for (var i = 0; i < padLength; i++) { + result = padding + result; + } + + return result; +} + +/* + * Returns an escape sequence for given character. Uses \x for characters <= + * 0xFF to save space, \u for the rest. + * + * The code needs to be in sync with th code template in the compilation + * function for "action" nodes. + */ +function escape(ch) { + var charCode = ch.charCodeAt(0); + + if (charCode <= 0xFF) { + var escapeChar = 'x'; + var length = 2; + } else { + var escapeChar = 'u'; + var length = 4; + } + + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); +} + +/* + * Surrounds the string with quotes and escapes characters inside so that the + * result is a valid JavaScript string. + * + * The code needs to be in sync with th code template in the compilation + * function for "action" nodes. + */ +function quote(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string + * literal except for the closing quote character, backslash, carriage return, + * line separator, paragraph separator, and line feed. Any character may + * appear in the form of an escape sequence. + * + * For portability, we also escape escape all non-ASCII characters. + */ + return '"' + s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\r/g, '\\r') // carriage return + .replace(/\n/g, '\\n') // line feed + .replace(/[\x80-\uFFFF]/g, escape) // non-ASCII characters + + '"'; +}; + +/* + * Escapes characters inside the string so that it can be used as a list of + * characters in a character class of a regular expression. + */ +function quoteForRegexpClass(s) { + /* + * Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1. + * + * For portability, we also escape escape all non-ASCII characters. + */ + return s + .replace(/\\/g, '\\\\') // backslash + .replace(/\0/g, '\\0') // null, IE needs this + .replace(/\//g, '\\/') // closing slash + .replace(/]/g, '\\]') // closing bracket + .replace(/-/g, '\\-') // dash + .replace(/\r/g, '\\r') // carriage return + .replace(/\n/g, '\\n') // line feed + .replace(/[\x80-\uFFFF]/g, escape) // non-ASCII characters +} + +/* + * Builds a node visitor -- a function which takes a node and any number of + * other parameters, calls an appropriate function according to the node type, + * passes it all its parameters and returns its value. The functions for various + * node types are passed in a parameter to |buildNodeVisitor| as a hash. + */ +function buildNodeVisitor(functions) { + return function(node) { + return functions[node.type].apply(null, arguments); + } +} +PEG.parser = (function(){ + /* Generated by PEG.js 0.6.2 (http://pegjs.majda.cz/). */ + + var result = { + /* + * Parses the input with a generated parser. If the parsing is successfull, + * returns a value explicitly or implicitly specified by the grammar from + * which the parser was generated (see |PEG.buildParser|). If the parsing is + * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. + */ + parse: function(input, startRule) { + var parseFunctions = { + "__": parse___, + "action": parse_action, + "and": parse_and, + "braced": parse_braced, + "bracketDelimitedCharacter": parse_bracketDelimitedCharacter, + "choice": parse_choice, + "class": parse_class, + "classCharacter": parse_classCharacter, + "classCharacterRange": parse_classCharacterRange, + "colon": parse_colon, + "comment": parse_comment, + "digit": parse_digit, + "dot": parse_dot, + "doubleQuotedCharacter": parse_doubleQuotedCharacter, + "doubleQuotedLiteral": parse_doubleQuotedLiteral, + "eol": parse_eol, + "eolChar": parse_eolChar, + "eolEscapeSequence": parse_eolEscapeSequence, + "equals": parse_equals, + "grammar": parse_grammar, + "hexDigit": parse_hexDigit, + "hexEscapeSequence": parse_hexEscapeSequence, + "identifier": parse_identifier, + "initializer": parse_initializer, + "labeled": parse_labeled, + "letter": parse_letter, + "literal": parse_literal, + "lowerCaseLetter": parse_lowerCaseLetter, + "lparen": parse_lparen, + "multiLineComment": parse_multiLineComment, + "nonBraceCharacter": parse_nonBraceCharacter, + "nonBraceCharacters": parse_nonBraceCharacters, + "not": parse_not, + "plus": parse_plus, + "prefixed": parse_prefixed, + "primary": parse_primary, + "question": parse_question, + "rparen": parse_rparen, + "rule": parse_rule, + "semicolon": parse_semicolon, + "sequence": parse_sequence, + "simpleBracketDelimitedCharacter": parse_simpleBracketDelimitedCharacter, + "simpleDoubleQuotedCharacter": parse_simpleDoubleQuotedCharacter, + "simpleEscapeSequence": parse_simpleEscapeSequence, + "simpleSingleQuotedCharacter": parse_simpleSingleQuotedCharacter, + "singleLineComment": parse_singleLineComment, + "singleQuotedCharacter": parse_singleQuotedCharacter, + "singleQuotedLiteral": parse_singleQuotedLiteral, + "slash": parse_slash, + "star": parse_star, + "suffixed": parse_suffixed, + "unicodeEscapeSequence": parse_unicodeEscapeSequence, + "upperCaseLetter": parse_upperCaseLetter, + "whitespace": parse_whitespace, + "zeroEscapeSequence": parse_zeroEscapeSequence + }; + + if (startRule !== undefined) { + if (parseFunctions[startRule] === undefined) { + throw new Error("Invalid rule name: " + quote(startRule) + "."); + } + } else { + startRule = "grammar"; + } + + var pos = 0; + var reportMatchFailures = true; + var rightmostMatchFailuresPos = 0; + var rightmostMatchFailuresExpected = []; + var cache = {}; + + function padLeft(input, padding, length) { + var result = input; + + var padLength = length - input.length; + for (var i = 0; i < padLength; i++) { + result = padding + result; + } + + return result; + } + + function escape(ch) { + var charCode = ch.charCodeAt(0); + + if (charCode <= 0xFF) { + var escapeChar = 'x'; + var length = 2; + } else { + var escapeChar = 'u'; + var length = 4; + } + + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); + } + + function quote(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a + * string literal except for the closing quote character, backslash, + * carriage return, line separator, paragraph separator, and line feed. + * Any character may appear in the form of an escape sequence. + */ + return '"' + s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\r/g, '\\r') // carriage return + .replace(/\n/g, '\\n') // line feed + .replace(/[\x80-\uFFFF]/g, escape) // non-ASCII characters + + '"'; + } + + function matchFailed(failure) { + if (pos < rightmostMatchFailuresPos) { + return; + } + + if (pos > rightmostMatchFailuresPos) { + rightmostMatchFailuresPos = pos; + rightmostMatchFailuresExpected = []; + } + + rightmostMatchFailuresExpected.push(failure); + } + + function parse_grammar() { + var cacheKey = 'grammar@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var result3 = parse___(); + if (result3 !== null) { + var result7 = parse_initializer(); + var result4 = result7 !== null ? result7 : ''; + if (result4 !== null) { + var result6 = parse_rule(); + if (result6 !== null) { + var result5 = []; + while (result6 !== null) { + result5.push(result6); + var result6 = parse_rule(); + } + } else { + var result5 = null; + } + if (result5 !== null) { + var result1 = [result3, result4, result5]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(initializer, rules) { + var rulesConverted = {}; + each(rules, function(rule) { rulesConverted[rule.name] = rule; }); + + return { + type: "grammar", + initializer: initializer !== "" ? initializer : null, + rules: rulesConverted, + startRule: rules[0].name + } + })(result1[1], result1[2]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_initializer() { + var cacheKey = 'initializer@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var result3 = parse_action(); + if (result3 !== null) { + var result5 = parse_semicolon(); + var result4 = result5 !== null ? result5 : ''; + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(code) { + return { + type: "initializer", + code: code + }; + })(result1[0]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_rule() { + var cacheKey = 'rule@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var result3 = parse_identifier(); + if (result3 !== null) { + var result10 = parse_literal(); + if (result10 !== null) { + var result4 = result10; + } else { + if (input.substr(pos, 0) === "") { + var result9 = ""; + pos += 0; + } else { + var result9 = null; + if (reportMatchFailures) { + matchFailed("\"\""); + } + } + if (result9 !== null) { + var result4 = result9; + } else { + var result4 = null;; + }; + } + if (result4 !== null) { + var result5 = parse_equals(); + if (result5 !== null) { + var result6 = parse_choice(); + if (result6 !== null) { + var result8 = parse_semicolon(); + var result7 = result8 !== null ? result8 : ''; + if (result7 !== null) { + var result1 = [result3, result4, result5, result6, result7]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(name, displayName, expression) { + return { + type: "rule", + name: name, + displayName: displayName !== "" ? displayName : null, + expression: expression + }; + })(result1[0], result1[1], result1[3]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_choice() { + var cacheKey = 'choice@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var result3 = parse_sequence(); + if (result3 !== null) { + var result4 = []; + var savedPos2 = pos; + var result6 = parse_slash(); + if (result6 !== null) { + var result7 = parse_sequence(); + if (result7 !== null) { + var result5 = [result6, result7]; + } else { + var result5 = null; + pos = savedPos2; + } + } else { + var result5 = null; + pos = savedPos2; + } + while (result5 !== null) { + result4.push(result5); + var savedPos2 = pos; + var result6 = parse_slash(); + if (result6 !== null) { + var result7 = parse_sequence(); + if (result7 !== null) { + var result5 = [result6, result7]; + } else { + var result5 = null; + pos = savedPos2; + } + } else { + var result5 = null; + pos = savedPos2; + } + } + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(head, tail) { + if (tail.length > 0) { + var alternatives = [head].concat(map( + tail, + function(element) { return element[1]; } + )); + return { + type: "choice", + alternatives: alternatives + } + } else { + return head; + } + })(result1[0], result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_sequence() { + var cacheKey = 'sequence@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos1 = pos; + var savedPos2 = pos; + var result8 = []; + var result10 = parse_labeled(); + while (result10 !== null) { + result8.push(result10); + var result10 = parse_labeled(); + } + if (result8 !== null) { + var result9 = parse_action(); + if (result9 !== null) { + var result6 = [result8, result9]; + } else { + var result6 = null; + pos = savedPos2; + } + } else { + var result6 = null; + pos = savedPos2; + } + var result7 = result6 !== null + ? (function(elements, code) { + var expression = elements.length != 1 + ? { + type: "sequence", + elements: elements + } + : elements[0]; + return { + type: "action", + expression: expression, + code: code + }; + })(result6[0], result6[1]) + : null; + if (result7 !== null) { + var result5 = result7; + } else { + var result5 = null; + pos = savedPos1; + } + if (result5 !== null) { + var result0 = result5; + } else { + var savedPos0 = pos; + var result2 = []; + var result4 = parse_labeled(); + while (result4 !== null) { + result2.push(result4); + var result4 = parse_labeled(); + } + var result3 = result2 !== null + ? (function(elements) { + return elements.length != 1 + ? { + type: "sequence", + elements: elements + } + : elements[0]; + })(result2) + : null; + if (result3 !== null) { + var result1 = result3; + } else { + var result1 = null; + pos = savedPos0; + } + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_labeled() { + var cacheKey = 'labeled@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var result5 = parse_identifier(); + if (result5 !== null) { + var result6 = parse_colon(); + if (result6 !== null) { + var result7 = parse_prefixed(); + if (result7 !== null) { + var result3 = [result5, result6, result7]; + } else { + var result3 = null; + pos = savedPos1; + } + } else { + var result3 = null; + pos = savedPos1; + } + } else { + var result3 = null; + pos = savedPos1; + } + var result4 = result3 !== null + ? (function(label, expression) { + return { + type: "labeled", + label: label, + expression: expression + }; + })(result3[0], result3[2]) + : null; + if (result4 !== null) { + var result2 = result4; + } else { + var result2 = null; + pos = savedPos0; + } + if (result2 !== null) { + var result0 = result2; + } else { + var result1 = parse_prefixed(); + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_prefixed() { + var cacheKey = 'prefixed@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos6 = pos; + var savedPos7 = pos; + var result20 = parse_and(); + if (result20 !== null) { + var result21 = parse_action(); + if (result21 !== null) { + var result18 = [result20, result21]; + } else { + var result18 = null; + pos = savedPos7; + } + } else { + var result18 = null; + pos = savedPos7; + } + var result19 = result18 !== null + ? (function(code) { + return { + type: "semantic_and", + code: code + }; + })(result18[1]) + : null; + if (result19 !== null) { + var result17 = result19; + } else { + var result17 = null; + pos = savedPos6; + } + if (result17 !== null) { + var result0 = result17; + } else { + var savedPos4 = pos; + var savedPos5 = pos; + var result15 = parse_and(); + if (result15 !== null) { + var result16 = parse_suffixed(); + if (result16 !== null) { + var result13 = [result15, result16]; + } else { + var result13 = null; + pos = savedPos5; + } + } else { + var result13 = null; + pos = savedPos5; + } + var result14 = result13 !== null + ? (function(expression) { + return { + type: "simple_and", + expression: expression + }; + })(result13[1]) + : null; + if (result14 !== null) { + var result12 = result14; + } else { + var result12 = null; + pos = savedPos4; + } + if (result12 !== null) { + var result0 = result12; + } else { + var savedPos2 = pos; + var savedPos3 = pos; + var result10 = parse_not(); + if (result10 !== null) { + var result11 = parse_action(); + if (result11 !== null) { + var result8 = [result10, result11]; + } else { + var result8 = null; + pos = savedPos3; + } + } else { + var result8 = null; + pos = savedPos3; + } + var result9 = result8 !== null + ? (function(code) { + return { + type: "semantic_not", + code: code + }; + })(result8[1]) + : null; + if (result9 !== null) { + var result7 = result9; + } else { + var result7 = null; + pos = savedPos2; + } + if (result7 !== null) { + var result0 = result7; + } else { + var savedPos0 = pos; + var savedPos1 = pos; + var result5 = parse_not(); + if (result5 !== null) { + var result6 = parse_suffixed(); + if (result6 !== null) { + var result3 = [result5, result6]; + } else { + var result3 = null; + pos = savedPos1; + } + } else { + var result3 = null; + pos = savedPos1; + } + var result4 = result3 !== null + ? (function(expression) { + return { + type: "simple_not", + expression: expression + }; + })(result3[1]) + : null; + if (result4 !== null) { + var result2 = result4; + } else { + var result2 = null; + pos = savedPos0; + } + if (result2 !== null) { + var result0 = result2; + } else { + var result1 = parse_suffixed(); + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + }; + }; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_suffixed() { + var cacheKey = 'suffixed@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos4 = pos; + var savedPos5 = pos; + var result15 = parse_primary(); + if (result15 !== null) { + var result16 = parse_question(); + if (result16 !== null) { + var result13 = [result15, result16]; + } else { + var result13 = null; + pos = savedPos5; + } + } else { + var result13 = null; + pos = savedPos5; + } + var result14 = result13 !== null + ? (function(expression) { + return { + type: "optional", + expression: expression + }; + })(result13[0]) + : null; + if (result14 !== null) { + var result12 = result14; + } else { + var result12 = null; + pos = savedPos4; + } + if (result12 !== null) { + var result0 = result12; + } else { + var savedPos2 = pos; + var savedPos3 = pos; + var result10 = parse_primary(); + if (result10 !== null) { + var result11 = parse_star(); + if (result11 !== null) { + var result8 = [result10, result11]; + } else { + var result8 = null; + pos = savedPos3; + } + } else { + var result8 = null; + pos = savedPos3; + } + var result9 = result8 !== null + ? (function(expression) { + return { + type: "zero_or_more", + expression: expression + }; + })(result8[0]) + : null; + if (result9 !== null) { + var result7 = result9; + } else { + var result7 = null; + pos = savedPos2; + } + if (result7 !== null) { + var result0 = result7; + } else { + var savedPos0 = pos; + var savedPos1 = pos; + var result5 = parse_primary(); + if (result5 !== null) { + var result6 = parse_plus(); + if (result6 !== null) { + var result3 = [result5, result6]; + } else { + var result3 = null; + pos = savedPos1; + } + } else { + var result3 = null; + pos = savedPos1; + } + var result4 = result3 !== null + ? (function(expression) { + return { + type: "one_or_more", + expression: expression + }; + })(result3[0]) + : null; + if (result4 !== null) { + var result2 = result4; + } else { + var result2 = null; + pos = savedPos0; + } + if (result2 !== null) { + var result0 = result2; + } else { + var result1 = parse_primary(); + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + }; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_primary() { + var cacheKey = 'primary@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos4 = pos; + var savedPos5 = pos; + var result17 = parse_identifier(); + if (result17 !== null) { + var savedPos6 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + var savedPos7 = pos; + var result23 = parse_literal(); + if (result23 !== null) { + var result20 = result23; + } else { + if (input.substr(pos, 0) === "") { + var result22 = ""; + pos += 0; + } else { + var result22 = null; + if (reportMatchFailures) { + matchFailed("\"\""); + } + } + if (result22 !== null) { + var result20 = result22; + } else { + var result20 = null;; + }; + } + if (result20 !== null) { + var result21 = parse_equals(); + if (result21 !== null) { + var result19 = [result20, result21]; + } else { + var result19 = null; + pos = savedPos7; + } + } else { + var result19 = null; + pos = savedPos7; + } + reportMatchFailures = savedReportMatchFailuresVar0; + if (result19 === null) { + var result18 = ''; + } else { + var result18 = null; + pos = savedPos6; + } + if (result18 !== null) { + var result15 = [result17, result18]; + } else { + var result15 = null; + pos = savedPos5; + } + } else { + var result15 = null; + pos = savedPos5; + } + var result16 = result15 !== null + ? (function(name) { + return { + type: "rule_ref", + name: name + }; + })(result15[0]) + : null; + if (result16 !== null) { + var result14 = result16; + } else { + var result14 = null; + pos = savedPos4; + } + if (result14 !== null) { + var result0 = result14; + } else { + var savedPos3 = pos; + var result12 = parse_literal(); + var result13 = result12 !== null + ? (function(value) { + return { + type: "literal", + value: value + }; + })(result12) + : null; + if (result13 !== null) { + var result11 = result13; + } else { + var result11 = null; + pos = savedPos3; + } + if (result11 !== null) { + var result0 = result11; + } else { + var savedPos2 = pos; + var result9 = parse_dot(); + var result10 = result9 !== null + ? (function() { return { type: "any" }; })() + : null; + if (result10 !== null) { + var result8 = result10; + } else { + var result8 = null; + pos = savedPos2; + } + if (result8 !== null) { + var result0 = result8; + } else { + var result7 = parse_class(); + if (result7 !== null) { + var result0 = result7; + } else { + var savedPos0 = pos; + var savedPos1 = pos; + var result4 = parse_lparen(); + if (result4 !== null) { + var result5 = parse_choice(); + if (result5 !== null) { + var result6 = parse_rparen(); + if (result6 !== null) { + var result2 = [result4, result5, result6]; + } else { + var result2 = null; + pos = savedPos1; + } + } else { + var result2 = null; + pos = savedPos1; + } + } else { + var result2 = null; + pos = savedPos1; + } + var result3 = result2 !== null + ? (function(expression) { return expression; })(result2[1]) + : null; + if (result3 !== null) { + var result1 = result3; + } else { + var result1 = null; + pos = savedPos0; + } + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + }; + }; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_action() { + var cacheKey = 'action@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var savedReportMatchFailures = reportMatchFailures; + reportMatchFailures = false; + var savedPos0 = pos; + var savedPos1 = pos; + var result3 = parse_braced(); + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(braced) { return braced.substr(1, braced.length - 2); })(result1[0]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + reportMatchFailures = savedReportMatchFailures; + if (reportMatchFailures && result0 === null) { + matchFailed("action"); + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_braced() { + var cacheKey = 'braced@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "{") { + var result3 = "{"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"{\""); + } + } + if (result3 !== null) { + var result4 = []; + var result8 = parse_braced(); + if (result8 !== null) { + var result6 = result8; + } else { + var result7 = parse_nonBraceCharacter(); + if (result7 !== null) { + var result6 = result7; + } else { + var result6 = null;; + }; + } + while (result6 !== null) { + result4.push(result6); + var result8 = parse_braced(); + if (result8 !== null) { + var result6 = result8; + } else { + var result7 = parse_nonBraceCharacter(); + if (result7 !== null) { + var result6 = result7; + } else { + var result6 = null;; + }; + } + } + if (result4 !== null) { + if (input.substr(pos, 1) === "}") { + var result5 = "}"; + pos += 1; + } else { + var result5 = null; + if (reportMatchFailures) { + matchFailed("\"}\""); + } + } + if (result5 !== null) { + var result1 = [result3, result4, result5]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(parts) { + return "{" + parts.join("") + "}"; + })(result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_nonBraceCharacters() { + var cacheKey = 'nonBraceCharacters@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var result3 = parse_nonBraceCharacter(); + if (result3 !== null) { + var result1 = []; + while (result3 !== null) { + result1.push(result3); + var result3 = parse_nonBraceCharacter(); + } + } else { + var result1 = null; + } + var result2 = result1 !== null + ? (function(chars) { return chars.join(""); })(result1) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_nonBraceCharacter() { + var cacheKey = 'nonBraceCharacter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + if (input.substr(pos).match(/^[^{}]/) !== null) { + var result0 = input.charAt(pos); + pos++; + } else { + var result0 = null; + if (reportMatchFailures) { + matchFailed("[^{}]"); + } + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_equals() { + var cacheKey = 'equals@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "=") { + var result3 = "="; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"=\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "="; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_colon() { + var cacheKey = 'colon@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === ":") { + var result3 = ":"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\":\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return ":"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_semicolon() { + var cacheKey = 'semicolon@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === ";") { + var result3 = ";"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\";\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return ";"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_slash() { + var cacheKey = 'slash@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "/") { + var result3 = "/"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"/\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "/"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_and() { + var cacheKey = 'and@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "&") { + var result3 = "&"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"&\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "&"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_not() { + var cacheKey = 'not@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "!") { + var result3 = "!"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"!\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "!"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_question() { + var cacheKey = 'question@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "?") { + var result3 = "?"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"?\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "?"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_star() { + var cacheKey = 'star@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "*") { + var result3 = "*"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"*\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "*"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_plus() { + var cacheKey = 'plus@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "+") { + var result3 = "+"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"+\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "+"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_lparen() { + var cacheKey = 'lparen@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "(") { + var result3 = "("; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"(\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "("; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_rparen() { + var cacheKey = 'rparen@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === ")") { + var result3 = ")"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\")\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return ")"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_dot() { + var cacheKey = 'dot@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === ".") { + var result3 = "."; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\".\""); + } + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "."; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_identifier() { + var cacheKey = 'identifier@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var savedReportMatchFailures = reportMatchFailures; + reportMatchFailures = false; + var savedPos0 = pos; + var savedPos1 = pos; + var result13 = parse_letter(); + if (result13 !== null) { + var result3 = result13; + } else { + if (input.substr(pos, 1) === "_") { + var result12 = "_"; + pos += 1; + } else { + var result12 = null; + if (reportMatchFailures) { + matchFailed("\"_\""); + } + } + if (result12 !== null) { + var result3 = result12; + } else { + if (input.substr(pos, 1) === "$") { + var result11 = "$"; + pos += 1; + } else { + var result11 = null; + if (reportMatchFailures) { + matchFailed("\"$\""); + } + } + if (result11 !== null) { + var result3 = result11; + } else { + var result3 = null;; + }; + }; + } + if (result3 !== null) { + var result4 = []; + var result10 = parse_letter(); + if (result10 !== null) { + var result6 = result10; + } else { + var result9 = parse_digit(); + if (result9 !== null) { + var result6 = result9; + } else { + if (input.substr(pos, 1) === "_") { + var result8 = "_"; + pos += 1; + } else { + var result8 = null; + if (reportMatchFailures) { + matchFailed("\"_\""); + } + } + if (result8 !== null) { + var result6 = result8; + } else { + if (input.substr(pos, 1) === "$") { + var result7 = "$"; + pos += 1; + } else { + var result7 = null; + if (reportMatchFailures) { + matchFailed("\"$\""); + } + } + if (result7 !== null) { + var result6 = result7; + } else { + var result6 = null;; + }; + }; + }; + } + while (result6 !== null) { + result4.push(result6); + var result10 = parse_letter(); + if (result10 !== null) { + var result6 = result10; + } else { + var result9 = parse_digit(); + if (result9 !== null) { + var result6 = result9; + } else { + if (input.substr(pos, 1) === "_") { + var result8 = "_"; + pos += 1; + } else { + var result8 = null; + if (reportMatchFailures) { + matchFailed("\"_\""); + } + } + if (result8 !== null) { + var result6 = result8; + } else { + if (input.substr(pos, 1) === "$") { + var result7 = "$"; + pos += 1; + } else { + var result7 = null; + if (reportMatchFailures) { + matchFailed("\"$\""); + } + } + if (result7 !== null) { + var result6 = result7; + } else { + var result6 = null;; + }; + }; + }; + } + } + if (result4 !== null) { + var result5 = parse___(); + if (result5 !== null) { + var result1 = [result3, result4, result5]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(head, tail) { + return head + tail.join(""); + })(result1[0], result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + reportMatchFailures = savedReportMatchFailures; + if (reportMatchFailures && result0 === null) { + matchFailed("identifier"); + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_literal() { + var cacheKey = 'literal@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var savedReportMatchFailures = reportMatchFailures; + reportMatchFailures = false; + var savedPos0 = pos; + var savedPos1 = pos; + var result6 = parse_doubleQuotedLiteral(); + if (result6 !== null) { + var result3 = result6; + } else { + var result5 = parse_singleQuotedLiteral(); + if (result5 !== null) { + var result3 = result5; + } else { + var result3 = null;; + }; + } + if (result3 !== null) { + var result4 = parse___(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(literal) { return literal; })(result1[0]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + reportMatchFailures = savedReportMatchFailures; + if (reportMatchFailures && result0 === null) { + matchFailed("literal"); + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_doubleQuotedLiteral() { + var cacheKey = 'doubleQuotedLiteral@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "\"") { + var result3 = "\""; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"\\\"\""); + } + } + if (result3 !== null) { + var result4 = []; + var result6 = parse_doubleQuotedCharacter(); + while (result6 !== null) { + result4.push(result6); + var result6 = parse_doubleQuotedCharacter(); + } + if (result4 !== null) { + if (input.substr(pos, 1) === "\"") { + var result5 = "\""; + pos += 1; + } else { + var result5 = null; + if (reportMatchFailures) { + matchFailed("\"\\\"\""); + } + } + if (result5 !== null) { + var result1 = [result3, result4, result5]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(chars) { return chars.join(""); })(result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_doubleQuotedCharacter() { + var cacheKey = 'doubleQuotedCharacter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var result6 = parse_simpleDoubleQuotedCharacter(); + if (result6 !== null) { + var result0 = result6; + } else { + var result5 = parse_simpleEscapeSequence(); + if (result5 !== null) { + var result0 = result5; + } else { + var result4 = parse_zeroEscapeSequence(); + if (result4 !== null) { + var result0 = result4; + } else { + var result3 = parse_hexEscapeSequence(); + if (result3 !== null) { + var result0 = result3; + } else { + var result2 = parse_unicodeEscapeSequence(); + if (result2 !== null) { + var result0 = result2; + } else { + var result1 = parse_eolEscapeSequence(); + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + }; + }; + }; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_simpleDoubleQuotedCharacter() { + var cacheKey = 'simpleDoubleQuotedCharacter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + if (input.substr(pos, 1) === "\"") { + var result8 = "\""; + pos += 1; + } else { + var result8 = null; + if (reportMatchFailures) { + matchFailed("\"\\\"\""); + } + } + if (result8 !== null) { + var result5 = result8; + } else { + if (input.substr(pos, 1) === "\\") { + var result7 = "\\"; + pos += 1; + } else { + var result7 = null; + if (reportMatchFailures) { + matchFailed("\"\\\\\""); + } + } + if (result7 !== null) { + var result5 = result7; + } else { + var result6 = parse_eolChar(); + if (result6 !== null) { + var result5 = result6; + } else { + var result5 = null;; + }; + }; + } + reportMatchFailures = savedReportMatchFailuresVar0; + if (result5 === null) { + var result3 = ''; + } else { + var result3 = null; + pos = savedPos2; + } + if (result3 !== null) { + if (input.length > pos) { + var result4 = input.charAt(pos); + pos++; + } else { + var result4 = null; + if (reportMatchFailures) { + matchFailed('any character'); + } + } + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(char_) { return char_; })(result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_singleQuotedLiteral() { + var cacheKey = 'singleQuotedLiteral@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "'") { + var result3 = "'"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"'\""); + } + } + if (result3 !== null) { + var result4 = []; + var result6 = parse_singleQuotedCharacter(); + while (result6 !== null) { + result4.push(result6); + var result6 = parse_singleQuotedCharacter(); + } + if (result4 !== null) { + if (input.substr(pos, 1) === "'") { + var result5 = "'"; + pos += 1; + } else { + var result5 = null; + if (reportMatchFailures) { + matchFailed("\"'\""); + } + } + if (result5 !== null) { + var result1 = [result3, result4, result5]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(chars) { return chars.join(""); })(result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_singleQuotedCharacter() { + var cacheKey = 'singleQuotedCharacter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var result6 = parse_simpleSingleQuotedCharacter(); + if (result6 !== null) { + var result0 = result6; + } else { + var result5 = parse_simpleEscapeSequence(); + if (result5 !== null) { + var result0 = result5; + } else { + var result4 = parse_zeroEscapeSequence(); + if (result4 !== null) { + var result0 = result4; + } else { + var result3 = parse_hexEscapeSequence(); + if (result3 !== null) { + var result0 = result3; + } else { + var result2 = parse_unicodeEscapeSequence(); + if (result2 !== null) { + var result0 = result2; + } else { + var result1 = parse_eolEscapeSequence(); + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + }; + }; + }; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_simpleSingleQuotedCharacter() { + var cacheKey = 'simpleSingleQuotedCharacter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + if (input.substr(pos, 1) === "'") { + var result8 = "'"; + pos += 1; + } else { + var result8 = null; + if (reportMatchFailures) { + matchFailed("\"'\""); + } + } + if (result8 !== null) { + var result5 = result8; + } else { + if (input.substr(pos, 1) === "\\") { + var result7 = "\\"; + pos += 1; + } else { + var result7 = null; + if (reportMatchFailures) { + matchFailed("\"\\\\\""); + } + } + if (result7 !== null) { + var result5 = result7; + } else { + var result6 = parse_eolChar(); + if (result6 !== null) { + var result5 = result6; + } else { + var result5 = null;; + }; + }; + } + reportMatchFailures = savedReportMatchFailuresVar0; + if (result5 === null) { + var result3 = ''; + } else { + var result3 = null; + pos = savedPos2; + } + if (result3 !== null) { + if (input.length > pos) { + var result4 = input.charAt(pos); + pos++; + } else { + var result4 = null; + if (reportMatchFailures) { + matchFailed('any character'); + } + } + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(char_) { return char_; })(result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_class() { + var cacheKey = 'class@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var savedReportMatchFailures = reportMatchFailures; + reportMatchFailures = false; + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "[") { + var result3 = "["; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"[\""); + } + } + if (result3 !== null) { + if (input.substr(pos, 1) === "^") { + var result11 = "^"; + pos += 1; + } else { + var result11 = null; + if (reportMatchFailures) { + matchFailed("\"^\""); + } + } + var result4 = result11 !== null ? result11 : ''; + if (result4 !== null) { + var result5 = []; + var result10 = parse_classCharacterRange(); + if (result10 !== null) { + var result8 = result10; + } else { + var result9 = parse_classCharacter(); + if (result9 !== null) { + var result8 = result9; + } else { + var result8 = null;; + }; + } + while (result8 !== null) { + result5.push(result8); + var result10 = parse_classCharacterRange(); + if (result10 !== null) { + var result8 = result10; + } else { + var result9 = parse_classCharacter(); + if (result9 !== null) { + var result8 = result9; + } else { + var result8 = null;; + }; + } + } + if (result5 !== null) { + if (input.substr(pos, 1) === "]") { + var result6 = "]"; + pos += 1; + } else { + var result6 = null; + if (reportMatchFailures) { + matchFailed("\"]\""); + } + } + if (result6 !== null) { + var result7 = parse___(); + if (result7 !== null) { + var result1 = [result3, result4, result5, result6, result7]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(inverted, parts) { + var partsConverted = map(parts, function(part) { return part.data; }); + var rawText = "[" + + inverted + + map(parts, function(part) { return part.rawText; }).join("") + + "]"; + + return { + type: "class", + inverted: inverted === "^", + parts: partsConverted, + // FIXME: Get the raw text from the input directly. + rawText: rawText + }; + })(result1[1], result1[2]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + reportMatchFailures = savedReportMatchFailures; + if (reportMatchFailures && result0 === null) { + matchFailed("character class"); + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_classCharacterRange() { + var cacheKey = 'classCharacterRange@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var result3 = parse_classCharacter(); + if (result3 !== null) { + if (input.substr(pos, 1) === "-") { + var result4 = "-"; + pos += 1; + } else { + var result4 = null; + if (reportMatchFailures) { + matchFailed("\"-\""); + } + } + if (result4 !== null) { + var result5 = parse_classCharacter(); + if (result5 !== null) { + var result1 = [result3, result4, result5]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(begin, end) { + if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) { + throw new this.SyntaxError( + "Invalid character range: " + begin.rawText + "-" + end.rawText + "." + ); + } + + return { + data: [begin.data, end.data], + // FIXME: Get the raw text from the input directly. + rawText: begin.rawText + "-" + end.rawText + } + })(result1[0], result1[2]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_classCharacter() { + var cacheKey = 'classCharacter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var result1 = parse_bracketDelimitedCharacter(); + var result2 = result1 !== null + ? (function(char_) { + return { + data: char_, + // FIXME: Get the raw text from the input directly. + rawText: quoteForRegexpClass(char_) + }; + })(result1) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_bracketDelimitedCharacter() { + var cacheKey = 'bracketDelimitedCharacter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var result6 = parse_simpleBracketDelimitedCharacter(); + if (result6 !== null) { + var result0 = result6; + } else { + var result5 = parse_simpleEscapeSequence(); + if (result5 !== null) { + var result0 = result5; + } else { + var result4 = parse_zeroEscapeSequence(); + if (result4 !== null) { + var result0 = result4; + } else { + var result3 = parse_hexEscapeSequence(); + if (result3 !== null) { + var result0 = result3; + } else { + var result2 = parse_unicodeEscapeSequence(); + if (result2 !== null) { + var result0 = result2; + } else { + var result1 = parse_eolEscapeSequence(); + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + }; + }; + }; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_simpleBracketDelimitedCharacter() { + var cacheKey = 'simpleBracketDelimitedCharacter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + if (input.substr(pos, 1) === "]") { + var result8 = "]"; + pos += 1; + } else { + var result8 = null; + if (reportMatchFailures) { + matchFailed("\"]\""); + } + } + if (result8 !== null) { + var result5 = result8; + } else { + if (input.substr(pos, 1) === "\\") { + var result7 = "\\"; + pos += 1; + } else { + var result7 = null; + if (reportMatchFailures) { + matchFailed("\"\\\\\""); + } + } + if (result7 !== null) { + var result5 = result7; + } else { + var result6 = parse_eolChar(); + if (result6 !== null) { + var result5 = result6; + } else { + var result5 = null;; + }; + }; + } + reportMatchFailures = savedReportMatchFailuresVar0; + if (result5 === null) { + var result3 = ''; + } else { + var result3 = null; + pos = savedPos2; + } + if (result3 !== null) { + if (input.length > pos) { + var result4 = input.charAt(pos); + pos++; + } else { + var result4 = null; + if (reportMatchFailures) { + matchFailed('any character'); + } + } + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(char_) { return char_; })(result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_simpleEscapeSequence() { + var cacheKey = 'simpleEscapeSequence@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "\\") { + var result3 = "\\"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"\\\\\""); + } + } + if (result3 !== null) { + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + var result10 = parse_digit(); + if (result10 !== null) { + var result6 = result10; + } else { + if (input.substr(pos, 1) === "x") { + var result9 = "x"; + pos += 1; + } else { + var result9 = null; + if (reportMatchFailures) { + matchFailed("\"x\""); + } + } + if (result9 !== null) { + var result6 = result9; + } else { + if (input.substr(pos, 1) === "u") { + var result8 = "u"; + pos += 1; + } else { + var result8 = null; + if (reportMatchFailures) { + matchFailed("\"u\""); + } + } + if (result8 !== null) { + var result6 = result8; + } else { + var result7 = parse_eolChar(); + if (result7 !== null) { + var result6 = result7; + } else { + var result6 = null;; + }; + }; + }; + } + reportMatchFailures = savedReportMatchFailuresVar0; + if (result6 === null) { + var result4 = ''; + } else { + var result4 = null; + pos = savedPos2; + } + if (result4 !== null) { + if (input.length > pos) { + var result5 = input.charAt(pos); + pos++; + } else { + var result5 = null; + if (reportMatchFailures) { + matchFailed('any character'); + } + } + if (result5 !== null) { + var result1 = [result3, result4, result5]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(char_) { + return char_ + .replace("b", "\b") + .replace("f", "\f") + .replace("n", "\n") + .replace("r", "\r") + .replace("t", "\t") + .replace("v", "\x0B") // IE does not recognize "\v". + })(result1[2]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_zeroEscapeSequence() { + var cacheKey = 'zeroEscapeSequence@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 2) === "\\0") { + var result3 = "\\0"; + pos += 2; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"\\\\0\""); + } + } + if (result3 !== null) { + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + var result5 = parse_digit(); + reportMatchFailures = savedReportMatchFailuresVar0; + if (result5 === null) { + var result4 = ''; + } else { + var result4 = null; + pos = savedPos2; + } + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function() { return "\0"; })() + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_hexEscapeSequence() { + var cacheKey = 'hexEscapeSequence@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 2) === "\\x") { + var result3 = "\\x"; + pos += 2; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"\\\\x\""); + } + } + if (result3 !== null) { + var result4 = parse_hexDigit(); + if (result4 !== null) { + var result5 = parse_hexDigit(); + if (result5 !== null) { + var result1 = [result3, result4, result5]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(h1, h2) { + return String.fromCharCode(parseInt("0x" + h1 + h2)); + })(result1[1], result1[2]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_unicodeEscapeSequence() { + var cacheKey = 'unicodeEscapeSequence@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 2) === "\\u") { + var result3 = "\\u"; + pos += 2; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"\\\\u\""); + } + } + if (result3 !== null) { + var result4 = parse_hexDigit(); + if (result4 !== null) { + var result5 = parse_hexDigit(); + if (result5 !== null) { + var result6 = parse_hexDigit(); + if (result6 !== null) { + var result7 = parse_hexDigit(); + if (result7 !== null) { + var result1 = [result3, result4, result5, result6, result7]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(h1, h2, h3, h4) { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); + })(result1[1], result1[2], result1[3], result1[4]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_eolEscapeSequence() { + var cacheKey = 'eolEscapeSequence@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + var savedPos1 = pos; + if (input.substr(pos, 1) === "\\") { + var result3 = "\\"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"\\\\\""); + } + } + if (result3 !== null) { + var result4 = parse_eol(); + if (result4 !== null) { + var result1 = [result3, result4]; + } else { + var result1 = null; + pos = savedPos1; + } + } else { + var result1 = null; + pos = savedPos1; + } + var result2 = result1 !== null + ? (function(eol) { return eol; })(result1[1]) + : null; + if (result2 !== null) { + var result0 = result2; + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_digit() { + var cacheKey = 'digit@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + if (input.substr(pos).match(/^[0-9]/) !== null) { + var result0 = input.charAt(pos); + pos++; + } else { + var result0 = null; + if (reportMatchFailures) { + matchFailed("[0-9]"); + } + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_hexDigit() { + var cacheKey = 'hexDigit@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + if (input.substr(pos).match(/^[0-9a-fA-F]/) !== null) { + var result0 = input.charAt(pos); + pos++; + } else { + var result0 = null; + if (reportMatchFailures) { + matchFailed("[0-9a-fA-F]"); + } + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_letter() { + var cacheKey = 'letter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var result2 = parse_lowerCaseLetter(); + if (result2 !== null) { + var result0 = result2; + } else { + var result1 = parse_upperCaseLetter(); + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_lowerCaseLetter() { + var cacheKey = 'lowerCaseLetter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + if (input.substr(pos).match(/^[a-z]/) !== null) { + var result0 = input.charAt(pos); + pos++; + } else { + var result0 = null; + if (reportMatchFailures) { + matchFailed("[a-z]"); + } + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_upperCaseLetter() { + var cacheKey = 'upperCaseLetter@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + if (input.substr(pos).match(/^[A-Z]/) !== null) { + var result0 = input.charAt(pos); + pos++; + } else { + var result0 = null; + if (reportMatchFailures) { + matchFailed("[A-Z]"); + } + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse___() { + var cacheKey = '__@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var result0 = []; + var result4 = parse_whitespace(); + if (result4 !== null) { + var result1 = result4; + } else { + var result3 = parse_eol(); + if (result3 !== null) { + var result1 = result3; + } else { + var result2 = parse_comment(); + if (result2 !== null) { + var result1 = result2; + } else { + var result1 = null;; + }; + }; + } + while (result1 !== null) { + result0.push(result1); + var result4 = parse_whitespace(); + if (result4 !== null) { + var result1 = result4; + } else { + var result3 = parse_eol(); + if (result3 !== null) { + var result1 = result3; + } else { + var result2 = parse_comment(); + if (result2 !== null) { + var result1 = result2; + } else { + var result1 = null;; + }; + }; + } + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_comment() { + var cacheKey = 'comment@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var savedReportMatchFailures = reportMatchFailures; + reportMatchFailures = false; + var result2 = parse_singleLineComment(); + if (result2 !== null) { + var result0 = result2; + } else { + var result1 = parse_multiLineComment(); + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + } + reportMatchFailures = savedReportMatchFailures; + if (reportMatchFailures && result0 === null) { + matchFailed("comment"); + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_singleLineComment() { + var cacheKey = 'singleLineComment@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + if (input.substr(pos, 2) === "//") { + var result1 = "//"; + pos += 2; + } else { + var result1 = null; + if (reportMatchFailures) { + matchFailed("\"//\""); + } + } + if (result1 !== null) { + var result2 = []; + var savedPos1 = pos; + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + var result6 = parse_eolChar(); + reportMatchFailures = savedReportMatchFailuresVar0; + if (result6 === null) { + var result4 = ''; + } else { + var result4 = null; + pos = savedPos2; + } + if (result4 !== null) { + if (input.length > pos) { + var result5 = input.charAt(pos); + pos++; + } else { + var result5 = null; + if (reportMatchFailures) { + matchFailed('any character'); + } + } + if (result5 !== null) { + var result3 = [result4, result5]; + } else { + var result3 = null; + pos = savedPos1; + } + } else { + var result3 = null; + pos = savedPos1; + } + while (result3 !== null) { + result2.push(result3); + var savedPos1 = pos; + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + var result6 = parse_eolChar(); + reportMatchFailures = savedReportMatchFailuresVar0; + if (result6 === null) { + var result4 = ''; + } else { + var result4 = null; + pos = savedPos2; + } + if (result4 !== null) { + if (input.length > pos) { + var result5 = input.charAt(pos); + pos++; + } else { + var result5 = null; + if (reportMatchFailures) { + matchFailed('any character'); + } + } + if (result5 !== null) { + var result3 = [result4, result5]; + } else { + var result3 = null; + pos = savedPos1; + } + } else { + var result3 = null; + pos = savedPos1; + } + } + if (result2 !== null) { + var result0 = [result1, result2]; + } else { + var result0 = null; + pos = savedPos0; + } + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_multiLineComment() { + var cacheKey = 'multiLineComment@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + var savedPos0 = pos; + if (input.substr(pos, 2) === "/*") { + var result1 = "/*"; + pos += 2; + } else { + var result1 = null; + if (reportMatchFailures) { + matchFailed("\"/*\""); + } + } + if (result1 !== null) { + var result2 = []; + var savedPos1 = pos; + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + if (input.substr(pos, 2) === "*/") { + var result7 = "*/"; + pos += 2; + } else { + var result7 = null; + if (reportMatchFailures) { + matchFailed("\"*/\""); + } + } + reportMatchFailures = savedReportMatchFailuresVar0; + if (result7 === null) { + var result5 = ''; + } else { + var result5 = null; + pos = savedPos2; + } + if (result5 !== null) { + if (input.length > pos) { + var result6 = input.charAt(pos); + pos++; + } else { + var result6 = null; + if (reportMatchFailures) { + matchFailed('any character'); + } + } + if (result6 !== null) { + var result4 = [result5, result6]; + } else { + var result4 = null; + pos = savedPos1; + } + } else { + var result4 = null; + pos = savedPos1; + } + while (result4 !== null) { + result2.push(result4); + var savedPos1 = pos; + var savedPos2 = pos; + var savedReportMatchFailuresVar0 = reportMatchFailures; + reportMatchFailures = false; + if (input.substr(pos, 2) === "*/") { + var result7 = "*/"; + pos += 2; + } else { + var result7 = null; + if (reportMatchFailures) { + matchFailed("\"*/\""); + } + } + reportMatchFailures = savedReportMatchFailuresVar0; + if (result7 === null) { + var result5 = ''; + } else { + var result5 = null; + pos = savedPos2; + } + if (result5 !== null) { + if (input.length > pos) { + var result6 = input.charAt(pos); + pos++; + } else { + var result6 = null; + if (reportMatchFailures) { + matchFailed('any character'); + } + } + if (result6 !== null) { + var result4 = [result5, result6]; + } else { + var result4 = null; + pos = savedPos1; + } + } else { + var result4 = null; + pos = savedPos1; + } + } + if (result2 !== null) { + if (input.substr(pos, 2) === "*/") { + var result3 = "*/"; + pos += 2; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"*/\""); + } + } + if (result3 !== null) { + var result0 = [result1, result2, result3]; + } else { + var result0 = null; + pos = savedPos0; + } + } else { + var result0 = null; + pos = savedPos0; + } + } else { + var result0 = null; + pos = savedPos0; + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_eol() { + var cacheKey = 'eol@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var savedReportMatchFailures = reportMatchFailures; + reportMatchFailures = false; + if (input.substr(pos, 1) === "\n") { + var result5 = "\n"; + pos += 1; + } else { + var result5 = null; + if (reportMatchFailures) { + matchFailed("\"\\n\""); + } + } + if (result5 !== null) { + var result0 = result5; + } else { + if (input.substr(pos, 2) === "\r\n") { + var result4 = "\r\n"; + pos += 2; + } else { + var result4 = null; + if (reportMatchFailures) { + matchFailed("\"\\r\\n\""); + } + } + if (result4 !== null) { + var result0 = result4; + } else { + if (input.substr(pos, 1) === "\r") { + var result3 = "\r"; + pos += 1; + } else { + var result3 = null; + if (reportMatchFailures) { + matchFailed("\"\\r\""); + } + } + if (result3 !== null) { + var result0 = result3; + } else { + if (input.substr(pos, 1) === "\u2028") { + var result2 = "\u2028"; + pos += 1; + } else { + var result2 = null; + if (reportMatchFailures) { + matchFailed("\"\\u2028\""); + } + } + if (result2 !== null) { + var result0 = result2; + } else { + if (input.substr(pos, 1) === "\u2029") { + var result1 = "\u2029"; + pos += 1; + } else { + var result1 = null; + if (reportMatchFailures) { + matchFailed("\"\\u2029\""); + } + } + if (result1 !== null) { + var result0 = result1; + } else { + var result0 = null;; + }; + }; + }; + }; + } + reportMatchFailures = savedReportMatchFailures; + if (reportMatchFailures && result0 === null) { + matchFailed("end of line"); + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_eolChar() { + var cacheKey = 'eolChar@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + + if (input.substr(pos).match(/^[\n\r\u2028\u2029]/) !== null) { + var result0 = input.charAt(pos); + pos++; + } else { + var result0 = null; + if (reportMatchFailures) { + matchFailed("[\\n\\r\\u2028\\u2029]"); + } + } + + + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_whitespace() { + var cacheKey = 'whitespace@' + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var savedReportMatchFailures = reportMatchFailures; + reportMatchFailures = false; + if (input.substr(pos).match(/^[ \xA0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]/) !== null) { + var result0 = input.charAt(pos); + pos++; + } else { + var result0 = null; + if (reportMatchFailures) { + matchFailed("[ \\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]"); + } + } + reportMatchFailures = savedReportMatchFailures; + if (reportMatchFailures && result0 === null) { + matchFailed("whitespace"); + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function buildErrorMessage() { + function buildExpected(failuresExpected) { + failuresExpected.sort(); + + var lastFailure = null; + var failuresExpectedUnique = []; + for (var i = 0; i < failuresExpected.length; i++) { + if (failuresExpected[i] !== lastFailure) { + failuresExpectedUnique.push(failuresExpected[i]); + lastFailure = failuresExpected[i]; + } + } + + switch (failuresExpectedUnique.length) { + case 0: + return 'end of input'; + case 1: + return failuresExpectedUnique[0]; + default: + return failuresExpectedUnique.slice(0, failuresExpectedUnique.length - 1).join(', ') + + ' or ' + + failuresExpectedUnique[failuresExpectedUnique.length - 1]; + } + } + + var expected = buildExpected(rightmostMatchFailuresExpected); + var actualPos = Math.max(pos, rightmostMatchFailuresPos); + var actual = actualPos < input.length + ? quote(input.charAt(actualPos)) + : 'end of input'; + + return 'Expected ' + expected + ' but ' + actual + ' found.'; + } + + function computeErrorPosition() { + /* + * The first idea was to use |String.split| to break the input up to the + * error position along newlines and derive the line and column from + * there. However IE's |split| implementation is so broken that it was + * enough to prevent it. + */ + + var line = 1; + var column = 1; + var seenCR = false; + + for (var i = 0; i < rightmostMatchFailuresPos; i++) { + var ch = input.charAt(i); + if (ch === '\n') { + if (!seenCR) { line++; } + column = 1; + seenCR = false; + } else if (ch === '\r' | ch === '\u2028' || ch === '\u2029') { + line++; + column = 1; + seenCR = true; + } else { + column++; + seenCR = false; + } + } + + return { line: line, column: column }; + } + + + + var result = parseFunctions[startRule](); + + /* + * The parser is now in one of the following three states: + * + * 1. The parser successfully parsed the whole input. + * + * - |result !== null| + * - |pos === input.length| + * - |rightmostMatchFailuresExpected| may or may not contain something + * + * 2. The parser successfully parsed only a part of the input. + * + * - |result !== null| + * - |pos < input.length| + * - |rightmostMatchFailuresExpected| may or may not contain something + * + * 3. The parser did not successfully parse any part of the input. + * + * - |result === null| + * - |pos === 0| + * - |rightmostMatchFailuresExpected| contains at least one failure + * + * All code following this comment (including called functions) must + * handle these states. + */ + if (result === null || pos !== input.length) { + var errorPosition = computeErrorPosition(); + throw new this.SyntaxError( + buildErrorMessage(), + errorPosition.line, + errorPosition.column + ); + } + + return result; + }, + + /* Returns the parser source code. */ + toSource: function() { return this._source; } + }; + + /* Thrown when a parser encounters a syntax error. */ + + result.SyntaxError = function(message, line, column) { + this.name = 'SyntaxError'; + this.message = message; + this.line = line; + this.column = column; + }; + + result.SyntaxError.prototype = Error.prototype; + + return result; +})(); +PEG.compiler = { + /* + * Generates a parser from a specified grammar AST. Throws |PEG.GrammarError| + * if the AST contains a semantic error. Note that not all errors are detected + * during the generation and some may protrude to the generated parser and + * cause its malfunction. + */ + compile: function(ast) { + var CHECK_NAMES = [ + "missingReferencedRules", + "leftRecursion" + ]; + + var PASS_NAMES = [ + "proxyRules" + ]; + + for (var i = 0; i < CHECK_NAMES.length; i++) { + this.checks[CHECK_NAMES[i]](ast); + } + + for (var i = 0; i < PASS_NAMES.length; i++) { + ast = this.passes[PASS_NAMES[i]](ast); + } + + var source = this.emitter(ast); + var result = eval(source); + result._source = source; + + return result; + } +}; + +/* + * Checks made on the grammar AST before compilation. Each check is a function + * that is passed the AST and does not return anything. If the check passes, the + * function does not do anything special, otherwise it throws + * |PEG.GrammarError|. The order in which the checks are run is specified in + * |PEG.compiler.compile| and should be the same as the order of definitions + * here. + */ +PEG.compiler.checks = { + /* Checks that all referenced rules exist. */ + missingReferencedRules: function(ast) { + function nop() {} + + function checkExpression(node) { check(node.expression); } + + function checkSubnodes(propertyName) { + return function(node) { each(node[propertyName], check); }; + } + + var check = buildNodeVisitor({ + grammar: + function(node) { + for (var name in node.rules) { + check(node.rules[name]); + } + }, + + rule: checkExpression, + choice: checkSubnodes("alternatives"), + sequence: checkSubnodes("elements"), + labeled: checkExpression, + simple_and: checkExpression, + simple_not: checkExpression, + semantic_and: nop, + semantic_not: nop, + optional: checkExpression, + zero_or_more: checkExpression, + one_or_more: checkExpression, + action: checkExpression, + + rule_ref: + function(node) { + if (ast.rules[node.name] === undefined) { + throw new PEG.GrammarError( + "Referenced rule \"" + node.name + "\" does not exist." + ); + } + }, + + literal: nop, + any: nop, + "class": nop + }); + + check(ast); + }, + + /* Checks that no left recursion is present. */ + leftRecursion: function(ast) { + function nop() {} + + function checkExpression(node, appliedRules) { + check(node.expression, appliedRules); + } + + var check = buildNodeVisitor({ + grammar: + function(node, appliedRules) { + for (var name in node.rules) { + check(node.rules[name], appliedRules); + } + }, + + rule: + function(node, appliedRules) { + check(node.expression, appliedRules.concat(node.name)); + }, + + choice: + function(node, appliedRules) { + each(node.alternatives, function(alternative) { + check(alternative, appliedRules); + }); + }, + + sequence: + function(node, appliedRules) { + if (node.elements.length > 0) { + check(node.elements[0], appliedRules); + } + }, + + labeled: checkExpression, + simple_and: checkExpression, + simple_not: checkExpression, + semantic_and: nop, + semantic_not: nop, + optional: checkExpression, + zero_or_more: checkExpression, + one_or_more: checkExpression, + action: checkExpression, + + rule_ref: + function(node, appliedRules) { + if (contains(appliedRules, node.name)) { + throw new PEG.GrammarError( + "Left recursion detected for rule \"" + node.name + "\"." + ); + } + check(ast.rules[node.name], appliedRules); + }, + + literal: nop, + any: nop, + "class": nop + }); + + check(ast, []); + } +}; +/* + * Optimalization passes made on the grammar AST before compilation. Each pass + * is a function that is passed the AST and returns a new AST. The AST can be + * modified in-place by the pass. The order in which the passes are run is + * specified in |PEG.compiler.compile| and should be the same as the order of + * definitions here. + */ +PEG.compiler.passes = { + /* + * Removes proxy rules -- that is, rules that only delegate to other rule. + */ + proxyRules: function(ast) { + function isProxyRule(node) { + return node.type === "rule" && node.expression.type === "rule_ref"; + } + + function replaceRuleRefs(ast, from, to) { + function nop() {} + + function replaceInExpression(node, from, to) { + replace(node.expression, from, to); + } + + function replaceInSubnodes(propertyName) { + return function(node, from, to) { + each(node[propertyName], function(subnode) { + replace(subnode, from, to); + }); + }; + } + + var replace = buildNodeVisitor({ + grammar: + function(node, from, to) { + for (var name in node.rules) { + replace(node.rules[name], from, to); + } + }, + + rule: replaceInExpression, + choice: replaceInSubnodes("alternatives"), + sequence: replaceInSubnodes("elements"), + labeled: replaceInExpression, + simple_and: replaceInExpression, + simple_not: replaceInExpression, + semantic_and: nop, + semantic_not: nop, + optional: replaceInExpression, + zero_or_more: replaceInExpression, + one_or_more: replaceInExpression, + action: replaceInExpression, + + rule_ref: + function(node, from, to) { + if (node.name === from) { + node.name = to; + } + }, + + literal: nop, + any: nop, + "class": nop + }); + + replace(ast, from, to); + } + + for (var name in ast.rules) { + if (isProxyRule(ast.rules[name])) { + replaceRuleRefs(ast, ast.rules[name].name, ast.rules[name].expression.name); + if (name === ast.startRule) { + ast.startRule = ast.rules[name].expression.name; + } + delete ast.rules[name]; + } + } + + return ast; + } +}; +/* Emits the generated code for the AST. */ +PEG.compiler.emitter = function(ast) { + /* + * Takes parts of code, interpolates variables inside them and joins them with + * a newline. + * + * Variables are delimited with "${" and "}" and their names must be valid + * identifiers (i.e. they must match [a-zA-Z_][a-zA-Z0-9_]*). Variable values + * are specified as properties of the last parameter (if this is an object, + * otherwise empty variable set is assumed). Undefined variables result in + * throwing |Error|. + * + * There can be a filter specified after the variable name, prefixed with "|". + * The filter name must be a valid identifier. The only recognized filter + * right now is "string", which quotes the variable value as a JavaScript + * string. Unrecognized filters result in throwing |Error|. + * + * If any part has multiple lines and the first line is indented by some + * amount of whitespace (as defined by the /\s+/ JavaScript regular + * expression), second to last lines are indented by the same amount of + * whitespace. This results in nicely indented multiline code in variables + * without making the templates look ugly. + * + * Examples: + * + * formatCode("foo", "bar"); // "foo\nbar" + * formatCode("foo", "${bar}", { bar: "baz" }); // "foo\nbaz" + * formatCode("foo", "${bar}"); // throws Error + * formatCode("foo", "${bar|string}", { bar: "baz" }); // "foo\n\"baz\"" + * formatCode("foo", "${bar|eeek}", { bar: "baz" }); // throws Error + * formatCode("foo", "${bar}", { bar: " baz\nqux" }); // "foo\n baz\n qux" + */ + function formatCode() { + function interpolateVariablesInParts(parts) { + return map(parts, function(part) { + return part.replace( + /\$\{([a-zA-Z_][a-zA-Z0-9_]*)(\|([a-zA-Z_][a-zA-Z0-9_]*))?\}/g, + function(match, name, dummy, filter) { + var value = vars[name]; + if (value === undefined) { + throw new Error("Undefined variable: \"" + name + "\"."); + } + + if (filter !== undefined && filter != "") { // JavaScript engines differ here. + if (filter === "string") { + return quote(value); + } else { + throw new Error("Unrecognized filter: \"" + filter + "\"."); + } + } else { + return value; + } + } + ); + }); + } + + function indentMultilineParts(parts) { + return map(parts, function(part) { + if (!/\n/.test(part)) { return part; } + + var firstLineWhitespacePrefix = part.match(/^\s*/)[0]; + var lines = part.split("\n"); + var linesIndented = [lines[0]].concat( + map(lines.slice(1), function(line) { + return firstLineWhitespacePrefix + line; + }) + ); + return linesIndented.join("\n"); + }); + } + + var args = Array.prototype.slice.call(arguments); + var vars = args[args.length - 1] instanceof Object ? args.pop() : {}; + + return indentMultilineParts(interpolateVariablesInParts(args)).join("\n"); + }; + + /* Unique ID generator. */ + var UID = { + _counters: {}, + + next: function(prefix) { + this._counters[prefix] = this._counters[prefix] || 0; + return prefix + this._counters[prefix]++; + }, + + reset: function() { + this._counters = {}; + } + }; + + var emit = buildNodeVisitor({ + grammar: function(node) { + var initializerCode = node.initializer !== null + ? emit(node.initializer) + : ""; + + var parseFunctionTableItems = []; + for (var name in node.rules) { + parseFunctionTableItems.push(quote(name) + ": parse_" + name); + } + parseFunctionTableItems.sort(); + + var parseFunctionDefinitions = []; + for (var name in node.rules) { + parseFunctionDefinitions.push(emit(node.rules[name])); + } + + return formatCode( + "(function(){", + " /* Generated by PEG.js 0.6.2 (http://pegjs.majda.cz/). */", + " ", + " var result = {", + " /*", + " * Parses the input with a generated parser. If the parsing is successfull,", + " * returns a value explicitly or implicitly specified by the grammar from", + " * which the parser was generated (see |PEG.buildParser|). If the parsing is", + " * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.", + " */", + " parse: function(input, startRule) {", + " var parseFunctions = {", + " ${parseFunctionTableItems}", + " };", + " ", + " if (startRule !== undefined) {", + " if (parseFunctions[startRule] === undefined) {", + " throw new Error(\"Invalid rule name: \" + quote(startRule) + \".\");", + " }", + " } else {", + " startRule = ${startRule|string};", + " }", + " ", + " var pos = 0;", + " var reportMatchFailures = true;", + " var rightmostMatchFailuresPos = 0;", + " var rightmostMatchFailuresExpected = [];", + " var cache = {};", + " ", + /* This needs to be in sync with |padLeft| in utils.js. */ + " function padLeft(input, padding, length) {", + " var result = input;", + " ", + " var padLength = length - input.length;", + " for (var i = 0; i < padLength; i++) {", + " result = padding + result;", + " }", + " ", + " return result;", + " }", + " ", + /* This needs to be in sync with |escape| in utils.js. */ + " function escape(ch) {", + " var charCode = ch.charCodeAt(0);", + " ", + " if (charCode <= 0xFF) {", + " var escapeChar = 'x';", + " var length = 2;", + " } else {", + " var escapeChar = 'u';", + " var length = 4;", + " }", + " ", + " return '\\\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);", + " }", + " ", + /* This needs to be in sync with |quote| in utils.js. */ + " function quote(s) {", + " /*", + " * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a", + " * string literal except for the closing quote character, backslash,", + " * carriage return, line separator, paragraph separator, and line feed.", + " * Any character may appear in the form of an escape sequence.", + " */", + " return '\"' + s", + " .replace(/\\\\/g, '\\\\\\\\') // backslash", + " .replace(/\"/g, '\\\\\"') // closing quote character", + " .replace(/\\r/g, '\\\\r') // carriage return", + " .replace(/\\n/g, '\\\\n') // line feed", + " .replace(/[\\x80-\\uFFFF]/g, escape) // non-ASCII characters", + " + '\"';", + " }", + " ", + " function matchFailed(failure) {", + " if (pos < rightmostMatchFailuresPos) {", + " return;", + " }", + " ", + " if (pos > rightmostMatchFailuresPos) {", + " rightmostMatchFailuresPos = pos;", + " rightmostMatchFailuresExpected = [];", + " }", + " ", + " rightmostMatchFailuresExpected.push(failure);", + " }", + " ", + " ${parseFunctionDefinitions}", + " ", + " function buildErrorMessage() {", + " function buildExpected(failuresExpected) {", + " failuresExpected.sort();", + " ", + " var lastFailure = null;", + " var failuresExpectedUnique = [];", + " for (var i = 0; i < failuresExpected.length; i++) {", + " if (failuresExpected[i] !== lastFailure) {", + " failuresExpectedUnique.push(failuresExpected[i]);", + " lastFailure = failuresExpected[i];", + " }", + " }", + " ", + " switch (failuresExpectedUnique.length) {", + " case 0:", + " return 'end of input';", + " case 1:", + " return failuresExpectedUnique[0];", + " default:", + " return failuresExpectedUnique.slice(0, failuresExpectedUnique.length - 1).join(', ')", + " + ' or '", + " + failuresExpectedUnique[failuresExpectedUnique.length - 1];", + " }", + " }", + " ", + " var expected = buildExpected(rightmostMatchFailuresExpected);", + " var actualPos = Math.max(pos, rightmostMatchFailuresPos);", + " var actual = actualPos < input.length", + " ? quote(input.charAt(actualPos))", + " : 'end of input';", + " ", + " return 'Expected ' + expected + ' but ' + actual + ' found.';", + " }", + " ", + " function computeErrorPosition() {", + " /*", + " * The first idea was to use |String.split| to break the input up to the", + " * error position along newlines and derive the line and column from", + " * there. However IE's |split| implementation is so broken that it was", + " * enough to prevent it.", + " */", + " ", + " var line = 1;", + " var column = 1;", + " var seenCR = false;", + " ", + " for (var i = 0; i < rightmostMatchFailuresPos; i++) {", + " var ch = input.charAt(i);", + " if (ch === '\\n') {", + " if (!seenCR) { line++; }", + " column = 1;", + " seenCR = false;", + " } else if (ch === '\\r' | ch === '\\u2028' || ch === '\\u2029') {", + " line++;", + " column = 1;", + " seenCR = true;", + " } else {", + " column++;", + " seenCR = false;", + " }", + " }", + " ", + " return { line: line, column: column };", + " }", + " ", + " ${initializerCode}", + " ", + " var result = parseFunctions[startRule]();", + " ", + " /*", + " * The parser is now in one of the following three states:", + " *", + " * 1. The parser successfully parsed the whole input.", + " *", + " * - |result !== null|", + " * - |pos === input.length|", + " * - |rightmostMatchFailuresExpected| may or may not contain something", + " *", + " * 2. The parser successfully parsed only a part of the input.", + " *", + " * - |result !== null|", + " * - |pos < input.length|", + " * - |rightmostMatchFailuresExpected| may or may not contain something", + " *", + " * 3. The parser did not successfully parse any part of the input.", + " *", + " * - |result === null|", + " * - |pos === 0|", + " * - |rightmostMatchFailuresExpected| contains at least one failure", + " *", + " * All code following this comment (including called functions) must", + " * handle these states.", + " */", + " if (result === null || pos !== input.length) {", + " var errorPosition = computeErrorPosition();", + " throw new this.SyntaxError(", + " buildErrorMessage(),", + " errorPosition.line,", + " errorPosition.column", + " );", + " }", + " ", + " return result;", + " },", + " ", + " /* Returns the parser source code. */", + " toSource: function() { return this._source; }", + " };", + " ", + " /* Thrown when a parser encounters a syntax error. */", + " ", + " result.SyntaxError = function(message, line, column) {", + " this.name = 'SyntaxError';", + " this.message = message;", + " this.line = line;", + " this.column = column;", + " };", + " ", + " result.SyntaxError.prototype = Error.prototype;", + " ", + " return result;", + "})()", + { + initializerCode: initializerCode, + parseFunctionTableItems: parseFunctionTableItems.join(",\n"), + parseFunctionDefinitions: parseFunctionDefinitions.join("\n\n"), + startRule: node.startRule + } + ); + }, + + initializer: function(node) { + return node.code; + }, + + rule: function(node) { + /* + * We want to reset variable names at the beginning of every function so + * that a little change in the source grammar does not change variables in + * all the generated code. This is desired especially when one has the + * generated grammar stored in a VCS (this is true e.g. for our + * metagrammar). + */ + UID.reset(); + + var resultVar = UID.next("result"); + + if (node.displayName !== null) { + var setReportMatchFailuresCode = formatCode( + "var savedReportMatchFailures = reportMatchFailures;", + "reportMatchFailures = false;" + ); + var restoreReportMatchFailuresCode = formatCode( + "reportMatchFailures = savedReportMatchFailures;" + ); + var reportMatchFailureCode = formatCode( + "if (reportMatchFailures && ${resultVar} === null) {", + " matchFailed(${displayName|string});", + "}", + { + displayName: node.displayName, + resultVar: resultVar + } + ); + } else { + var setReportMatchFailuresCode = ""; + var restoreReportMatchFailuresCode = ""; + var reportMatchFailureCode = ""; + } + + return formatCode( + "function parse_${name}() {", + " var cacheKey = '${name}@' + pos;", + " var cachedResult = cache[cacheKey];", + " if (cachedResult) {", + " pos = cachedResult.nextPos;", + " return cachedResult.result;", + " }", + " ", + " ${setReportMatchFailuresCode}", + " ${code}", + " ${restoreReportMatchFailuresCode}", + " ${reportMatchFailureCode}", + " ", + " cache[cacheKey] = {", + " nextPos: pos,", + " result: ${resultVar}", + " };", + " return ${resultVar};", + "}", + { + name: node.name, + setReportMatchFailuresCode: setReportMatchFailuresCode, + restoreReportMatchFailuresCode: restoreReportMatchFailuresCode, + reportMatchFailureCode: reportMatchFailureCode, + code: emit(node.expression, resultVar), + resultVar: resultVar + } + ); + }, + + /* + * The contract for all code fragments generated by the following functions + * is as follows: + * + * * The code fragment should try to match a part of the input starting with + * the position indicated in |pos|. That position may point past the end of + * the input. + * + * * If the code fragment matches the input, it advances |pos| after the + * matched part of the input and sets variable with a name stored in + * |resultVar| to appropriate value, which is always non-null. + * + * * If the code fragment does not match the input, it does not change |pos| + * and it sets a variable with a name stored in |resultVar| to |null|. + */ + + choice: function(node, resultVar) { + var code = formatCode( + "var ${resultVar} = null;", + { resultVar: resultVar } + ); + + for (var i = node.alternatives.length - 1; i >= 0; i--) { + var alternativeResultVar = UID.next("result"); + code = formatCode( + "${alternativeCode}", + "if (${alternativeResultVar} !== null) {", + " var ${resultVar} = ${alternativeResultVar};", + "} else {", + " ${code};", + "}", + { + alternativeCode: emit(node.alternatives[i], alternativeResultVar), + alternativeResultVar: alternativeResultVar, + code: code, + resultVar: resultVar + } + ); + } + + return code; + }, + + sequence: function(node, resultVar) { + var savedPosVar = UID.next("savedPos"); + + var elementResultVars = map(node.elements, function() { + return UID.next("result") + }); + + var code = formatCode( + "var ${resultVar} = ${elementResultVarArray};", + { + resultVar: resultVar, + elementResultVarArray: "[" + elementResultVars.join(", ") + "]" + } + ); + + for (var i = node.elements.length - 1; i >= 0; i--) { + code = formatCode( + "${elementCode}", + "if (${elementResultVar} !== null) {", + " ${code}", + "} else {", + " var ${resultVar} = null;", + " pos = ${savedPosVar};", + "}", + { + elementCode: emit(node.elements[i], elementResultVars[i]), + elementResultVar: elementResultVars[i], + code: code, + savedPosVar: savedPosVar, + resultVar: resultVar + } + ); + } + + return formatCode( + "var ${savedPosVar} = pos;", + "${code}", + { + code: code, + savedPosVar: savedPosVar + } + ); + }, + + labeled: function(node, resultVar) { + return emit(node.expression, resultVar); + }, + + simple_and: function(node, resultVar) { + var savedPosVar = UID.next("savedPos"); + var savedReportMatchFailuresVar = UID.next("savedReportMatchFailuresVar"); + var expressionResultVar = UID.next("result"); + + return formatCode( + "var ${savedPosVar} = pos;", + "var ${savedReportMatchFailuresVar} = reportMatchFailures;", + "reportMatchFailures = false;", + "${expressionCode}", + "reportMatchFailures = ${savedReportMatchFailuresVar};", + "if (${expressionResultVar} !== null) {", + " var ${resultVar} = '';", + " pos = ${savedPosVar};", + "} else {", + " var ${resultVar} = null;", + "}", + { + expressionCode: emit(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + savedPosVar: savedPosVar, + savedReportMatchFailuresVar: savedReportMatchFailuresVar, + resultVar: resultVar + } + ); + }, + + simple_not: function(node, resultVar) { + var savedPosVar = UID.next("savedPos"); + var savedReportMatchFailuresVar = UID.next("savedReportMatchFailuresVar"); + var expressionResultVar = UID.next("result"); + + return formatCode( + "var ${savedPosVar} = pos;", + "var ${savedReportMatchFailuresVar} = reportMatchFailures;", + "reportMatchFailures = false;", + "${expressionCode}", + "reportMatchFailures = ${savedReportMatchFailuresVar};", + "if (${expressionResultVar} === null) {", + " var ${resultVar} = '';", + "} else {", + " var ${resultVar} = null;", + " pos = ${savedPosVar};", + "}", + { + expressionCode: emit(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + savedPosVar: savedPosVar, + savedReportMatchFailuresVar: savedReportMatchFailuresVar, + resultVar: resultVar + } + ); + }, + + semantic_and: function(node, resultVar) { + return formatCode( + "var ${resultVar} = (function() {${actionCode}})() ? '' : null;", + { + actionCode: node.code, + resultVar: resultVar + } + ); + }, + + semantic_not: function(node, resultVar) { + return formatCode( + "var ${resultVar} = (function() {${actionCode}})() ? null : '';", + { + actionCode: node.code, + resultVar: resultVar + } + ); + }, + + optional: function(node, resultVar) { + var expressionResultVar = UID.next("result"); + + return formatCode( + "${expressionCode}", + "var ${resultVar} = ${expressionResultVar} !== null ? ${expressionResultVar} : '';", + { + expressionCode: emit(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + resultVar: resultVar + } + ); + }, + + zero_or_more: function(node, resultVar) { + var expressionResultVar = UID.next("result"); + + return formatCode( + "var ${resultVar} = [];", + "${expressionCode}", + "while (${expressionResultVar} !== null) {", + " ${resultVar}.push(${expressionResultVar});", + " ${expressionCode}", + "}", + { + expressionCode: emit(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + resultVar: resultVar + } + ); + }, + + one_or_more: function(node, resultVar) { + var expressionResultVar = UID.next("result"); + + return formatCode( + "${expressionCode}", + "if (${expressionResultVar} !== null) {", + " var ${resultVar} = [];", + " while (${expressionResultVar} !== null) {", + " ${resultVar}.push(${expressionResultVar});", + " ${expressionCode}", + " }", + "} else {", + " var ${resultVar} = null;", + "}", + { + expressionCode: emit(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + resultVar: resultVar + } + ); + }, + + action: function(node, resultVar) { + /* + * In case of sequences, we splat their elements into function arguments + * one by one. Example: + * + * start: a:"a" b:"b" c:"c" { alert(arguments.length) } // => 3 + * + * This behavior is reflected in this function. + */ + + var expressionResultVar = UID.next("result"); + var actionResultVar = UID.next("result"); + var savedPosVar = UID.next("savedPos"); + + if (node.expression.type === "sequence") { + var formalParams = []; + var actualParams = []; + + var elements = node.expression.elements; + var elementsLength = elements.length; + for (var i = 0; i < elementsLength; i++) { + if (elements[i].type === "labeled") { + formalParams.push(elements[i].label); + actualParams.push(expressionResultVar + "[" + i + "]"); + } + } + } else if (node.expression.type === "labeled") { + var formalParams = [node.expression.label]; + var actualParams = [expressionResultVar]; + } else { + var formalParams = []; + var actualParams = []; + } + + return formatCode( + "var ${savedPosVar} = pos;", + "${expressionCode}", + "var ${actionResultVar} = ${expressionResultVar} !== null", + " ? (function(${formalParams}) {${actionCode}})(${actualParams})", + " : null;", + "if (${actionResultVar} !== null) {", + " var ${resultVar} = ${actionResultVar};", + "} else {", + " var ${resultVar} = null;", + " pos = ${savedPosVar};", + "}", + { + expressionCode: emit(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + actionCode: node.code, + actionResultVar: actionResultVar, + formalParams: formalParams.join(", "), + actualParams: actualParams.join(", "), + savedPosVar: savedPosVar, + resultVar: resultVar + } + ); + }, + + rule_ref: function(node, resultVar) { + return formatCode( + "var ${resultVar} = ${ruleMethod}();", + { + ruleMethod: "parse_" + node.name, + resultVar: resultVar + } + ); + }, + + literal: function(node, resultVar) { + return formatCode( + "if (input.substr(pos, ${length}) === ${value|string}) {", + " var ${resultVar} = ${value|string};", + " pos += ${length};", + "} else {", + " var ${resultVar} = null;", + " if (reportMatchFailures) {", + " matchFailed(${valueQuoted|string});", + " }", + "}", + { + value: node.value, + valueQuoted: quote(node.value), + length: node.value.length, + resultVar: resultVar + } + ); + }, + + any: function(node, resultVar) { + return formatCode( + "if (input.length > pos) {", + " var ${resultVar} = input.charAt(pos);", + " pos++;", + "} else {", + " var ${resultVar} = null;", + " if (reportMatchFailures) {", + " matchFailed('any character');", + " }", + "}", + { resultVar: resultVar } + ); + }, + + "class": function(node, resultVar) { + if (node.parts.length > 0) { + var regexp = "/^[" + + (node.inverted ? "^" : "") + + map(node.parts, function(part) { + return part instanceof Array + ? quoteForRegexpClass(part[0]) + + "-" + + quoteForRegexpClass(part[1]) + : quoteForRegexpClass(part); + }).join("") + + "]/"; + } else { + /* + * Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so + * we translate them into euqivalents it can handle. + */ + var regexp = node.inverted ? "/^[\\S\\s]/" : "/^(?!)/"; + } + + return formatCode( + "if (input.substr(pos).match(${regexp}) !== null) {", + " var ${resultVar} = input.charAt(pos);", + " pos++;", + "} else {", + " var ${resultVar} = null;", + " if (reportMatchFailures) {", + " matchFailed(${rawText|string});", + " }", + "}", + { + regexp: regexp, + rawText: node.rawText, + resultVar: resultVar + } + ); + } + }); + + return emit(ast); +}; + +if (typeof module === "object") { + module.exports = PEG; +} else if (typeof window === "object") { + window.PEG = PEG; +} else { + throw new Error("Can't export PEG library (no \"module\" nor \"window\" object detected)."); +} + +})(); \ No newline at end of file diff -r 000000000000 -r 3d1b8e96f5dc testparse.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testparse.html Sun Mar 18 12:03:04 2012 -0700 @@ -0,0 +1,15 @@ + + + + Parser Test + + + + + + + +
+
+ +