Permalink
Browse files

Initial commit.

  • Loading branch information...
0 parents commit 8a964b19a3ca36d3d5f17a16772aa764c7586029 @weaver committed Aug 18, 2010
Showing with 2,384 additions and 0 deletions.
  1. +196 −0 README.md
  2. +52 −0 examples/email-address.js
  3. +143 −0 examples/json.js
  4. +1,747 −0 examples/pegjson.js
  5. +246 −0 lib/reparse.js
196 README.md
@@ -0,0 +1,196 @@
+# ReParse #
+
+ReParse is a parser combinator library for Javascript like [Parsec][1]
+for Haskell.
+
+## Installation ##
+
+Download `lib/reparse.js` and add it to your project.
+
+[1]: http://legacy.cs.uu.nl/daan/parsec.html
+
+## API ##
+
+To use ReParse, construct a `new ReParse(input)` object, then call the
+`.start()`, passing it the top-level production of your grammar. Each
+production may be a RegExp or a function.
+
+A RegExp will produce the first captured group or the entire value it
+matched if there are no groups. Functions are called with `this`
+bound to the parser. They take no arguments. A function should
+invoke one or more parser methods, optionally transforming the results
+into an appropriate return value.
+
+This is a grammar for a subset of JSON that supports arrays and
+positive integers. See `examples/json.js` for a more complete
+example:
+
+ function parse(data) {
+ return (new ReParse(data, true)).start(value);
+ }
+
+ function value() {
+ return this.choice(number, array);
+ }
+
+ function array() {
+ return this.between(/^\[/, /^\]/, elements);
+ }
+
+ function elements() {
+ return this.sepBy(value, /^,/);
+ }
+
+ function number() {
+ return iPart(this.match(/^\d+/));
+ }
+
+ function iPart(digits) {
+ for (var i = 0, l = digits.length, r = 0; i < l; i++)
+ r = r * 10 + digits.charCodeAt(i) - 48;
+ return r;
+ }
+
+ReParse indicates failure internally using exceptions, so it's safe to
+use the result of any production immediately without checking for an
+error state.
+
+### ReParse(input, [ignorews]) ###
+
+Create a new parser for an `input` string. If `ignorews` is `true`,
+skip whitespace before and after each production.
+
+#### .start(method) ####
+
+Return the value produced by `method`. All input must be consumed.
+
+#### .eof() ####
+
+Return `true` if the input is exhausted.
+
+#### .fail() ####
+
+Call this method to indicate that a production has failed; an
+exception will be raised and caught by the previous production.
+
+#### .produce(method) ####
+
+Apply the production `method` to the input and return the result.
+
+#### .maybe(method) ####
+
+Apply the production `method` to the input, restoring the input to its
+previous state if it fails.
+
+#### .option(method, otherwise) ####
+
+Try to produce `method`. If it fails, restore the input and return
+`otherwise`.
+
+#### .match(regexp) ####
+
+Match a regular expression against the input, returning the first
+captured group. If no group is captured, return the matched string.
+
+#### .choice(alt1, alt2, ...) ####
+
+Try several alternatives, returning the value of the first one that's
+successful.
+
+#### .seq(group1, group2, ...) ####
+
+All groups must match the input. Return an array of capture groups
+like a regular expression match would. Index 0 is the entire matched
+string, index 1 corresponds to `group1`, etc.
+
+#### .many(method) ####
+
+Return an array of zero or more values produced by `method`.
+
+#### .many1(method) ####
+
+Return an array of one or more values produced by `method`.
+
+#### .between(left, right, body) ####
+
+This is equivalent to `.seq(left, body, right)[0]`.
+
+#### .skip(method) ####
+
+Ignore zero or more instances of `method`. Return the parser object.
+
+#### .skip1(method) ####
+
+Ignore one or more instances of `method`. Return the parser object.
+
+#### .skipWS() ####
+
+Ignore whitespace. Return the parser object.
+
+#### .sepBy(method, sep) ####
+
+Return an array of zero or more values produced by `method`. Each
+value is separated by `sep`.
+
+#### .sepBy1(method, sep) ####
+
+Return an array of one or more values produced by `method`. Each
+value is separated by `sep`.
+
+#### .endBy(method, end) ####
+
+This is equivalent to `.many(method)` followed by `.option(end)`.
+
+#### .endBy1(method, end) ####
+
+This is equivalent to `.many1(method)` followed by `.option(end)`.
+
+#### .sepEndBy(method, sep) ####
+
+Return an array of zero or more values produced by `method`. Each
+value is separated by `sep` and the entire sequence is optionally
+terminated by `sep`.
+
+#### .sepEndBy1(method, sep) ####
+
+Return an array of one or more values produced by `method`. Each
+value is separated by `sep` and the entire sequence is optionally
+terminated by `sep`.
+
+## Compatibility ##
+
+ReParse has been tested with Node.JS version `v0.1.103`. It should
+work in a browser if you comment out the `exports` line.
+
+## License ##
+
+Copyright (c) 2010, Ben Weaver &lt;ben@orangesoda.net&gt;
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of the <organization> nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT
+HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
52 examples/email-address.js
@@ -0,0 +1,52 @@
+/// email-address - Parse a string of email addresses into an array.
+//
+// This parser supports a subset of RFC 5322.
+
+var sys = require('sys'),
+ ReParse = require('../lib/reparse').ReParse;
+
+function readAddressList(str) {
+ return (new ReParse(str)).start(addressList);
+}
+
+function addressList() {
+ return this.sepEndBy(address, /^\s*,\s*/);
+}
+
+function address() {
+ return this.choice(namedAddress, bareAddress);
+}
+
+function namedAddress() {
+ return this.seq(phrase, /^\s*</m, bareAddress, /^>/)[3];
+}
+
+function bareAddress() {
+ return this.seq(word, /^@/, word).slice(1).join('');
+}
+
+function phrase() {
+ return this.many(word);
+}
+
+function word() {
+ return this.skip(/^\s+/).choice(quoted, dottedAtom);
+}
+
+function quoted() {
+ return this.match(/^"(?:\\.|[^"\r\n])+"/m);
+}
+
+function dottedAtom() {
+ return this.match(/^[!#\$%&'\*\+\-\/\w=\?\^`\{\|\}~]+(?:\.[!#\$%&'\*\+\-\/\w=\?\^`\{\|\}~]+)*/m);
+}
+
+
+/// --- Main Program
+
+if (process.argv.length != 3) {
+ sys.puts('Usage: node ' + process.argv[1] + ' list-of-addresses');
+ process.exit(1);
+}
+
+sys.puts(sys.inspect(readAddressList(process.argv[2])));
143 examples/json.js
@@ -0,0 +1,143 @@
+/// json -- an example JSON parser
+//
+// Running this program compares parse times for the Node.JS built-in
+// JSON parser, a PEG.js parser built from the PEG.js example JSON
+// grammar, and ReParse.
+
+var sys = require('sys'),
+ ReParse = require('../lib/reparse').ReParse,
+ peg = require('./pegjson').parser;
+
+function parse(data) {
+ return (new ReParse(data, true)).start(value);
+}
+
+function object() {
+ return this.between(/^\{/, /^\}/, members).reduce(function(obj, pair) {
+ obj[pair[1]] = pair[3];
+ return obj;
+ }, {});
+}
+
+function members() {
+ return this.sepBy(pair, /^,/);
+}
+
+function pair() {
+ return this.seq(string, /^:/, value);
+}
+
+function array() {
+ return this.between(/^\[/, /^\]/, elements);
+}
+
+function elements() {
+ return this.sepBy(value, /^,/);
+}
+
+function value() {
+ return this.choice(literal, string, number, array, object);
+}
+
+var LITERAL = { 'true': true, 'false': false, 'null': null };
+function literal() {
+ return LITERAL[this.match(/^(true|false|null)/)];
+}
+
+var SPECIAL = { '"': 34, '\\': 92, '/': 47, 'b': 8, 'f': 12, 'n': 10, 'r': 13, 't': 9};
+function string() {
+ var chars = this.match(/^"((?:\\["\\/bfnrt]|\\u[0-9a-fA-F]{4}|[^"\\])*)"/);
+ return chars.replace(/\\(["\\/bfnrt])|\\u([0-9a-fA-F]{4})/g, function(_, $1, $2) {
+ return String.fromCharCode($1 ? SPECIAL[$1] : hex($2));
+ });
+}
+
+function number() {
+ var ipart = this.produce(integer),
+ fpart = this.option(frac, 0),
+ epart = this.option(exp, 0);
+ return ((ipart < 0) ? ipart - fpart : ipart + fpart) * Math.pow(10, epart);
+}
+
+function integer() {
+ return (this.option(/^\-/) ? -1 : 1) * this.produce(digits);
+}
+
+function digits() {
+ return iPart(this.match(/^\d+/));
+}
+
+function frac() {
+ return fPart(this.match(/^\.(\d+)/));
+}
+
+function exp() {
+ var sign = (this.match(/^e([\+\-]?)/i) == '-') ? -1 : 1;
+ return sign * this.produce(digits);
+}
+
+
+/// --- Aux
+
+function iPart(digits) {
+ for (var i = 0, l = digits.length, r = 0; i < l; i++)
+ r = r * 10 + digits.charCodeAt(i) - 48;
+ return r;
+}
+
+function fPart(digits) {
+ for (var i = 0, l = digits.length, s = 10, r = 0; i < l; i++, s *= 10)
+ r += ((digits.charCodeAt(i) - 48) / s);
+ return r;
+}
+
+function hex(digits) {
+ var result = 0,
+ code;
+
+ digits = digits.toUpperCase();
+ for (var i = 0, l = digits.length; i < l; i++) {
+ code = digits.charCodeAt(i);
+ result = result * 16 + code - (code >= 65 ? 55 : 48);
+ }
+
+ return result;
+}
+
+function capture(stream, encoding, fn) {
+ var data = '';
+
+ stream.setEncoding(encoding);
+
+ stream.on('data', function(chunk) {
+ data += chunk;
+ });
+
+ stream.on('end', function() {
+ fn(data);
+ });
+}
+
+function time(label, reps, fn) {
+ var start = Date.now();
+ for (var i = 0; i < reps; i++)
+ fn();
+ sys.puts(label + ': ' + (Date.now() - start));
+}
+
+
+/// --- Main Program
+
+var input = '{"a": [1, "foo", [], {"foo": 1, "bar": [1, 2, 3]}] }';
+
+time('JSON', 1000, function() {
+ JSON.parse(input);
+});
+
+time('PEG.js', 1000, function() {
+ peg.parse(input);;
+});
+
+time('ReParse', 1000, function() {
+ parse(input);
+});
1,747 examples/pegjson.js
@@ -0,0 +1,1747 @@
+exports.parser = (function(){
+ /* Generated by PEG.js (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.grammarParser.SyntaxError| describing the error.
+ */
+ parse: function(input) {
+ var pos = 0;
+ var rightmostMatchFailuresPos = 0;
+ var rightmostMatchFailuresExpected = [];
+ var cache = {};
+
+ function quoteString(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(/\u2028/g, '\\u2028') // line separator
+ .replace(/\u2029/g, '\\u2029') // paragraph separator
+ .replace(/\n/g, '\\n') // line feed
+ + '"';
+ }
+
+ function arrayContains(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 matchFailed(failure) {
+ if (pos < rightmostMatchFailuresPos) {
+ return;
+ }
+
+ if (pos > rightmostMatchFailuresPos) {
+ rightmostMatchFailuresPos = pos;
+ rightmostMatchFailuresExpected = [];
+ }
+
+ if (!arrayContains(rightmostMatchFailuresExpected, failure)) {
+ rightmostMatchFailuresExpected.push(failure);
+ }
+ }
+
+ function parse_start(context) {
+ var cacheKey = "start" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos0 = pos;
+ var result2 = parse__(context);
+ if (result2 !== null) {
+ var result3 = parse_object(context);
+ if (result3 !== null) {
+ var result1 = [result2, result3];
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ var result0 = result1 !== null
+ ? (function(object) { return object; })(result1[1])
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_object(context) {
+ var cacheKey = "object" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos1 = pos;
+ if (input.substr(pos, 1) === "{") {
+ var result10 = "{";
+ pos += 1;
+ } else {
+ var result10 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("{"));
+ }
+ }
+ if (result10 !== null) {
+ var result11 = parse__(context);
+ if (result11 !== null) {
+ if (input.substr(pos, 1) === "}") {
+ var result12 = "}";
+ pos += 1;
+ } else {
+ var result12 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("}"));
+ }
+ }
+ if (result12 !== null) {
+ var result13 = parse__(context);
+ if (result13 !== null) {
+ var result9 = [result10, result11, result12, result13];
+ } else {
+ var result9 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result9 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result9 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result9 = null;
+ pos = savedPos1;
+ }
+ var result8 = result9 !== null
+ ? (function() { return {}; })()
+ : null;
+ if (result8 !== null) {
+ var result0 = result8;
+ } else {
+ var savedPos0 = pos;
+ if (input.substr(pos, 1) === "{") {
+ var result3 = "{";
+ pos += 1;
+ } else {
+ var result3 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("{"));
+ }
+ }
+ if (result3 !== null) {
+ var result4 = parse__(context);
+ if (result4 !== null) {
+ var result5 = parse_members(context);
+ if (result5 !== null) {
+ if (input.substr(pos, 1) === "}") {
+ var result6 = "}";
+ pos += 1;
+ } else {
+ var result6 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("}"));
+ }
+ }
+ if (result6 !== null) {
+ var result7 = parse__(context);
+ if (result7 !== null) {
+ var result2 = [result3, result4, result5, result6, result7];
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ var result1 = result2 !== null
+ ? (function(members) { return members; })(result2[2])
+ : null;
+ if (result1 !== null) {
+ var result0 = result1;
+ } else {
+ var result0 = null;;
+ };
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_members(context) {
+ var cacheKey = "members" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos0 = pos;
+ var result2 = parse_pair(context);
+ if (result2 !== null) {
+ var result3 = [];
+ var savedPos1 = pos;
+ if (input.substr(pos, 1) === ",") {
+ var result5 = ",";
+ pos += 1;
+ } else {
+ var result5 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString(","));
+ }
+ }
+ if (result5 !== null) {
+ var result6 = parse__(context);
+ if (result6 !== null) {
+ var result7 = parse_pair(context);
+ if (result7 !== null) {
+ var result4 = [result5, result6, result7];
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ while (result4 !== null) {
+ result3.push(result4);
+ var savedPos1 = pos;
+ if (input.substr(pos, 1) === ",") {
+ var result5 = ",";
+ pos += 1;
+ } else {
+ var result5 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString(","));
+ }
+ }
+ if (result5 !== null) {
+ var result6 = parse__(context);
+ if (result6 !== null) {
+ var result7 = parse_pair(context);
+ if (result7 !== null) {
+ var result4 = [result5, result6, result7];
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ }
+ if (result3 !== null) {
+ var result1 = [result2, result3];
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ var result0 = result1 !== null
+ ? (function(head, tail) {
+ var result = {};
+ result[head[0]] = head[1];
+ for (var i = 0; i < tail.length; i++) {
+ result[tail[i][2][0]] = tail[i][2][1];
+ }
+ return result;
+ })(result1[0], result1[1])
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_pair(context) {
+ var cacheKey = "pair" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos0 = pos;
+ var result2 = parse_string(context);
+ if (result2 !== null) {
+ if (input.substr(pos, 1) === ":") {
+ var result3 = ":";
+ pos += 1;
+ } else {
+ var result3 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString(":"));
+ }
+ }
+ if (result3 !== null) {
+ var result4 = parse__(context);
+ if (result4 !== null) {
+ var result5 = parse_value(context);
+ if (result5 !== null) {
+ var result1 = [result2, result3, result4, result5];
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ var result0 = result1 !== null
+ ? (function(name, value) { return [name, value]; })(result1[0], result1[3])
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_array(context) {
+ var cacheKey = "array" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos1 = pos;
+ if (input.substr(pos, 1) === "[") {
+ var result10 = "[";
+ pos += 1;
+ } else {
+ var result10 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("["));
+ }
+ }
+ if (result10 !== null) {
+ var result11 = parse__(context);
+ if (result11 !== null) {
+ if (input.substr(pos, 1) === "]") {
+ var result12 = "]";
+ pos += 1;
+ } else {
+ var result12 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("]"));
+ }
+ }
+ if (result12 !== null) {
+ var result13 = parse__(context);
+ if (result13 !== null) {
+ var result9 = [result10, result11, result12, result13];
+ } else {
+ var result9 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result9 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result9 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result9 = null;
+ pos = savedPos1;
+ }
+ var result8 = result9 !== null
+ ? (function() { return []; })()
+ : null;
+ if (result8 !== null) {
+ var result0 = result8;
+ } else {
+ var savedPos0 = pos;
+ if (input.substr(pos, 1) === "[") {
+ var result3 = "[";
+ pos += 1;
+ } else {
+ var result3 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("["));
+ }
+ }
+ if (result3 !== null) {
+ var result4 = parse__(context);
+ if (result4 !== null) {
+ var result5 = parse_elements(context);
+ if (result5 !== null) {
+ if (input.substr(pos, 1) === "]") {
+ var result6 = "]";
+ pos += 1;
+ } else {
+ var result6 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("]"));
+ }
+ }
+ if (result6 !== null) {
+ var result7 = parse__(context);
+ if (result7 !== null) {
+ var result2 = [result3, result4, result5, result6, result7];
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ var result1 = result2 !== null
+ ? (function(elements) { return elements; })(result2[2])
+ : null;
+ if (result1 !== null) {
+ var result0 = result1;
+ } else {
+ var result0 = null;;
+ };
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_elements(context) {
+ var cacheKey = "elements" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos0 = pos;
+ var result2 = parse_value(context);
+ if (result2 !== null) {
+ var result3 = [];
+ var savedPos1 = pos;
+ if (input.substr(pos, 1) === ",") {
+ var result5 = ",";
+ pos += 1;
+ } else {
+ var result5 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString(","));
+ }
+ }
+ if (result5 !== null) {
+ var result6 = parse__(context);
+ if (result6 !== null) {
+ var result7 = parse_value(context);
+ if (result7 !== null) {
+ var result4 = [result5, result6, result7];
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ while (result4 !== null) {
+ result3.push(result4);
+ var savedPos1 = pos;
+ if (input.substr(pos, 1) === ",") {
+ var result5 = ",";
+ pos += 1;
+ } else {
+ var result5 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString(","));
+ }
+ }
+ if (result5 !== null) {
+ var result6 = parse__(context);
+ if (result6 !== null) {
+ var result7 = parse_value(context);
+ if (result7 !== null) {
+ var result4 = [result5, result6, result7];
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result4 = null;
+ pos = savedPos1;
+ }
+ }
+ if (result3 !== null) {
+ var result1 = [result2, result3];
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ var result0 = result1 !== null
+ ? (function(head, tail) {
+ var result = [head];
+ for (var i = 0; i < tail.length; i++) {
+ result.push(tail[i][2]);
+ }
+ return result;
+ })(result1[0], result1[1])
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_value(context) {
+ var cacheKey = "value" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var result16 = parse_string(context);
+ if (result16 !== null) {
+ var result0 = result16;
+ } else {
+ var result15 = parse_number(context);
+ if (result15 !== null) {
+ var result0 = result15;
+ } else {
+ var result14 = parse_object(context);
+ if (result14 !== null) {
+ var result0 = result14;
+ } else {
+ var result13 = parse_array(context);
+ if (result13 !== null) {
+ var result0 = result13;
+ } else {
+ var savedPos2 = pos;
+ if (input.substr(pos, 4) === "true") {
+ var result11 = "true";
+ pos += 4;
+ } else {
+ var result11 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("true"));
+ }
+ }
+ if (result11 !== null) {
+ var result12 = parse__(context);
+ if (result12 !== null) {
+ var result10 = [result11, result12];
+ } else {
+ var result10 = null;
+ pos = savedPos2;
+ }
+ } else {
+ var result10 = null;
+ pos = savedPos2;
+ }
+ var result9 = result10 !== null
+ ? (function() { return true; })()
+ : null;
+ if (result9 !== null) {
+ var result0 = result9;
+ } else {
+ var savedPos1 = pos;
+ if (input.substr(pos, 5) === "false") {
+ var result7 = "false";
+ pos += 5;
+ } else {
+ var result7 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("false"));
+ }
+ }
+ if (result7 !== null) {
+ var result8 = parse__(context);
+ if (result8 !== null) {
+ var result6 = [result7, result8];
+ } else {
+ var result6 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result6 = null;
+ pos = savedPos1;
+ }
+ var result5 = result6 !== null
+ ? (function() { return false; })()
+ : null;
+ if (result5 !== null) {
+ var result0 = result5;
+ } else {
+ var savedPos0 = pos;
+ if (input.substr(pos, 4) === "null") {
+ var result3 = "null";
+ pos += 4;
+ } else {
+ var result3 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("null"));
+ }
+ }
+ if (result3 !== null) {
+ var result4 = parse__(context);
+ if (result4 !== null) {
+ var result2 = [result3, result4];
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ var result1 = result2 !== null
+ ? (function() { return "null"; })()
+ : null;
+ if (result1 !== null) {
+ var result0 = result1;
+ } else {
+ var result0 = null;;
+ };
+ };
+ };
+ };
+ };
+ };
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_string(context) {
+ var cacheKey = "string" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+ var savedReportMatchFailures = context.reportMatchFailures;
+ context.reportMatchFailures = false;
+ var savedPos1 = pos;
+ if (input.substr(pos, 1) === "\"") {
+ var result9 = "\"";
+ pos += 1;
+ } else {
+ var result9 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\""));
+ }
+ }
+ if (result9 !== null) {
+ if (input.substr(pos, 1) === "\"") {
+ var result10 = "\"";
+ pos += 1;
+ } else {
+ var result10 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\""));
+ }
+ }
+ if (result10 !== null) {
+ var result11 = parse__(context);
+ if (result11 !== null) {
+ var result8 = [result9, result10, result11];
+ } else {
+ var result8 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result8 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result8 = null;
+ pos = savedPos1;
+ }
+ var result7 = result8 !== null
+ ? (function() { return ""; })()
+ : null;
+ if (result7 !== null) {
+ var result0 = result7;
+ } else {
+ var savedPos0 = pos;
+ if (input.substr(pos, 1) === "\"") {
+ var result3 = "\"";
+ pos += 1;
+ } else {
+ var result3 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\""));
+ }
+ }
+ if (result3 !== null) {
+ var result4 = parse_chars(context);
+ if (result4 !== null) {
+ if (input.substr(pos, 1) === "\"") {
+ var result5 = "\"";
+ pos += 1;
+ } else {
+ var result5 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\""));
+ }
+ }
+ if (result5 !== null) {
+ var result6 = parse__(context);
+ if (result6 !== null) {
+ var result2 = [result3, result4, result5, result6];
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ var result1 = result2 !== null
+ ? (function(chars) { return chars; })(result2[1])
+ : null;
+ if (result1 !== null) {
+ var result0 = result1;
+ } else {
+ var result0 = null;;
+ };
+ }
+ context.reportMatchFailures = savedReportMatchFailures;
+ if (context.reportMatchFailures && result0 === null) {
+ matchFailed("string");
+ }
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_chars(context) {
+ var cacheKey = "chars" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var result2 = parse_char(context);
+ if (result2 !== null) {
+ var result1 = [];
+ while (result2 !== null) {
+ result1.push(result2);
+ var result2 = parse_char(context);
+ }
+ } else {
+ var result1 = null;
+ }
+ var result0 = result1 !== null
+ ? (function(chars) { return chars.join(""); })(result1)
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_char(context) {
+ var cacheKey = "char" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ if (input.substr(pos).match(/^[^"\\\0-]/) !== null) {
+ var result24 = input.charAt(pos);
+ pos++;
+ } else {
+ var result24 = null;
+ if (context.reportMatchFailures) {
+ matchFailed("[^\"\\\\\\0-]");
+ }
+ }
+ if (result24 !== null) {
+ var result0 = result24;
+ } else {
+ if (input.substr(pos, 2) === "\\\"") {
+ var result23 = "\\\"";
+ pos += 2;
+ } else {
+ var result23 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\\""));
+ }
+ }
+ var result22 = result23 !== null
+ ? (function() { return '"'; })()
+ : null;
+ if (result22 !== null) {
+ var result0 = result22;
+ } else {
+ if (input.substr(pos, 2) === "\\\\") {
+ var result21 = "\\\\";
+ pos += 2;
+ } else {
+ var result21 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\\\"));
+ }
+ }
+ var result20 = result21 !== null
+ ? (function() { return "\\"; })()
+ : null;
+ if (result20 !== null) {
+ var result0 = result20;
+ } else {
+ if (input.substr(pos, 2) === "\\/") {
+ var result19 = "\\/";
+ pos += 2;
+ } else {
+ var result19 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\/"));
+ }
+ }
+ var result18 = result19 !== null
+ ? (function() { return "/"; })()
+ : null;
+ if (result18 !== null) {
+ var result0 = result18;
+ } else {
+ if (input.substr(pos, 2) === "\\b") {
+ var result17 = "\\b";
+ pos += 2;
+ } else {
+ var result17 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\b"));
+ }
+ }
+ var result16 = result17 !== null
+ ? (function() { return "\b"; })()
+ : null;
+ if (result16 !== null) {
+ var result0 = result16;
+ } else {
+ if (input.substr(pos, 2) === "\\f") {
+ var result15 = "\\f";
+ pos += 2;
+ } else {
+ var result15 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\f"));
+ }
+ }
+ var result14 = result15 !== null
+ ? (function() { return "\f"; })()
+ : null;
+ if (result14 !== null) {
+ var result0 = result14;
+ } else {
+ if (input.substr(pos, 2) === "\\n") {
+ var result13 = "\\n";
+ pos += 2;
+ } else {
+ var result13 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\n"));
+ }
+ }
+ var result12 = result13 !== null
+ ? (function() { return "\n"; })()
+ : null;
+ if (result12 !== null) {
+ var result0 = result12;
+ } else {
+ if (input.substr(pos, 2) === "\\r") {
+ var result11 = "\\r";
+ pos += 2;
+ } else {
+ var result11 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\r"));
+ }
+ }
+ var result10 = result11 !== null
+ ? (function() { return "\r"; })()
+ : null;
+ if (result10 !== null) {
+ var result0 = result10;
+ } else {
+ if (input.substr(pos, 2) === "\\t") {
+ var result9 = "\\t";
+ pos += 2;
+ } else {
+ var result9 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\t"));
+ }
+ }
+ var result8 = result9 !== null
+ ? (function() { return "\t"; })()
+ : null;
+ if (result8 !== null) {
+ var result0 = result8;
+ } else {
+ var savedPos0 = pos;
+ if (input.substr(pos, 2) === "\\u") {
+ var result3 = "\\u";
+ pos += 2;
+ } else {
+ var result3 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("\\u"));
+ }
+ }
+ if (result3 !== null) {
+ var result4 = parse_hexDigit(context);
+ if (result4 !== null) {
+ var result5 = parse_hexDigit(context);
+ if (result5 !== null) {
+ var result6 = parse_hexDigit(context);
+ if (result6 !== null) {
+ var result7 = parse_hexDigit(context);
+ if (result7 !== null) {
+ var result2 = [result3, result4, result5, result6, result7];
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ var result1 = result2 !== null
+ ? (function(h1, h2, h3, h4) {
+ return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4));
+ })(result2[1], result2[2], result2[3], result2[4])
+ : null;
+ if (result1 !== null) {
+ var result0 = result1;
+ } else {
+ var result0 = null;;
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_number(context) {
+ var cacheKey = "number" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+ var savedReportMatchFailures = context.reportMatchFailures;
+ context.reportMatchFailures = false;
+ var savedPos3 = pos;
+ var result17 = parse_int(context);
+ if (result17 !== null) {
+ var result18 = parse_frac(context);
+ if (result18 !== null) {
+ var result19 = parse_exp(context);
+ if (result19 !== null) {
+ var result20 = parse__(context);
+ if (result20 !== null) {
+ var result16 = [result17, result18, result19, result20];
+ } else {
+ var result16 = null;
+ pos = savedPos3;
+ }
+ } else {
+ var result16 = null;
+ pos = savedPos3;
+ }
+ } else {
+ var result16 = null;
+ pos = savedPos3;
+ }
+ } else {
+ var result16 = null;
+ pos = savedPos3;
+ }
+ var result15 = result16 !== null
+ ? (function(int_, frac, exp) { return parseFloat(int_ + frac + exp); })(result16[0], result16[1], result16[2])
+ : null;
+ if (result15 !== null) {
+ var result0 = result15;
+ } else {
+ var savedPos2 = pos;
+ var result12 = parse_int(context);
+ if (result12 !== null) {
+ var result13 = parse_frac(context);
+ if (result13 !== null) {
+ var result14 = parse__(context);
+ if (result14 !== null) {
+ var result11 = [result12, result13, result14];
+ } else {
+ var result11 = null;
+ pos = savedPos2;
+ }
+ } else {
+ var result11 = null;
+ pos = savedPos2;
+ }
+ } else {
+ var result11 = null;
+ pos = savedPos2;
+ }
+ var result10 = result11 !== null
+ ? (function(int_, frac) { return parseFloat(int_ + frac); })(result11[0], result11[1])
+ : null;
+ if (result10 !== null) {
+ var result0 = result10;
+ } else {
+ var savedPos1 = pos;
+ var result7 = parse_int(context);
+ if (result7 !== null) {
+ var result8 = parse_exp(context);
+ if (result8 !== null) {
+ var result9 = parse__(context);
+ if (result9 !== null) {
+ var result6 = [result7, result8, result9];
+ } else {
+ var result6 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result6 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result6 = null;
+ pos = savedPos1;
+ }
+ var result5 = result6 !== null
+ ? (function(int_, exp) { return parseFloat(int_ + exp); })(result6[0], result6[1])
+ : null;
+ if (result5 !== null) {
+ var result0 = result5;
+ } else {
+ var savedPos0 = pos;
+ var result3 = parse_int(context);
+ if (result3 !== null) {
+ var result4 = parse__(context);
+ if (result4 !== null) {
+ var result2 = [result3, result4];
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ var result1 = result2 !== null
+ ? (function(int_) { return parseFloat(int_); })(result2[0])
+ : null;
+ if (result1 !== null) {
+ var result0 = result1;
+ } else {
+ var result0 = null;;
+ };
+ };
+ };
+ }
+ context.reportMatchFailures = savedReportMatchFailures;
+ if (context.reportMatchFailures && result0 === null) {
+ matchFailed("number");
+ }
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_int(context) {
+ var cacheKey = "int" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos2 = pos;
+ var result13 = parse_digit19(context);
+ if (result13 !== null) {
+ var result14 = parse_digits(context);
+ if (result14 !== null) {
+ var result12 = [result13, result14];
+ } else {
+ var result12 = null;
+ pos = savedPos2;
+ }
+ } else {
+ var result12 = null;
+ pos = savedPos2;
+ }
+ var result11 = result12 !== null
+ ? (function(digit19, digits) { return digit19 + digits; })(result12[0], result12[1])
+ : null;
+ if (result11 !== null) {
+ var result0 = result11;
+ } else {
+ var result10 = parse_digit(context);
+ if (result10 !== null) {
+ var result0 = result10;
+ } else {
+ var savedPos1 = pos;
+ if (input.substr(pos, 1) === "-") {
+ var result7 = "-";
+ pos += 1;
+ } else {
+ var result7 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("-"));
+ }
+ }
+ if (result7 !== null) {
+ var result8 = parse_digit19(context);
+ if (result8 !== null) {
+ var result9 = parse_digits(context);
+ if (result9 !== null) {
+ var result6 = [result7, result8, result9];
+ } else {
+ var result6 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result6 = null;
+ pos = savedPos1;
+ }
+ } else {
+ var result6 = null;
+ pos = savedPos1;
+ }
+ var result5 = result6 !== null
+ ? (function(digit19, digits) { return "-" + digit19 + digits; })(result6[1], result6[2])
+ : null;
+ if (result5 !== null) {
+ var result0 = result5;
+ } else {
+ var savedPos0 = pos;
+ if (input.substr(pos, 1) === "-") {
+ var result3 = "-";
+ pos += 1;
+ } else {
+ var result3 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("-"));
+ }
+ }
+ if (result3 !== null) {
+ var result4 = parse_digit(context);
+ if (result4 !== null) {
+ var result2 = [result3, result4];
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result2 = null;
+ pos = savedPos0;
+ }
+ var result1 = result2 !== null
+ ? (function(digit) { return "-" + digit; })(result2[1])
+ : null;
+ if (result1 !== null) {
+ var result0 = result1;
+ } else {
+ var result0 = null;;
+ };
+ };
+ };
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_frac(context) {
+ var cacheKey = "frac" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos0 = pos;
+ if (input.substr(pos, 1) === ".") {
+ var result2 = ".";
+ pos += 1;
+ } else {
+ var result2 = null;
+ if (context.reportMatchFailures) {
+ matchFailed(quoteString("."));
+ }
+ }
+ if (result2 !== null) {
+ var result3 = parse_digits(context);
+ if (result3 !== null) {
+ var result1 = [result2, result3];
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ var result0 = result1 !== null
+ ? (function(digits) { return "." + digits; })(result1[1])
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_exp(context) {
+ var cacheKey = "exp" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos0 = pos;
+ var result2 = parse_e(context);
+ if (result2 !== null) {
+ var result3 = parse_digits(context);
+ if (result3 !== null) {
+ var result1 = [result2, result3];
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ var result0 = result1 !== null
+ ? (function(e, digits) { return e + digits; })(result1[0], result1[1])
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_digits(context) {
+ var cacheKey = "digits" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var result2 = parse_digit(context);
+ if (result2 !== null) {
+ var result1 = [];
+ while (result2 !== null) {
+ result1.push(result2);
+ var result2 = parse_digit(context);
+ }
+ } else {
+ var result1 = null;
+ }
+ var result0 = result1 !== null
+ ? (function(digits) { return digits.join(""); })(result1)
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_e(context) {
+ var cacheKey = "e" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ var savedPos0 = pos;
+ if (input.substr(pos).match(/^[eE]/) !== null) {
+ var result2 = input.charAt(pos);
+ pos++;
+ } else {
+ var result2 = null;
+ if (context.reportMatchFailures) {
+ matchFailed("[eE]");
+ }
+ }
+ if (result2 !== null) {
+ if (input.substr(pos).match(/^[+\-]/) !== null) {
+ var result4 = input.charAt(pos);
+ pos++;
+ } else {
+ var result4 = null;
+ if (context.reportMatchFailures) {
+ matchFailed("[+\\-]");
+ }
+ }
+ var result3 = result4 !== null ? result4 : '';
+ if (result3 !== null) {
+ var result1 = [result2, result3];
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ } else {
+ var result1 = null;
+ pos = savedPos0;
+ }
+ var result0 = result1 !== null
+ ? (function(e, sign) { return e + sign; })(result1[0], result1[1])
+ : null;
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_digit(context) {
+ 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 (context.reportMatchFailures) {
+ matchFailed("[0-9]");
+ }
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_digit19(context) {
+ var cacheKey = "digit19" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ if (input.substr(pos).match(/^[1-9]/) !== null) {
+ var result0 = input.charAt(pos);
+ pos++;
+ } else {
+ var result0 = null;
+ if (context.reportMatchFailures) {
+ matchFailed("[1-9]");
+ }
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_hexDigit(context) {
+ 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 (context.reportMatchFailures) {
+ matchFailed("[0-9a-fA-F]");
+ }
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse__(context) {
+ var cacheKey = "_" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+ var savedReportMatchFailures = context.reportMatchFailures;
+ context.reportMatchFailures = false;
+ var result0 = [];
+ var result1 = parse_whitespace(context);
+ while (result1 !== null) {
+ result0.push(result1);
+ var result1 = parse_whitespace(context);
+ }
+ context.reportMatchFailures = savedReportMatchFailures;
+ if (context.reportMatchFailures && result0 === null) {
+ matchFailed("whitespace");
+ }
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function parse_whitespace(context) {
+ var cacheKey = "whitespace" + '@' + pos;
+ var cachedResult = cache[cacheKey];
+ if (cachedResult) {
+ pos = cachedResult.nextPos;
+ return cachedResult.result;
+ }
+
+
+ if (input.substr(pos).match(/^[ \n\r]/) !== null) {
+ var result0 = input.charAt(pos);
+ pos++;
+ } else {
+ var result0 = null;
+ if (context.reportMatchFailures) {
+ matchFailed("[ \\n\\r]");
+ }
+ }
+
+
+
+ cache[cacheKey] = {
+ nextPos: pos,
+ result: result0
+ };
+ return result0;
+ }
+
+ function buildErrorMessage() {
+ function buildExpected(failuresExpected) {
+ switch (failuresExpected.length) {
+ case 0:
+ return 'end of input';
+ case 1:
+ return failuresExpected[0];
+ default:
+ failuresExpected.sort();
+ return failuresExpected.slice(0, failuresExpected.length - 1).join(', ')
+ + ' or '
+ + failuresExpected[failuresExpected.length - 1];
+ }
+ }
+
+ var expected = buildExpected(rightmostMatchFailuresExpected);
+ var actualPos = Math.max(pos, rightmostMatchFailuresPos);
+ var actual = actualPos < input.length
+ ? quoteString(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 = parse_start({ reportMatchFailures: true });
+
+ /*
+ * 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;
+})();
246 lib/reparse.js
@@ -0,0 +1,246 @@
+exports.ReParse = ReParse;
+
+function ReParse(input, ignorews) {
+ this.input = input;
+ this.ignoreWS = ignorews;
+}
+
+ReParse.prototype.eof = function() {
+ return this.input == '';
+};
+
+// Indicate failure, optionally resetting the input to a previous
+// state.
+ReParse.prototype.fail = function(input) {
+ if (input !== undefined)
+ this.input = input;
+ throw this.fail;
+};
+
+// Execute a production, which could be a function or a RegExp.
+ReParse.prototype.produce = function(method) {
+ var val = (method instanceof RegExp) ? this.match(method) : method.call(this);
+ this.ignoreWS && this.skipWS();
+ return val;
+};
+
+// Begin parsing using the given production, return the result. All
+// input must be consumed.
+ReParse.prototype.start = function(method) {
+ var val;
+
+ this.ignoreWS && this.skipWS();
+
+ try {
+ val = this.produce(method);
+ if (this.eof())
+ return val;
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ }
+
+ throw new Error("Could not parse '" + this.input + "'.");
+};
+
+// Try to produce a value from method. If it fails, restore the input
+// to its previous state.
+ReParse.prototype.maybe = function(method) {
+ var input = this.input;
+
+ try {
+ return this.produce(method);
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ }
+ return this.fail(input);
+};
+
+// If the production method fails, don't fail, just return otherwise.
+ReParse.prototype.option = function(method, otherwise) {
+ try {
+ return this.maybe(method);
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ return otherwise;
+ }
+};
+
+// Return the value produced by body. This is equivalent to
+// seq(left, body, right)[0].
+ReParse.prototype.between = function(left, right, body) {
+ var input = this.input,
+ val;
+
+ try {
+ this.produce(left);
+ val = this.produce(body);
+ this.produce(right);
+ return val;
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ }
+
+ return this.fail(input);
+};
+
+// Match a regular expression, returning the first captured group or
+// the matched string.
+ReParse.prototype.match = function match(pattern) {
+ var probe = this.input.match(pattern);
+
+ if (!probe)
+ return this.fail();
+
+ this.input = this.input.substr(probe[0].length);
+ return probe[1] === undefined ? probe[0] : probe[1];
+};
+
+// Return the result of the first production that matches.
+ReParse.prototype.choice = function choice() {
+ var input = this.input;
+
+ for (var i = 0, l = arguments.length; (i < l); i++)
+ try {
+ return this.produce(arguments[i]);
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ }
+
+ return this.fail(input);
+};
+
+// Match every production in a sequence, returning a list of the
+// values produced.
+ReParse.prototype.seq = function every() {
+ var val = new Array(arguments.length + 1),
+ input = this.input;
+
+ try {
+ for (var i = 0, l = arguments.length; i < l; i++)
+ val[i + 1] = this.produce(arguments[i]);
+ val[0] = input.substr(0, input.length - this.input.length);
+ return val;
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ }
+
+ return this.fail(input);
+};
+
+// Skip zero or more instances of method. Return the parser.
+ReParse.prototype.skip = function skip(method, min) {
+ var found = 0,
+ input = this.input;
+
+ while (!this.eof())
+ try {
+ this.maybe(method);
+ found += 1;
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ break;
+ }
+
+ return (min && found < min) ? this.fail(input) : this;
+};
+
+ReParse.prototype.skip1 = function(method) {
+ return this.skip(method, 1);
+};
+
+ReParse.prototype.skipWS = function() {
+ this.match(/^\s*/);
+ return this;
+};
+
+// Return a list of zero or more productions.
+ReParse.prototype.many = function many(method, min) {
+ var result = [],
+ input = this.input;
+
+ while (!this.eof())
+ try {
+ result.push(this.maybe(method));
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ break;
+ }
+
+ return (min && (result.length < min)) ? this.fail(input) : result;
+};
+
+ReParse.prototype.many1 = function(method) {
+ return this.many(method, 1);
+};
+
+// Return the array of values produced by method with sep between each
+// value.
+ReParse.prototype.sepBy = function(method, sep, min) {
+ var result = [],
+ input;
+
+ try {
+ result.push(this.produce(method));
+ while (!this.eof())
+ try {
+ input = this.input;
+ this.produce(sep);
+ result.push(this.produce(method));
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ this.fail(input);
+ }
+ } catch (err) {
+ if (err !== this.fail)
+ throw err;
+ }
+
+ return (min && (result.length < min)) ? this.fail(input) : result;
+};
+
+ReParse.prototype.sepBy1 = function(method, sep) {
+ return this.sepBy(method, sep, 1);
+};
+
+// Return the array of values produced by method. The series must be
+// terminated by end.
+ReParse.prototype.endBy = function(method, end, min) {
+ var val = this.many(method, min);
+ this.option(end);
+ return val;
+};
+
+ReParse.prototype.endBy1 = function(method, end) {
+ return this.endBy(method, end, 1);
+};
+
+// Return the array of values produced by method with sep between each
+// value. The series may be terminated by a sep.
+ReParse.prototype.sepEndBy = function(method, sep, min) {
+ var val = this.sepBy(method, sep, min);
+ this.option(sep);
+ return val;
+};
+
+ReParse.prototype.sepEndBy1 = function(method, sep) {
+ return this.sepEndBy(method, sep, 1);
+};
+
+if (!Error) {
+ function Error(message) {
+ this.message = message;
+ };
+
+ Error.prototype.toString = function() {
+ return 'ERROR: ' + this.message;
+ };
+}

0 comments on commit 8a964b1

Please sign in to comment.