pegjs-0.7.0/0000755000175000017500000000000012206663530012103 5ustar danieldanielpegjs-0.7.0/README.md0000644000175000017500000003565712206663530013402 0ustar danieldanielPEG.js ====== PEG.js is a simple parser generator for JavaScript that produces fast parsers with excellent error reporting. You can use it to process complex data or computer languages and build transformers, interpreters, compilers and other tools easily. Features -------- * Simple and expressive grammar syntax * Integrates both lexical and syntactical analysis * Parsers have excellent error reporting out of the box * Based on [parsing expression grammar](http://en.wikipedia.org/wiki/Parsing_expression_grammar) formalism — more powerful than traditional LL(*k*) and LR(*k*) parsers * Usable [from your browser](http://pegjs.majda.cz/online), from the command line, or via JavaScript API Getting Started --------------- [Online version](http://pegjs.majda.cz/online) is the easiest way to generate a parser. Just enter your grammar, try parsing few inputs, and download generated parser code. Installation ------------ ### Node.js To use the `pegjs` command, install PEG.js globally: $ npm install -g pegjs To use the JavaScript API, install PEG.js locally: $ npm install pegjs If you need both the `pegjs` command and the JavaScript API, install PEG.js both ways. ### Browser [Download](http://pegjs.majda.cz/#download) the PEG.js library (regular or minified version). Generating a Parser ------------------- PEG.js generates parser from a grammar that describes expected input and can specify what the parser returns (using semantic actions on matched parts of the input). Generated parser itself is a JavaScript object with a simple API. ### Command Line To generate a parser from your grammar, use the `pegjs` command: $ pegjs arithmetics.pegjs This writes parser source code into a file with the same name as the grammar file but with “.js” extension. You can also specify the output file explicitly: $ pegjs arithmetics.pegjs arithmetics-parser.js If you omit both input and ouptut file, standard input and output are used. By default, the parser object is assigned to `module.exports`, which makes the output a Node.js module. You can assign it to another variable by passing a variable name using the `-e`/`--export-var` option. This may be helpful if you want to use the parser in browser environment. You can tweak the generated parser with two options: * `--cache` — makes the parser cache results, avoiding exponential parsing time in pathological cases but making the parser slower * `--track-line-and-column` — makes the parser track line and column (available as `line` and `column` variables in the actions and predicates) ### JavaScript API In Node.js, require the PEG.js parser generator module: var PEG = require("pegjs"); In browser, include the PEG.js library in your web page or application using the `

PEG.js Test Suite

    pegjs-0.7.0/test/passes-test.js0000644000175000017500000003731612206663530015705 0ustar danieldaniel(function() { module("PEG.compiler.passes"); test("reports missing referenced rules", function() { function testGrammar(grammar) { raises( function() { var ast = PEG.parser.parse(grammar); PEG.compiler.passes.reportMissingRules(ast); }, function(e) { return e instanceof PEG.GrammarError && e.message === "Referenced rule \"missing\" does not exist."; } ); } var grammars = [ 'start = missing', 'start = missing / "a" / "b"', 'start = "a" / "b" / missing', 'start = missing "a" "b"', 'start = "a" "b" missing', 'start = label:missing', 'start = &missing', 'start = !missing', 'start = missing?', 'start = missing*', 'start = missing+', 'start = missing { }' ]; for (var i = 0; i < grammars.length; i++) { testGrammar(grammars[i]); } }); test("reports left recursion", function() { function testGrammar(grammar) { raises( function() { var ast = PEG.parser.parse(grammar); PEG.compiler.passes.reportLeftRecursion(ast); }, function(e) { return e instanceof PEG.GrammarError && e.message === "Left recursion detected for rule \"start\"."; } ); } var grammars = [ /* Direct */ 'start = start', 'start = start / "a" / "b"', 'start = "a" / "b" / start', 'start = start "a" "b"', 'start = label:start', 'start = &start', 'start = !start', 'start = start?', 'start = start*', 'start = start+', 'start = start { }', /* Indirect */ 'start = stop; stop = start' ]; for (var i = 0; i < grammars.length; i++) { testGrammar(grammars[i]); } }); test("removes proxy rules", function() { function simpleGrammar(rules, startRule) { return { type: "grammar", initializer: null, rules: rules, startRule: startRule }; } var proxiedRule = { type: "rule", name: "proxied", displayName: null, expression: { type: "literal", value: "a", ignoreCase: false } }; var proxiedRuleRef = { type: "rule_ref", name: "proxied" }; function simpleGrammarWithStartAndProxied(startRuleExpression) { return simpleGrammar( [ { type: "rule", name: "start", displayName: null, expression: startRuleExpression }, proxiedRule ], "start" ); } var cases = [ { grammar: 'start = proxy; proxy = proxied; proxied = "a"', ast: simpleGrammar([proxiedRule], "proxied") }, { grammar: 'start = proxy / "a" / "b"; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "choice", alternatives: [ proxiedRuleRef, { type: "literal", value: "a", ignoreCase: false }, { type: "literal", value: "b", ignoreCase: false } ] }) }, { grammar: 'start = "a" / "b" / proxy; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "choice", alternatives: [ { type: "literal", value: "a", ignoreCase: false }, { type: "literal", value: "b", ignoreCase: false }, proxiedRuleRef ] }) }, { grammar: 'start = proxy "a" "b"; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "sequence", elements: [ proxiedRuleRef, { type: "literal", value: "a", ignoreCase: false }, { type: "literal", value: "b", ignoreCase: false } ] }) }, { grammar: 'start = "a" "b" proxy; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "sequence", elements: [ { type: "literal", value: "a", ignoreCase: false }, { type: "literal", value: "b", ignoreCase: false }, proxiedRuleRef ] }) }, { grammar: 'start = label:proxy; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "labeled", label: "label", expression: proxiedRuleRef }) }, { grammar: 'start = &proxy; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "simple_and", expression: proxiedRuleRef }) }, { grammar: 'start = !proxy; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "simple_not", expression: proxiedRuleRef }) }, { grammar: 'start = proxy?; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "optional", expression: proxiedRuleRef }) }, { grammar: 'start = proxy*; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "zero_or_more", expression: proxiedRuleRef }) }, { grammar: 'start = proxy+; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "one_or_more", expression: proxiedRuleRef }) }, { grammar: 'start = proxy { }; proxy = proxied; proxied = "a"', ast: simpleGrammarWithStartAndProxied({ type: "action", code: " ", expression: proxiedRuleRef }) } ]; for (var i = 0; i < cases.length; i++) { var ast = PEG.parser.parse(cases[i].grammar); PEG.compiler.passes.removeProxyRules(ast); deepEqual(ast, cases[i].ast); } }); test("computes variable names", function() { var leafDetails = { resultVar: "result0" }, choiceDetails = { resultVar: "result0", alternatives: [ { resultVar: "result0", posVar: "pos0" }, { resultVar: "result0", posVar: "pos0" }, { resultVar: "result0", posVar: "pos0" } ] }, sequenceDetails = { resultVar: "result0", posVar: "pos0", elements: [ { resultVar: "result0", posVar: "pos1" }, { resultVar: "result1", posVar: "pos1" }, { resultVar: "result2", posVar: "pos1" } ] }; var cases = [ /* Choice */ { grammar: 'start = &"a" / &"b" / &"c"', resultVars: ["result0"], posVars: ["pos0"], details: choiceDetails }, { grammar: 'start = &"a" / &"b"* / &"c"', resultVars: ["result0", "result1"], posVars: ["pos0"], details: choiceDetails }, { grammar: 'start = &"a" / &(&"b") / &"c"', resultVars: ["result0"], posVars: ["pos0", "pos1"], details: choiceDetails }, /* Sequence */ { grammar: 'start = ', resultVars: ["result0"], posVars: ["pos0"], details: { resultVar: "result0", posVar: "pos0" } }, { grammar: 'start = &"a" &"b" &"c"', resultVars: ["result0", "result1", "result2"], posVars: ["pos0", "pos1"], details: sequenceDetails }, { grammar: 'start = &"a" &"b" &"c"*', resultVars: ["result0", "result1", "result2", "result3"], posVars: ["pos0", "pos1"], details: sequenceDetails }, { grammar: 'start = &"a" &"b"* &"c"', resultVars: ["result0", "result1", "result2"], posVars: ["pos0", "pos1"], details: sequenceDetails }, { grammar: 'start = &"a" &("b"*)* &"c"', resultVars: ["result0", "result1", "result2", "result3"], posVars: ["pos0", "pos1"], details: sequenceDetails }, { grammar: 'start = &"a"* &"b" &"c"', resultVars: ["result0", "result1", "result2"], posVars: ["pos0", "pos1"], details: sequenceDetails }, { grammar: 'start = &("a"*)* &"b" &"c"', resultVars: ["result0", "result1", "result2"], posVars: ["pos0", "pos1"], details: sequenceDetails }, { grammar: 'start = &(("a"*)*)* &"b" &"c"', resultVars: ["result0", "result1", "result2", "result3"], posVars: ["pos0", "pos1"], details: sequenceDetails }, { grammar: 'start = &"a" &(&"b") &"c"', resultVars: ["result0", "result1", "result2"], posVars: ["pos0", "pos1", "pos2"], details: sequenceDetails }, /* Others */ { grammar: 'start = label:&"a"', resultVars: ["result0"], posVars: ["pos0"], details: { resultVar: "result0", expression: { resultVar: "result0", posVar: "pos0" } } }, { grammar: 'start = &(&"a")', resultVars: ["result0"], posVars: ["pos0", "pos1"], details: { resultVar: "result0", posVar: "pos0", expression: { resultVar: "result0", posVar: "pos1" } } }, { grammar: 'start = !(&"a")', resultVars: ["result0"], posVars: ["pos0", "pos1"], details: { resultVar: "result0", posVar: "pos0", expression: { resultVar: "result0", posVar: "pos1" } } }, { grammar: 'start = &{ code }', resultVars: ["result0"], posVars: [], details: leafDetails }, { grammar: 'start = !{ code }', resultVars: ["result0"], posVars: [], details: leafDetails }, { grammar: 'start = (&"a")?', resultVars: ["result0"], posVars: ["pos0"], details: { resultVar: "result0", expression: { resultVar: "result0", posVar: "pos0" } } }, { grammar: 'start = (&"a")*', resultVars: ["result0", "result1"], posVars: ["pos0"], details: { resultVar: "result0", expression: { resultVar: "result1", posVar: "pos0" } } }, { grammar: 'start = (&"a")+', resultVars: ["result0", "result1"], posVars: ["pos0"], details: { resultVar: "result0", expression: { resultVar: "result1", posVar: "pos0" } } }, { grammar: 'start = &"a" { code }', resultVars: ["result0"], posVars: ["pos0", "pos1"], details: { resultVar: "result0", posVar: "pos0", expression: { resultVar: "result0", posVar: "pos1" } } }, { grammar: 'start = a', resultVars: ["result0"], posVars: [], details: leafDetails }, { grammar: 'start = "a"', resultVars: ["result0"], posVars: [], details: leafDetails }, { grammar: 'start = .', resultVars: ["result0"], posVars: [], details: leafDetails }, { grammar: 'start = [a-z]', resultVars: ["result0"], posVars: [], details: leafDetails } ]; function checkDetails(node, details) { for (var key in details) { if (Object.prototype.toString.call(details[key]) === "[object Array]") { for (var i = 0; i < details[key].length; i++) { checkDetails(node[key][i], details[key][i]); } } else if (typeof details[key] === "object") { checkDetails(node[key], details[key]); } else { strictEqual(node[key], details[key]); } } } for (var i = 0; i < cases.length; i++) { var ast = PEG.parser.parse(cases[i].grammar); PEG.compiler.passes.computeVarNames(ast); deepEqual(ast.rules[0].resultVars, cases[i].resultVars); deepEqual(ast.rules[0].posVars, cases[i].posVars); checkDetails(ast.rules[0].expression, cases[i].details); } }); test("computes params", function() { function extractNode(node) { return node; } function extractExpression(node) { return node.expression; } var cases = [ /* Bacics */ { grammar: 'start = a:"a" { }', extractor: extractNode, params: { a: "result0" } }, { grammar: 'start = a:"a" &{ }', extractor: function(node) { return node.elements[1]; }, params: { a: "result0" } }, { grammar: 'start = a:"a" !{ }', extractor: function(node) { return node.elements[1]; }, params: { a: "result0" } }, /* Recursive walk */ { grammar: 'start = a:"a" { } / "b" / "c"', extractor: function(node) { return node.alternatives[0]; }, params: { a: "result0" } }, { grammar: 'start = "a" / "b" / c:"c" { }', extractor: function(node) { return node.alternatives[2]; }, params: { c: "result0" } }, { grammar: 'start = (a:"a" { }) "b" "c"', extractor: function(node) { return node.elements[0]; }, params: { a: "result0" } }, { grammar: 'start = "a" "b" (c:"c" { })', extractor: function(node) { return node.elements[2]; }, params: { c: "result2" } }, { grammar: 'start = a:(b:"b" { })', extractor: extractExpression, params: { b: "result0" } }, { grammar: 'start = &(a:"a" { })', extractor: extractExpression, params: { a: "result0" } }, { grammar: 'start = !(a:"a" { })', extractor: extractExpression, params: { a: "result0" } }, { grammar: 'start = (a:"a" { })?', extractor: extractExpression, params: { a: "result0" } }, { grammar: 'start = (a:"a" { })*', extractor: extractExpression, params: { a: "result1" } }, { grammar: 'start = (a:"a" { })+', extractor: extractExpression, params: { a: "result1" } }, { grammar: 'start = (a:"a" { }) { }', extractor: extractExpression, params: { a: "result0" } }, /* Scoping */ { grammar: 'start = (a:"a" / b:"b" / c:"c") { }', extractor: extractNode, params: { } }, { grammar: 'start = a:(b:"b") { }', extractor: extractNode, params: { a: "result0" } }, { grammar: 'start = &(a:"a") { }', extractor: extractNode, params: { } }, { grammar: 'start = !(a:"a") { }', extractor: extractNode, params: { } }, { grammar: 'start = (a:"a")? { }', extractor: extractNode, params: { } }, { grammar: 'start = (a:"a")* { }', extractor: extractNode, params: { } }, { grammar: 'start = (a:"a")+ { }', extractor: extractNode, params: { } }, { grammar: 'start = (a:"a" { }) { }', extractor: extractNode, params: { } }, /* Sequences */ { grammar: 'start = a:"a" b:"b" c:"c" { }', extractor: extractNode, params: { a: "result0[0]", b: "result0[1]", c: "result0[2]" } }, { grammar: 'start = a:"a" (b:"b" c:"c" d:"d") e:"e"{ }', extractor: extractNode, params: { a: "result0[0]", b: "result0[1][0]", c: "result0[1][1]", d: "result0[1][2]", e: "result0[2]" } }, /* * Regression tests for a bug where e.g. resultVar names like |result10| * were incorrectly treated as names derived from |result1|, leading to * incorrect substitution. */ { grammar: 'start = ("a" "b" "c" "d" "e" "f" "g" "h" "i" j:"j" { })*', extractor: extractExpression, params: { j: "result1[9]" } // Buggy code put "result1[0]0" here. } ]; for (var i = 0; i < cases.length; i++) { var ast = PEG.parser.parse(cases[i].grammar); PEG.compiler.passes.computeVarNames(ast); PEG.compiler.passes.computeParams(ast); deepEqual( cases[i].extractor(ast.rules[0].expression).params, cases[i].params ); } }); })(); pegjs-0.7.0/test/run0000755000175000017500000000401712206663530013616 0ustar danieldaniel#!/usr/bin/env node var util = require("util"), fs = require("fs"), PEG = require("../lib/peg"), QUnit = require("./vendor/qunit/qunit"); var failedAssertions = []; function bold(s) { return "\u001B[1m" + s + "\u001B[22m"; }; function message(s) { return "\u001B[35m" + s + "\u001B[39m"; }; function ok(s) { return "\u001B[32m" + s + "\u001B[39m"; }; function error(s) { return "\u001B[31m" + s + "\u001B[39m"; }; function indent(s) { return s.replace(/^/gm, " "); } QUnit.init(); QUnit.config.blocking = true; QUnit.config.updateRate = 0; QUnit.moduleStart(function(details) { util.puts(""); util.puts(bold(details.name)); }); QUnit.testStart(function(details) { failedAssertions = []; }); QUnit.testDone(function(details) { if (details.failed == 0) { util.puts('✔ ' + details.name); } else { util.puts(error('✖ ' + details.name)); util.puts(""); failedAssertions.forEach(function(assertion) { util.puts(assertion); }); } }); QUnit.log(function(details) { var output = ""; if (details.result) { return; } if (details.message) { output += indent("Message: " + message(details.message)) + "\n"; } if (details.actual && details.expected) { output += indent("Expected: " + QUnit.jsDump.parse(details.expected)) + "\n"; if (details.actual != details.expected) { output += indent("Actual: " + QUnit.jsDump.parse(details.actual)); } } failedAssertions.push(output); }); QUnit.done(function(details) { util.puts(""); if (details.failed > 0) { util.puts(bold(error("FAILURES: ")) + details.failed + "/" + details.total + " assertions failed (" + details.runtime + " ms)" ); } else { util.puts(bold(ok('OK: ')) + details.total + " assertions (" + details.runtime + " ms)" ) } }); [ "helpers.js", "parser-test.js", "passes-test.js", "compiler-test.js", ].forEach(function(file) { eval("with (QUnit) {" + fs.readFileSync(__dirname + "/" + file, "utf8") + "}"); }); QUnit.start(); pegjs-0.7.0/test/compiler-test.js0000644000175000017500000010611512206663530016213 0ustar danieldaniel(function() { module("PEG.compiler"); function testWithVaryingTrackLineAndColumn(name, callback) { test( name + " (with trackLineAndColumn: false) ", function() { callback({ trackLineAndColumn: false }); } ); test( name + " (with trackLineAndColumn: true) ", function() { callback({ trackLineAndColumn: true }); } ); } testWithVaryingTrackLineAndColumn("choices", function(options) { var parser = PEG.buildParser('start = "a" / "b" / "c"', options); parses(parser, "a", "a"); parses(parser, "b", "b"); parses(parser, "c", "c"); doesNotParse(parser, ""); doesNotParse(parser, "ab"); doesNotParse(parser, "d"); }); testWithVaryingTrackLineAndColumn("sequences", function(options) { var emptySequenceParser = PEG.buildParser('start = ', options); parses(emptySequenceParser, "", []); doesNotParse(emptySequenceParser, "abc"); var nonEmptySequenceParser = PEG.buildParser('start = "a" "b" "c"', options); parses(nonEmptySequenceParser, "abc", ["a", "b", "c"]); doesNotParse(nonEmptySequenceParser, ""); doesNotParse(nonEmptySequenceParser, "ab"); doesNotParse(nonEmptySequenceParser, "abcd"); doesNotParse(nonEmptySequenceParser, "efg"); /* * Test that the parsing position returns after unsuccessful parsing of a * sequence. */ var posTestParser = PEG.buildParser('start = ("a" "b") / "a"', options); parses(posTestParser, "a", "a"); }); testWithVaryingTrackLineAndColumn("labels", function(options) { var parser = PEG.buildParser('start = label:"a"', options); parses(parser, "a", "a"); doesNotParse(parser, "b"); }); testWithVaryingTrackLineAndColumn("simple and", function(options) { var parser = PEG.buildParser('start = "a" &"b" "b"', options); parses(parser, "ab", ["a", "", "b"]); doesNotParse(parser, "ac"); /* * Test that the parsing position returns after successful parsing of a * predicate is not needed, it is implicit in the tests above. */ }); testWithVaryingTrackLineAndColumn("simple not", function(options) { var parser = PEG.buildParser('start = "a" !"b"', options); parses(parser, "a", ["a", ""]); doesNotParse(parser, "ab"); /* * Test that the parsing position returns after successful parsing of a * predicate. */ var posTestParser = PEG.buildParser('start = "a" !"b" "c"'); parses(posTestParser, "ac", ["a", "", "c"]); }); test("semantic and (with trackLineAndColumn: false)", function() { var options = { trackLineAndColumn: false }; var acceptingParser = PEG.buildParser( 'start = "a" &{ return true; } "b"', options ); parses(acceptingParser, "ab", ["a", "", "b"]); var rejectingParser = PEG.buildParser( 'start = "a" &{ return false; } "b"', options ); doesNotParse(rejectingParser, "ab"); var singleElementUnlabeledParser = PEG.buildParser( 'start = "a" &{ return arguments.length === 1 && offset === 1; }', options ); parses(singleElementUnlabeledParser, "a", ["a", ""]); var singleElementLabeledParser = PEG.buildParser([ 'start = a:"a" &{', ' return arguments.length === 2', ' && offset === 1', ' && a === "a";', ' }' ].join("\n"), options); parses(singleElementLabeledParser, "a", ["a", ""]); var multiElementUnlabeledParser = PEG.buildParser( 'start = "a" "b" "c" &{ return arguments.length === 1 && offset === 3; }', options ); parses(multiElementUnlabeledParser, "abc", ["a", "b", "c", ""]); var multiElementLabeledParser = PEG.buildParser([ 'start = a:"a" "b" c:"c" &{', ' return arguments.length === 3', ' && offset === 3', ' && a === "a"', ' && c === "c";', ' }' ].join("\n"), options); parses(multiElementLabeledParser, "abc", ["a", "b", "c", ""]); var innerElementsUnlabeledParser = PEG.buildParser([ 'start = "a"', ' ("b" "c" "d" &{ return arguments.length === 1 && offset === 4; })', ' "e"' ].join("\n"), options); parses(innerElementsUnlabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); var innerElementsLabeledParser = PEG.buildParser([ 'start = "a"', ' (', ' b:"b" "c" d:"d" &{', ' return arguments.length === 3', ' && offset === 4', ' && b === "b"', ' && d === "d";', ' }', ' )', ' "e"' ].join("\n"), options); parses(innerElementsLabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); }); test("semantic and (with trackLineAndColumn: true)", function() { var options = { trackLineAndColumn: true }; var acceptingParser = PEG.buildParser( 'start = "a" &{ return true; } "b"', options ); parses(acceptingParser, "ab", ["a", "", "b"]); var rejectingParser = PEG.buildParser( 'start = "a" &{ return false; } "b"', options ); doesNotParse(rejectingParser, "ab"); var singleElementUnlabeledParser = PEG.buildParser([ 'start = "a" &{', ' return arguments.length === 3', ' && offset === 1', ' && line === 1', ' && column === 2;', ' }' ].join("\n"), options); parses(singleElementUnlabeledParser, "a", ["a", ""]); var singleElementLabeledParser = PEG.buildParser([ 'start = a:"a" &{', ' return arguments.length === 4', ' && offset === 1', ' && line === 1', ' && column === 2', ' && a === "a";', ' }' ].join("\n"), options); parses(singleElementLabeledParser, "a", ["a", ""]); var multiElementUnlabeledParser = PEG.buildParser([ 'start = "a" "b" "c" &{', ' return arguments.length === 3', ' && offset === 3', ' && line === 1', ' && column === 4;', ' }' ].join("\n"), options); parses(multiElementUnlabeledParser, "abc", ["a", "b", "c", ""]); var multiElementLabeledParser = PEG.buildParser([ 'start = a:"a" "b" c:"c" &{', ' return arguments.length === 5', ' && offset === 3', ' && line === 1', ' && column === 4', ' && a === "a"', ' && c === "c";', ' }' ].join("\n"), options); parses(multiElementLabeledParser, "abc", ["a", "b", "c", ""]); var innerElementsUnlabeledParser = PEG.buildParser([ 'start = "a"', ' (', ' "b" "c" "d" &{', ' return arguments.length === 3', ' && offset === 4', ' && line === 1', ' && column === 5;', ' }', ' )', ' "e"' ].join("\n"), options); parses(innerElementsUnlabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); var innerElementsLabeledParser = PEG.buildParser([ 'start = "a"', ' (', ' b:"b" "c" d:"d" &{', ' return arguments.length === 5', ' && offset === 4', ' && line === 1', ' && column === 5', ' && b === "b"', ' && d === "d";', ' }', ' )', ' "e"' ].join("\n"), options); parses(innerElementsLabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); var digitsParser = PEG.buildParser([ '{ var result; }', 'start = line (nl+ line)* { return result; }', 'line = thing (" "+ thing)*', 'thing = digit / mark', 'digit = [0-9]', 'mark = &{ result = [line, column]; return true; } "x"', 'nl = ("\\r" / "\\n" / "\\u2028" / "\\u2029")' ].join("\n"), options); parses(digitsParser, "1\n2\n\n3\n\n\n4 5 x", [7, 5]); /* Non-Unix newlines */ parses(digitsParser, "1\rx", [2, 1]); // Old Mac parses(digitsParser, "1\r\nx", [2, 1]); // Windows parses(digitsParser, "1\n\rx", [3, 1]); // mismatched /* Strange newlines */ parses(digitsParser, "1\u2028x", [2, 1]); // line separator parses(digitsParser, "1\u2029x", [2, 1]); // paragraph separator }); test("semantic not (with trackLineAndColumn: false)", function() { var options = { trackLineAndColumn: false }; var acceptingParser = PEG.buildParser( 'start = "a" !{ return false; } "b"', options ); parses(acceptingParser, "ab", ["a", "", "b"]); var rejectingParser = PEG.buildParser( 'start = "a" !{ return true; } "b"', options ); doesNotParse(rejectingParser, "ab"); var singleElementUnlabeledParser = PEG.buildParser( 'start = "a" !{ return arguments.length !== 1 || offset !== 1; }', options ); parses(singleElementUnlabeledParser, "a", ["a", ""]); var singleElementLabeledParser = PEG.buildParser([ 'start = a:"a" !{', ' return arguments.length !== 2', ' || offset !== 1', ' || a !== "a";', ' }' ].join("\n"), options); parses(singleElementLabeledParser, "a", ["a", ""]); var multiElementUnlabeledParser = PEG.buildParser( 'start = "a" "b" "c" !{ return arguments.length !== 1 || offset !== 3; }', options ); parses(multiElementUnlabeledParser, "abc", ["a", "b", "c", ""]); var multiElementLabeledParser = PEG.buildParser([ 'start = a:"a" "b" c:"c" !{', ' return arguments.length !== 3', ' || offset !== 3', ' || a !== "a"', ' || c !== "c";', ' }' ].join("\n"), options); parses(multiElementLabeledParser, "abc", ["a", "b", "c", ""]); var innerElementsUnlabeledParser = PEG.buildParser([ 'start = "a"', ' ("b" "c" "d" !{ return arguments.length !== 1 || offset !== 4; })', ' "e"' ].join("\n"), options); parses(innerElementsUnlabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); var innerElementsLabeledParser = PEG.buildParser([ 'start = "a"', ' (', ' b:"b" "c" d:"d" !{', ' return arguments.length !== 3', ' || offset !== 4', ' || b !== "b"', ' || d !== "d";', ' }', ' )', ' "e"' ].join("\n"), options); parses(innerElementsLabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); }); test("semantic not (with trackLineAndColumn: true)", function() { var options = { trackLineAndColumn: true }; var acceptingParser = PEG.buildParser( 'start = "a" !{ return false; } "b"', options ); parses(acceptingParser, "ab", ["a", "", "b"]); var rejectingParser = PEG.buildParser( 'start = "a" !{ return true; } "b"', options ); doesNotParse(rejectingParser, "ab"); var singleElementUnlabeledParser = PEG.buildParser([ 'start = "a" !{', ' return arguments.length !== 3', ' || offset !== 1', ' || line !== 1', ' || column !== 2;', ' }' ].join("\n"), options); parses(singleElementUnlabeledParser, "a", ["a", ""]); var singleElementLabeledParser = PEG.buildParser([ 'start = a:"a" !{', ' return arguments.length !== 4', ' || offset !== 1', ' || line !== 1', ' || column !== 2', ' || a !== "a";', ' }' ].join("\n"), options); parses(singleElementLabeledParser, "a", ["a", ""]); var multiElementUnlabeledParser = PEG.buildParser([ 'start = "a" "b" "c" !{', ' return arguments.length !== 3', ' || offset !== 3', ' || line !== 1', ' || column !== 4;', ' }' ].join("\n"), options); parses(multiElementUnlabeledParser, "abc", ["a", "b", "c", ""]); var multiElementLabeledParser = PEG.buildParser([ 'start = a:"a" "b" c:"c" !{', ' return arguments.length !== 5', ' || offset !== 3', ' || line !== 1', ' || column !== 4', ' || a !== "a"', ' || c !== "c";', ' }' ].join("\n"), options); parses(multiElementLabeledParser, "abc", ["a", "b", "c", ""]); var innerElementsUnlabeledParser = PEG.buildParser([ 'start = "a"', ' (', ' "b" "c" "d" !{', ' return arguments.length !== 3', ' || offset !== 4', ' || line !== 1', ' || column !== 5;', ' }', ' )', ' "e"' ].join("\n"), options); parses(innerElementsUnlabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); var innerElementsLabeledParser = PEG.buildParser([ 'start = "a"', ' (', ' b:"b" "c" d:"d" !{', ' return arguments.length !== 5', ' || offset !== 4', ' || line !== 1', ' || column !== 5', ' || b !== "b"', ' || d !== "d";', ' }', ' )', ' "e"' ].join("\n"), options); parses(innerElementsLabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); var digitsParser = PEG.buildParser([ '{ var result; }', 'start = line (nl+ line)* { return result; }', 'line = thing (" "+ thing)*', 'thing = digit / mark', 'digit = [0-9]', 'mark = !{ result = [line, column]; return false; } "x"', 'nl = ("\\r" / "\\n" / "\\u2028" / "\\u2029")' ].join("\n"), options); parses(digitsParser, "1\n2\n\n3\n\n\n4 5 x", [7, 5]); /* Non-Unix newlines */ parses(digitsParser, "1\rx", [2, 1]); // Old Mac parses(digitsParser, "1\r\nx", [2, 1]); // Windows parses(digitsParser, "1\n\rx", [3, 1]); // mismatched /* Strange newlines */ parses(digitsParser, "1\u2028x", [2, 1]); // line separator parses(digitsParser, "1\u2029x", [2, 1]); // paragraph separator }); testWithVaryingTrackLineAndColumn("optional expressions", function(options) { var parser = PEG.buildParser('start = "a"?', options); parses(parser, "", ""); parses(parser, "a", "a"); }); testWithVaryingTrackLineAndColumn("zero or more expressions", function(options) { var parser = PEG.buildParser('start = "a"*', options); parses(parser, "", []); parses(parser, "a", ["a"]); parses(parser, "aaa", ["a", "a", "a"]); }); testWithVaryingTrackLineAndColumn("one or more expressions", function(options) { var parser = PEG.buildParser('start = "a"+', options); doesNotParse(parser, ""); parses(parser, "a", ["a"]); parses(parser, "aaa", ["a", "a", "a"]); }); test("actions (with trackLineAndColumn: false)", function() { var options = { trackLineAndColumn: false }; var singleElementUnlabeledParser = PEG.buildParser( 'start = "a" { return arguments.length; }', options ); parses(singleElementUnlabeledParser, "a", 1); var singleElementLabeledParser = PEG.buildParser( 'start = a:"a" { return [arguments.length, offset, a]; }', options ); parses(singleElementLabeledParser, "a", [2, 0, "a"]); var multiElementUnlabeledParser = PEG.buildParser( 'start = "a" "b" "c" { return arguments.length; }', options ); parses(multiElementUnlabeledParser, "abc", 1); var multiElementLabeledParser = PEG.buildParser( 'start = a:"a" "b" c:"c" { return [arguments.length, offset, a, c]; }', options ); parses(multiElementLabeledParser, "abc", [3, 0, "a", "c"]); var innerElementsUnlabeledParser = PEG.buildParser( 'start = "a" ("b" "c" "d" { return arguments.length; }) "e"', options ); parses(innerElementsUnlabeledParser, "abcde", ["a", 1, "e"]); var innerElementsLabeledParser = PEG.buildParser([ 'start = "a"', ' (b:"b" "c" d:"d" { return [arguments.length, offset, b, d]; })', ' "e"' ].join("\n"), options); parses(innerElementsLabeledParser, "abcde", ["a", [3, 1, "b", "d"], "e"]); /* * Test that the parsing position returns after successfull parsing of the * action expression and action returning |null|. */ var posTestParser = PEG.buildParser( 'start = "a" { return null; } / "a"', options ); parses(posTestParser, "a", "a"); /* Test that the action is not called when its expression does not match. */ var notAMatchParser = PEG.buildParser( 'start = "a" { ok(false, "action got called when it should not be"); }', options ); doesNotParse(notAMatchParser, "b"); }); test("actions (with trackLineAndColumn: true)", function() { var options = { trackLineAndColumn: true }; var singleElementUnlabeledParser = PEG.buildParser( 'start = "a" { return arguments.length; }', options ); parses(singleElementUnlabeledParser, "a", 3); var singleElementLabeledParser = PEG.buildParser( 'start = a:"a" { return [arguments.length, offset, line, column, a]; }', options ); parses(singleElementLabeledParser, "a", [4, 0, 1, 1, "a"]); var multiElementUnlabeledParser = PEG.buildParser( 'start = "a" "b" "c" { return arguments.length; }', options ); parses(multiElementUnlabeledParser, "abc", 3); var multiElementLabeledParser = PEG.buildParser([ 'start = a:"a" "b" c:"c" {', ' return [arguments.length, offset, line, column, a, c];', '}' ].join("\n"), options); parses(multiElementLabeledParser, "abc", [5, 0, 1, 1, "a", "c"]); var innerElementsUnlabeledParser = PEG.buildParser( 'start = "a" ("b" "c" "d" { return arguments.length; }) "e"', options ); parses(innerElementsUnlabeledParser, "abcde", ["a", 3, "e"]); var innerElementsLabeledParser = PEG.buildParser([ 'start = "a"', ' (', ' b:"b" "c" d:"d" {', ' return [arguments.length, offset, line, column, b, d];', ' }', ' )', ' "e"' ].join("\n"), options); parses( innerElementsLabeledParser, "abcde", ["a", [5, 1, 1, 2, "b", "d"], "e"] ); /* * Test that the parsing position returns after successfull parsing of the * action expression and action returning |null|. */ var posTestParser = PEG.buildParser( 'start = "a" { return null; } / "a"', options ); parses(posTestParser, "a", "a"); /* Test that the action is not called when its expression does not match. */ var notAMatchParser = PEG.buildParser( 'start = "a" { ok(false, "action got called when it should not be"); }', options ); doesNotParse(notAMatchParser, "b"); var numbersParser = PEG.buildParser([ '{ var result; }', 'start = line (nl+ line)* { return result; }', 'line = thing (" "+ thing)*', 'thing = digit / mark', 'digit = [0-9]', 'mark = "x" { result = [line, column]; }', 'nl = ("\\r" / "\\n" / "\\u2028" / "\\u2029")' ].join("\n"), options); parses(numbersParser, "1\n2\n\n3\n\n\n4 5 x", [7, 5]); /* Non-Unix newlines */ parses(numbersParser, "1\rx", [2, 1]); // Old Mac parses(numbersParser, "1\r\nx", [2, 1]); // Windows parses(numbersParser, "1\n\rx", [3, 1]); // mismatched /* Strange newlines */ parses(numbersParser, "1\u2028x", [2, 1]); // line separator parses(numbersParser, "1\u2029x", [2, 1]); // paragraph separator }); testWithVaryingTrackLineAndColumn("initializer", function(options) { var variableInActionParser = PEG.buildParser( '{ a = 42; }; start = "a" { return a; }', options ); parses(variableInActionParser, "a", 42); var functionInActionParser = PEG.buildParser( '{ function f() { return 42; } }; start = "a" { return f(); }', options ); parses(functionInActionParser, "a", 42); var variableInSemanticAndParser = PEG.buildParser( '{ a = 42; }; start = "a" &{ return a === 42; }', options ); parses(variableInSemanticAndParser, "a", ["a", ""]); var functionInSemanticAndParser = PEG.buildParser( '{ function f() { return 42; } }; start = "a" &{ return f() === 42; }', options ); parses(functionInSemanticAndParser, "a", ["a", ""]); var variableInSemanticNotParser = PEG.buildParser( '{ a = 42; }; start = "a" !{ return a !== 42; }', options ); parses(variableInSemanticNotParser, "a", ["a", ""]); var functionInSemanticNotParser = PEG.buildParser( '{ function f() { return 42; } }; start = "a" !{ return f() !== 42; }', options ); parses(functionInSemanticNotParser, "a", ["a", ""]); }); testWithVaryingTrackLineAndColumn("rule references", function(options) { var parser = PEG.buildParser([ 'start = static / dynamic', 'static = "C" / "C++" / "Java" / "C#"', 'dynamic = "Ruby" / "Python" / "JavaScript"' ].join("\n"), options); parses(parser, "Java", "Java"); parses(parser, "Python", "Python"); }); testWithVaryingTrackLineAndColumn("literals", function(options) { var zeroCharParser = PEG.buildParser('start = ""', options); parses(zeroCharParser, "", ""); doesNotParse(zeroCharParser, "a"); var oneCharCaseSensitiveParser = PEG.buildParser('start = "a"', options); parses(oneCharCaseSensitiveParser, "a", "a"); doesNotParse(oneCharCaseSensitiveParser, ""); doesNotParse(oneCharCaseSensitiveParser, "A"); doesNotParse(oneCharCaseSensitiveParser, "b"); var multiCharCaseSensitiveParser = PEG.buildParser('start = "abcd"', options); parses(multiCharCaseSensitiveParser, "abcd", "abcd"); doesNotParse(multiCharCaseSensitiveParser, ""); doesNotParse(multiCharCaseSensitiveParser, "abc"); doesNotParse(multiCharCaseSensitiveParser, "abcde"); doesNotParse(multiCharCaseSensitiveParser, "ABCD"); doesNotParse(multiCharCaseSensitiveParser, "efgh"); var oneCharCaseInsensitiveParser = PEG.buildParser('start = "a"i', options); parses(oneCharCaseInsensitiveParser, "a", "a"); parses(oneCharCaseInsensitiveParser, "A", "A"); doesNotParse(oneCharCaseInsensitiveParser, ""); doesNotParse(oneCharCaseInsensitiveParser, "b"); var multiCharCaseInsensitiveParser = PEG.buildParser( 'start = "abcd"i', options ); parses(multiCharCaseInsensitiveParser, "abcd", "abcd"); parses(multiCharCaseInsensitiveParser, "ABCD", "ABCD"); doesNotParse(multiCharCaseInsensitiveParser, ""); doesNotParse(multiCharCaseInsensitiveParser, "abc"); doesNotParse(multiCharCaseInsensitiveParser, "abcde"); doesNotParse(multiCharCaseInsensitiveParser, "efgh"); /* * Test that the parsing position moves forward after successful parsing of * a literal. */ var posTestParser = PEG.buildParser('start = "a" "b"', options); parses(posTestParser, "ab", ["a", "b"]); }); testWithVaryingTrackLineAndColumn("anys", function(options) { var parser = PEG.buildParser('start = .', options); parses(parser, "a", "a"); doesNotParse(parser, ""); doesNotParse(parser, "ab"); /* * Test that the parsing position moves forward after successful parsing of * an any. */ var posTestParser = PEG.buildParser('start = . .', options); parses(posTestParser, "ab", ["a", "b"]); }); testWithVaryingTrackLineAndColumn("classes", function(options) { var emptyClassParser = PEG.buildParser('start = []', options); doesNotParse(emptyClassParser, ""); doesNotParse(emptyClassParser, "a"); doesNotParse(emptyClassParser, "ab"); var invertedEmptyClassParser = PEG.buildParser('start = [^]', options); doesNotParse(invertedEmptyClassParser, ""); parses(invertedEmptyClassParser, "a", "a"); doesNotParse(invertedEmptyClassParser, "ab"); var nonEmptyCaseSensitiveClassParser = PEG.buildParser( 'start = [ab-d]', options ); parses(nonEmptyCaseSensitiveClassParser, "a", "a"); parses(nonEmptyCaseSensitiveClassParser, "b", "b"); parses(nonEmptyCaseSensitiveClassParser, "c", "c"); parses(nonEmptyCaseSensitiveClassParser, "d", "d"); doesNotParse(nonEmptyCaseSensitiveClassParser, ""); doesNotParse(nonEmptyCaseSensitiveClassParser, "A"); doesNotParse(nonEmptyCaseSensitiveClassParser, "B"); doesNotParse(nonEmptyCaseSensitiveClassParser, "C"); doesNotParse(nonEmptyCaseSensitiveClassParser, "D"); doesNotParse(nonEmptyCaseSensitiveClassParser, "e"); doesNotParse(nonEmptyCaseSensitiveClassParser, "ab"); var invertedNonEmptyCaseSensitiveClassParser = PEG.buildParser( 'start = [^ab-d]', options ); parses(invertedNonEmptyCaseSensitiveClassParser, "A", "A"); parses(invertedNonEmptyCaseSensitiveClassParser, "B", "B"); parses(invertedNonEmptyCaseSensitiveClassParser, "C", "C"); parses(invertedNonEmptyCaseSensitiveClassParser, "D", "D"); parses(invertedNonEmptyCaseSensitiveClassParser, "e", "e"); doesNotParse(invertedNonEmptyCaseSensitiveClassParser, "a", "a"); doesNotParse(invertedNonEmptyCaseSensitiveClassParser, "b", "b"); doesNotParse(invertedNonEmptyCaseSensitiveClassParser, "c", "c"); doesNotParse(invertedNonEmptyCaseSensitiveClassParser, "d", "d"); doesNotParse(invertedNonEmptyCaseSensitiveClassParser, ""); doesNotParse(invertedNonEmptyCaseSensitiveClassParser, "ab"); var nonEmptyCaseInsensitiveClassParser = PEG.buildParser( 'start = [ab-d]i', options ); parses(nonEmptyCaseInsensitiveClassParser, "a", "a"); parses(nonEmptyCaseInsensitiveClassParser, "b", "b"); parses(nonEmptyCaseInsensitiveClassParser, "c", "c"); parses(nonEmptyCaseInsensitiveClassParser, "d", "d"); parses(nonEmptyCaseInsensitiveClassParser, "A", "A"); parses(nonEmptyCaseInsensitiveClassParser, "B", "B"); parses(nonEmptyCaseInsensitiveClassParser, "C", "C"); parses(nonEmptyCaseInsensitiveClassParser, "D", "D"); doesNotParse(nonEmptyCaseInsensitiveClassParser, ""); doesNotParse(nonEmptyCaseInsensitiveClassParser, "e"); doesNotParse(nonEmptyCaseInsensitiveClassParser, "ab"); var invertedNonEmptyCaseInsensitiveClassParser = PEG.buildParser( 'start = [^ab-d]i', options ); parses(invertedNonEmptyCaseInsensitiveClassParser, "e", "e"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "a", "a"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "b", "b"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "c", "c"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "d", "d"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "A", "A"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "B", "B"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "C", "C"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "D", "D"); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, ""); doesNotParse(invertedNonEmptyCaseInsensitiveClassParser, "ab"); /* * Test that the parsing position moves forward after successful parsing of * a class. */ var posTestParser = PEG.buildParser('start = [ab-d] [ab-d]', options); parses(posTestParser, "ab", ["a", "b"]); }); testWithVaryingTrackLineAndColumn("cache", function(options) { var grammar = [ '{ var n = 0; }', 'start = (a "b") / (a "c") { return n; }', 'a = "a" { n++; }' ].join("\n"); /* Without cache */ parses(PEG.buildParser(grammar, options), "ac", 2); options.cache = false; parses(PEG.buildParser(grammar, options), "ac", 2); /* With cache */ options.cache = true; parses(PEG.buildParser(grammar, options), "ac", 1); }); testWithVaryingTrackLineAndColumn("indempotence", function(options) { var parser1 = PEG.buildParser('start = "abcd"', options); var parser2 = PEG.buildParser('start = "abcd"', options); strictEqual(parser1.toSource(), parser2.toSource()); }); testWithVaryingTrackLineAndColumn("error details", function(options) { var literalParser = PEG.buildParser('start = "abcd"', options); doesNotParseWithDetails( literalParser, "", ["\"abcd\""], null, 'Expected "abcd" but end of input found.' ); doesNotParseWithDetails( literalParser, "efgh", ["\"abcd\""], "e", 'Expected "abcd" but "e" found.' ); doesNotParseWithDetails( literalParser, "abcde", [], "e", 'Expected end of input but "e" found.' ); var classParser = PEG.buildParser('start = [a-d]', options); doesNotParseWithDetails( classParser, "", ["[a-d]"], null, 'Expected [a-d] but end of input found.' ); var negativeClassParser = PEG.buildParser('start = [^a-d]', options); doesNotParseWithDetails( negativeClassParser, "", ["[^a-d]"], null, 'Expected [^a-d] but end of input found.' ); var anyParser = PEG.buildParser('start = .', options); doesNotParseWithDetails( anyParser, "", ["any character"], null, 'Expected any character but end of input found.' ); var namedRuleWithLiteralParser = PEG.buildParser( 'start "digit" = [0-9]', options ); doesNotParseWithDetails( namedRuleWithLiteralParser, "a", ["digit"], "a", 'Expected digit but "a" found.' ); var namedRuleWithAnyParser = PEG.buildParser('start "whatever" = .', options); doesNotParseWithDetails( namedRuleWithAnyParser, "", ["whatever"], null, 'Expected whatever but end of input found.' ); var namedRuleWithNamedRuleParser = PEG.buildParser([ 'start "digits" = digit+', 'digit "digit" = [0-9]' ].join("\n"), options); doesNotParseWithDetails( namedRuleWithNamedRuleParser, "", ["digits"], null, 'Expected digits but end of input found.' ); var choiceParser1 = PEG.buildParser('start = "a" / "b" / "c"', options); doesNotParseWithDetails( choiceParser1, "def", ["\"a\"", "\"b\"", "\"c\""], "d", 'Expected "a", "b" or "c" but "d" found.' ); var choiceParser2 = PEG.buildParser('start = "a" "b" "c" / "a"', options); doesNotParseWithDetails( choiceParser2, "abd", ["\"c\""], "d", 'Expected "c" but "d" found.' ); var simpleNotParser = PEG.buildParser('start = !"a" "b"', options); doesNotParseWithDetails( simpleNotParser, "c", ["\"b\""], "c", 'Expected "b" but "c" found.' ); var simpleAndParser = PEG.buildParser('start = &"a" [a-b]', options); doesNotParseWithDetails( simpleAndParser, "c", [], "c", 'Expected end of input but "c" found.' ); var emptyParser = PEG.buildParser('start = ', options); doesNotParseWithDetails( emptyParser, "something", [], "s", 'Expected end of input but "s" found.' ); var duplicateErrorParser = PEG.buildParser('start = "a" / "a"', options); doesNotParseWithDetails( duplicateErrorParser, "", ["\"a\""], null, 'Expected "a" but end of input found.' ); var unsortedErrorsParser = PEG.buildParser('start = "b" / "a"', options); doesNotParseWithDetails( unsortedErrorsParser, "", ["\"a\"", "\"b\""], null, 'Expected "a" or "b" but end of input found.' ); }); testWithVaryingTrackLineAndColumn("error positions", function(options) { var simpleParser = PEG.buildParser('start = "a"', options); /* Regular match failure */ doesNotParseWithPos(simpleParser, "b", 0, 1, 1); /* Trailing input */ doesNotParseWithPos(simpleParser, "ab", 1, 1, 2); var digitsParser = PEG.buildParser([ 'start = line (("\\r" / "\\n" / "\\u2028" / "\\u2029")+ line)*', 'line = digits (" "+ digits)*', 'digits = digits:[0-9]+ { return digits.join(""); }' ].join("\n"), options); doesNotParseWithPos(digitsParser, "1\n2\n\n3\n\n\n4 5 x", 13, 7, 5); /* Non-Unix newlines */ doesNotParseWithPos(digitsParser, "1\rx", 2, 2, 1); // Old Mac doesNotParseWithPos(digitsParser, "1\r\nx", 3, 2, 1); // Windows doesNotParseWithPos(digitsParser, "1\n\rx", 3, 3, 1); // mismatched /* Strange newlines */ doesNotParseWithPos(digitsParser, "1\u2028x", 2, 2, 1); // line separator doesNotParseWithPos(digitsParser, "1\u2029x", 2, 2, 1); // paragraph separator }); testWithVaryingTrackLineAndColumn("start rule", function(options) { var parser = PEG.buildParser([ 'a = .* { return "alpha"; }', 'b = .* { return "beta"; }' ].join("\n"), options); /* Default start rule = the first one */ parses(parser, "whatever", "alpha"); /* Explicit specification of the start rule */ parsesWithStartRule(parser, "whatever", "a", "alpha"); parsesWithStartRule(parser, "whatever", "b", "beta"); /* Invalid rule name */ raises( function() { parser.parse("whatever", "c"); }, function(e) { return e instanceof Error && e.message === "Invalid rule name: \"c\"."; } ); }); /* * Following examples are from Wikipedia, see * http://en.wikipedia.org/w/index.php?title=Parsing_expression_grammar&oldid=335106938. */ testWithVaryingTrackLineAndColumn("arithmetics", function(options) { /* * Value ← [0-9]+ / '(' Expr ')' * Product ← Value (('*' / '/') Value)* * Sum ← Product (('+' / '-') Product)* * Expr ← Sum */ var parser = PEG.buildParser([ 'Expr = Sum', 'Sum = head:Product tail:(("+" / "-") Product)* {', ' var result = head;', ' for (var i = 0; i < tail.length; i++) {', ' if (tail[i][0] == "+") { result += tail[i][1]; }', ' if (tail[i][0] == "-") { result -= tail[i][1]; }', ' }', ' return result;', ' }', 'Product = head:Value tail:(("*" / "/") Value)* {', ' var result = head;', ' for (var i = 0; i < tail.length; i++) {', ' if (tail[i][0] == "*") { result *= tail[i][1]; }', ' if (tail[i][0] == "/") { result /= tail[i][1]; }', ' }', ' return result;', ' }', 'Value = digits:[0-9]+ { return parseInt(digits.join("")); }', ' / "(" expr:Expr ")" { return expr; }' ].join("\n"), options); /* Test "value" rule. */ parses(parser, "0", 0); parses(parser, "123", 123); parses(parser, "(42+43)", 42+43); /* Test "product" rule. */ parses(parser, "42", 42); parses(parser, "42*43", 42*43); parses(parser, "42*43*44*45", 42*43*44*45); parses(parser, "42/43", 42/43); parses(parser, "42/43/44/45", 42/43/44/45); /* Test "sum" rule. */ parses(parser, "42*43", 42*43); parses(parser, "42*43+44*45", 42*43+44*45); parses(parser, "42*43+44*45+46*47+48*49", 42*43+44*45+46*47+48*49); parses(parser, "42*43-44*45", 42*43-44*45); parses(parser, "42*43-44*45-46*47-48*49", 42*43-44*45-46*47-48*49); /* Test "expr" rule. */ parses(parser, "42+43", 42+43); /* Complex test */ parses(parser, "(1+2)*(3+4)",(1+2)*(3+4)); }); testWithVaryingTrackLineAndColumn("non-context-free language", function(options) { /* The following parsing expression grammar describes the classic * non-context-free language { a^n b^n c^n : n >= 1 }: * * S ← &(A c) a+ B !(a/b/c) * A ← a A? b * B ← b B? c */ var parser = PEG.buildParser([ 'S = &(A "c") a:"a"+ B:B !("a" / "b" / "c") { return a.join("") + B; }', 'A = a:"a" A:A? b:"b" { return a + A + b; }', 'B = b:"b" B:B? c:"c" { return b + B + c; }' ].join("\n"), options); parses(parser, "abc", "abc"); parses(parser, "aaabbbccc", "aaabbbccc"); doesNotParse(parser, "aabbbccc"); doesNotParse(parser, "aaaabbbccc"); doesNotParse(parser, "aaabbccc"); doesNotParse(parser, "aaabbbbccc"); doesNotParse(parser, "aaabbbcc"); doesNotParse(parser, "aaabbbcccc"); }); testWithVaryingTrackLineAndColumn("nested comments", function(options) { /* * Begin ← "(*" * End ← "*)" * C ← Begin N* End * N ← C / (!Begin !End Z) * Z ← any single character */ var parser = PEG.buildParser([ 'C = begin:Begin ns:N* end:End { return begin + ns.join("") + end; }', 'N = C', ' / !Begin !End z:Z { return z; }', 'Z = .', 'Begin = "(*"', 'End = "*)"' ].join("\n"), options); parses(parser, "(**)", "(**)"); parses(parser, "(*abc*)", "(*abc*)"); parses(parser, "(*(**)*)", "(*(**)*)"); parses( parser, "(*abc(*def*)ghi(*(*(*jkl*)*)*)mno*)", "(*abc(*def*)ghi(*(*(*jkl*)*)*)mno*)" ); }); })(); pegjs-0.7.0/test/vendor/0000755000175000017500000000000012206663530014357 5ustar danieldanielpegjs-0.7.0/test/vendor/qunit/0000755000175000017500000000000012206663530015517 5ustar danieldanielpegjs-0.7.0/test/vendor/qunit/qunit.css0000644000175000017500000001105612206663530017374 0ustar danieldaniel/** * QUnit v1.5.0 - A JavaScript Unit Testing Framework * * http://docs.jquery.com/QUnit * * Copyright (c) 2012 John Resig, Jörn Zaefferer * Dual licensed under the MIT (MIT-LICENSE.txt) * or GPL (GPL-LICENSE.txt) licenses. */ /** Font Family and Sizes */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } #qunit-tests { font-size: smaller; } /** Resets */ #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { margin: 0; padding: 0; } /** Header */ #qunit-header { padding: 0.5em 0 0.5em 1em; color: #8699a4; background-color: #0d3349; font-size: 1.5em; line-height: 1em; font-weight: normal; border-radius: 15px 15px 0 0; -moz-border-radius: 15px 15px 0 0; -webkit-border-top-right-radius: 15px; -webkit-border-top-left-radius: 15px; } #qunit-header a { text-decoration: none; color: #c2ccd1; } #qunit-header a:hover, #qunit-header a:focus { color: #fff; } #qunit-header label { display: inline-block; } #qunit-banner { height: 5px; } #qunit-testrunner-toolbar { padding: 0.5em 0 0.5em 2em; color: #5E740B; background-color: #eee; } #qunit-userAgent { padding: 0.5em 0 0.5em 2.5em; background-color: #2b81af; color: #fff; text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; } /** Tests: Pass/Fail */ #qunit-tests { list-style-position: inside; } #qunit-tests li { padding: 0.4em 0.5em 0.4em 2.5em; border-bottom: 1px solid #fff; list-style-position: inside; } #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { display: none; } #qunit-tests li strong { cursor: pointer; } #qunit-tests li a { padding: 0.5em; color: #c2ccd1; text-decoration: none; } #qunit-tests li a:hover, #qunit-tests li a:focus { color: #000; } #qunit-tests ol { margin-top: 0.5em; padding: 0.5em; background-color: #fff; border-radius: 15px; -moz-border-radius: 15px; -webkit-border-radius: 15px; box-shadow: inset 0px 2px 13px #999; -moz-box-shadow: inset 0px 2px 13px #999; -webkit-box-shadow: inset 0px 2px 13px #999; } #qunit-tests table { border-collapse: collapse; margin-top: .2em; } #qunit-tests th { text-align: right; vertical-align: top; padding: 0 .5em 0 0; } #qunit-tests td { vertical-align: top; } #qunit-tests pre { margin: 0; white-space: pre-wrap; word-wrap: break-word; } #qunit-tests del { background-color: #e0f2be; color: #374e0c; text-decoration: none; } #qunit-tests ins { background-color: #ffcaca; color: #500; text-decoration: none; } /*** Test Counts */ #qunit-tests b.counts { color: black; } #qunit-tests b.passed { color: #5E740B; } #qunit-tests b.failed { color: #710909; } #qunit-tests li li { margin: 0.5em; padding: 0.4em 0.5em 0.4em 0.5em; background-color: #fff; border-bottom: none; list-style-position: inside; } /*** Passing Styles */ #qunit-tests li li.pass { color: #5E740B; background-color: #fff; border-left: 26px solid #C6E746; } #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } #qunit-tests .pass .test-name { color: #366097; } #qunit-tests .pass .test-actual, #qunit-tests .pass .test-expected { color: #999999; } #qunit-banner.qunit-pass { background-color: #C6E746; } /*** Failing Styles */ #qunit-tests li li.fail { color: #710909; background-color: #fff; border-left: 26px solid #EE5757; white-space: pre; } #qunit-tests > li:last-child { border-radius: 0 0 15px 15px; -moz-border-radius: 0 0 15px 15px; -webkit-border-bottom-right-radius: 15px; -webkit-border-bottom-left-radius: 15px; } #qunit-tests .fail { color: #000000; background-color: #EE5757; } #qunit-tests .fail .test-name, #qunit-tests .fail .module-name { color: #000000; } #qunit-tests .fail .test-actual { color: #EE5757; } #qunit-tests .fail .test-expected { color: green; } #qunit-banner.qunit-fail { background-color: #EE5757; } /** Result */ #qunit-testresult { padding: 0.5em 0.5em 0.5em 2.5em; color: #2b81af; background-color: #D2E0E6; border-bottom: 1px solid white; } #qunit-testresult .module-name { font-weight: bold; } /** Fixture */ #qunit-fixture { position: absolute; top: -10000px; left: -10000px; width: 1000px; height: 1000px; } pegjs-0.7.0/test/vendor/qunit/qunit.js0000644000175000017500000012504412206663530017223 0ustar danieldaniel/** * QUnit v1.5.0 - A JavaScript Unit Testing Framework * * http://docs.jquery.com/QUnit * * Copyright (c) 2012 John Resig, Jörn Zaefferer * Dual licensed under the MIT (MIT-LICENSE.txt) * or GPL (GPL-LICENSE.txt) licenses. */ (function(window) { var defined = { setTimeout: typeof window.setTimeout !== "undefined", sessionStorage: (function() { var x = "qunit-test-string"; try { sessionStorage.setItem(x, x); sessionStorage.removeItem(x); return true; } catch(e) { return false; } }()) }; var testId = 0, toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty; var Test = function(name, testName, expected, async, callback) { this.name = name; this.testName = testName; this.expected = expected; this.async = async; this.callback = callback; this.assertions = []; }; Test.prototype = { init: function() { var tests = id("qunit-tests"); if (tests) { var b = document.createElement("strong"); b.innerHTML = "Running " + this.name; var li = document.createElement("li"); li.appendChild( b ); li.className = "running"; li.id = this.id = "test-output" + testId++; tests.appendChild( li ); } }, setup: function() { if (this.module != config.previousModule) { if ( config.previousModule ) { runLoggingCallbacks('moduleDone', QUnit, { name: config.previousModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all } ); } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0 }; runLoggingCallbacks( 'moduleStart', QUnit, { name: this.module } ); } else if (config.autorun) { runLoggingCallbacks( 'moduleStart', QUnit, { name: this.module } ); } config.current = this; this.testEnvironment = extend({ setup: function() {}, teardown: function() {} }, this.moduleTestEnvironment); runLoggingCallbacks( 'testStart', QUnit, { name: this.testName, module: this.module }); // allow utility functions to access the current test environment // TODO why?? QUnit.current_testEnvironment = this.testEnvironment; if ( !config.pollution ) { saveGlobal(); } if ( config.notrycatch ) { this.testEnvironment.setup.call(this.testEnvironment); return; } try { this.testEnvironment.setup.call(this.testEnvironment); } catch(e) { QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); } }, run: function() { config.current = this; var running = id("qunit-testresult"); if ( running ) { running.innerHTML = "Running:
    " + this.name; } if ( this.async ) { QUnit.stop(); } if ( config.notrycatch ) { this.callback.call(this.testEnvironment); return; } try { this.callback.call(this.testEnvironment); } catch(e) { QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) ); // else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking if ( config.blocking ) { QUnit.start(); } } }, teardown: function() { config.current = this; if ( config.notrycatch ) { this.testEnvironment.teardown.call(this.testEnvironment); return; } else { try { this.testEnvironment.teardown.call(this.testEnvironment); } catch(e) { QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); } } checkPollution(); }, finish: function() { config.current = this; if ( this.expected != null && this.expected != this.assertions.length ) { QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); } else if ( this.expected == null && !this.assertions.length ) { QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions." ); } var good = 0, bad = 0, li, i, tests = id("qunit-tests"); config.stats.all += this.assertions.length; config.moduleStats.all += this.assertions.length; if ( tests ) { var ol = document.createElement("ol"); for ( i = 0; i < this.assertions.length; i++ ) { var assertion = this.assertions[i]; li = document.createElement("li"); li.className = assertion.result ? "pass" : "fail"; li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); ol.appendChild( li ); if ( assertion.result ) { good++; } else { bad++; config.stats.bad++; config.moduleStats.bad++; } } // store result when possible if ( QUnit.config.reorder && defined.sessionStorage ) { if (bad) { sessionStorage.setItem("qunit-test-" + this.module + "-" + this.testName, bad); } else { sessionStorage.removeItem("qunit-test-" + this.module + "-" + this.testName); } } if (bad === 0) { ol.style.display = "none"; } var b = document.createElement("strong"); b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; var a = document.createElement("a"); a.innerHTML = "Rerun"; a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); addEvent(b, "click", function() { var next = b.nextSibling.nextSibling, display = next.style.display; next.style.display = display === "none" ? "block" : "none"; }); addEvent(b, "dblclick", function(e) { var target = e && e.target ? e.target : window.event.srcElement; if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { target = target.parentNode; } if ( window.location && target.nodeName.toLowerCase() === "strong" ) { window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); } }); li = id(this.id); li.className = bad ? "fail" : "pass"; li.removeChild( li.firstChild ); li.appendChild( b ); li.appendChild( a ); li.appendChild( ol ); } else { for ( i = 0; i < this.assertions.length; i++ ) { if ( !this.assertions[i].result ) { bad++; config.stats.bad++; config.moduleStats.bad++; } } } QUnit.reset(); runLoggingCallbacks( 'testDone', QUnit, { name: this.testName, module: this.module, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length } ); }, queue: function() { var test = this; synchronize(function() { test.init(); }); function run() { // each of these can by async synchronize(function() { test.setup(); }); synchronize(function() { test.run(); }); synchronize(function() { test.teardown(); }); synchronize(function() { test.finish(); }); } // defer when previous test run passed, if storage is available var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-test-" + this.module + "-" + this.testName); if (bad) { run(); } else { synchronize(run, true); } } }; var QUnit = { // call on start of module test to prepend name to all tests module: function(name, testEnvironment) { config.currentModule = name; config.currentModuleTestEnviroment = testEnvironment; }, asyncTest: function(testName, expected, callback) { if ( arguments.length === 2 ) { callback = expected; expected = null; } QUnit.test(testName, expected, callback, true); }, test: function(testName, expected, callback, async) { var name = '' + escapeInnerText(testName) + ''; if ( arguments.length === 2 ) { callback = expected; expected = null; } if ( config.currentModule ) { name = '' + config.currentModule + ": " + name; } if ( !validTest(config.currentModule + ": " + testName) ) { return; } var test = new Test(name, testName, expected, async, callback); test.module = config.currentModule; test.moduleTestEnvironment = config.currentModuleTestEnviroment; test.queue(); }, // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. expect: function(asserts) { config.current.expected = asserts; }, // Asserts true. // @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); ok: function(result, msg) { if (!config.current) { throw new Error("ok() assertion outside test context, was " + sourceFromStacktrace(2)); } result = !!result; var details = { result: result, message: msg }; msg = escapeInnerText(msg || (result ? "okay" : "failed")); if ( !result ) { var source = sourceFromStacktrace(2); if (source) { details.source = source; msg += '
    Source:
    ' + escapeInnerText(source) + '
    '; } } runLoggingCallbacks( 'log', QUnit, details ); config.current.assertions.push({ result: result, message: msg }); }, // Checks that the first two arguments are equal, with an optional message. Prints out both actual and expected values. // @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); equal: function(actual, expected, message) { QUnit.push(expected == actual, actual, expected, message); }, notEqual: function(actual, expected, message) { QUnit.push(expected != actual, actual, expected, message); }, deepEqual: function(actual, expected, message) { QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); }, notDeepEqual: function(actual, expected, message) { QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); }, strictEqual: function(actual, expected, message) { QUnit.push(expected === actual, actual, expected, message); }, notStrictEqual: function(actual, expected, message) { QUnit.push(expected !== actual, actual, expected, message); }, raises: function(block, expected, message) { var actual, ok = false; if (typeof expected === 'string') { message = expected; expected = null; } try { block.call(config.current.testEnvironment); } catch (e) { actual = e; } if (actual) { // we don't want to validate thrown error if (!expected) { ok = true; // expected is a regexp } else if (QUnit.objectType(expected) === "regexp") { ok = expected.test(actual); // expected is a constructor } else if (actual instanceof expected) { ok = true; // expected is a validation function which returns true is validation passed } else if (expected.call({}, actual) === true) { ok = true; } } QUnit.ok(ok, message); }, start: function(count) { config.semaphore -= count || 1; if (config.semaphore > 0) { // don't start until equal number of stop-calls return; } if (config.semaphore < 0) { // ignore if start is called more often then stop config.semaphore = 0; } // A slight delay, to avoid any current callbacks if ( defined.setTimeout ) { window.setTimeout(function() { if (config.semaphore > 0) { return; } if ( config.timeout ) { clearTimeout(config.timeout); } config.blocking = false; process(true); }, 13); } else { config.blocking = false; process(true); } }, stop: function(count) { config.semaphore += count || 1; config.blocking = true; if ( config.testTimeout && defined.setTimeout ) { clearTimeout(config.timeout); config.timeout = window.setTimeout(function() { QUnit.ok( false, "Test timed out" ); config.semaphore = 1; QUnit.start(); }, config.testTimeout); } } }; //We want access to the constructor's prototype (function() { function F(){} F.prototype = QUnit; QUnit = new F(); //Make F QUnit's constructor so that we can add to the prototype later QUnit.constructor = F; }()); // deprecated; still export them to window to provide clear error messages // next step: remove entirely QUnit.equals = function() { QUnit.push(false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead"); }; QUnit.same = function() { QUnit.push(false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead"); }; // Maintain internal state var config = { // The queue of tests to run queue: [], // block until document ready blocking: true, // when enabled, show only failing tests // gets persisted through sessionStorage and can be changed in UI via checkbox hidepassed: false, // by default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, // by default, modify document.title when suite is done altertitle: true, urlConfig: ['noglobals', 'notrycatch'], //logging callback queues begin: [], done: [], log: [], testStart: [], testDone: [], moduleStart: [], moduleDone: [] }; // Load paramaters (function() { var location = window.location || { search: "", protocol: "file:" }, params = location.search.slice( 1 ).split( "&" ), length = params.length, urlParams = {}, current; if ( params[ 0 ] ) { for ( var i = 0; i < length; i++ ) { current = params[ i ].split( "=" ); current[ 0 ] = decodeURIComponent( current[ 0 ] ); // allow just a key to turn on a flag, e.g., test.html?noglobals current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; urlParams[ current[ 0 ] ] = current[ 1 ]; } } QUnit.urlParams = urlParams; config.filter = urlParams.filter; // Figure out if we're running the tests from a server or not QUnit.isLocal = location.protocol === 'file:'; }()); // Expose the API as global variables, unless an 'exports' // object exists, in that case we assume we're in CommonJS - export everything at the end if ( typeof exports === "undefined" || typeof require === "undefined" ) { extend(window, QUnit); window.QUnit = QUnit; } // define these after exposing globals to keep them in these QUnit namespace only extend(QUnit, { config: config, // Initialize the configuration options init: function() { extend(config, { stats: { all: 0, bad: 0 }, moduleStats: { all: 0, bad: 0 }, started: +new Date(), updateRate: 1000, blocking: false, autostart: true, autorun: false, filter: "", queue: [], semaphore: 0 }); var qunit = id( "qunit" ); if ( qunit ) { qunit.innerHTML = '

    ' + escapeInnerText( document.title ) + '

    ' + '

    ' + '
    ' + '

    ' + '
      '; } var tests = id( "qunit-tests" ), banner = id( "qunit-banner" ), result = id( "qunit-testresult" ); if ( tests ) { tests.innerHTML = ""; } if ( banner ) { banner.className = ""; } if ( result ) { result.parentNode.removeChild( result ); } if ( tests ) { result = document.createElement( "p" ); result.id = "qunit-testresult"; result.className = "result"; tests.parentNode.insertBefore( result, tests ); result.innerHTML = 'Running...
       '; } }, // Resets the test setup. Useful for tests that modify the DOM. // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. reset: function() { if ( window.jQuery ) { jQuery( "#qunit-fixture" ).html( config.fixture ); } else { var main = id( 'qunit-fixture' ); if ( main ) { main.innerHTML = config.fixture; } } }, // Trigger an event on an element. // @example triggerEvent( document.body, "click" ); triggerEvent: function( elem, type, event ) { if ( document.createEvent ) { event = document.createEvent("MouseEvents"); event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null); elem.dispatchEvent( event ); } else if ( elem.fireEvent ) { elem.fireEvent("on"+type); } }, // Safe object type checking is: function( type, obj ) { return QUnit.objectType( obj ) == type; }, objectType: function( obj ) { if (typeof obj === "undefined") { return "undefined"; // consider: typeof null === object } if (obj === null) { return "null"; } var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ''; switch (type) { case 'Number': if (isNaN(obj)) { return "nan"; } return "number"; case 'String': case 'Boolean': case 'Array': case 'Date': case 'RegExp': case 'Function': return type.toLowerCase(); } if (typeof obj === "object") { return "object"; } return undefined; }, push: function(result, actual, expected, message) { if (!config.current) { throw new Error("assertion outside test context, was " + sourceFromStacktrace()); } var details = { result: result, message: message, actual: actual, expected: expected }; message = escapeInnerText(message) || (result ? "okay" : "failed"); message = '' + message + ""; var output = message; if (!result) { expected = escapeInnerText(QUnit.jsDump.parse(expected)); actual = escapeInnerText(QUnit.jsDump.parse(actual)); output += ''; if (actual != expected) { output += ''; output += ''; } var source = sourceFromStacktrace(); if (source) { details.source = source; output += ''; } output += "
      Expected:
      ' + expected + '
      Result:
      ' + actual + '
      Diff:
      ' + QUnit.diff(expected, actual) +'
      Source:
      ' + escapeInnerText(source) + '
      "; } runLoggingCallbacks( 'log', QUnit, details ); config.current.assertions.push({ result: !!result, message: output }); }, pushFailure: function(message, source) { var details = { result: false, message: message }; var output = escapeInnerText(message); if (source) { details.source = source; output += '
      Source:
      ' + escapeInnerText(source) + '
      '; } runLoggingCallbacks( 'log', QUnit, details ); config.current.assertions.push({ result: false, message: output }); }, url: function( params ) { params = extend( extend( {}, QUnit.urlParams ), params ); var querystring = "?", key; for ( key in params ) { if ( !hasOwn.call( params, key ) ) { continue; } querystring += encodeURIComponent( key ) + "=" + encodeURIComponent( params[ key ] ) + "&"; } return window.location.pathname + querystring.slice( 0, -1 ); }, extend: extend, id: id, addEvent: addEvent }); //QUnit.constructor is set to the empty F() above so that we can add to it's prototype later //Doing this allows us to tell if the following methods have been overwritten on the actual //QUnit object, which is a deprecated way of using the callbacks. extend(QUnit.constructor.prototype, { // Logging callbacks; all receive a single argument with the listed properties // run test/logs.html for any related changes begin: registerLoggingCallback('begin'), // done: { failed, passed, total, runtime } done: registerLoggingCallback('done'), // log: { result, actual, expected, message } log: registerLoggingCallback('log'), // testStart: { name } testStart: registerLoggingCallback('testStart'), // testDone: { name, failed, passed, total } testDone: registerLoggingCallback('testDone'), // moduleStart: { name } moduleStart: registerLoggingCallback('moduleStart'), // moduleDone: { name, failed, passed, total } moduleDone: registerLoggingCallback('moduleDone') }); if ( typeof document === "undefined" || document.readyState === "complete" ) { config.autorun = true; } QUnit.load = function() { runLoggingCallbacks( 'begin', QUnit, {} ); // Initialize the config, saving the execution queue var oldconfig = extend({}, config); QUnit.init(); extend(config, oldconfig); config.blocking = false; var urlConfigHtml = '', len = config.urlConfig.length; for ( var i = 0, val; i < len; i++ ) { val = config.urlConfig[i]; config[val] = QUnit.urlParams[val]; urlConfigHtml += ''; } var userAgent = id("qunit-userAgent"); if ( userAgent ) { userAgent.innerHTML = navigator.userAgent; } var banner = id("qunit-header"); if ( banner ) { banner.innerHTML = ' ' + banner.innerHTML + ' ' + urlConfigHtml; addEvent( banner, "change", function( event ) { var params = {}; params[ event.target.name ] = event.target.checked ? true : undefined; window.location = QUnit.url( params ); }); } var toolbar = id("qunit-testrunner-toolbar"); if ( toolbar ) { var filter = document.createElement("input"); filter.type = "checkbox"; filter.id = "qunit-filter-pass"; addEvent( filter, "click", function() { var ol = document.getElementById("qunit-tests"); if ( filter.checked ) { ol.className = ol.className + " hidepass"; } else { var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; ol.className = tmp.replace(/ hidepass /, " "); } if ( defined.sessionStorage ) { if (filter.checked) { sessionStorage.setItem("qunit-filter-passed-tests", "true"); } else { sessionStorage.removeItem("qunit-filter-passed-tests"); } } }); if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { filter.checked = true; var ol = document.getElementById("qunit-tests"); ol.className = ol.className + " hidepass"; } toolbar.appendChild( filter ); var label = document.createElement("label"); label.setAttribute("for", "qunit-filter-pass"); label.innerHTML = "Hide passed tests"; toolbar.appendChild( label ); } var main = id('qunit-fixture'); if ( main ) { config.fixture = main.innerHTML; } if (config.autostart) { QUnit.start(); } }; addEvent(window, "load", QUnit.load); // addEvent(window, "error") gives us a useless event object window.onerror = function( message, file, line ) { if ( QUnit.config.current ) { QUnit.pushFailure( message, file + ":" + line ); } else { QUnit.test( "global failure", function() { QUnit.pushFailure( message, file + ":" + line ); }); } }; function done() { config.autorun = true; // Log the last module results if ( config.currentModule ) { runLoggingCallbacks( 'moduleDone', QUnit, { name: config.currentModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all } ); } var banner = id("qunit-banner"), tests = id("qunit-tests"), runtime = +new Date() - config.started, passed = config.stats.all - config.stats.bad, html = [ 'Tests completed in ', runtime, ' milliseconds.
      ', '', passed, ' tests of ', config.stats.all, ' passed, ', config.stats.bad, ' failed.' ].join(''); if ( banner ) { banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); } if ( tests ) { id( "qunit-testresult" ).innerHTML = html; } if ( config.altertitle && typeof document !== "undefined" && document.title ) { // show ✖ for good, ✔ for bad suite result in title // use escape sequences in case file gets loaded with non-utf-8-charset document.title = [ (config.stats.bad ? "\u2716" : "\u2714"), document.title.replace(/^[\u2714\u2716] /i, "") ].join(" "); } // clear own sessionStorage items if all tests passed if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { var key; for ( var i = 0; i < sessionStorage.length; i++ ) { key = sessionStorage.key( i++ ); if ( key.indexOf("qunit-test-") === 0 ) { sessionStorage.removeItem( key ); } } } runLoggingCallbacks( 'done', QUnit, { failed: config.stats.bad, passed: passed, total: config.stats.all, runtime: runtime } ); } function validTest( name ) { var filter = config.filter, run = false; if ( !filter ) { return true; } var not = filter.charAt( 0 ) === "!"; if ( not ) { filter = filter.slice( 1 ); } if ( name.indexOf( filter ) !== -1 ) { return !not; } if ( not ) { run = true; } return run; } // so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) // Later Safari and IE10 are supposed to support error.stack as well // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { offset = offset || 3; if (e.stacktrace) { // Opera return e.stacktrace.split("\n")[offset + 3]; } else if (e.stack) { // Firefox, Chrome var stack = e.stack.split("\n"); if (/^error$/i.test(stack[0])) { stack.shift(); } return stack[offset]; } else if (e.sourceURL) { // Safari, PhantomJS // hopefully one day Safari provides actual stacktraces // exclude useless self-reference for generated Error objects if ( /qunit.js$/.test( e.sourceURL ) ) { return; } // for actual exceptions, this is useful return e.sourceURL + ":" + e.line; } } function sourceFromStacktrace(offset) { try { throw new Error(); } catch ( e ) { return extractStacktrace( e, offset ); } } function escapeInnerText(s) { if (!s) { return ""; } s = s + ""; return s.replace(/[\&<>]/g, function(s) { switch(s) { case "&": return "&"; case "<": return "<"; case ">": return ">"; default: return s; } }); } function synchronize( callback, last ) { config.queue.push( callback ); if ( config.autorun && !config.blocking ) { process(last); } } function process( last ) { function next() { process( last ); } var start = new Date().getTime(); config.depth = config.depth ? config.depth + 1 : 1; while ( config.queue.length && !config.blocking ) { if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { config.queue.shift()(); } else { window.setTimeout( next, 13 ); break; } } config.depth--; if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { done(); } } function saveGlobal() { config.pollution = []; if ( config.noglobals ) { for ( var key in window ) { if ( !hasOwn.call( window, key ) ) { continue; } config.pollution.push( key ); } } } function checkPollution( name ) { var old = config.pollution; saveGlobal(); var newGlobals = diff( config.pollution, old ); if ( newGlobals.length > 0 ) { QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); } var deletedGlobals = diff( old, config.pollution ); if ( deletedGlobals.length > 0 ) { QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); } } // returns a new Array with the elements that are in a but not in b function diff( a, b ) { var result = a.slice(); for ( var i = 0; i < result.length; i++ ) { for ( var j = 0; j < b.length; j++ ) { if ( result[i] === b[j] ) { result.splice(i, 1); i--; break; } } } return result; } function extend(a, b) { for ( var prop in b ) { if ( b[prop] === undefined ) { delete a[prop]; // Avoid "Member not found" error in IE8 caused by setting window.constructor } else if ( prop !== "constructor" || a !== window ) { a[prop] = b[prop]; } } return a; } function addEvent(elem, type, fn) { if ( elem.addEventListener ) { elem.addEventListener( type, fn, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, fn ); } else { fn(); } } function id(name) { return !!(typeof document !== "undefined" && document && document.getElementById) && document.getElementById( name ); } function registerLoggingCallback(key){ return function(callback){ config[key].push( callback ); }; } // Supports deprecated method of completely overwriting logging callbacks function runLoggingCallbacks(key, scope, args) { //debugger; var callbacks; if ( QUnit.hasOwnProperty(key) ) { QUnit[key].call(scope, args); } else { callbacks = config[key]; for( var i = 0; i < callbacks.length; i++ ) { callbacks[i].call( scope, args ); } } } // Test for equality any JavaScript type. // Author: Philippe Rathé QUnit.equiv = (function() { var innerEquiv; // the real equiv function var callers = []; // stack to decide between skip/abort functions var parents = []; // stack to avoiding loops from circular referencing // Call the o related callback with the given arguments. function bindCallbacks(o, callbacks, args) { var prop = QUnit.objectType(o); if (prop) { if (QUnit.objectType(callbacks[prop]) === "function") { return callbacks[prop].apply(callbacks, args); } else { return callbacks[prop]; // or undefined } } } var getProto = Object.getPrototypeOf || function (obj) { return obj.__proto__; }; var callbacks = (function () { // for string, boolean, number and null function useStrictEquality(b, a) { if (b instanceof a.constructor || a instanceof b.constructor) { // to catch short annotaion VS 'new' annotation of a // declaration // e.g. var i = 1; // var j = new Number(1); return a == b; } else { return a === b; } } return { "string" : useStrictEquality, "boolean" : useStrictEquality, "number" : useStrictEquality, "null" : useStrictEquality, "undefined" : useStrictEquality, "nan" : function(b) { return isNaN(b); }, "date" : function(b, a) { return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); }, "regexp" : function(b, a) { return QUnit.objectType(b) === "regexp" && // the regex itself a.source === b.source && // and its modifers a.global === b.global && // (gmi) ... a.ignoreCase === b.ignoreCase && a.multiline === b.multiline; }, // - skip when the property is a method of an instance (OOP) // - abort otherwise, // initial === would have catch identical references anyway "function" : function() { var caller = callers[callers.length - 1]; return caller !== Object && typeof caller !== "undefined"; }, "array" : function(b, a) { var i, j, loop; var len; // b could be an object literal here if (QUnit.objectType(b) !== "array") { return false; } len = a.length; if (len !== b.length) { // safe and faster return false; } // track reference to avoid circular references parents.push(a); for (i = 0; i < len; i++) { loop = false; for (j = 0; j < parents.length; j++) { if (parents[j] === a[i]) { loop = true;// dont rewalk array } } if (!loop && !innerEquiv(a[i], b[i])) { parents.pop(); return false; } } parents.pop(); return true; }, "object" : function(b, a) { var i, j, loop; var eq = true; // unless we can proove it var aProperties = [], bProperties = []; // collection of // strings // comparing constructors is more strict than using // instanceof if (a.constructor !== b.constructor) { // Allow objects with no prototype to be equivalent to // objects with Object as their constructor. if (!((getProto(a) === null && getProto(b) === Object.prototype) || (getProto(b) === null && getProto(a) === Object.prototype))) { return false; } } // stack constructor before traversing properties callers.push(a.constructor); // track reference to avoid circular references parents.push(a); for (i in a) { // be strict: don't ensures hasOwnProperty // and go deep loop = false; for (j = 0; j < parents.length; j++) { if (parents[j] === a[i]) { // don't go down the same path twice loop = true; } } aProperties.push(i); // collect a's properties if (!loop && !innerEquiv(a[i], b[i])) { eq = false; break; } } callers.pop(); // unstack, we are done parents.pop(); for (i in b) { bProperties.push(i); // collect b's properties } // Ensures identical properties name return eq && innerEquiv(aProperties.sort(), bProperties.sort()); } }; }()); innerEquiv = function() { // can take multiple arguments var args = Array.prototype.slice.apply(arguments); if (args.length < 2) { return true; // end transition } return (function(a, b) { if (a === b) { return true; // catch the most you can } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) { return false; // don't lose time with error prone cases } else { return bindCallbacks(a, callbacks, [ b, a ]); } // apply transition with (1..n) arguments }(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length - 1))); }; return innerEquiv; }()); /** * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | * http://flesler.blogspot.com Licensed under BSD * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 * * @projectDescription Advanced and extensible data dumping for Javascript. * @version 1.0.0 * @author Ariel Flesler * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} */ QUnit.jsDump = (function() { function quote( str ) { return '"' + str.toString().replace(/"/g, '\\"') + '"'; } function literal( o ) { return o + ''; } function join( pre, arr, post ) { var s = jsDump.separator(), base = jsDump.indent(), inner = jsDump.indent(1); if ( arr.join ) { arr = arr.join( ',' + s + inner ); } if ( !arr ) { return pre + post; } return [ pre, inner + arr, base + post ].join(s); } function array( arr, stack ) { var i = arr.length, ret = new Array(i); this.up(); while ( i-- ) { ret[i] = this.parse( arr[i] , undefined , stack); } this.down(); return join( '[', ret, ']' ); } var reName = /^function (\w+)/; var jsDump = { parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance stack = stack || [ ]; var parser = this.parsers[ type || this.typeOf(obj) ]; type = typeof parser; var inStack = inArray(obj, stack); if (inStack != -1) { return 'recursion('+(inStack - stack.length)+')'; } //else if (type == 'function') { stack.push(obj); var res = parser.call( this, obj, stack ); stack.pop(); return res; } // else return (type == 'string') ? parser : this.parsers.error; }, typeOf: function( obj ) { var type; if ( obj === null ) { type = "null"; } else if (typeof obj === "undefined") { type = "undefined"; } else if (QUnit.is("RegExp", obj)) { type = "regexp"; } else if (QUnit.is("Date", obj)) { type = "date"; } else if (QUnit.is("Function", obj)) { type = "function"; } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") { type = "window"; } else if (obj.nodeType === 9) { type = "document"; } else if (obj.nodeType) { type = "node"; } else if ( // native arrays toString.call( obj ) === "[object Array]" || // NodeList objects ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) ) { type = "array"; } else { type = typeof obj; } return type; }, separator: function() { return this.multiline ? this.HTML ? '
      ' : '\n' : this.HTML ? ' ' : ' '; }, indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing if ( !this.multiline ) { return ''; } var chr = this.indentChar; if ( this.HTML ) { chr = chr.replace(/\t/g,' ').replace(/ /g,' '); } return new Array( this._depth_ + (extra||0) ).join(chr); }, up: function( a ) { this._depth_ += a || 1; }, down: function( a ) { this._depth_ -= a || 1; }, setParser: function( name, parser ) { this.parsers[name] = parser; }, // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, // _depth_: 1, // This is the list of parsers, to modify them, use jsDump.setParser parsers: { window: '[Window]', document: '[Document]', error: '[ERROR]', //when no parser is found, shouldn't happen unknown: '[Unknown]', 'null': 'null', 'undefined': 'undefined', 'function': function( fn ) { var ret = 'function', name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE if ( name ) { ret += ' ' + name; } ret += '('; ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); }, array: array, nodelist: array, 'arguments': array, object: function( map, stack ) { var ret = [ ], keys, key, val, i; QUnit.jsDump.up(); if (Object.keys) { keys = Object.keys( map ); } else { keys = []; for (key in map) { keys.push( key ); } } keys.sort(); for (i = 0; i < keys.length; i++) { key = keys[ i ]; val = map[ key ]; ret.push( QUnit.jsDump.parse( key, 'key' ) + ': ' + QUnit.jsDump.parse( val, undefined, stack ) ); } QUnit.jsDump.down(); return join( '{', ret, '}' ); }, node: function( node ) { var open = QUnit.jsDump.HTML ? '<' : '<', close = QUnit.jsDump.HTML ? '>' : '>'; var tag = node.nodeName.toLowerCase(), ret = open + tag; for ( var a in QUnit.jsDump.DOMAttrs ) { var val = node[QUnit.jsDump.DOMAttrs[a]]; if ( val ) { ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); } } return ret + close + open + '/' + tag + close; }, functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function var l = fn.length; if ( !l ) { return ''; } var args = new Array(l); while ( l-- ) { args[l] = String.fromCharCode(97+l);//97 is 'a' } return ' ' + args.join(', ') + ' '; }, key: quote, //object calls it internally, the key part of an item in a map functionCode: '[code]', //function calls it internally, it's the content of the function attribute: quote, //node calls it internally, it's an html attribute value string: quote, date: quote, regexp: literal, //regex number: literal, 'boolean': literal }, DOMAttrs:{//attributes to dump from nodes, name=>realName id:'id', name:'name', 'class':'className' }, HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) indentChar:' ',//indentation unit multiline:true //if true, items in a collection, are separated by a \n, else just a space. }; return jsDump; }()); // from Sizzle.js function getText( elems ) { var ret = "", elem; for ( var i = 0; elems[i]; i++ ) { elem = elems[i]; // Get the text from text nodes and CDATA nodes if ( elem.nodeType === 3 || elem.nodeType === 4 ) { ret += elem.nodeValue; // Traverse everything else, except comment nodes } else if ( elem.nodeType !== 8 ) { ret += getText( elem.childNodes ); } } return ret; } //from jquery.js function inArray( elem, array ) { if ( array.indexOf ) { return array.indexOf( elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; } /* * Javascript Diff Algorithm * By John Resig (http://ejohn.org/) * Modified by Chu Alan "sprite" * * Released under the MIT license. * * More Info: * http://ejohn.org/projects/javascript-diff-algorithm/ * * Usage: QUnit.diff(expected, actual) * * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" */ QUnit.diff = (function() { function diff(o, n) { var ns = {}; var os = {}; var i; for (i = 0; i < n.length; i++) { if (ns[n[i]] == null) { ns[n[i]] = { rows: [], o: null }; } ns[n[i]].rows.push(i); } for (i = 0; i < o.length; i++) { if (os[o[i]] == null) { os[o[i]] = { rows: [], n: null }; } os[o[i]].rows.push(i); } for (i in ns) { if ( !hasOwn.call( ns, i ) ) { continue; } if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { n[ns[i].rows[0]] = { text: n[ns[i].rows[0]], row: os[i].rows[0] }; o[os[i].rows[0]] = { text: o[os[i].rows[0]], row: ns[i].rows[0] }; } } for (i = 0; i < n.length - 1; i++) { if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && n[i + 1] == o[n[i].row + 1]) { n[i + 1] = { text: n[i + 1], row: n[i].row + 1 }; o[n[i].row + 1] = { text: o[n[i].row + 1], row: i + 1 }; } } for (i = n.length - 1; i > 0; i--) { if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && n[i - 1] == o[n[i].row - 1]) { n[i - 1] = { text: n[i - 1], row: n[i].row - 1 }; o[n[i].row - 1] = { text: o[n[i].row - 1], row: i - 1 }; } } return { o: o, n: n }; } return function(o, n) { o = o.replace(/\s+$/, ''); n = n.replace(/\s+$/, ''); var out = diff(o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/)); var str = ""; var i; var oSpace = o.match(/\s+/g); if (oSpace == null) { oSpace = [" "]; } else { oSpace.push(" "); } var nSpace = n.match(/\s+/g); if (nSpace == null) { nSpace = [" "]; } else { nSpace.push(" "); } if (out.n.length === 0) { for (i = 0; i < out.o.length; i++) { str += '' + out.o[i] + oSpace[i] + ""; } } else { if (out.n[0].text == null) { for (n = 0; n < out.o.length && out.o[n].text == null; n++) { str += '' + out.o[n] + oSpace[n] + ""; } } for (i = 0; i < out.n.length; i++) { if (out.n[i].text == null) { str += '' + out.n[i] + nSpace[i] + ""; } else { var pre = ""; for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { pre += '' + out.o[n] + oSpace[n] + ""; } str += " " + out.n[i].text + nSpace[i] + pre; } } } return str; }; }()); // for CommonJS enviroments, export everything if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { extend(exports, QUnit); } // get at whatever the global object is, like window in browsers }( (function() {return this;}.call()) )); pegjs-0.7.0/tools/0000755000175000017500000000000012206663530013243 5ustar danieldanielpegjs-0.7.0/tools/impact0000755000175000017500000000412712206663530014452 0ustar danieldaniel#!/bin/sh # Measures impact of a Git commit (or multiple commits) on generated parsers' # speed and size. Makes sense to use only on PEG.js Git repository checkout. set -e # Measurement prepare() { git checkout --quiet "$1" make build } run_benchmark() { echo $(make benchmark | awk 'BEGIN { FS = " *│ *" } /Total/ { split($5, a, " "); print a[1] }') } measure_speed() { bc <<-EOT scale = 2 ($(run_benchmark) + $(run_benchmark) + $(run_benchmark) + $(run_benchmark) + $(run_benchmark)) / 5 EOT } measure_size() { for file in examples/*.pegjs; do bin/pegjs "$file" done echo $(cat examples/*.js | wc -c) rm examples/*.js } difference() { bc <<-EOT scale = 4 ($2 / $1 - 1) * 100 EOT } # Helpers print_results() { echo echo "Speed impact" echo "------------" echo "Before: $1 kB/s" echo "After: $2 kB/s" printf "Difference: %0.2f%%\n" $(difference $1 $2) echo echo "Size impact" echo "-----------" echo "Before: $3 b" echo "After: $4 b" printf "Difference: %0.2f%%\n" $(difference $3 $4) echo echo "(Measured by /tools/impact with Node.js $(node --version) on $(uname --operating-system --machine).)" } print_usage() { echo "Usage:" echo " $0 " echo " $0 " echo echo "Measures impact of a Git commit (or multiple commits) on generated parsers'" echo "speed and size. Makes sense to use only on PEG.js Git repository checkout." } cd_to_root() { if [ -L "$0" ]; then THIS_FILE=$(readlink "$0") else THIS_FILE="$0" fi cd "$(dirname "$THIS_FILE")/.." } exit_failure() { exit 1 } # Main if [ $# -eq 1 ]; then commit_before="$1~1" commit_after="$1" elif [ $# -eq 2 ]; then commit_before="$1" commit_after="$2" else print_usage exit_failure fi cd_to_root echo -n "Measuring commit $commit_before..." prepare "$commit_before" speed1=$(measure_speed) size1=$(measure_size) echo " OK" echo -n "Measuring commit $commit_after..." prepare "$commit_after" speed2=$(measure_speed) size2=$(measure_size) echo " OK" print_results $speed1 $speed2 $size1 $size2 pegjs-0.7.0/LICENSE0000644000175000017500000000204412206663530013110 0ustar danieldanielCopyright (c) 2010-2012 David Majda Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pegjs-0.7.0/package.json0000644000175000017500000000103412206663530014367 0ustar danieldaniel{ "name": "pegjs", "version": "@VERSION", "description": "Parser generator for JavaScript", "homepage": "http://pegjs.majda.cz/", "author": { "name": "David Majda", "email": "david@majda.cz", "url": "http://majda.cz/" }, "main": "lib/peg", "bin": "bin/pegjs", "repository": { "type": "git", "url": "http://github.com/dmajda/pegjs.git" }, "devDependencies": { "uglify-js": ">= 1.2.4", "jshint": ">= 0.5.5" }, "engines": { "node": ">= 0.6.6" } } pegjs-0.7.0/CHANGELOG0000644000175000017500000001757312206663530013332 0ustar danieldaniel0.7.0 (2012-04-18) ------------------ Big Changes: * Added ability to pass options to |PEG.buildParser|. * Implemented the |trackLineAndColumn| option for |PEG.buildParser| (together with the "--track-line-and-column" command-line option). It makes the generated parser track line and column during parsing. These are made available inside actions and predicates as |line| and |column| variables. * Implemented the |cache| option for |PEG.buildParser| (together with the "--cache" command-line option). This option enables/disables the results cache in generated parsers, resulting in dramatic speedup when the cache is disabled (the default now). The cost is breaking the linear parsing time guarantee. * The current parse position is visible inside actions and predicates as the |offset| variable. * Exceptions thrown by the parser have |offset|, |expected| and |found| properties containing machine-readable information about the parse failure (based on a patch by Marcin Stefaniuk). * Semantic predicates have access to preceding labels. [GH-69] * Implemented case-insensitive literal and class matching. [GH-34] * Rewrote the code generator -- split some computations into separate passes and based it on a proper templating system (Codie). * Rewrote variable handling in generated parsers in a stack-like fashion, simplifying the code and making the parsers smaller and faster. * Adapted to Node.js 0.6.6+ (no longer supported in older versions). * Dropped support for IE < 8. * As a result of several optimizations, parsers generated by 0.7.0 are ~6.4 times faster and ~19% smaller than those generated by 0.6.2 (as reported by /tools/impact). Small Changes: * Fixed reported error position when part of the input is not consumed. [GH-48] * Fixed incorrect disjunction operator in |computeErrorPosition| (original patch by Wolfgang Kluge). * Fixed regexp for detecting command-line options in /bin/pegjs. [GH-51] * Generate more efficient code for empty literals (original patch by Wolfgang Kluge). * Fixed comment typos (patches by Wolfgang Kluge and Jason Davies). [GH-59] * Fixed a typo in JavaScript example grammar. [GH-62] * Made copy & paste inclusion of the PEG.js library into another code easier by changing how the library is exported. * Improved the copyright comment and the "Generated by..." header. * Replaced Jakefile with Makefile. * Added "make hint" task that checks all JavaScript files using JSHint and resolved all issues it reported. All JavaScript files and also generated parsers are JSHint-clean now. * Fixed output printed during test failures (expected value was being printed instead of the actual one). Original patch by Wolfgang Kluge. * Added a /tools/impact script to measure speed and size impact of commits. * Various generated code improvements and fixes. * Various internal code improvements and fixes. * Improved README.md. 0.6.2 (2011-08-20) ------------------ Small Changes: * Reset parser position when action returns |null|. * Fixed typo in JavaScript example grammar. 0.6.1 (2011-04-14) ------------------ Small Changes: * Use --ascii option when generating a minified version. 0.6.0 (2011-04-14) ------------------ Big Changes: * Rewrote the command-line mode to be based on Node.js instead of Rhino -- no more Java dependency. This also means that PEG.js is available as a Node.js package and can be required as a module. * Version for the browser is built separately from the command-ine one in two flavors (normal and minified). * Parser variable name is no longer required argument of bin/pegjs -- it is "module.exports" by default and can be set using the -e/--export-var option. This makes parsers generated by /bin/pegjs Node.js modules by default. * Added ability to start parsing from any grammar rule. * Added several compiler optimizations -- 0.6 is ~12% faster than 0.5.1 in the benchmark on V8. Small Changes: * Split the source code into multiple files combined together using a build system. * Jake is now used instead of Rake for build scripts -- no more Ruby dependency. * Test suite can be run from the command-line. * Benchmark suite can be run from the command-line. * Benchmark browser runner improvements (users can specify number of runs, benchmarks are run using |setTimeout|, table is centered and fixed-width). * Added PEG.js version to "Generated by..." line in generated parsers. * Added PEG.js version information and homepage header to peg.js. * Generated code improvements and fixes. * Internal code improvements and fixes. * Rewrote README.md. 0.5.1 (2010-11-28) ------------------ Small Changes: * Fixed a problem where "SyntaxError: Invalid range in character class." error appeared when using command-line version on Widnows (GH-13). * Fixed wrong version reported by "bin/pegjs --version". * Removed two unused variables in the code. * Fixed incorrect variable name on two places. 0.5 (2010-06-10) ---------------- Big Changes: * Syntax change: Use labeled expressions and variables instead of $1, $2, etc. * Syntax change: Replaced ":" after a rule name with "=". * Syntax change: Allow trailing semicolon (";") for rules * Semantic change: Start rule of the grammar is now implicitly its first rule. * Implemented semantic predicates. * Implemented initializers. * Removed ability to change the start rule when generating the parser. * Added several compiler optimizations -- 0.5 is ~11% faster than 0.4 in the benchmark on V8. Small Changes: * PEG.buildParser now accepts grammars only in string format. * Added "Generated by ..." message to the generated parsers. * Formatted all grammars more consistently and transparently. * Added notes about ECMA-262, 5th ed. compatibility to the JSON example grammar. * Guarded against redefinition of |undefined|. * Made bin/pegjs work when called via a symlink (issue #1). * Fixed bug causing incorrect error messages (issue #2). * Fixed error message for invalid character range. * Fixed string literal parsing in the JavaScript grammar. * Generated code improvements and fixes. * Internal code improvements and fixes. * Improved README.md. 0.4 (2010-04-17) ---------------- Big Changes: * Improved IE compatibility -- IE6+ is now fully supported. * Generated parsers are now standalone (no runtime is required). * Added example grammars for JavaScript, CSS and JSON. * Added a benchmark suite. * Implemented negative character classes (e.g. [^a-z]). * Project moved from BitBucket to GitHub. Small Changes: * Code generated for the character classes is now regexp-based (= simpler and more scalable). * Added \uFEFF (BOM) to the definition of whitespace in the metagrammar. * When building a parser, left-recursive rules (both direct and indirect) are reported as errors. * When building a parser, missing rules are reported as errors. * Expected items in the error messages do not contain duplicates and they are sorted. * Fixed several bugs in the example arithmetics grammar. * Converted README to GitHub Flavored Markdown and improved it. * Added CHANGELOG. * Internal code improvements. 0.3 (2010-03-14) ---------------- * Wrote README. * Bootstrapped the grammar parser. * Metagrammar recognizes JavaScript-like comments. * Changed standard grammar extension from .peg to .pegjs (it is more specific). * Simplified the example arithmetics grammar + added comment. * Fixed a bug with reporting of invalid ranges such as [b-a] in the metagrammar. * Fixed --start vs. --start-rule inconsistency between help and actual option processing code. * Avoided ugliness in QUnit output. * Fixed typo in help: "parserVar" -> "parser_var". * Internal code improvements. 0.2.1 (2010-03-08) ------------------ * Added "pegjs-" prefix to the name of the minified runtime file. 0.2 (2010-03-08) ---------------- * Added Rakefile that builds minified runtime using Google Closure Compiler API. * Removed trailing commas in object initializers (Google Closure does not like them). 0.1 (2010-03-08) ---------------- * Initial release. pegjs-0.7.0/src/0000755000175000017500000000000012206663530012672 5ustar danieldanielpegjs-0.7.0/src/passes.js0000644000175000017500000002714212206663530014534 0ustar danieldaniel/* * Compiler passes. * * Each pass is a function that is passed the AST. It can perform checks on it * or modify it as needed. If the pass encounters a semantic error, it throws * |PEG.GrammarError|. */ PEG.compiler.passes = { /* Checks that all referenced rules exist. */ reportMissingRules: function(ast) { function nop() {} function checkExpression(node) { check(node.expression); } function checkSubnodes(propertyName) { return function(node) { each(node[propertyName], check); }; } var check = buildNodeVisitor({ grammar: checkSubnodes("rules"), 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 (!findRuleByName(ast, node.name)) { 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. */ reportLeftRecursion: function(ast) { function nop() {} function checkExpression(node, appliedRules) { check(node.expression, appliedRules); } function checkSubnodes(propertyName) { return function(node, appliedRules) { each(node[propertyName], function(subnode) { check(subnode, appliedRules); }); }; } var check = buildNodeVisitor({ grammar: checkSubnodes("rules"), rule: function(node, appliedRules) { check(node.expression, appliedRules.concat(node.name)); }, choice: checkSubnodes("alternatives"), 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(findRuleByName(ast, node.name), appliedRules); }, literal: nop, any: nop, "class": nop }); check(ast, []); }, /* * Removes proxy rules -- that is, rules that only delegate to other rule. */ removeProxyRules: 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: replaceInSubnodes("rules"), 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); } var indices = []; each(ast.rules, function(rule, i) { if (isProxyRule(rule)) { replaceRuleRefs(ast, rule.name, rule.expression.name); if (rule.name === ast.startRule) { ast.startRule = rule.expression.name; } indices.push(i); } }); indices.reverse(); each(indices, function(index) { ast.rules.splice(index, 1); }); }, /* * Computes names of variables used for storing match results and parse * positions in generated code. These variables are organized as two stacks. * The following will hold after running this pass: * * * All nodes except "grammar" and "rule" nodes will have a |resultVar| * property. It will contain a name of the variable that will store a * match result of the expression represented by the node in generated * code. * * * Some nodes will have a |posVar| property. It will contain a name of the * variable that will store a parse position in generated code. * * * All "rule" nodes will contain |resultVars| and |posVars| properties. * They will contain a list of values of |resultVar| and |posVar| * properties used in rule's subnodes. (This is useful to declare * variables in generated code.) */ computeVarNames: function(ast) { function resultVar(index) { return "result" + index; } function posVar(index) { return "pos" + index; } function computeLeaf(node, index) { node.resultVar = resultVar(index.result); return { result: 0, pos: 0 }; } function computeFromExpression(delta) { return function(node, index) { var depth = compute( node.expression, { result: index.result + delta.result, pos: index.pos + delta.pos } ); node.resultVar = resultVar(index.result); if (delta.pos !== 0) { node.posVar = posVar(index.pos); } return { result: depth.result + delta.result, pos: depth.pos + delta.pos }; }; } var compute = buildNodeVisitor({ grammar: function(node, index) { each(node.rules, function(node) { compute(node, index); }); }, rule: function(node, index) { var depth = compute(node.expression, index); node.resultVar = resultVar(index.result); node.resultVars = map(range(depth.result + 1), resultVar); node.posVars = map(range(depth.pos), posVar); }, choice: function(node, index) { var depths = map(node.alternatives, function(alternative) { return compute(alternative, index); }); node.resultVar = resultVar(index.result); return { result: Math.max.apply(null, pluck(depths, "result")), pos: Math.max.apply(null, pluck(depths, "pos")) }; }, sequence: function(node, index) { var depths = map(node.elements, function(element, i) { return compute( element, { result: index.result + i, pos: index.pos + 1 } ); }); node.resultVar = resultVar(index.result); node.posVar = posVar(index.pos); return { result: node.elements.length > 0 ? Math.max.apply( null, map(depths, function(d, i) { return i + d.result; }) ) : 0, pos: node.elements.length > 0 ? 1 + Math.max.apply(null, pluck(depths, "pos")) : 1 }; }, labeled: computeFromExpression({ result: 0, pos: 0 }), simple_and: computeFromExpression({ result: 0, pos: 1 }), simple_not: computeFromExpression({ result: 0, pos: 1 }), semantic_and: computeLeaf, semantic_not: computeLeaf, optional: computeFromExpression({ result: 0, pos: 0 }), zero_or_more: computeFromExpression({ result: 1, pos: 0 }), one_or_more: computeFromExpression({ result: 1, pos: 0 }), action: computeFromExpression({ result: 0, pos: 1 }), rule_ref: computeLeaf, literal: computeLeaf, any: computeLeaf, "class": computeLeaf }); compute(ast, { result: 0, pos: 0 }); }, /* * This pass walks through the AST and tracks what labels are visible at each * point. For "action", "semantic_and" and "semantic_or" nodes it computes * parameter names and values for the function used in generated code. (In the * emitter, user's code is wrapped into a function that is immediately * executed. Its parameter names correspond to visible labels and its * parameter values to their captured values). Implicitly, this pass defines * scoping rules for labels. * * After running this pass, all "action", "semantic_and" and "semantic_or" * nodes will have a |params| property containing an object mapping parameter * names to the expressions that will be used as their values. */ computeParams: function(ast) { var envs = []; function scoped(f) { envs.push({}); f(); envs.pop(); } function nop() {} function computeForScopedExpression(node) { scoped(function() { compute(node.expression); }); } function computeParams(node) { var env = envs[envs.length - 1], params = {}, name; for (name in env) { params[name] = env[name]; } node.params = params; } var compute = buildNodeVisitor({ grammar: function(node) { each(node.rules, compute); }, rule: computeForScopedExpression, choice: function(node) { scoped(function() { each(node.alternatives, compute); }); }, sequence: function(node) { var env = envs[envs.length - 1], name; function fixup(name) { each(pluck(node.elements, "resultVar"), function(resultVar, i) { if ((new RegExp("^" + resultVar + "(\\[\\d+\\])*$")).test(env[name])) { env[name] = node.resultVar + "[" + i + "]" + env[name].substr(resultVar.length); } }); } each(node.elements, compute); for (name in env) { fixup(name); } }, labeled: function(node) { envs[envs.length - 1][node.label] = node.resultVar; scoped(function() { compute(node.expression); }); }, simple_and: computeForScopedExpression, simple_not: computeForScopedExpression, semantic_and: computeParams, semantic_not: computeParams, optional: computeForScopedExpression, zero_or_more: computeForScopedExpression, one_or_more: computeForScopedExpression, action: function(node) { scoped(function() { compute(node.expression); computeParams(node); }); }, rule_ref: nop, literal: nop, any: nop, "class": nop }); compute(ast); } }; pegjs-0.7.0/src/parser.pegjs0000644000175000017500000001765512206663530015236 0ustar danieldanielgrammar = __ initializer:initializer? rules:rule+ { return { type: "grammar", initializer: initializer !== "" ? initializer : null, rules: rules, startRule: rules[0].name }; } initializer = code:action semicolon? { return { type: "initializer", code: code }; } rule = name:identifier displayName:string? equals expression:expression semicolon? { return { type: "rule", name: name, displayName: displayName !== "" ? displayName : null, expression: expression }; } expression = choice choice = head:sequence tail:(slash sequence)* { if (tail.length > 0) { var alternatives = [head].concat(map( tail, function(element) { return element[1]; } )); return { type: "choice", alternatives: alternatives }; } else { return head; } } sequence = elements:labeled* code:action { var expression = elements.length !== 1 ? { type: "sequence", elements: elements } : elements[0]; return { type: "action", expression: expression, code: code }; } / elements:labeled* { return elements.length !== 1 ? { type: "sequence", elements: elements } : elements[0]; } labeled = label:identifier colon expression:prefixed { return { type: "labeled", label: label, expression: expression }; } / prefixed prefixed = and code:action { return { type: "semantic_and", code: code }; } / and expression:suffixed { return { type: "simple_and", expression: expression }; } / not code:action { return { type: "semantic_not", code: code }; } / not expression:suffixed { return { type: "simple_not", expression: expression }; } / suffixed suffixed = expression:primary question { return { type: "optional", expression: expression }; } / expression:primary star { return { type: "zero_or_more", expression: expression }; } / expression:primary plus { return { type: "one_or_more", expression: expression }; } / primary primary = name:identifier !(string? equals) { return { type: "rule_ref", name: name }; } / literal / dot { return { type: "any" }; } / class / lparen expression:expression rparen { return expression; } /* "Lexical" elements */ action "action" = braced:braced __ { return braced.substr(1, braced.length - 2); } braced = "{" parts:(braced / nonBraceCharacter)* "}" { return "{" + parts.join("") + "}"; } nonBraceCharacters = chars:nonBraceCharacter+ { return chars.join(""); } nonBraceCharacter = [^{}] equals = "=" __ { return "="; } colon = ":" __ { return ":"; } semicolon = ";" __ { return ";"; } slash = "/" __ { return "/"; } and = "&" __ { return "&"; } not = "!" __ { return "!"; } question = "?" __ { return "?"; } star = "*" __ { return "*"; } plus = "+" __ { return "+"; } lparen = "(" __ { return "("; } rparen = ")" __ { return ")"; } dot = "." __ { return "."; } /* * Modelled after ECMA-262, 5th ed., 7.6, but much simplified: * * * no Unicode escape sequences * * * "Unicode combining marks" and "Unicode connection punctuation" can't be * part of the identifier * * * only [a-zA-Z] is considered a "Unicode letter" * * * only [0-9] is considered a "Unicode digit" * * The simplifications were made just to make the implementation little bit * easier, there is no "philosophical" reason behind them. */ identifier "identifier" = head:(letter / "_" / "$") tail:(letter / digit / "_" / "$")* __ { return head + tail.join(""); } /* * Modelled after ECMA-262, 5th ed., 7.8.4. (syntax & semantics, rules only * vaguely). */ literal "literal" = value:(doubleQuotedString / singleQuotedString) flags:"i"? __ { return { type: "literal", value: value, ignoreCase: flags === "i" }; } string "string" = string:(doubleQuotedString / singleQuotedString) __ { return string; } doubleQuotedString = '"' chars:doubleQuotedCharacter* '"' { return chars.join(""); } doubleQuotedCharacter = simpleDoubleQuotedCharacter / simpleEscapeSequence / zeroEscapeSequence / hexEscapeSequence / unicodeEscapeSequence / eolEscapeSequence simpleDoubleQuotedCharacter = !('"' / "\\" / eolChar) char_:. { return char_; } singleQuotedString = "'" chars:singleQuotedCharacter* "'" { return chars.join(""); } singleQuotedCharacter = simpleSingleQuotedCharacter / simpleEscapeSequence / zeroEscapeSequence / hexEscapeSequence / unicodeEscapeSequence / eolEscapeSequence simpleSingleQuotedCharacter = !("'" / "\\" / eolChar) char_:. { return char_; } class "character class" = "[" inverted:"^"? parts:(classCharacterRange / classCharacter)* "]" flags:"i"? __ { var partsConverted = map(parts, function(part) { return part.data; }); var rawText = "[" + inverted + map(parts, function(part) { return part.rawText; }).join("") + "]" + flags; return { type: "class", inverted: inverted === "^", ignoreCase: flags === "i", parts: partsConverted, // FIXME: Get the raw text from the input directly. rawText: rawText }; } classCharacterRange = begin:classCharacter "-" end:classCharacter { 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 }; } classCharacter = char_:bracketDelimitedCharacter { return { data: char_, // FIXME: Get the raw text from the input directly. rawText: quoteForRegexpClass(char_) }; } bracketDelimitedCharacter = simpleBracketDelimitedCharacter / simpleEscapeSequence / zeroEscapeSequence / hexEscapeSequence / unicodeEscapeSequence / eolEscapeSequence simpleBracketDelimitedCharacter = !("]" / "\\" / eolChar) char_:. { return char_; } simpleEscapeSequence = "\\" !(digit / "x" / "u" / eolChar) 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". } zeroEscapeSequence = "\\0" !digit { return "\x00"; } hexEscapeSequence = "\\x" h1:hexDigit h2:hexDigit { return String.fromCharCode(parseInt(h1 + h2, 16)); } unicodeEscapeSequence = "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { return String.fromCharCode(parseInt(h1 + h2 + h3 + h4, 16)); } eolEscapeSequence = "\\" eol:eol { return eol; } digit = [0-9] hexDigit = [0-9a-fA-F] letter = lowerCaseLetter / upperCaseLetter lowerCaseLetter = [a-z] upperCaseLetter = [A-Z] __ = (whitespace / eol / comment)* /* Modelled after ECMA-262, 5th ed., 7.4. */ comment "comment" = singleLineComment / multiLineComment singleLineComment = "//" (!eolChar .)* multiLineComment = "/*" (!"*/" .)* "*/" /* Modelled after ECMA-262, 5th ed., 7.3. */ eol "end of line" = "\n" / "\r\n" / "\r" / "\u2028" / "\u2029" eolChar = [\n\r\u2028\u2029] /* Modelled after ECMA-262, 5th ed., 7.2. */ whitespace "whitespace" = [ \t\v\f\u00A0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000] pegjs-0.7.0/src/peg.js0000644000175000017500000000226412206663530014007 0ustar danieldaniel/* * PEG.js @VERSION * * http://pegjs.majda.cz/ * * Copyright (c) 2010-2012 David Majda * Licensend under the MIT license. */ var PEG = (function(undefined) { var PEG = { /* PEG.js version (uses semantic versioning). */ VERSION: "@VERSION", /* * 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, options) { return PEG.compiler.compile(PEG.parser.parse(grammar), options); } }; /* Thrown when the grammar contains an error. */ PEG.GrammarError = function(message) { this.name = "PEG.GrammarError"; this.message = message; }; PEG.GrammarError.prototype = Error.prototype; // @include "utils.js" // @include "parser.js" // @include "compiler.js" return PEG; })(); if (typeof module !== "undefined") { module.exports = PEG; } pegjs-0.7.0/src/emitter.js0000644000175000017500000010360712206663530014710 0ustar danieldaniel/* Emits the generated code for the AST. */ PEG.compiler.emitter = function(ast, options) { options = options || {}; if (options.cache === undefined) { options.cache = false; } if (options.trackLineAndColumn === undefined) { options.trackLineAndColumn = false; } /* * Codie 1.1.0 * * https://github.com/dmajda/codie * * Copyright (c) 2011-2012 David Majda * Licensend under the MIT license. */ var Codie = (function(undefined) { function stringEscape(s) { function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); } /* * 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 control and non-ASCII * characters. Note that "\0" and "\v" escape sequences are not used * because JSHint does not like the first and IE the second. */ return s .replace(/\\/g, '\\\\') // backslash .replace(/"/g, '\\"') // closing double quote .replace(/\x08/g, '\\b') // backspace .replace(/\t/g, '\\t') // horizontal tab .replace(/\n/g, '\\n') // line feed .replace(/\f/g, '\\f') // form feed .replace(/\r/g, '\\r') // carriage return .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); }) .replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); }) .replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); }); } function push(s) { return '__p.push(' + s + ');'; } function pushRaw(template, length, state) { function unindent(code, level, unindentFirst) { return code.replace( new RegExp('^.{' + level +'}', "gm"), function(str, offset) { if (offset === 0) { return unindentFirst ? '' : str; } else { return ""; } } ); } var escaped = stringEscape(unindent( template.substring(0, length), state.indentLevel(), state.atBOL )); return escaped.length > 0 ? push('"' + escaped + '"') : ''; } var Codie = { /* Codie version (uses semantic versioning). */ VERSION: "1.1.0", /* * Specifies by how many characters do #if/#else and #for unindent their * content in the generated code. */ indentStep: 2, /* Description of #-commands. Extend to define your own commands. */ commands: { "if": { params: /^(.*)$/, compile: function(state, prefix, params) { return ['if(' + params[0] + '){', []]; }, stackOp: "push" }, "else": { params: /^$/, compile: function(state) { var stack = state.commandStack, insideElse = stack[stack.length - 1] === "else", insideIf = stack[stack.length - 1] === "if"; if (insideElse) { throw new Error("Multiple #elses."); } if (!insideIf) { throw new Error("Using #else outside of #if."); } return ['}else{', []]; }, stackOp: "replace" }, "for": { params: /^([a-zA-Z_][a-zA-Z0-9_]*)[ \t]+in[ \t]+(.*)$/, init: function(state) { state.forCurrLevel = 0; // current level of #for loop nesting state.forMaxLevel = 0; // maximum level of #for loop nesting }, compile: function(state, prefix, params) { var c = '__c' + state.forCurrLevel, // __c for "collection" l = '__l' + state.forCurrLevel, // __l for "length" i = '__i' + state.forCurrLevel; // __i for "index" state.forCurrLevel++; if (state.forMaxLevel < state.forCurrLevel) { state.forMaxLevel = state.forCurrLevel; } return [ c + '=' + params[1] + ';' + l + '=' + c + '.length;' + 'for(' + i + '=0;' + i + '<' + l + ';' + i + '++){' + params[0] + '=' + c + '[' + i + '];', [params[0], c, l, i] ]; }, exit: function(state) { state.forCurrLevel--; }, stackOp: "push" }, "end": { params: /^$/, compile: function(state) { var stack = state.commandStack, exit; if (stack.length === 0) { throw new Error("Too many #ends."); } exit = Codie.commands[stack[stack.length - 1]].exit; if (exit) { exit(state); } return ['}', []]; }, stackOp: "pop" }, "block": { params: /^(.*)$/, compile: function(state, prefix, params) { var x = '__x', // __x for "prefix", n = '__n', // __n for "lines" l = '__l', // __l for "length" i = '__i'; // __i for "index" /* * Originally, the generated code used |String.prototype.replace|, but * it is buggy in certain versions of V8 so it was rewritten. See the * tests for details. */ return [ x + '="' + stringEscape(prefix.substring(state.indentLevel())) + '";' + n + '=(' + params[0] + ').toString().split("\\n");' + l + '=' + n + '.length;' + 'for(' + i + '=0;' + i + '<' + l + ';' + i + '++){' + n + '[' + i +']=' + x + '+' + n + '[' + i + ']+"\\n";' + '}' + push(n + '.join("")'), [x, n, l, i] ]; }, stackOp: "nop" } }, /* * Compiles a template into a function. When called, this function will * execute the template in the context of an object passed in a parameter and * return the result. */ template: function(template) { var stackOps = { push: function(stack, name) { stack.push(name); }, replace: function(stack, name) { stack[stack.length - 1] = name; }, pop: function(stack) { stack.pop(); }, nop: function() { } }; function compileExpr(state, expr) { state.atBOL = false; return [push(expr), []]; } function compileCommand(state, prefix, name, params) { var command, match, result; command = Codie.commands[name]; if (!command) { throw new Error("Unknown command: #" + name + "."); } match = command.params.exec(params); if (match === null) { throw new Error( "Invalid params for command #" + name + ": " + params + "." ); } result = command.compile(state, prefix, match.slice(1)); stackOps[command.stackOp](state.commandStack, name); state.atBOL = true; return result; } var state = { // compilation state commandStack: [], // stack of commands as they were nested atBOL: true, // is the next character to process at BOL? indentLevel: function() { return Codie.indentStep * this.commandStack.length; } }, code = '', // generated template function code vars = ['__p=[]'], // variables used by generated code name, match, result, i; /* Initialize state. */ for (name in Codie.commands) { if (Codie.commands[name].init) { Codie.commands[name].init(state); } } /* Compile the template. */ while ((match = /^([ \t]*)#([a-zA-Z_][a-zA-Z0-9_]*)(?:[ \t]+([^ \t\n][^\n]*))?[ \t]*(?:\n|$)|#\{([^}]*)\}/m.exec(template)) !== null) { code += pushRaw(template, match.index, state); result = match[2] !== undefined && match[2] !== "" ? compileCommand(state, match[1], match[2], match[3] || "") // #-command : compileExpr(state, match[4]); // #{...} code += result[0]; vars = vars.concat(result[1]); template = template.substring(match.index + match[0].length); } code += pushRaw(template, template.length, state); /* Check the final state. */ if (state.commandStack.length > 0) { throw new Error("Missing #end."); } /* Sanitize the list of variables used by commands. */ vars.sort(); for (i = 0; i < vars.length; i++) { if (vars[i] === vars[i - 1]) { vars.splice(i--, 1); } } /* Create the resulting function. */ return new Function("__v", [ '__v=__v||{};', 'var ' + vars.join(',') + ';', 'with(__v){', code, 'return __p.join("").replace(/^\\n+|\\n+$/g,"");};' ].join('')); } }; return Codie; })(); var templates = (function() { var name, templates = {}, sources = { grammar: [ '(function(){', ' /*', ' * Generated by PEG.js @VERSION.', ' *', ' * http://pegjs.majda.cz/', ' */', ' ', /* 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.', ' *', ' * For portability, we also escape escape all control and non-ASCII', ' * characters. Note that "\\0" and "\\v" escape sequences are not used', ' * because JSHint does not like the first and IE the second.', ' */', ' return \'"\' + s', ' .replace(/\\\\/g, \'\\\\\\\\\') // backslash', ' .replace(/"/g, \'\\\\"\') // closing quote character', ' .replace(/\\x08/g, \'\\\\b\') // backspace', ' .replace(/\\t/g, \'\\\\t\') // horizontal tab', ' .replace(/\\n/g, \'\\\\n\') // line feed', ' .replace(/\\f/g, \'\\\\f\') // form feed', ' .replace(/\\r/g, \'\\\\r\') // carriage return', ' .replace(/[\\x00-\\x07\\x0B\\x0E-\\x1F\\x80-\\uFFFF]/g, escape)', ' + \'"\';', ' }', ' ', ' 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 = {', ' #for rule in node.rules', ' #{string(rule.name) + ": parse_" + rule.name + (rule !== node.rules[node.rules.length - 1] ? "," : "")}', ' #end', ' };', ' ', ' if (startRule !== undefined) {', ' if (parseFunctions[startRule] === undefined) {', ' throw new Error("Invalid rule name: " + quote(startRule) + ".");', ' }', ' } else {', ' startRule = #{string(node.startRule)};', ' }', ' ', ' #{posInit("pos")};', ' var reportFailures = 0;', // 0 = report, anything > 0 = do not report ' #{posInit("rightmostFailuresPos")};', ' var rightmostFailuresExpected = [];', ' #if options.cache', ' var cache = {};', ' #end', ' ', /* 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);', ' var escapeChar;', ' var length;', ' ', ' if (charCode <= 0xFF) {', ' escapeChar = \'x\';', ' length = 2;', ' } else {', ' escapeChar = \'u\';', ' length = 4;', ' }', ' ', ' return \'\\\\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), \'0\', length);', ' }', ' ', ' #if options.trackLineAndColumn', ' function clone(object) {', ' var result = {};', ' for (var key in object) {', ' result[key] = object[key];', ' }', ' return result;', ' }', ' ', ' function advance(pos, n) {', ' var endOffset = pos.offset + n;', ' ', ' for (var offset = pos.offset; offset < endOffset; offset++) {', ' var ch = input.charAt(offset);', ' if (ch === "\\n") {', ' if (!pos.seenCR) { pos.line++; }', ' pos.column = 1;', ' pos.seenCR = false;', ' } else if (ch === "\\r" || ch === "\\u2028" || ch === "\\u2029") {', ' pos.line++;', ' pos.column = 1;', ' pos.seenCR = true;', ' } else {', ' pos.column++;', ' pos.seenCR = false;', ' }', ' }', ' ', ' pos.offset += n;', ' }', ' ', ' #end', ' function matchFailed(failure) {', ' if (#{posOffset("pos")} < #{posOffset("rightmostFailuresPos")}) {', ' return;', ' }', ' ', ' if (#{posOffset("pos")} > #{posOffset("rightmostFailuresPos")}) {', ' rightmostFailuresPos = #{posClone("pos")};', ' rightmostFailuresExpected = [];', ' }', ' ', ' rightmostFailuresExpected.push(failure);', ' }', ' ', ' #for rule in node.rules', ' #block emit(rule)', ' ', ' #end', ' ', ' function cleanupExpected(expected) {', ' expected.sort();', ' ', ' var lastExpected = null;', ' var cleanExpected = [];', ' for (var i = 0; i < expected.length; i++) {', ' if (expected[i] !== lastExpected) {', ' cleanExpected.push(expected[i]);', ' lastExpected = expected[i];', ' }', ' }', ' return cleanExpected;', ' }', ' ', ' #if !options.trackLineAndColumn', ' 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 < Math.max(pos, rightmostFailuresPos); 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 };', ' }', ' #end', ' ', ' #if node.initializer', ' #block emit(node.initializer)', ' #end', ' ', ' 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|', ' * - |#{posOffset("pos")} === input.length|', ' * - |rightmostFailuresExpected| may or may not contain something', ' *', ' * 2. The parser successfully parsed only a part of the input.', ' *', ' * - |result !== null|', ' * - |#{posOffset("pos")} < input.length|', ' * - |rightmostFailuresExpected| may or may not contain something', ' *', ' * 3. The parser did not successfully parse any part of the input.', ' *', ' * - |result === null|', ' * - |#{posOffset("pos")} === 0|', ' * - |rightmostFailuresExpected| contains at least one failure', ' *', ' * All code following this comment (including called functions) must', ' * handle these states.', ' */', ' if (result === null || #{posOffset("pos")} !== input.length) {', ' var offset = Math.max(#{posOffset("pos")}, #{posOffset("rightmostFailuresPos")});', ' var found = offset < input.length ? input.charAt(offset) : null;', ' #if options.trackLineAndColumn', ' var errorPosition = #{posOffset("pos")} > #{posOffset("rightmostFailuresPos")} ? pos : rightmostFailuresPos;', ' #else', ' var errorPosition = computeErrorPosition();', ' #end', ' ', ' throw new this.SyntaxError(', ' cleanupExpected(rightmostFailuresExpected),', ' found,', ' offset,', ' 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(expected, found, offset, line, column) {', ' function buildMessage(expected, found) {', ' var expectedHumanized, foundHumanized;', ' ', ' switch (expected.length) {', ' case 0:', ' expectedHumanized = "end of input";', ' break;', ' case 1:', ' expectedHumanized = expected[0];', ' break;', ' default:', ' expectedHumanized = expected.slice(0, expected.length - 1).join(", ")', ' + " or "', ' + expected[expected.length - 1];', ' }', ' ', ' foundHumanized = found ? quote(found) : "end of input";', ' ', ' return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";', ' }', ' ', ' this.name = "SyntaxError";', ' this.expected = expected;', ' this.found = found;', ' this.message = buildMessage(expected, found);', ' this.offset = offset;', ' this.line = line;', ' this.column = column;', ' };', ' ', ' result.SyntaxError.prototype = Error.prototype;', ' ', ' return result;', '})()' ], rule: [ 'function parse_#{node.name}() {', ' #if options.cache', ' var cacheKey = "#{node.name}@" + #{posOffset("pos")};', ' var cachedResult = cache[cacheKey];', ' if (cachedResult) {', ' pos = #{posClone("cachedResult.nextPos")};', ' return cachedResult.result;', ' }', ' ', ' #end', ' #if node.resultVars.length > 0', ' var #{node.resultVars.join(", ")};', ' #end', ' #if node.posVars.length > 0', ' var #{node.posVars.join(", ")};', ' #end', ' ', ' #if node.displayName !== null', ' reportFailures++;', ' #end', ' #block emit(node.expression)', ' #if node.displayName !== null', ' reportFailures--;', ' if (reportFailures === 0 && #{node.resultVar} === null) {', ' matchFailed(#{string(node.displayName)});', ' }', ' #end', ' #if options.cache', ' ', ' cache[cacheKey] = {', ' nextPos: #{posClone("pos")},', ' result: #{node.resultVar}', ' };', ' #end', ' return #{node.resultVar};', '}' ], choice: [ '#block emit(alternative)', '#block nextAlternativesCode' ], "choice.next": [ 'if (#{node.resultVar} === null) {', ' #block code', '}' ], sequence: [ '#{posSave(node)};', '#block code' ], "sequence.iteration": [ '#block emit(element)', 'if (#{element.resultVar} !== null) {', ' #block code', '} else {', ' #{node.resultVar} = null;', ' #{posRestore(node)};', '}' ], "sequence.inner": [ '#{node.resultVar} = [#{pluck(node.elements, "resultVar").join(", ")}];' ], simple_and: [ '#{posSave(node)};', 'reportFailures++;', '#block emit(node.expression)', 'reportFailures--;', 'if (#{node.resultVar} !== null) {', ' #{node.resultVar} = "";', ' #{posRestore(node)};', '} else {', ' #{node.resultVar} = null;', '}' ], simple_not: [ '#{posSave(node)};', 'reportFailures++;', '#block emit(node.expression)', 'reportFailures--;', 'if (#{node.resultVar} === null) {', ' #{node.resultVar} = "";', '} else {', ' #{node.resultVar} = null;', ' #{posRestore(node)};', '}' ], semantic_and: [ '#{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? ["pos.offset", "pos.line", "pos.column"] : ["pos"]).concat(values(node.params)).join(", ")}) ? "" : null;' ], semantic_not: [ '#{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? ["pos.offset", "pos.line", "pos.column"] : ["pos"]).concat(values(node.params)).join(", ")}) ? null : "";' ], optional: [ '#block emit(node.expression)', '#{node.resultVar} = #{node.resultVar} !== null ? #{node.resultVar} : "";' ], zero_or_more: [ '#{node.resultVar} = [];', '#block emit(node.expression)', 'while (#{node.expression.resultVar} !== null) {', ' #{node.resultVar}.push(#{node.expression.resultVar});', ' #block emit(node.expression)', '}' ], one_or_more: [ '#block emit(node.expression)', 'if (#{node.expression.resultVar} !== null) {', ' #{node.resultVar} = [];', ' while (#{node.expression.resultVar} !== null) {', ' #{node.resultVar}.push(#{node.expression.resultVar});', ' #block emit(node.expression)', ' }', '} else {', ' #{node.resultVar} = null;', '}' ], action: [ '#{posSave(node)};', '#block emit(node.expression)', 'if (#{node.resultVar} !== null) {', ' #{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? [node.posVar + ".offset", node.posVar + ".line", node.posVar + ".column"] : [node.posVar]).concat(values(node.params)).join(", ")});', '}', 'if (#{node.resultVar} === null) {', ' #{posRestore(node)};', '}' ], rule_ref: [ '#{node.resultVar} = parse_#{node.name}();' ], literal: [ '#if node.value.length === 0', ' #{node.resultVar} = "";', '#else', ' #if !node.ignoreCase', ' #if node.value.length === 1', ' if (input.charCodeAt(#{posOffset("pos")}) === #{node.value.charCodeAt(0)}) {', ' #else', ' if (input.substr(#{posOffset("pos")}, #{node.value.length}) === #{string(node.value)}) {', ' #end', ' #else', /* * One-char literals are not optimized when case-insensitive * matching is enabled. This is because there is no simple way to * lowercase a character code that works for character outside ASCII * letters. Moreover, |toLowerCase| can change string length, * meaning the result of lowercasing a character can be more * characters. */ ' if (input.substr(#{posOffset("pos")}, #{node.value.length}).toLowerCase() === #{string(node.value.toLowerCase())}) {', ' #end', ' #if !node.ignoreCase', ' #{node.resultVar} = #{string(node.value)};', ' #else', ' #{node.resultVar} = input.substr(#{posOffset("pos")}, #{node.value.length});', ' #end', ' #{posAdvance(node.value.length)};', ' } else {', ' #{node.resultVar} = null;', ' if (reportFailures === 0) {', ' matchFailed(#{string(string(node.value))});', ' }', ' }', '#end' ], any: [ 'if (input.length > #{posOffset("pos")}) {', ' #{node.resultVar} = input.charAt(#{posOffset("pos")});', ' #{posAdvance(1)};', '} else {', ' #{node.resultVar} = null;', ' if (reportFailures === 0) {', ' matchFailed("any character");', ' }', '}' ], "class": [ 'if (#{regexp}.test(input.charAt(#{posOffset("pos")}))) {', ' #{node.resultVar} = input.charAt(#{posOffset("pos")});', ' #{posAdvance(1)};', '} else {', ' #{node.resultVar} = null;', ' if (reportFailures === 0) {', ' matchFailed(#{string(node.rawText)});', ' }', '}' ] }; for (name in sources) { templates[name] = Codie.template(sources[name].join('\n')); } return templates; })(); function fill(name, vars) { vars.string = quote; vars.pluck = pluck; vars.keys = keys; vars.values = values; vars.emit = emit; vars.options = options; /* Position-handling macros */ if (options.trackLineAndColumn) { vars.posInit = function(name) { return "var " + name + " = " + "{ offset: 0, line: 1, column: 1, seenCR: false }"; }; vars.posClone = function(name) { return "clone(" + name + ")"; }; vars.posOffset = function(name) { return name + ".offset"; }; vars.posAdvance = function(n) { return "advance(pos, " + n + ")"; }; } else { vars.posInit = function(name) { return "var " + name + " = 0"; }; vars.posClone = function(name) { return name; }; vars.posOffset = function(name) { return name; }; vars.posAdvance = function(n) { return n === 1 ? "pos++" : "pos += " + n; }; } vars.posSave = function(node) { return node.posVar + " = " + vars.posClone("pos"); }; vars.posRestore = function(node) { return "pos" + " = " + vars.posClone(node.posVar); }; return templates[name](vars); } function emitSimple(name) { return function(node) { return fill(name, { node: node }); }; } var emit = buildNodeVisitor({ grammar: emitSimple("grammar"), initializer: function(node) { return node.code; }, rule: emitSimple("rule"), /* * The contract for all code fragments generated by the following functions * is as follows. * * The code fragment tries 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| to point to * the first chracter following the matched part of the input and sets * variable with a name stored in |node.resultVar| to an appropriate * value. This value is always non-|null|. * * * If the code fragment does not match the input, it returns with |pos| * set to the original value and it sets a variable with a name stored in * |node.resultVar| to |null|. * * The code can use variables with names stored in |resultVar| and |posVar| * properties of the current node's subnodes. It can't use any other * variables. */ choice: function(node) { var code, nextAlternativesCode; for (var i = node.alternatives.length - 1; i >= 0; i--) { nextAlternativesCode = i !== node.alternatives.length - 1 ? fill("choice.next", { node: node, code: code }) : ''; code = fill("choice", { alternative: node.alternatives[i], nextAlternativesCode: nextAlternativesCode }); } return code; }, sequence: function(node) { var code = fill("sequence.inner", { node: node }); for (var i = node.elements.length - 1; i >= 0; i--) { code = fill("sequence.iteration", { node: node, element: node.elements[i], code: code }); } return fill("sequence", { node: node, code: code }); }, labeled: function(node) { return emit(node.expression); }, simple_and: emitSimple("simple_and"), simple_not: emitSimple("simple_not"), semantic_and: emitSimple("semantic_and"), semantic_not: emitSimple("semantic_not"), optional: emitSimple("optional"), zero_or_more: emitSimple("zero_or_more"), one_or_more: emitSimple("one_or_more"), action: emitSimple("action"), rule_ref: emitSimple("rule_ref"), literal: emitSimple("literal"), any: emitSimple("any"), "class": function(node) { var regexp; if (node.parts.length > 0) { regexp = '/^[' + (node.inverted ? '^' : '') + map(node.parts, function(part) { return part instanceof Array ? quoteForRegexpClass(part[0]) + '-' + quoteForRegexpClass(part[1]) : quoteForRegexpClass(part); }).join('') + ']/' + (node.ignoreCase ? 'i' : ''); } else { /* * Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so * we translate them into euqivalents it can handle. */ regexp = node.inverted ? '/^[\\S\\s]/' : '/^(?!)/'; } return fill("class", { node: node, regexp: regexp }); } }); return emit(ast); }; pegjs-0.7.0/src/parser.js0000644000175000017500000023733612206663530014542 0ustar danieldanielPEG.parser = (function(){ /* * Generated by PEG.js 0.7.0. * * http://pegjs.majda.cz/ */ 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 control and non-ASCII * characters. Note that "\0" and "\v" escape sequences are not used * because JSHint does not like the first and IE the second. */ return '"' + s .replace(/\\/g, '\\\\') // backslash .replace(/"/g, '\\"') // closing quote character .replace(/\x08/g, '\\b') // backspace .replace(/\t/g, '\\t') // horizontal tab .replace(/\n/g, '\\n') // line feed .replace(/\f/g, '\\f') // form feed .replace(/\r/g, '\\r') // carriage return .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"'; } 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 = { "grammar": parse_grammar, "initializer": parse_initializer, "rule": parse_rule, "choice": parse_choice, "sequence": parse_sequence, "labeled": parse_labeled, "prefixed": parse_prefixed, "suffixed": parse_suffixed, "primary": parse_primary, "action": parse_action, "braced": parse_braced, "nonBraceCharacters": parse_nonBraceCharacters, "nonBraceCharacter": parse_nonBraceCharacter, "equals": parse_equals, "colon": parse_colon, "semicolon": parse_semicolon, "slash": parse_slash, "and": parse_and, "not": parse_not, "question": parse_question, "star": parse_star, "plus": parse_plus, "lparen": parse_lparen, "rparen": parse_rparen, "dot": parse_dot, "identifier": parse_identifier, "literal": parse_literal, "string": parse_string, "doubleQuotedString": parse_doubleQuotedString, "doubleQuotedCharacter": parse_doubleQuotedCharacter, "simpleDoubleQuotedCharacter": parse_simpleDoubleQuotedCharacter, "singleQuotedString": parse_singleQuotedString, "singleQuotedCharacter": parse_singleQuotedCharacter, "simpleSingleQuotedCharacter": parse_simpleSingleQuotedCharacter, "class": parse_class, "classCharacterRange": parse_classCharacterRange, "classCharacter": parse_classCharacter, "bracketDelimitedCharacter": parse_bracketDelimitedCharacter, "simpleBracketDelimitedCharacter": parse_simpleBracketDelimitedCharacter, "simpleEscapeSequence": parse_simpleEscapeSequence, "zeroEscapeSequence": parse_zeroEscapeSequence, "hexEscapeSequence": parse_hexEscapeSequence, "unicodeEscapeSequence": parse_unicodeEscapeSequence, "eolEscapeSequence": parse_eolEscapeSequence, "digit": parse_digit, "hexDigit": parse_hexDigit, "letter": parse_letter, "lowerCaseLetter": parse_lowerCaseLetter, "upperCaseLetter": parse_upperCaseLetter, "__": parse___, "comment": parse_comment, "singleLineComment": parse_singleLineComment, "multiLineComment": parse_multiLineComment, "eol": parse_eol, "eolChar": parse_eolChar, "whitespace": parse_whitespace }; if (startRule !== undefined) { if (parseFunctions[startRule] === undefined) { throw new Error("Invalid rule name: " + quote(startRule) + "."); } } else { startRule = "grammar"; } var pos = 0; var reportFailures = 0; var rightmostFailuresPos = 0; var rightmostFailuresExpected = []; 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); var escapeChar; var length; if (charCode <= 0xFF) { escapeChar = 'x'; length = 2; } else { escapeChar = 'u'; length = 4; } return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); } function matchFailed(failure) { if (pos < rightmostFailuresPos) { return; } if (pos > rightmostFailuresPos) { rightmostFailuresPos = pos; rightmostFailuresExpected = []; } rightmostFailuresExpected.push(failure); } function parse_grammar() { var result0, result1, result2, result3; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse___(); if (result0 !== null) { result1 = parse_initializer(); result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result3 = parse_rule(); if (result3 !== null) { result2 = []; while (result3 !== null) { result2.push(result3); result3 = parse_rule(); } } else { result2 = null; } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, initializer, rules) { return { type: "grammar", initializer: initializer !== "" ? initializer : null, rules: rules, startRule: rules[0].name }; })(pos0, result0[1], result0[2]); } if (result0 === null) { pos = pos0; } return result0; } function parse_initializer() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_action(); if (result0 !== null) { result1 = parse_semicolon(); result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, code) { return { type: "initializer", code: code }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } return result0; } function parse_rule() { var result0, result1, result2, result3, result4; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_identifier(); if (result0 !== null) { result1 = parse_string(); result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result2 = parse_equals(); if (result2 !== null) { result3 = parse_choice(); if (result3 !== null) { result4 = parse_semicolon(); result4 = result4 !== null ? result4 : ""; if (result4 !== null) { result0 = [result0, result1, result2, result3, result4]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, name, displayName, expression) { return { type: "rule", name: name, displayName: displayName !== "" ? displayName : null, expression: expression }; })(pos0, result0[0], result0[1], result0[3]); } if (result0 === null) { pos = pos0; } return result0; } function parse_choice() { var result0, result1, result2, result3; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; result0 = parse_sequence(); if (result0 !== null) { result1 = []; pos2 = pos; result2 = parse_slash(); if (result2 !== null) { result3 = parse_sequence(); if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos2; } } else { result2 = null; pos = pos2; } while (result2 !== null) { result1.push(result2); pos2 = pos; result2 = parse_slash(); if (result2 !== null) { result3 = parse_sequence(); if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos2; } } else { result2 = null; pos = pos2; } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, 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; } })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_sequence() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = []; result1 = parse_labeled(); while (result1 !== null) { result0.push(result1); result1 = parse_labeled(); } if (result0 !== null) { result1 = parse_action(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, elements, code) { var expression = elements.length !== 1 ? { type: "sequence", elements: elements } : elements[0]; return { type: "action", expression: expression, code: code }; })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; result0 = []; result1 = parse_labeled(); while (result1 !== null) { result0.push(result1); result1 = parse_labeled(); } if (result0 !== null) { result0 = (function(offset, elements) { return elements.length !== 1 ? { type: "sequence", elements: elements } : elements[0]; })(pos0, result0); } if (result0 === null) { pos = pos0; } } return result0; } function parse_labeled() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_identifier(); if (result0 !== null) { result1 = parse_colon(); if (result1 !== null) { result2 = parse_prefixed(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, label, expression) { return { type: "labeled", label: label, expression: expression }; })(pos0, result0[0], result0[2]); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_prefixed(); } return result0; } function parse_prefixed() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_and(); if (result0 !== null) { result1 = parse_action(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, code) { return { type: "semantic_and", code: code }; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_and(); if (result0 !== null) { result1 = parse_suffixed(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "simple_and", expression: expression }; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_not(); if (result0 !== null) { result1 = parse_action(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, code) { return { type: "semantic_not", code: code }; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_not(); if (result0 !== null) { result1 = parse_suffixed(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "simple_not", expression: expression }; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_suffixed(); } } } } return result0; } function parse_suffixed() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_primary(); if (result0 !== null) { result1 = parse_question(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "optional", expression: expression }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_primary(); if (result0 !== null) { result1 = parse_star(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "zero_or_more", expression: expression }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_primary(); if (result0 !== null) { result1 = parse_plus(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "one_or_more", expression: expression }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_primary(); } } } return result0; } function parse_primary() { var result0, result1, result2; var pos0, pos1, pos2, pos3; pos0 = pos; pos1 = pos; result0 = parse_identifier(); if (result0 !== null) { pos2 = pos; reportFailures++; pos3 = pos; result1 = parse_string(); result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result2 = parse_equals(); if (result2 !== null) { result1 = [result1, result2]; } else { result1 = null; pos = pos3; } } else { result1 = null; pos = pos3; } reportFailures--; if (result1 === null) { result1 = ""; } else { result1 = null; pos = pos2; } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, name) { return { type: "rule_ref", name: name }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_literal(); if (result0 === null) { pos0 = pos; result0 = parse_dot(); if (result0 !== null) { result0 = (function(offset) { return { type: "any" }; })(pos0); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_class(); if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_lparen(); if (result0 !== null) { result1 = parse_choice(); if (result1 !== null) { result2 = parse_rparen(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return expression; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } } } } } return result0; } function parse_action() { var result0, result1; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; result0 = parse_braced(); if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, braced) { return braced.substr(1, braced.length - 2); })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("action"); } return result0; } function parse_braced() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 123) { result0 = "{"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"{\""); } } if (result0 !== null) { result1 = []; result2 = parse_braced(); if (result2 === null) { result2 = parse_nonBraceCharacter(); } while (result2 !== null) { result1.push(result2); result2 = parse_braced(); if (result2 === null) { result2 = parse_nonBraceCharacter(); } } if (result1 !== null) { if (input.charCodeAt(pos) === 125) { result2 = "}"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"}\""); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, parts) { return "{" + parts.join("") + "}"; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_nonBraceCharacters() { var result0, result1; var pos0; pos0 = pos; result1 = parse_nonBraceCharacter(); if (result1 !== null) { result0 = []; while (result1 !== null) { result0.push(result1); result1 = parse_nonBraceCharacter(); } } else { result0 = null; } if (result0 !== null) { result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0); } if (result0 === null) { pos = pos0; } return result0; } function parse_nonBraceCharacter() { var result0; if (/^[^{}]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[^{}]"); } } return result0; } function parse_equals() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 61) { result0 = "="; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"=\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "="; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_colon() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 58) { result0 = ":"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\":\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return ":"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_semicolon() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 59) { result0 = ";"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\";\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return ";"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_slash() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 47) { result0 = "/"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"/\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "/"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_and() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 38) { result0 = "&"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"&\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "&"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_not() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 33) { result0 = "!"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"!\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "!"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_question() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 63) { result0 = "?"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"?\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "?"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_star() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 42) { result0 = "*"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"*\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "*"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_plus() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 43) { result0 = "+"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"+\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "+"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_lparen() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 40) { result0 = "("; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"(\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "("; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_rparen() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 41) { result0 = ")"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\")\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return ")"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_dot() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 46) { result0 = "."; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\".\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "."; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_identifier() { var result0, result1, result2; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; result0 = parse_letter(); if (result0 === null) { if (input.charCodeAt(pos) === 95) { result0 = "_"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"_\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 36) { result0 = "$"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"$\""); } } } } if (result0 !== null) { result1 = []; result2 = parse_letter(); if (result2 === null) { result2 = parse_digit(); if (result2 === null) { if (input.charCodeAt(pos) === 95) { result2 = "_"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"_\""); } } if (result2 === null) { if (input.charCodeAt(pos) === 36) { result2 = "$"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"$\""); } } } } } while (result2 !== null) { result1.push(result2); result2 = parse_letter(); if (result2 === null) { result2 = parse_digit(); if (result2 === null) { if (input.charCodeAt(pos) === 95) { result2 = "_"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"_\""); } } if (result2 === null) { if (input.charCodeAt(pos) === 36) { result2 = "$"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"$\""); } } } } } } if (result1 !== null) { result2 = parse___(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, head, tail) { return head + tail.join(""); })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("identifier"); } return result0; } function parse_literal() { var result0, result1, result2; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; result0 = parse_doubleQuotedString(); if (result0 === null) { result0 = parse_singleQuotedString(); } if (result0 !== null) { if (input.charCodeAt(pos) === 105) { result1 = "i"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"i\""); } } result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result2 = parse___(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, value, flags) { return { type: "literal", value: value, ignoreCase: flags === "i" }; })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("literal"); } return result0; } function parse_string() { var result0, result1; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; result0 = parse_doubleQuotedString(); if (result0 === null) { result0 = parse_singleQuotedString(); } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, string) { return string; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("string"); } return result0; } function parse_doubleQuotedString() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 34) { result0 = "\""; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\"\""); } } if (result0 !== null) { result1 = []; result2 = parse_doubleQuotedCharacter(); while (result2 !== null) { result1.push(result2); result2 = parse_doubleQuotedCharacter(); } if (result1 !== null) { if (input.charCodeAt(pos) === 34) { result2 = "\""; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"\\\"\""); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_doubleQuotedCharacter() { var result0; result0 = parse_simpleDoubleQuotedCharacter(); if (result0 === null) { result0 = parse_simpleEscapeSequence(); if (result0 === null) { result0 = parse_zeroEscapeSequence(); if (result0 === null) { result0 = parse_hexEscapeSequence(); if (result0 === null) { result0 = parse_unicodeEscapeSequence(); if (result0 === null) { result0 = parse_eolEscapeSequence(); } } } } } return result0; } function parse_simpleDoubleQuotedCharacter() { var result0, result1; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; pos2 = pos; reportFailures++; if (input.charCodeAt(pos) === 34) { result0 = "\""; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\"\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 === null) { result0 = parse_eolChar(); } } reportFailures--; if (result0 === null) { result0 = ""; } else { result0 = null; pos = pos2; } if (result0 !== null) { if (input.length > pos) { result1 = input.charAt(pos); pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, char_) { return char_; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_singleQuotedString() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 39) { result0 = "'"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"'\""); } } if (result0 !== null) { result1 = []; result2 = parse_singleQuotedCharacter(); while (result2 !== null) { result1.push(result2); result2 = parse_singleQuotedCharacter(); } if (result1 !== null) { if (input.charCodeAt(pos) === 39) { result2 = "'"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"'\""); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_singleQuotedCharacter() { var result0; result0 = parse_simpleSingleQuotedCharacter(); if (result0 === null) { result0 = parse_simpleEscapeSequence(); if (result0 === null) { result0 = parse_zeroEscapeSequence(); if (result0 === null) { result0 = parse_hexEscapeSequence(); if (result0 === null) { result0 = parse_unicodeEscapeSequence(); if (result0 === null) { result0 = parse_eolEscapeSequence(); } } } } } return result0; } function parse_simpleSingleQuotedCharacter() { var result0, result1; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; pos2 = pos; reportFailures++; if (input.charCodeAt(pos) === 39) { result0 = "'"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"'\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 === null) { result0 = parse_eolChar(); } } reportFailures--; if (result0 === null) { result0 = ""; } else { result0 = null; pos = pos2; } if (result0 !== null) { if (input.length > pos) { result1 = input.charAt(pos); pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, char_) { return char_; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_class() { var result0, result1, result2, result3, result4, result5; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 91) { result0 = "["; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"[\""); } } if (result0 !== null) { if (input.charCodeAt(pos) === 94) { result1 = "^"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"^\""); } } result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result2 = []; result3 = parse_classCharacterRange(); if (result3 === null) { result3 = parse_classCharacter(); } while (result3 !== null) { result2.push(result3); result3 = parse_classCharacterRange(); if (result3 === null) { result3 = parse_classCharacter(); } } if (result2 !== null) { if (input.charCodeAt(pos) === 93) { result3 = "]"; pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("\"]\""); } } if (result3 !== null) { if (input.charCodeAt(pos) === 105) { result4 = "i"; pos++; } else { result4 = null; if (reportFailures === 0) { matchFailed("\"i\""); } } result4 = result4 !== null ? result4 : ""; if (result4 !== null) { result5 = parse___(); if (result5 !== null) { result0 = [result0, result1, result2, result3, result4, result5]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, inverted, parts, flags) { var partsConverted = map(parts, function(part) { return part.data; }); var rawText = "[" + inverted + map(parts, function(part) { return part.rawText; }).join("") + "]" + flags; return { type: "class", inverted: inverted === "^", ignoreCase: flags === "i", parts: partsConverted, // FIXME: Get the raw text from the input directly. rawText: rawText }; })(pos0, result0[1], result0[2], result0[4]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("character class"); } return result0; } function parse_classCharacterRange() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_classCharacter(); if (result0 !== null) { if (input.charCodeAt(pos) === 45) { result1 = "-"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"-\""); } } if (result1 !== null) { result2 = parse_classCharacter(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, 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 }; })(pos0, result0[0], result0[2]); } if (result0 === null) { pos = pos0; } return result0; } function parse_classCharacter() { var result0; var pos0; pos0 = pos; result0 = parse_bracketDelimitedCharacter(); if (result0 !== null) { result0 = (function(offset, char_) { return { data: char_, // FIXME: Get the raw text from the input directly. rawText: quoteForRegexpClass(char_) }; })(pos0, result0); } if (result0 === null) { pos = pos0; } return result0; } function parse_bracketDelimitedCharacter() { var result0; result0 = parse_simpleBracketDelimitedCharacter(); if (result0 === null) { result0 = parse_simpleEscapeSequence(); if (result0 === null) { result0 = parse_zeroEscapeSequence(); if (result0 === null) { result0 = parse_hexEscapeSequence(); if (result0 === null) { result0 = parse_unicodeEscapeSequence(); if (result0 === null) { result0 = parse_eolEscapeSequence(); } } } } } return result0; } function parse_simpleBracketDelimitedCharacter() { var result0, result1; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; pos2 = pos; reportFailures++; if (input.charCodeAt(pos) === 93) { result0 = "]"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"]\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 === null) { result0 = parse_eolChar(); } } reportFailures--; if (result0 === null) { result0 = ""; } else { result0 = null; pos = pos2; } if (result0 !== null) { if (input.length > pos) { result1 = input.charAt(pos); pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, char_) { return char_; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_simpleEscapeSequence() { var result0, result1, result2; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 !== null) { pos2 = pos; reportFailures++; result1 = parse_digit(); if (result1 === null) { if (input.charCodeAt(pos) === 120) { result1 = "x"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"x\""); } } if (result1 === null) { if (input.charCodeAt(pos) === 117) { result1 = "u"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"u\""); } } if (result1 === null) { result1 = parse_eolChar(); } } } reportFailures--; if (result1 === null) { result1 = ""; } else { result1 = null; pos = pos2; } if (result1 !== null) { if (input.length > pos) { result2 = input.charAt(pos); pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, 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". })(pos0, result0[2]); } if (result0 === null) { pos = pos0; } return result0; } function parse_zeroEscapeSequence() { var result0, result1; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; if (input.substr(pos, 2) === "\\0") { result0 = "\\0"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\0\""); } } if (result0 !== null) { pos2 = pos; reportFailures++; result1 = parse_digit(); reportFailures--; if (result1 === null) { result1 = ""; } else { result1 = null; pos = pos2; } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "\x00"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_hexEscapeSequence() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.substr(pos, 2) === "\\x") { result0 = "\\x"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\x\""); } } if (result0 !== null) { result1 = parse_hexDigit(); if (result1 !== null) { result2 = parse_hexDigit(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, h1, h2) { return String.fromCharCode(parseInt(h1 + h2, 16)); })(pos0, result0[1], result0[2]); } if (result0 === null) { pos = pos0; } return result0; } function parse_unicodeEscapeSequence() { var result0, result1, result2, result3, result4; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.substr(pos, 2) === "\\u") { result0 = "\\u"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\u\""); } } if (result0 !== null) { result1 = parse_hexDigit(); if (result1 !== null) { result2 = parse_hexDigit(); if (result2 !== null) { result3 = parse_hexDigit(); if (result3 !== null) { result4 = parse_hexDigit(); if (result4 !== null) { result0 = [result0, result1, result2, result3, result4]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, h1, h2, h3, h4) { return String.fromCharCode(parseInt(h1 + h2 + h3 + h4, 16)); })(pos0, result0[1], result0[2], result0[3], result0[4]); } if (result0 === null) { pos = pos0; } return result0; } function parse_eolEscapeSequence() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 !== null) { result1 = parse_eol(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, eol) { return eol; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_digit() { var result0; if (/^[0-9]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[0-9]"); } } return result0; } function parse_hexDigit() { var result0; if (/^[0-9a-fA-F]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[0-9a-fA-F]"); } } return result0; } function parse_letter() { var result0; result0 = parse_lowerCaseLetter(); if (result0 === null) { result0 = parse_upperCaseLetter(); } return result0; } function parse_lowerCaseLetter() { var result0; if (/^[a-z]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[a-z]"); } } return result0; } function parse_upperCaseLetter() { var result0; if (/^[A-Z]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[A-Z]"); } } return result0; } function parse___() { var result0, result1; result0 = []; result1 = parse_whitespace(); if (result1 === null) { result1 = parse_eol(); if (result1 === null) { result1 = parse_comment(); } } while (result1 !== null) { result0.push(result1); result1 = parse_whitespace(); if (result1 === null) { result1 = parse_eol(); if (result1 === null) { result1 = parse_comment(); } } } return result0; } function parse_comment() { var result0; reportFailures++; result0 = parse_singleLineComment(); if (result0 === null) { result0 = parse_multiLineComment(); } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("comment"); } return result0; } function parse_singleLineComment() { var result0, result1, result2, result3; var pos0, pos1, pos2; pos0 = pos; if (input.substr(pos, 2) === "//") { result0 = "//"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"//\""); } } if (result0 !== null) { result1 = []; pos1 = pos; pos2 = pos; reportFailures++; result2 = parse_eolChar(); reportFailures--; if (result2 === null) { result2 = ""; } else { result2 = null; pos = pos2; } if (result2 !== null) { if (input.length > pos) { result3 = input.charAt(pos); pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos1; } } else { result2 = null; pos = pos1; } while (result2 !== null) { result1.push(result2); pos1 = pos; pos2 = pos; reportFailures++; result2 = parse_eolChar(); reportFailures--; if (result2 === null) { result2 = ""; } else { result2 = null; pos = pos2; } if (result2 !== null) { if (input.length > pos) { result3 = input.charAt(pos); pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos1; } } else { result2 = null; pos = pos1; } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos0; } } else { result0 = null; pos = pos0; } return result0; } function parse_multiLineComment() { var result0, result1, result2, result3; var pos0, pos1, pos2; pos0 = pos; if (input.substr(pos, 2) === "/*") { result0 = "/*"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"/*\""); } } if (result0 !== null) { result1 = []; pos1 = pos; pos2 = pos; reportFailures++; if (input.substr(pos, 2) === "*/") { result2 = "*/"; pos += 2; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"*/\""); } } reportFailures--; if (result2 === null) { result2 = ""; } else { result2 = null; pos = pos2; } if (result2 !== null) { if (input.length > pos) { result3 = input.charAt(pos); pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos1; } } else { result2 = null; pos = pos1; } while (result2 !== null) { result1.push(result2); pos1 = pos; pos2 = pos; reportFailures++; if (input.substr(pos, 2) === "*/") { result2 = "*/"; pos += 2; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"*/\""); } } reportFailures--; if (result2 === null) { result2 = ""; } else { result2 = null; pos = pos2; } if (result2 !== null) { if (input.length > pos) { result3 = input.charAt(pos); pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos1; } } else { result2 = null; pos = pos1; } } if (result1 !== null) { if (input.substr(pos, 2) === "*/") { result2 = "*/"; pos += 2; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"*/\""); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos0; } } else { result0 = null; pos = pos0; } } else { result0 = null; pos = pos0; } return result0; } function parse_eol() { var result0; reportFailures++; if (input.charCodeAt(pos) === 10) { result0 = "\n"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\n\""); } } if (result0 === null) { if (input.substr(pos, 2) === "\r\n") { result0 = "\r\n"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\r\\n\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 13) { result0 = "\r"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\r\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 8232) { result0 = "\u2028"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\u2028\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 8233) { result0 = "\u2029"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\u2029\""); } } } } } } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("end of line"); } return result0; } function parse_eolChar() { var result0; if (/^[\n\r\u2028\u2029]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[\\n\\r\\u2028\\u2029]"); } } return result0; } function parse_whitespace() { var result0; reportFailures++; if (/^[ \t\x0B\f\xA0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[ \\t\\x0B\\f\\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]"); } } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("whitespace"); } return result0; } function cleanupExpected(expected) { expected.sort(); var lastExpected = null; var cleanExpected = []; for (var i = 0; i < expected.length; i++) { if (expected[i] !== lastExpected) { cleanExpected.push(expected[i]); lastExpected = expected[i]; } } return cleanExpected; } 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 < Math.max(pos, rightmostFailuresPos); 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| * - |rightmostFailuresExpected| may or may not contain something * * 2. The parser successfully parsed only a part of the input. * * - |result !== null| * - |pos < input.length| * - |rightmostFailuresExpected| may or may not contain something * * 3. The parser did not successfully parse any part of the input. * * - |result === null| * - |pos === 0| * - |rightmostFailuresExpected| contains at least one failure * * All code following this comment (including called functions) must * handle these states. */ if (result === null || pos !== input.length) { var offset = Math.max(pos, rightmostFailuresPos); var found = offset < input.length ? input.charAt(offset) : null; var errorPosition = computeErrorPosition(); throw new this.SyntaxError( cleanupExpected(rightmostFailuresExpected), found, offset, 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(expected, found, offset, line, column) { function buildMessage(expected, found) { var expectedHumanized, foundHumanized; switch (expected.length) { case 0: expectedHumanized = "end of input"; break; case 1: expectedHumanized = expected[0]; break; default: expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + " or " + expected[expected.length - 1]; } foundHumanized = found ? quote(found) : "end of input"; return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; } this.name = "SyntaxError"; this.expected = expected; this.found = found; this.message = buildMessage(expected, found); this.offset = offset; this.line = line; this.column = column; }; result.SyntaxError.prototype = Error.prototype; return result; })(); pegjs-0.7.0/src/utils.js0000644000175000017500000001141412206663530014371 0ustar danieldaniel/* Like Python's |range|, but without |step|. */ function range(start, stop) { if (stop === undefined) { stop = start; start = 0; } var result = new Array(Math.max(0, stop - start)); for (var i = 0, j = start; j < stop; i++, j++) { result[i] = j; } return result; } function find(array, callback) { var length = array.length; for (var i = 0; i < length; i++) { if (callback(array[i])) { return array[i]; } } } 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], i); } } function map(array, callback) { var result = []; var length = array.length; for (var i = 0; i < length; i++) { result[i] = callback(array[i], i); } return result; } function pluck(array, key) { return map(array, function (e) { return e[key]; }); } function keys(object) { var result = []; for (var key in object) { result.push(key); } return result; } function values(object) { var result = []; for (var key in object) { result.push(object[key]); } return result; } /* * Returns a string padded on the left to a desired length with a character. * * The code needs to be in sync with the 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 the code template in the compilation * function for "action" nodes. */ function escape(ch) { var charCode = ch.charCodeAt(0); var escapeChar; var length; if (charCode <= 0xFF) { escapeChar = 'x'; length = 2; } else { escapeChar = 'u'; 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 the 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 control and non-ASCII * characters. Note that "\0" and "\v" escape sequences are not used because * JSHint does not like the first and IE the second. */ return '"' + s .replace(/\\/g, '\\\\') // backslash .replace(/"/g, '\\"') // closing quote character .replace(/\x08/g, '\\b') // backspace .replace(/\t/g, '\\t') // horizontal tab .replace(/\n/g, '\\n') // line feed .replace(/\f/g, '\\f') // form feed .replace(/\r/g, '\\r') // carriage return .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"'; } /* * 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 control and non-ASCII * characters. */ return s .replace(/\\/g, '\\\\') // backslash .replace(/\//g, '\\/') // closing slash .replace(/\]/g, '\\]') // closing bracket .replace(/-/g, '\\-') // dash .replace(/\0/g, '\\0') // null .replace(/\t/g, '\\t') // horizontal tab .replace(/\n/g, '\\n') // line feed .replace(/\v/g, '\\x0B') // vertical tab .replace(/\f/g, '\\f') // form feed .replace(/\r/g, '\\r') // carriage return .replace(/[\x01-\x08\x0E-\x1F\x80-\uFFFF]/g, escape); } /* * 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); }; } function findRuleByName(ast, name) { return find(ast.rules, function(r) { return r.name === name; }); } pegjs-0.7.0/src/compiler.js0000644000175000017500000000156212206663530015046 0ustar danieldanielPEG.compiler = { /* * Names of passes that will get run during the compilation (in the specified * order). */ appliedPassNames: [ "reportMissingRules", "reportLeftRecursion", "removeProxyRules", "computeVarNames", "computeParams" ], /* * 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, options) { var that = this; each(this.appliedPassNames, function(passName) { that.passes[passName](ast); }); var source = this.emitter(ast, options); var result = eval(source); result._source = source; return result; } }; // @include "passes.js" // @include "emitter.js" pegjs-0.7.0/bin/0000755000175000017500000000000012206663530012653 5ustar danieldanielpegjs-0.7.0/bin/pegjs0000755000175000017500000000737112206663530013721 0ustar danieldaniel#!/usr/bin/env node var util = require("util"); var fs = require("fs"); var PEG = require("../lib/peg"); /* Helpers */ function printVersion() { util.puts("PEG.js " + PEG.VERSION); } function printHelp() { util.puts("Usage: pegjs [options] [--] [] []"); util.puts(""); util.puts("Generates a parser from the PEG grammar specified in the and"); util.puts("writes it to the ."); util.puts(""); util.puts("If the is omitted, its name is generated by changing the"); util.puts(" extension to \".js\". If both and are"); util.puts("omitted, standard input and output are used."); util.puts(""); util.puts("Options:"); util.puts(" -e, --export-var name of the variable where the parser object"); util.puts(" will be stored (default: \"module.exports\")"); util.puts(" --cache make generated parser cache results"); util.puts(" --track-line-and-column make generated parser track line and column"); util.puts(" -v, --version print version information and exit"); util.puts(" -h, --help print help and exit"); } function exitSuccess() { process.exit(0); } function exitFailure() { process.exit(1); } function abort(message) { util.error(message); exitFailure(); } /* Arguments */ var args = process.argv.slice(2); // Trim "node" and the script path. function isOption(arg) { return /^-/.test(arg); } function nextArg() { args.shift(); } /* Files */ function readStream(inputStream, callback) { var input = ""; inputStream.on("data", function(data) { input += data; }); inputStream.on("end", function() { callback(input); }); } /* Main */ /* This makes the generated parser a CommonJS module by default. */ var exportVar = "module.exports"; var options = { cache: false, trackLineAndColumn: false }; while (args.length > 0 && isOption(args[0])) { switch (args[0]) { case "-e": case "--export-var": nextArg(); if (args.length === 0) { abort("Missing parameter of the -e/--export-var option."); } exportVar = args[0]; break; case "--cache": options.cache = true; break; case "--track-line-and-column": options.trackLineAndColumn = true; break; case "-v": case "--version": printVersion(); exitSuccess(); break; case "-h": case "--help": printHelp(); exitSuccess(); break; case "--": nextArg(); break; default: abort("Unknown option: " + args[0] + "."); } nextArg(); } switch (args.length) { case 0: process.stdin.resume(); var inputStream = process.stdin; var outputStream = process.stdout; break; case 1: case 2: var inputFile = args[0]; var inputStream = fs.createReadStream(inputFile); inputStream.on("error", function() { abort("Can't read from file \"" + inputFile + "\"."); }); var outputFile = args.length == 1 ? args[0].replace(/\.[^.]*$/, ".js") : args[1]; var outputStream = fs.createWriteStream(outputFile); outputStream.on("error", function() { abort("Can't write to file \"" + outputFile + "\"."); }); break; default: abort("Too many arguments."); } readStream(inputStream, function(input) { try { var parser = PEG.buildParser(input, options); } catch (e) { if (e.line !== undefined && e.column !== undefined) { abort(e.line + ":" + e.column + ": " + e.message); } else { abort(e.message); } } outputStream.write(exportVar + " = " + parser.toSource() + ";\n"); if (outputStream !== process.stdout) { outputStream.end(); } }); pegjs-0.7.0/Makefile0000644000175000017500000001327412206663530013552 0ustar danieldaniel# ===== Directories ===== SRC_DIR = src BIN_DIR = bin TEST_DIR = test BENCHMARK_DIR = benchmark EXAMPLES_DIR = examples LIB_DIR = lib DIST_DIR = dist DIST_WEB_DIR = $(DIST_DIR)/web DIST_NODE_DIR = $(DIST_DIR)/node # ===== Files ===== PARSER_SRC_FILE = $(SRC_DIR)/parser.pegjs PARSER_OUT_FILE = $(SRC_DIR)/parser.js PEGJS_SRC_FILE = $(SRC_DIR)/peg.js PEGJS_LIB_FILE = $(LIB_DIR)/peg.js PACKAGE_JSON_SRC_FILE = package.json PACKAGE_JSON_DIST_FILE = $(DIST_NODE_DIR)/package.json PEGJS_DIST_FILE_DEV = $(DIST_WEB_DIR)/peg-$(PEGJS_VERSION).js PEGJS_DIST_FILE_MIN = $(DIST_WEB_DIR)/peg-$(PEGJS_VERSION).min.js CHANGELOG_FILE = CHANGELOG LICENSE_FILE = LICENSE README_FILE = README.md VERSION_FILE = VERSION # ===== Executables ===== JSHINT ?= jshint UGLIFYJS ?= uglifyjs PEGJS = $(BIN_DIR)/pegjs TEST_RUN = $(TEST_DIR)/run BENCHMARK_RUN = $(BENCHMARK_DIR)/run # ===== Variables ===== PEGJS_VERSION = `cat $(VERSION_FILE)` DIST_NAME = pegjs DIST_VERSION = $(PEGJS_VERSION) DIST_BASE = $(DIST_NAME)-$(DIST_VERSION) # ===== Preprocessor ===== # A simple preprocessor that recognizes two directives: # # @VERSION -- insert PEG.js version # @include "" -- include here # # This could have been implemented many ways. I chose Perl because everyone will # have it. PREPROCESS=perl -e ' \ use strict; \ use warnings; \ \ use File::Basename; \ \ open(my $$f, "$(VERSION_FILE)") or die "Can\x27t open $(VERSION_FILE): $$!"; \ my $$PEGJS_VERSION = <$$f>; \ close($$f); \ chomp($$PEGJS_VERSION); \ \ sub preprocess { \ my $$file = shift; \ my $$output = ""; \ \ open(my $$f, $$file) or die "Can\x27t open $$file: $$!"; \ while(<$$f>) { \ s/\@VERSION/$$PEGJS_VERSION/g; \ \ if (/^\s*\/\/\s*\@include\s*"([^"]*)"\s*$$/) { \ $$output .= preprocess(dirname($$file) . "/" . $$1); \ next; \ } \ \ $$output .= $$_; \ } \ close($$f); \ \ return $$output; \ } \ \ print preprocess($$ARGV[0]); \ ' # ===== Targets ===== # Generate the grammar parser parser: $(PEGJS) --export-var PEG.parser $(PARSER_SRC_FILE) $(PARSER_OUT_FILE) # Build the PEG.js library build: mkdir -p $(LIB_DIR) $(PREPROCESS) $(PEGJS_SRC_FILE) > $(PEGJS_LIB_FILE) # Remove built PEG.js library (created by "build") clean: rm -rf $(LIB_DIR) # Prepare dstribution files dist: build # Web mkdir -p $(DIST_WEB_DIR) cp $(PEGJS_LIB_FILE) $(PEGJS_DIST_FILE_DEV) $(UGLIFYJS) --ascii -o $(PEGJS_DIST_FILE_MIN) $(PEGJS_LIB_FILE) # Node.js mkdir -p $(DIST_NODE_DIR) cp -r \ $(LIB_DIR) \ $(BIN_DIR) \ $(EXAMPLES_DIR) \ $(CHANGELOG_FILE) \ $(LICENSE_FILE) \ $(README_FILE) \ $(VERSION_FILE) \ $(DIST_NODE_DIR) $(PREPROCESS) $(PACKAGE_JSON_SRC_FILE) > $(PACKAGE_JSON_DIST_FILE) # Remove distribution file (created by "dist") distclean: rm -rf $(DIST_DIR) # Run the test suite test: build $(TEST_RUN) # Run the benchmark suite benchmark: build $(BENCHMARK_RUN) # Run JSHint on the source hint: build $(JSHINT) \ $(SRC_DIR)/*.js \ $(TEST_DIR)/*.js \ $(TEST_RUN) \ $(BENCHMARK_DIR)/*.js \ $(BENCHMARK_RUN) \ $(PEGJS) # Make a distribution tarball for packaging # Note: we don't currently include the benchmark tree in the dist tarball # because it contains non-human-readable jQuery artifacts and this can # be an impediment to distribution in free software archives such as # Debian and Fedora. # Run the benchmark from git if required. srcdist: -rm -rf $(DIST_BASE) mkdir $(DIST_BASE) cp -r bin CHANGELOG examples lib LICENSE Makefile package.json README.md src test tools VERSION $(DIST_BASE) tar czf $(DIST_BASE).tar.gz $(DIST_BASE) .PHONY: test benchmark hint parser build clean dist distclean .SILENT: test benchmark hint parser build clean dist distclean pegjs-0.7.0/lib/0000755000175000017500000000000012206663530012651 5ustar danieldanielpegjs-0.7.0/lib/peg.js0000644000175000017500000040756612206663530014004 0ustar danieldaniel/* * PEG.js 0.7.0 * * http://pegjs.majda.cz/ * * Copyright (c) 2010-2012 David Majda * Licensend under the MIT license. */ var PEG = (function(undefined) { var PEG = { /* PEG.js version (uses semantic versioning). */ VERSION: "0.7.0", /* * 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, options) { return PEG.compiler.compile(PEG.parser.parse(grammar), options); } }; /* Thrown when the grammar contains an error. */ PEG.GrammarError = function(message) { this.name = "PEG.GrammarError"; this.message = message; }; PEG.GrammarError.prototype = Error.prototype; /* Like Python's |range|, but without |step|. */ function range(start, stop) { if (stop === undefined) { stop = start; start = 0; } var result = new Array(Math.max(0, stop - start)); for (var i = 0, j = start; j < stop; i++, j++) { result[i] = j; } return result; } function find(array, callback) { var length = array.length; for (var i = 0; i < length; i++) { if (callback(array[i])) { return array[i]; } } } 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], i); } } function map(array, callback) { var result = []; var length = array.length; for (var i = 0; i < length; i++) { result[i] = callback(array[i], i); } return result; } function pluck(array, key) { return map(array, function (e) { return e[key]; }); } function keys(object) { var result = []; for (var key in object) { result.push(key); } return result; } function values(object) { var result = []; for (var key in object) { result.push(object[key]); } return result; } /* * Returns a string padded on the left to a desired length with a character. * * The code needs to be in sync with the 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 the code template in the compilation * function for "action" nodes. */ function escape(ch) { var charCode = ch.charCodeAt(0); var escapeChar; var length; if (charCode <= 0xFF) { escapeChar = 'x'; length = 2; } else { escapeChar = 'u'; 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 the 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 control and non-ASCII * characters. Note that "\0" and "\v" escape sequences are not used because * JSHint does not like the first and IE the second. */ return '"' + s .replace(/\\/g, '\\\\') // backslash .replace(/"/g, '\\"') // closing quote character .replace(/\x08/g, '\\b') // backspace .replace(/\t/g, '\\t') // horizontal tab .replace(/\n/g, '\\n') // line feed .replace(/\f/g, '\\f') // form feed .replace(/\r/g, '\\r') // carriage return .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"'; } /* * 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 control and non-ASCII * characters. */ return s .replace(/\\/g, '\\\\') // backslash .replace(/\//g, '\\/') // closing slash .replace(/\]/g, '\\]') // closing bracket .replace(/-/g, '\\-') // dash .replace(/\0/g, '\\0') // null .replace(/\t/g, '\\t') // horizontal tab .replace(/\n/g, '\\n') // line feed .replace(/\v/g, '\\x0B') // vertical tab .replace(/\f/g, '\\f') // form feed .replace(/\r/g, '\\r') // carriage return .replace(/[\x01-\x08\x0E-\x1F\x80-\uFFFF]/g, escape); } /* * 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); }; } function findRuleByName(ast, name) { return find(ast.rules, function(r) { return r.name === name; }); } PEG.parser = (function(){ /* * Generated by PEG.js 0.7.0. * * http://pegjs.majda.cz/ */ 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 control and non-ASCII * characters. Note that "\0" and "\v" escape sequences are not used * because JSHint does not like the first and IE the second. */ return '"' + s .replace(/\\/g, '\\\\') // backslash .replace(/"/g, '\\"') // closing quote character .replace(/\x08/g, '\\b') // backspace .replace(/\t/g, '\\t') // horizontal tab .replace(/\n/g, '\\n') // line feed .replace(/\f/g, '\\f') // form feed .replace(/\r/g, '\\r') // carriage return .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"'; } 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 = { "grammar": parse_grammar, "initializer": parse_initializer, "rule": parse_rule, "choice": parse_choice, "sequence": parse_sequence, "labeled": parse_labeled, "prefixed": parse_prefixed, "suffixed": parse_suffixed, "primary": parse_primary, "action": parse_action, "braced": parse_braced, "nonBraceCharacters": parse_nonBraceCharacters, "nonBraceCharacter": parse_nonBraceCharacter, "equals": parse_equals, "colon": parse_colon, "semicolon": parse_semicolon, "slash": parse_slash, "and": parse_and, "not": parse_not, "question": parse_question, "star": parse_star, "plus": parse_plus, "lparen": parse_lparen, "rparen": parse_rparen, "dot": parse_dot, "identifier": parse_identifier, "literal": parse_literal, "string": parse_string, "doubleQuotedString": parse_doubleQuotedString, "doubleQuotedCharacter": parse_doubleQuotedCharacter, "simpleDoubleQuotedCharacter": parse_simpleDoubleQuotedCharacter, "singleQuotedString": parse_singleQuotedString, "singleQuotedCharacter": parse_singleQuotedCharacter, "simpleSingleQuotedCharacter": parse_simpleSingleQuotedCharacter, "class": parse_class, "classCharacterRange": parse_classCharacterRange, "classCharacter": parse_classCharacter, "bracketDelimitedCharacter": parse_bracketDelimitedCharacter, "simpleBracketDelimitedCharacter": parse_simpleBracketDelimitedCharacter, "simpleEscapeSequence": parse_simpleEscapeSequence, "zeroEscapeSequence": parse_zeroEscapeSequence, "hexEscapeSequence": parse_hexEscapeSequence, "unicodeEscapeSequence": parse_unicodeEscapeSequence, "eolEscapeSequence": parse_eolEscapeSequence, "digit": parse_digit, "hexDigit": parse_hexDigit, "letter": parse_letter, "lowerCaseLetter": parse_lowerCaseLetter, "upperCaseLetter": parse_upperCaseLetter, "__": parse___, "comment": parse_comment, "singleLineComment": parse_singleLineComment, "multiLineComment": parse_multiLineComment, "eol": parse_eol, "eolChar": parse_eolChar, "whitespace": parse_whitespace }; if (startRule !== undefined) { if (parseFunctions[startRule] === undefined) { throw new Error("Invalid rule name: " + quote(startRule) + "."); } } else { startRule = "grammar"; } var pos = 0; var reportFailures = 0; var rightmostFailuresPos = 0; var rightmostFailuresExpected = []; 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); var escapeChar; var length; if (charCode <= 0xFF) { escapeChar = 'x'; length = 2; } else { escapeChar = 'u'; length = 4; } return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); } function matchFailed(failure) { if (pos < rightmostFailuresPos) { return; } if (pos > rightmostFailuresPos) { rightmostFailuresPos = pos; rightmostFailuresExpected = []; } rightmostFailuresExpected.push(failure); } function parse_grammar() { var result0, result1, result2, result3; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse___(); if (result0 !== null) { result1 = parse_initializer(); result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result3 = parse_rule(); if (result3 !== null) { result2 = []; while (result3 !== null) { result2.push(result3); result3 = parse_rule(); } } else { result2 = null; } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, initializer, rules) { return { type: "grammar", initializer: initializer !== "" ? initializer : null, rules: rules, startRule: rules[0].name }; })(pos0, result0[1], result0[2]); } if (result0 === null) { pos = pos0; } return result0; } function parse_initializer() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_action(); if (result0 !== null) { result1 = parse_semicolon(); result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, code) { return { type: "initializer", code: code }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } return result0; } function parse_rule() { var result0, result1, result2, result3, result4; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_identifier(); if (result0 !== null) { result1 = parse_string(); result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result2 = parse_equals(); if (result2 !== null) { result3 = parse_choice(); if (result3 !== null) { result4 = parse_semicolon(); result4 = result4 !== null ? result4 : ""; if (result4 !== null) { result0 = [result0, result1, result2, result3, result4]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, name, displayName, expression) { return { type: "rule", name: name, displayName: displayName !== "" ? displayName : null, expression: expression }; })(pos0, result0[0], result0[1], result0[3]); } if (result0 === null) { pos = pos0; } return result0; } function parse_choice() { var result0, result1, result2, result3; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; result0 = parse_sequence(); if (result0 !== null) { result1 = []; pos2 = pos; result2 = parse_slash(); if (result2 !== null) { result3 = parse_sequence(); if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos2; } } else { result2 = null; pos = pos2; } while (result2 !== null) { result1.push(result2); pos2 = pos; result2 = parse_slash(); if (result2 !== null) { result3 = parse_sequence(); if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos2; } } else { result2 = null; pos = pos2; } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, 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; } })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_sequence() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = []; result1 = parse_labeled(); while (result1 !== null) { result0.push(result1); result1 = parse_labeled(); } if (result0 !== null) { result1 = parse_action(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, elements, code) { var expression = elements.length !== 1 ? { type: "sequence", elements: elements } : elements[0]; return { type: "action", expression: expression, code: code }; })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; result0 = []; result1 = parse_labeled(); while (result1 !== null) { result0.push(result1); result1 = parse_labeled(); } if (result0 !== null) { result0 = (function(offset, elements) { return elements.length !== 1 ? { type: "sequence", elements: elements } : elements[0]; })(pos0, result0); } if (result0 === null) { pos = pos0; } } return result0; } function parse_labeled() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_identifier(); if (result0 !== null) { result1 = parse_colon(); if (result1 !== null) { result2 = parse_prefixed(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, label, expression) { return { type: "labeled", label: label, expression: expression }; })(pos0, result0[0], result0[2]); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_prefixed(); } return result0; } function parse_prefixed() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_and(); if (result0 !== null) { result1 = parse_action(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, code) { return { type: "semantic_and", code: code }; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_and(); if (result0 !== null) { result1 = parse_suffixed(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "simple_and", expression: expression }; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_not(); if (result0 !== null) { result1 = parse_action(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, code) { return { type: "semantic_not", code: code }; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_not(); if (result0 !== null) { result1 = parse_suffixed(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "simple_not", expression: expression }; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_suffixed(); } } } } return result0; } function parse_suffixed() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_primary(); if (result0 !== null) { result1 = parse_question(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "optional", expression: expression }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_primary(); if (result0 !== null) { result1 = parse_star(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "zero_or_more", expression: expression }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_primary(); if (result0 !== null) { result1 = parse_plus(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return { type: "one_or_more", expression: expression }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_primary(); } } } return result0; } function parse_primary() { var result0, result1, result2; var pos0, pos1, pos2, pos3; pos0 = pos; pos1 = pos; result0 = parse_identifier(); if (result0 !== null) { pos2 = pos; reportFailures++; pos3 = pos; result1 = parse_string(); result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result2 = parse_equals(); if (result2 !== null) { result1 = [result1, result2]; } else { result1 = null; pos = pos3; } } else { result1 = null; pos = pos3; } reportFailures--; if (result1 === null) { result1 = ""; } else { result1 = null; pos = pos2; } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, name) { return { type: "rule_ref", name: name }; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_literal(); if (result0 === null) { pos0 = pos; result0 = parse_dot(); if (result0 !== null) { result0 = (function(offset) { return { type: "any" }; })(pos0); } if (result0 === null) { pos = pos0; } if (result0 === null) { result0 = parse_class(); if (result0 === null) { pos0 = pos; pos1 = pos; result0 = parse_lparen(); if (result0 !== null) { result1 = parse_choice(); if (result1 !== null) { result2 = parse_rparen(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, expression) { return expression; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } } } } } return result0; } function parse_action() { var result0, result1; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; result0 = parse_braced(); if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, braced) { return braced.substr(1, braced.length - 2); })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("action"); } return result0; } function parse_braced() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 123) { result0 = "{"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"{\""); } } if (result0 !== null) { result1 = []; result2 = parse_braced(); if (result2 === null) { result2 = parse_nonBraceCharacter(); } while (result2 !== null) { result1.push(result2); result2 = parse_braced(); if (result2 === null) { result2 = parse_nonBraceCharacter(); } } if (result1 !== null) { if (input.charCodeAt(pos) === 125) { result2 = "}"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"}\""); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, parts) { return "{" + parts.join("") + "}"; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_nonBraceCharacters() { var result0, result1; var pos0; pos0 = pos; result1 = parse_nonBraceCharacter(); if (result1 !== null) { result0 = []; while (result1 !== null) { result0.push(result1); result1 = parse_nonBraceCharacter(); } } else { result0 = null; } if (result0 !== null) { result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0); } if (result0 === null) { pos = pos0; } return result0; } function parse_nonBraceCharacter() { var result0; if (/^[^{}]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[^{}]"); } } return result0; } function parse_equals() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 61) { result0 = "="; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"=\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "="; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_colon() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 58) { result0 = ":"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\":\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return ":"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_semicolon() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 59) { result0 = ";"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\";\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return ";"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_slash() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 47) { result0 = "/"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"/\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "/"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_and() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 38) { result0 = "&"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"&\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "&"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_not() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 33) { result0 = "!"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"!\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "!"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_question() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 63) { result0 = "?"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"?\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "?"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_star() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 42) { result0 = "*"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"*\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "*"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_plus() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 43) { result0 = "+"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"+\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "+"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_lparen() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 40) { result0 = "("; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"(\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "("; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_rparen() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 41) { result0 = ")"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\")\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return ")"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_dot() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 46) { result0 = "."; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\".\""); } } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "."; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_identifier() { var result0, result1, result2; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; result0 = parse_letter(); if (result0 === null) { if (input.charCodeAt(pos) === 95) { result0 = "_"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"_\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 36) { result0 = "$"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"$\""); } } } } if (result0 !== null) { result1 = []; result2 = parse_letter(); if (result2 === null) { result2 = parse_digit(); if (result2 === null) { if (input.charCodeAt(pos) === 95) { result2 = "_"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"_\""); } } if (result2 === null) { if (input.charCodeAt(pos) === 36) { result2 = "$"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"$\""); } } } } } while (result2 !== null) { result1.push(result2); result2 = parse_letter(); if (result2 === null) { result2 = parse_digit(); if (result2 === null) { if (input.charCodeAt(pos) === 95) { result2 = "_"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"_\""); } } if (result2 === null) { if (input.charCodeAt(pos) === 36) { result2 = "$"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"$\""); } } } } } } if (result1 !== null) { result2 = parse___(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, head, tail) { return head + tail.join(""); })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("identifier"); } return result0; } function parse_literal() { var result0, result1, result2; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; result0 = parse_doubleQuotedString(); if (result0 === null) { result0 = parse_singleQuotedString(); } if (result0 !== null) { if (input.charCodeAt(pos) === 105) { result1 = "i"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"i\""); } } result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result2 = parse___(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, value, flags) { return { type: "literal", value: value, ignoreCase: flags === "i" }; })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("literal"); } return result0; } function parse_string() { var result0, result1; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; result0 = parse_doubleQuotedString(); if (result0 === null) { result0 = parse_singleQuotedString(); } if (result0 !== null) { result1 = parse___(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, string) { return string; })(pos0, result0[0]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("string"); } return result0; } function parse_doubleQuotedString() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 34) { result0 = "\""; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\"\""); } } if (result0 !== null) { result1 = []; result2 = parse_doubleQuotedCharacter(); while (result2 !== null) { result1.push(result2); result2 = parse_doubleQuotedCharacter(); } if (result1 !== null) { if (input.charCodeAt(pos) === 34) { result2 = "\""; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"\\\"\""); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_doubleQuotedCharacter() { var result0; result0 = parse_simpleDoubleQuotedCharacter(); if (result0 === null) { result0 = parse_simpleEscapeSequence(); if (result0 === null) { result0 = parse_zeroEscapeSequence(); if (result0 === null) { result0 = parse_hexEscapeSequence(); if (result0 === null) { result0 = parse_unicodeEscapeSequence(); if (result0 === null) { result0 = parse_eolEscapeSequence(); } } } } } return result0; } function parse_simpleDoubleQuotedCharacter() { var result0, result1; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; pos2 = pos; reportFailures++; if (input.charCodeAt(pos) === 34) { result0 = "\""; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\"\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 === null) { result0 = parse_eolChar(); } } reportFailures--; if (result0 === null) { result0 = ""; } else { result0 = null; pos = pos2; } if (result0 !== null) { if (input.length > pos) { result1 = input.charAt(pos); pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, char_) { return char_; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_singleQuotedString() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 39) { result0 = "'"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"'\""); } } if (result0 !== null) { result1 = []; result2 = parse_singleQuotedCharacter(); while (result2 !== null) { result1.push(result2); result2 = parse_singleQuotedCharacter(); } if (result1 !== null) { if (input.charCodeAt(pos) === 39) { result2 = "'"; pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"'\""); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_singleQuotedCharacter() { var result0; result0 = parse_simpleSingleQuotedCharacter(); if (result0 === null) { result0 = parse_simpleEscapeSequence(); if (result0 === null) { result0 = parse_zeroEscapeSequence(); if (result0 === null) { result0 = parse_hexEscapeSequence(); if (result0 === null) { result0 = parse_unicodeEscapeSequence(); if (result0 === null) { result0 = parse_eolEscapeSequence(); } } } } } return result0; } function parse_simpleSingleQuotedCharacter() { var result0, result1; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; pos2 = pos; reportFailures++; if (input.charCodeAt(pos) === 39) { result0 = "'"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"'\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 === null) { result0 = parse_eolChar(); } } reportFailures--; if (result0 === null) { result0 = ""; } else { result0 = null; pos = pos2; } if (result0 !== null) { if (input.length > pos) { result1 = input.charAt(pos); pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, char_) { return char_; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_class() { var result0, result1, result2, result3, result4, result5; var pos0, pos1; reportFailures++; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 91) { result0 = "["; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"[\""); } } if (result0 !== null) { if (input.charCodeAt(pos) === 94) { result1 = "^"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"^\""); } } result1 = result1 !== null ? result1 : ""; if (result1 !== null) { result2 = []; result3 = parse_classCharacterRange(); if (result3 === null) { result3 = parse_classCharacter(); } while (result3 !== null) { result2.push(result3); result3 = parse_classCharacterRange(); if (result3 === null) { result3 = parse_classCharacter(); } } if (result2 !== null) { if (input.charCodeAt(pos) === 93) { result3 = "]"; pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("\"]\""); } } if (result3 !== null) { if (input.charCodeAt(pos) === 105) { result4 = "i"; pos++; } else { result4 = null; if (reportFailures === 0) { matchFailed("\"i\""); } } result4 = result4 !== null ? result4 : ""; if (result4 !== null) { result5 = parse___(); if (result5 !== null) { result0 = [result0, result1, result2, result3, result4, result5]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, inverted, parts, flags) { var partsConverted = map(parts, function(part) { return part.data; }); var rawText = "[" + inverted + map(parts, function(part) { return part.rawText; }).join("") + "]" + flags; return { type: "class", inverted: inverted === "^", ignoreCase: flags === "i", parts: partsConverted, // FIXME: Get the raw text from the input directly. rawText: rawText }; })(pos0, result0[1], result0[2], result0[4]); } if (result0 === null) { pos = pos0; } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("character class"); } return result0; } function parse_classCharacterRange() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; result0 = parse_classCharacter(); if (result0 !== null) { if (input.charCodeAt(pos) === 45) { result1 = "-"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"-\""); } } if (result1 !== null) { result2 = parse_classCharacter(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, 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 }; })(pos0, result0[0], result0[2]); } if (result0 === null) { pos = pos0; } return result0; } function parse_classCharacter() { var result0; var pos0; pos0 = pos; result0 = parse_bracketDelimitedCharacter(); if (result0 !== null) { result0 = (function(offset, char_) { return { data: char_, // FIXME: Get the raw text from the input directly. rawText: quoteForRegexpClass(char_) }; })(pos0, result0); } if (result0 === null) { pos = pos0; } return result0; } function parse_bracketDelimitedCharacter() { var result0; result0 = parse_simpleBracketDelimitedCharacter(); if (result0 === null) { result0 = parse_simpleEscapeSequence(); if (result0 === null) { result0 = parse_zeroEscapeSequence(); if (result0 === null) { result0 = parse_hexEscapeSequence(); if (result0 === null) { result0 = parse_unicodeEscapeSequence(); if (result0 === null) { result0 = parse_eolEscapeSequence(); } } } } } return result0; } function parse_simpleBracketDelimitedCharacter() { var result0, result1; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; pos2 = pos; reportFailures++; if (input.charCodeAt(pos) === 93) { result0 = "]"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"]\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 === null) { result0 = parse_eolChar(); } } reportFailures--; if (result0 === null) { result0 = ""; } else { result0 = null; pos = pos2; } if (result0 !== null) { if (input.length > pos) { result1 = input.charAt(pos); pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, char_) { return char_; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_simpleEscapeSequence() { var result0, result1, result2; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 !== null) { pos2 = pos; reportFailures++; result1 = parse_digit(); if (result1 === null) { if (input.charCodeAt(pos) === 120) { result1 = "x"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"x\""); } } if (result1 === null) { if (input.charCodeAt(pos) === 117) { result1 = "u"; pos++; } else { result1 = null; if (reportFailures === 0) { matchFailed("\"u\""); } } if (result1 === null) { result1 = parse_eolChar(); } } } reportFailures--; if (result1 === null) { result1 = ""; } else { result1 = null; pos = pos2; } if (result1 !== null) { if (input.length > pos) { result2 = input.charAt(pos); pos++; } else { result2 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, 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". })(pos0, result0[2]); } if (result0 === null) { pos = pos0; } return result0; } function parse_zeroEscapeSequence() { var result0, result1; var pos0, pos1, pos2; pos0 = pos; pos1 = pos; if (input.substr(pos, 2) === "\\0") { result0 = "\\0"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\0\""); } } if (result0 !== null) { pos2 = pos; reportFailures++; result1 = parse_digit(); reportFailures--; if (result1 === null) { result1 = ""; } else { result1 = null; pos = pos2; } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset) { return "\x00"; })(pos0); } if (result0 === null) { pos = pos0; } return result0; } function parse_hexEscapeSequence() { var result0, result1, result2; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.substr(pos, 2) === "\\x") { result0 = "\\x"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\x\""); } } if (result0 !== null) { result1 = parse_hexDigit(); if (result1 !== null) { result2 = parse_hexDigit(); if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, h1, h2) { return String.fromCharCode(parseInt(h1 + h2, 16)); })(pos0, result0[1], result0[2]); } if (result0 === null) { pos = pos0; } return result0; } function parse_unicodeEscapeSequence() { var result0, result1, result2, result3, result4; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.substr(pos, 2) === "\\u") { result0 = "\\u"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\u\""); } } if (result0 !== null) { result1 = parse_hexDigit(); if (result1 !== null) { result2 = parse_hexDigit(); if (result2 !== null) { result3 = parse_hexDigit(); if (result3 !== null) { result4 = parse_hexDigit(); if (result4 !== null) { result0 = [result0, result1, result2, result3, result4]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, h1, h2, h3, h4) { return String.fromCharCode(parseInt(h1 + h2 + h3 + h4, 16)); })(pos0, result0[1], result0[2], result0[3], result0[4]); } if (result0 === null) { pos = pos0; } return result0; } function parse_eolEscapeSequence() { var result0, result1; var pos0, pos1; pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 92) { result0 = "\\"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\\\\""); } } if (result0 !== null) { result1 = parse_eol(); if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos1; } } else { result0 = null; pos = pos1; } if (result0 !== null) { result0 = (function(offset, eol) { return eol; })(pos0, result0[1]); } if (result0 === null) { pos = pos0; } return result0; } function parse_digit() { var result0; if (/^[0-9]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[0-9]"); } } return result0; } function parse_hexDigit() { var result0; if (/^[0-9a-fA-F]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[0-9a-fA-F]"); } } return result0; } function parse_letter() { var result0; result0 = parse_lowerCaseLetter(); if (result0 === null) { result0 = parse_upperCaseLetter(); } return result0; } function parse_lowerCaseLetter() { var result0; if (/^[a-z]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[a-z]"); } } return result0; } function parse_upperCaseLetter() { var result0; if (/^[A-Z]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[A-Z]"); } } return result0; } function parse___() { var result0, result1; result0 = []; result1 = parse_whitespace(); if (result1 === null) { result1 = parse_eol(); if (result1 === null) { result1 = parse_comment(); } } while (result1 !== null) { result0.push(result1); result1 = parse_whitespace(); if (result1 === null) { result1 = parse_eol(); if (result1 === null) { result1 = parse_comment(); } } } return result0; } function parse_comment() { var result0; reportFailures++; result0 = parse_singleLineComment(); if (result0 === null) { result0 = parse_multiLineComment(); } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("comment"); } return result0; } function parse_singleLineComment() { var result0, result1, result2, result3; var pos0, pos1, pos2; pos0 = pos; if (input.substr(pos, 2) === "//") { result0 = "//"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"//\""); } } if (result0 !== null) { result1 = []; pos1 = pos; pos2 = pos; reportFailures++; result2 = parse_eolChar(); reportFailures--; if (result2 === null) { result2 = ""; } else { result2 = null; pos = pos2; } if (result2 !== null) { if (input.length > pos) { result3 = input.charAt(pos); pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos1; } } else { result2 = null; pos = pos1; } while (result2 !== null) { result1.push(result2); pos1 = pos; pos2 = pos; reportFailures++; result2 = parse_eolChar(); reportFailures--; if (result2 === null) { result2 = ""; } else { result2 = null; pos = pos2; } if (result2 !== null) { if (input.length > pos) { result3 = input.charAt(pos); pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos1; } } else { result2 = null; pos = pos1; } } if (result1 !== null) { result0 = [result0, result1]; } else { result0 = null; pos = pos0; } } else { result0 = null; pos = pos0; } return result0; } function parse_multiLineComment() { var result0, result1, result2, result3; var pos0, pos1, pos2; pos0 = pos; if (input.substr(pos, 2) === "/*") { result0 = "/*"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"/*\""); } } if (result0 !== null) { result1 = []; pos1 = pos; pos2 = pos; reportFailures++; if (input.substr(pos, 2) === "*/") { result2 = "*/"; pos += 2; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"*/\""); } } reportFailures--; if (result2 === null) { result2 = ""; } else { result2 = null; pos = pos2; } if (result2 !== null) { if (input.length > pos) { result3 = input.charAt(pos); pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos1; } } else { result2 = null; pos = pos1; } while (result2 !== null) { result1.push(result2); pos1 = pos; pos2 = pos; reportFailures++; if (input.substr(pos, 2) === "*/") { result2 = "*/"; pos += 2; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"*/\""); } } reportFailures--; if (result2 === null) { result2 = ""; } else { result2 = null; pos = pos2; } if (result2 !== null) { if (input.length > pos) { result3 = input.charAt(pos); pos++; } else { result3 = null; if (reportFailures === 0) { matchFailed("any character"); } } if (result3 !== null) { result2 = [result2, result3]; } else { result2 = null; pos = pos1; } } else { result2 = null; pos = pos1; } } if (result1 !== null) { if (input.substr(pos, 2) === "*/") { result2 = "*/"; pos += 2; } else { result2 = null; if (reportFailures === 0) { matchFailed("\"*/\""); } } if (result2 !== null) { result0 = [result0, result1, result2]; } else { result0 = null; pos = pos0; } } else { result0 = null; pos = pos0; } } else { result0 = null; pos = pos0; } return result0; } function parse_eol() { var result0; reportFailures++; if (input.charCodeAt(pos) === 10) { result0 = "\n"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\n\""); } } if (result0 === null) { if (input.substr(pos, 2) === "\r\n") { result0 = "\r\n"; pos += 2; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\r\\n\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 13) { result0 = "\r"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\r\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 8232) { result0 = "\u2028"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\u2028\""); } } if (result0 === null) { if (input.charCodeAt(pos) === 8233) { result0 = "\u2029"; pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("\"\\u2029\""); } } } } } } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("end of line"); } return result0; } function parse_eolChar() { var result0; if (/^[\n\r\u2028\u2029]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[\\n\\r\\u2028\\u2029]"); } } return result0; } function parse_whitespace() { var result0; reportFailures++; if (/^[ \t\x0B\f\xA0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]/.test(input.charAt(pos))) { result0 = input.charAt(pos); pos++; } else { result0 = null; if (reportFailures === 0) { matchFailed("[ \\t\\x0B\\f\\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]"); } } reportFailures--; if (reportFailures === 0 && result0 === null) { matchFailed("whitespace"); } return result0; } function cleanupExpected(expected) { expected.sort(); var lastExpected = null; var cleanExpected = []; for (var i = 0; i < expected.length; i++) { if (expected[i] !== lastExpected) { cleanExpected.push(expected[i]); lastExpected = expected[i]; } } return cleanExpected; } 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 < Math.max(pos, rightmostFailuresPos); 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| * - |rightmostFailuresExpected| may or may not contain something * * 2. The parser successfully parsed only a part of the input. * * - |result !== null| * - |pos < input.length| * - |rightmostFailuresExpected| may or may not contain something * * 3. The parser did not successfully parse any part of the input. * * - |result === null| * - |pos === 0| * - |rightmostFailuresExpected| contains at least one failure * * All code following this comment (including called functions) must * handle these states. */ if (result === null || pos !== input.length) { var offset = Math.max(pos, rightmostFailuresPos); var found = offset < input.length ? input.charAt(offset) : null; var errorPosition = computeErrorPosition(); throw new this.SyntaxError( cleanupExpected(rightmostFailuresExpected), found, offset, 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(expected, found, offset, line, column) { function buildMessage(expected, found) { var expectedHumanized, foundHumanized; switch (expected.length) { case 0: expectedHumanized = "end of input"; break; case 1: expectedHumanized = expected[0]; break; default: expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + " or " + expected[expected.length - 1]; } foundHumanized = found ? quote(found) : "end of input"; return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; } this.name = "SyntaxError"; this.expected = expected; this.found = found; this.message = buildMessage(expected, found); this.offset = offset; this.line = line; this.column = column; }; result.SyntaxError.prototype = Error.prototype; return result; })(); PEG.compiler = { /* * Names of passes that will get run during the compilation (in the specified * order). */ appliedPassNames: [ "reportMissingRules", "reportLeftRecursion", "removeProxyRules", "computeVarNames", "computeParams" ], /* * 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, options) { var that = this; each(this.appliedPassNames, function(passName) { that.passes[passName](ast); }); var source = this.emitter(ast, options); var result = eval(source); result._source = source; return result; } }; /* * Compiler passes. * * Each pass is a function that is passed the AST. It can perform checks on it * or modify it as needed. If the pass encounters a semantic error, it throws * |PEG.GrammarError|. */ PEG.compiler.passes = { /* Checks that all referenced rules exist. */ reportMissingRules: function(ast) { function nop() {} function checkExpression(node) { check(node.expression); } function checkSubnodes(propertyName) { return function(node) { each(node[propertyName], check); }; } var check = buildNodeVisitor({ grammar: checkSubnodes("rules"), 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 (!findRuleByName(ast, node.name)) { 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. */ reportLeftRecursion: function(ast) { function nop() {} function checkExpression(node, appliedRules) { check(node.expression, appliedRules); } function checkSubnodes(propertyName) { return function(node, appliedRules) { each(node[propertyName], function(subnode) { check(subnode, appliedRules); }); }; } var check = buildNodeVisitor({ grammar: checkSubnodes("rules"), rule: function(node, appliedRules) { check(node.expression, appliedRules.concat(node.name)); }, choice: checkSubnodes("alternatives"), 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(findRuleByName(ast, node.name), appliedRules); }, literal: nop, any: nop, "class": nop }); check(ast, []); }, /* * Removes proxy rules -- that is, rules that only delegate to other rule. */ removeProxyRules: 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: replaceInSubnodes("rules"), 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); } var indices = []; each(ast.rules, function(rule, i) { if (isProxyRule(rule)) { replaceRuleRefs(ast, rule.name, rule.expression.name); if (rule.name === ast.startRule) { ast.startRule = rule.expression.name; } indices.push(i); } }); indices.reverse(); each(indices, function(index) { ast.rules.splice(index, 1); }); }, /* * Computes names of variables used for storing match results and parse * positions in generated code. These variables are organized as two stacks. * The following will hold after running this pass: * * * All nodes except "grammar" and "rule" nodes will have a |resultVar| * property. It will contain a name of the variable that will store a * match result of the expression represented by the node in generated * code. * * * Some nodes will have a |posVar| property. It will contain a name of the * variable that will store a parse position in generated code. * * * All "rule" nodes will contain |resultVars| and |posVars| properties. * They will contain a list of values of |resultVar| and |posVar| * properties used in rule's subnodes. (This is useful to declare * variables in generated code.) */ computeVarNames: function(ast) { function resultVar(index) { return "result" + index; } function posVar(index) { return "pos" + index; } function computeLeaf(node, index) { node.resultVar = resultVar(index.result); return { result: 0, pos: 0 }; } function computeFromExpression(delta) { return function(node, index) { var depth = compute( node.expression, { result: index.result + delta.result, pos: index.pos + delta.pos } ); node.resultVar = resultVar(index.result); if (delta.pos !== 0) { node.posVar = posVar(index.pos); } return { result: depth.result + delta.result, pos: depth.pos + delta.pos }; }; } var compute = buildNodeVisitor({ grammar: function(node, index) { each(node.rules, function(node) { compute(node, index); }); }, rule: function(node, index) { var depth = compute(node.expression, index); node.resultVar = resultVar(index.result); node.resultVars = map(range(depth.result + 1), resultVar); node.posVars = map(range(depth.pos), posVar); }, choice: function(node, index) { var depths = map(node.alternatives, function(alternative) { return compute(alternative, index); }); node.resultVar = resultVar(index.result); return { result: Math.max.apply(null, pluck(depths, "result")), pos: Math.max.apply(null, pluck(depths, "pos")) }; }, sequence: function(node, index) { var depths = map(node.elements, function(element, i) { return compute( element, { result: index.result + i, pos: index.pos + 1 } ); }); node.resultVar = resultVar(index.result); node.posVar = posVar(index.pos); return { result: node.elements.length > 0 ? Math.max.apply( null, map(depths, function(d, i) { return i + d.result; }) ) : 0, pos: node.elements.length > 0 ? 1 + Math.max.apply(null, pluck(depths, "pos")) : 1 }; }, labeled: computeFromExpression({ result: 0, pos: 0 }), simple_and: computeFromExpression({ result: 0, pos: 1 }), simple_not: computeFromExpression({ result: 0, pos: 1 }), semantic_and: computeLeaf, semantic_not: computeLeaf, optional: computeFromExpression({ result: 0, pos: 0 }), zero_or_more: computeFromExpression({ result: 1, pos: 0 }), one_or_more: computeFromExpression({ result: 1, pos: 0 }), action: computeFromExpression({ result: 0, pos: 1 }), rule_ref: computeLeaf, literal: computeLeaf, any: computeLeaf, "class": computeLeaf }); compute(ast, { result: 0, pos: 0 }); }, /* * This pass walks through the AST and tracks what labels are visible at each * point. For "action", "semantic_and" and "semantic_or" nodes it computes * parameter names and values for the function used in generated code. (In the * emitter, user's code is wrapped into a function that is immediately * executed. Its parameter names correspond to visible labels and its * parameter values to their captured values). Implicitly, this pass defines * scoping rules for labels. * * After running this pass, all "action", "semantic_and" and "semantic_or" * nodes will have a |params| property containing an object mapping parameter * names to the expressions that will be used as their values. */ computeParams: function(ast) { var envs = []; function scoped(f) { envs.push({}); f(); envs.pop(); } function nop() {} function computeForScopedExpression(node) { scoped(function() { compute(node.expression); }); } function computeParams(node) { var env = envs[envs.length - 1], params = {}, name; for (name in env) { params[name] = env[name]; } node.params = params; } var compute = buildNodeVisitor({ grammar: function(node) { each(node.rules, compute); }, rule: computeForScopedExpression, choice: function(node) { scoped(function() { each(node.alternatives, compute); }); }, sequence: function(node) { var env = envs[envs.length - 1], name; function fixup(name) { each(pluck(node.elements, "resultVar"), function(resultVar, i) { if ((new RegExp("^" + resultVar + "(\\[\\d+\\])*$")).test(env[name])) { env[name] = node.resultVar + "[" + i + "]" + env[name].substr(resultVar.length); } }); } each(node.elements, compute); for (name in env) { fixup(name); } }, labeled: function(node) { envs[envs.length - 1][node.label] = node.resultVar; scoped(function() { compute(node.expression); }); }, simple_and: computeForScopedExpression, simple_not: computeForScopedExpression, semantic_and: computeParams, semantic_not: computeParams, optional: computeForScopedExpression, zero_or_more: computeForScopedExpression, one_or_more: computeForScopedExpression, action: function(node) { scoped(function() { compute(node.expression); computeParams(node); }); }, rule_ref: nop, literal: nop, any: nop, "class": nop }); compute(ast); } }; /* Emits the generated code for the AST. */ PEG.compiler.emitter = function(ast, options) { options = options || {}; if (options.cache === undefined) { options.cache = false; } if (options.trackLineAndColumn === undefined) { options.trackLineAndColumn = false; } /* * Codie 1.1.0 * * https://github.com/dmajda/codie * * Copyright (c) 2011-2012 David Majda * Licensend under the MIT license. */ var Codie = (function(undefined) { function stringEscape(s) { function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); } /* * 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 control and non-ASCII * characters. Note that "\0" and "\v" escape sequences are not used * because JSHint does not like the first and IE the second. */ return s .replace(/\\/g, '\\\\') // backslash .replace(/"/g, '\\"') // closing double quote .replace(/\x08/g, '\\b') // backspace .replace(/\t/g, '\\t') // horizontal tab .replace(/\n/g, '\\n') // line feed .replace(/\f/g, '\\f') // form feed .replace(/\r/g, '\\r') // carriage return .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); }) .replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); }) .replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); }); } function push(s) { return '__p.push(' + s + ');'; } function pushRaw(template, length, state) { function unindent(code, level, unindentFirst) { return code.replace( new RegExp('^.{' + level +'}', "gm"), function(str, offset) { if (offset === 0) { return unindentFirst ? '' : str; } else { return ""; } } ); } var escaped = stringEscape(unindent( template.substring(0, length), state.indentLevel(), state.atBOL )); return escaped.length > 0 ? push('"' + escaped + '"') : ''; } var Codie = { /* Codie version (uses semantic versioning). */ VERSION: "1.1.0", /* * Specifies by how many characters do #if/#else and #for unindent their * content in the generated code. */ indentStep: 2, /* Description of #-commands. Extend to define your own commands. */ commands: { "if": { params: /^(.*)$/, compile: function(state, prefix, params) { return ['if(' + params[0] + '){', []]; }, stackOp: "push" }, "else": { params: /^$/, compile: function(state) { var stack = state.commandStack, insideElse = stack[stack.length - 1] === "else", insideIf = stack[stack.length - 1] === "if"; if (insideElse) { throw new Error("Multiple #elses."); } if (!insideIf) { throw new Error("Using #else outside of #if."); } return ['}else{', []]; }, stackOp: "replace" }, "for": { params: /^([a-zA-Z_][a-zA-Z0-9_]*)[ \t]+in[ \t]+(.*)$/, init: function(state) { state.forCurrLevel = 0; // current level of #for loop nesting state.forMaxLevel = 0; // maximum level of #for loop nesting }, compile: function(state, prefix, params) { var c = '__c' + state.forCurrLevel, // __c for "collection" l = '__l' + state.forCurrLevel, // __l for "length" i = '__i' + state.forCurrLevel; // __i for "index" state.forCurrLevel++; if (state.forMaxLevel < state.forCurrLevel) { state.forMaxLevel = state.forCurrLevel; } return [ c + '=' + params[1] + ';' + l + '=' + c + '.length;' + 'for(' + i + '=0;' + i + '<' + l + ';' + i + '++){' + params[0] + '=' + c + '[' + i + '];', [params[0], c, l, i] ]; }, exit: function(state) { state.forCurrLevel--; }, stackOp: "push" }, "end": { params: /^$/, compile: function(state) { var stack = state.commandStack, exit; if (stack.length === 0) { throw new Error("Too many #ends."); } exit = Codie.commands[stack[stack.length - 1]].exit; if (exit) { exit(state); } return ['}', []]; }, stackOp: "pop" }, "block": { params: /^(.*)$/, compile: function(state, prefix, params) { var x = '__x', // __x for "prefix", n = '__n', // __n for "lines" l = '__l', // __l for "length" i = '__i'; // __i for "index" /* * Originally, the generated code used |String.prototype.replace|, but * it is buggy in certain versions of V8 so it was rewritten. See the * tests for details. */ return [ x + '="' + stringEscape(prefix.substring(state.indentLevel())) + '";' + n + '=(' + params[0] + ').toString().split("\\n");' + l + '=' + n + '.length;' + 'for(' + i + '=0;' + i + '<' + l + ';' + i + '++){' + n + '[' + i +']=' + x + '+' + n + '[' + i + ']+"\\n";' + '}' + push(n + '.join("")'), [x, n, l, i] ]; }, stackOp: "nop" } }, /* * Compiles a template into a function. When called, this function will * execute the template in the context of an object passed in a parameter and * return the result. */ template: function(template) { var stackOps = { push: function(stack, name) { stack.push(name); }, replace: function(stack, name) { stack[stack.length - 1] = name; }, pop: function(stack) { stack.pop(); }, nop: function() { } }; function compileExpr(state, expr) { state.atBOL = false; return [push(expr), []]; } function compileCommand(state, prefix, name, params) { var command, match, result; command = Codie.commands[name]; if (!command) { throw new Error("Unknown command: #" + name + "."); } match = command.params.exec(params); if (match === null) { throw new Error( "Invalid params for command #" + name + ": " + params + "." ); } result = command.compile(state, prefix, match.slice(1)); stackOps[command.stackOp](state.commandStack, name); state.atBOL = true; return result; } var state = { // compilation state commandStack: [], // stack of commands as they were nested atBOL: true, // is the next character to process at BOL? indentLevel: function() { return Codie.indentStep * this.commandStack.length; } }, code = '', // generated template function code vars = ['__p=[]'], // variables used by generated code name, match, result, i; /* Initialize state. */ for (name in Codie.commands) { if (Codie.commands[name].init) { Codie.commands[name].init(state); } } /* Compile the template. */ while ((match = /^([ \t]*)#([a-zA-Z_][a-zA-Z0-9_]*)(?:[ \t]+([^ \t\n][^\n]*))?[ \t]*(?:\n|$)|#\{([^}]*)\}/m.exec(template)) !== null) { code += pushRaw(template, match.index, state); result = match[2] !== undefined && match[2] !== "" ? compileCommand(state, match[1], match[2], match[3] || "") // #-command : compileExpr(state, match[4]); // #{...} code += result[0]; vars = vars.concat(result[1]); template = template.substring(match.index + match[0].length); } code += pushRaw(template, template.length, state); /* Check the final state. */ if (state.commandStack.length > 0) { throw new Error("Missing #end."); } /* Sanitize the list of variables used by commands. */ vars.sort(); for (i = 0; i < vars.length; i++) { if (vars[i] === vars[i - 1]) { vars.splice(i--, 1); } } /* Create the resulting function. */ return new Function("__v", [ '__v=__v||{};', 'var ' + vars.join(',') + ';', 'with(__v){', code, 'return __p.join("").replace(/^\\n+|\\n+$/g,"");};' ].join('')); } }; return Codie; })(); var templates = (function() { var name, templates = {}, sources = { grammar: [ '(function(){', ' /*', ' * Generated by PEG.js 0.7.0.', ' *', ' * http://pegjs.majda.cz/', ' */', ' ', /* 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.', ' *', ' * For portability, we also escape escape all control and non-ASCII', ' * characters. Note that "\\0" and "\\v" escape sequences are not used', ' * because JSHint does not like the first and IE the second.', ' */', ' return \'"\' + s', ' .replace(/\\\\/g, \'\\\\\\\\\') // backslash', ' .replace(/"/g, \'\\\\"\') // closing quote character', ' .replace(/\\x08/g, \'\\\\b\') // backspace', ' .replace(/\\t/g, \'\\\\t\') // horizontal tab', ' .replace(/\\n/g, \'\\\\n\') // line feed', ' .replace(/\\f/g, \'\\\\f\') // form feed', ' .replace(/\\r/g, \'\\\\r\') // carriage return', ' .replace(/[\\x00-\\x07\\x0B\\x0E-\\x1F\\x80-\\uFFFF]/g, escape)', ' + \'"\';', ' }', ' ', ' 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 = {', ' #for rule in node.rules', ' #{string(rule.name) + ": parse_" + rule.name + (rule !== node.rules[node.rules.length - 1] ? "," : "")}', ' #end', ' };', ' ', ' if (startRule !== undefined) {', ' if (parseFunctions[startRule] === undefined) {', ' throw new Error("Invalid rule name: " + quote(startRule) + ".");', ' }', ' } else {', ' startRule = #{string(node.startRule)};', ' }', ' ', ' #{posInit("pos")};', ' var reportFailures = 0;', // 0 = report, anything > 0 = do not report ' #{posInit("rightmostFailuresPos")};', ' var rightmostFailuresExpected = [];', ' #if options.cache', ' var cache = {};', ' #end', ' ', /* 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);', ' var escapeChar;', ' var length;', ' ', ' if (charCode <= 0xFF) {', ' escapeChar = \'x\';', ' length = 2;', ' } else {', ' escapeChar = \'u\';', ' length = 4;', ' }', ' ', ' return \'\\\\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), \'0\', length);', ' }', ' ', ' #if options.trackLineAndColumn', ' function clone(object) {', ' var result = {};', ' for (var key in object) {', ' result[key] = object[key];', ' }', ' return result;', ' }', ' ', ' function advance(pos, n) {', ' var endOffset = pos.offset + n;', ' ', ' for (var offset = pos.offset; offset < endOffset; offset++) {', ' var ch = input.charAt(offset);', ' if (ch === "\\n") {', ' if (!pos.seenCR) { pos.line++; }', ' pos.column = 1;', ' pos.seenCR = false;', ' } else if (ch === "\\r" || ch === "\\u2028" || ch === "\\u2029") {', ' pos.line++;', ' pos.column = 1;', ' pos.seenCR = true;', ' } else {', ' pos.column++;', ' pos.seenCR = false;', ' }', ' }', ' ', ' pos.offset += n;', ' }', ' ', ' #end', ' function matchFailed(failure) {', ' if (#{posOffset("pos")} < #{posOffset("rightmostFailuresPos")}) {', ' return;', ' }', ' ', ' if (#{posOffset("pos")} > #{posOffset("rightmostFailuresPos")}) {', ' rightmostFailuresPos = #{posClone("pos")};', ' rightmostFailuresExpected = [];', ' }', ' ', ' rightmostFailuresExpected.push(failure);', ' }', ' ', ' #for rule in node.rules', ' #block emit(rule)', ' ', ' #end', ' ', ' function cleanupExpected(expected) {', ' expected.sort();', ' ', ' var lastExpected = null;', ' var cleanExpected = [];', ' for (var i = 0; i < expected.length; i++) {', ' if (expected[i] !== lastExpected) {', ' cleanExpected.push(expected[i]);', ' lastExpected = expected[i];', ' }', ' }', ' return cleanExpected;', ' }', ' ', ' #if !options.trackLineAndColumn', ' 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 < Math.max(pos, rightmostFailuresPos); 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 };', ' }', ' #end', ' ', ' #if node.initializer', ' #block emit(node.initializer)', ' #end', ' ', ' 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|', ' * - |#{posOffset("pos")} === input.length|', ' * - |rightmostFailuresExpected| may or may not contain something', ' *', ' * 2. The parser successfully parsed only a part of the input.', ' *', ' * - |result !== null|', ' * - |#{posOffset("pos")} < input.length|', ' * - |rightmostFailuresExpected| may or may not contain something', ' *', ' * 3. The parser did not successfully parse any part of the input.', ' *', ' * - |result === null|', ' * - |#{posOffset("pos")} === 0|', ' * - |rightmostFailuresExpected| contains at least one failure', ' *', ' * All code following this comment (including called functions) must', ' * handle these states.', ' */', ' if (result === null || #{posOffset("pos")} !== input.length) {', ' var offset = Math.max(#{posOffset("pos")}, #{posOffset("rightmostFailuresPos")});', ' var found = offset < input.length ? input.charAt(offset) : null;', ' #if options.trackLineAndColumn', ' var errorPosition = #{posOffset("pos")} > #{posOffset("rightmostFailuresPos")} ? pos : rightmostFailuresPos;', ' #else', ' var errorPosition = computeErrorPosition();', ' #end', ' ', ' throw new this.SyntaxError(', ' cleanupExpected(rightmostFailuresExpected),', ' found,', ' offset,', ' 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(expected, found, offset, line, column) {', ' function buildMessage(expected, found) {', ' var expectedHumanized, foundHumanized;', ' ', ' switch (expected.length) {', ' case 0:', ' expectedHumanized = "end of input";', ' break;', ' case 1:', ' expectedHumanized = expected[0];', ' break;', ' default:', ' expectedHumanized = expected.slice(0, expected.length - 1).join(", ")', ' + " or "', ' + expected[expected.length - 1];', ' }', ' ', ' foundHumanized = found ? quote(found) : "end of input";', ' ', ' return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";', ' }', ' ', ' this.name = "SyntaxError";', ' this.expected = expected;', ' this.found = found;', ' this.message = buildMessage(expected, found);', ' this.offset = offset;', ' this.line = line;', ' this.column = column;', ' };', ' ', ' result.SyntaxError.prototype = Error.prototype;', ' ', ' return result;', '})()' ], rule: [ 'function parse_#{node.name}() {', ' #if options.cache', ' var cacheKey = "#{node.name}@" + #{posOffset("pos")};', ' var cachedResult = cache[cacheKey];', ' if (cachedResult) {', ' pos = #{posClone("cachedResult.nextPos")};', ' return cachedResult.result;', ' }', ' ', ' #end', ' #if node.resultVars.length > 0', ' var #{node.resultVars.join(", ")};', ' #end', ' #if node.posVars.length > 0', ' var #{node.posVars.join(", ")};', ' #end', ' ', ' #if node.displayName !== null', ' reportFailures++;', ' #end', ' #block emit(node.expression)', ' #if node.displayName !== null', ' reportFailures--;', ' if (reportFailures === 0 && #{node.resultVar} === null) {', ' matchFailed(#{string(node.displayName)});', ' }', ' #end', ' #if options.cache', ' ', ' cache[cacheKey] = {', ' nextPos: #{posClone("pos")},', ' result: #{node.resultVar}', ' };', ' #end', ' return #{node.resultVar};', '}' ], choice: [ '#block emit(alternative)', '#block nextAlternativesCode' ], "choice.next": [ 'if (#{node.resultVar} === null) {', ' #block code', '}' ], sequence: [ '#{posSave(node)};', '#block code' ], "sequence.iteration": [ '#block emit(element)', 'if (#{element.resultVar} !== null) {', ' #block code', '} else {', ' #{node.resultVar} = null;', ' #{posRestore(node)};', '}' ], "sequence.inner": [ '#{node.resultVar} = [#{pluck(node.elements, "resultVar").join(", ")}];' ], simple_and: [ '#{posSave(node)};', 'reportFailures++;', '#block emit(node.expression)', 'reportFailures--;', 'if (#{node.resultVar} !== null) {', ' #{node.resultVar} = "";', ' #{posRestore(node)};', '} else {', ' #{node.resultVar} = null;', '}' ], simple_not: [ '#{posSave(node)};', 'reportFailures++;', '#block emit(node.expression)', 'reportFailures--;', 'if (#{node.resultVar} === null) {', ' #{node.resultVar} = "";', '} else {', ' #{node.resultVar} = null;', ' #{posRestore(node)};', '}' ], semantic_and: [ '#{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? ["pos.offset", "pos.line", "pos.column"] : ["pos"]).concat(values(node.params)).join(", ")}) ? "" : null;' ], semantic_not: [ '#{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? ["pos.offset", "pos.line", "pos.column"] : ["pos"]).concat(values(node.params)).join(", ")}) ? null : "";' ], optional: [ '#block emit(node.expression)', '#{node.resultVar} = #{node.resultVar} !== null ? #{node.resultVar} : "";' ], zero_or_more: [ '#{node.resultVar} = [];', '#block emit(node.expression)', 'while (#{node.expression.resultVar} !== null) {', ' #{node.resultVar}.push(#{node.expression.resultVar});', ' #block emit(node.expression)', '}' ], one_or_more: [ '#block emit(node.expression)', 'if (#{node.expression.resultVar} !== null) {', ' #{node.resultVar} = [];', ' while (#{node.expression.resultVar} !== null) {', ' #{node.resultVar}.push(#{node.expression.resultVar});', ' #block emit(node.expression)', ' }', '} else {', ' #{node.resultVar} = null;', '}' ], action: [ '#{posSave(node)};', '#block emit(node.expression)', 'if (#{node.resultVar} !== null) {', ' #{node.resultVar} = (function(#{(options.trackLineAndColumn ? ["offset", "line", "column"] : ["offset"]).concat(keys(node.params)).join(", ")}) {#{node.code}})(#{(options.trackLineAndColumn ? [node.posVar + ".offset", node.posVar + ".line", node.posVar + ".column"] : [node.posVar]).concat(values(node.params)).join(", ")});', '}', 'if (#{node.resultVar} === null) {', ' #{posRestore(node)};', '}' ], rule_ref: [ '#{node.resultVar} = parse_#{node.name}();' ], literal: [ '#if node.value.length === 0', ' #{node.resultVar} = "";', '#else', ' #if !node.ignoreCase', ' #if node.value.length === 1', ' if (input.charCodeAt(#{posOffset("pos")}) === #{node.value.charCodeAt(0)}) {', ' #else', ' if (input.substr(#{posOffset("pos")}, #{node.value.length}) === #{string(node.value)}) {', ' #end', ' #else', /* * One-char literals are not optimized when case-insensitive * matching is enabled. This is because there is no simple way to * lowercase a character code that works for character outside ASCII * letters. Moreover, |toLowerCase| can change string length, * meaning the result of lowercasing a character can be more * characters. */ ' if (input.substr(#{posOffset("pos")}, #{node.value.length}).toLowerCase() === #{string(node.value.toLowerCase())}) {', ' #end', ' #if !node.ignoreCase', ' #{node.resultVar} = #{string(node.value)};', ' #else', ' #{node.resultVar} = input.substr(#{posOffset("pos")}, #{node.value.length});', ' #end', ' #{posAdvance(node.value.length)};', ' } else {', ' #{node.resultVar} = null;', ' if (reportFailures === 0) {', ' matchFailed(#{string(string(node.value))});', ' }', ' }', '#end' ], any: [ 'if (input.length > #{posOffset("pos")}) {', ' #{node.resultVar} = input.charAt(#{posOffset("pos")});', ' #{posAdvance(1)};', '} else {', ' #{node.resultVar} = null;', ' if (reportFailures === 0) {', ' matchFailed("any character");', ' }', '}' ], "class": [ 'if (#{regexp}.test(input.charAt(#{posOffset("pos")}))) {', ' #{node.resultVar} = input.charAt(#{posOffset("pos")});', ' #{posAdvance(1)};', '} else {', ' #{node.resultVar} = null;', ' if (reportFailures === 0) {', ' matchFailed(#{string(node.rawText)});', ' }', '}' ] }; for (name in sources) { templates[name] = Codie.template(sources[name].join('\n')); } return templates; })(); function fill(name, vars) { vars.string = quote; vars.pluck = pluck; vars.keys = keys; vars.values = values; vars.emit = emit; vars.options = options; /* Position-handling macros */ if (options.trackLineAndColumn) { vars.posInit = function(name) { return "var " + name + " = " + "{ offset: 0, line: 1, column: 1, seenCR: false }"; }; vars.posClone = function(name) { return "clone(" + name + ")"; }; vars.posOffset = function(name) { return name + ".offset"; }; vars.posAdvance = function(n) { return "advance(pos, " + n + ")"; }; } else { vars.posInit = function(name) { return "var " + name + " = 0"; }; vars.posClone = function(name) { return name; }; vars.posOffset = function(name) { return name; }; vars.posAdvance = function(n) { return n === 1 ? "pos++" : "pos += " + n; }; } vars.posSave = function(node) { return node.posVar + " = " + vars.posClone("pos"); }; vars.posRestore = function(node) { return "pos" + " = " + vars.posClone(node.posVar); }; return templates[name](vars); } function emitSimple(name) { return function(node) { return fill(name, { node: node }); }; } var emit = buildNodeVisitor({ grammar: emitSimple("grammar"), initializer: function(node) { return node.code; }, rule: emitSimple("rule"), /* * The contract for all code fragments generated by the following functions * is as follows. * * The code fragment tries 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| to point to * the first chracter following the matched part of the input and sets * variable with a name stored in |node.resultVar| to an appropriate * value. This value is always non-|null|. * * * If the code fragment does not match the input, it returns with |pos| * set to the original value and it sets a variable with a name stored in * |node.resultVar| to |null|. * * The code can use variables with names stored in |resultVar| and |posVar| * properties of the current node's subnodes. It can't use any other * variables. */ choice: function(node) { var code, nextAlternativesCode; for (var i = node.alternatives.length - 1; i >= 0; i--) { nextAlternativesCode = i !== node.alternatives.length - 1 ? fill("choice.next", { node: node, code: code }) : ''; code = fill("choice", { alternative: node.alternatives[i], nextAlternativesCode: nextAlternativesCode }); } return code; }, sequence: function(node) { var code = fill("sequence.inner", { node: node }); for (var i = node.elements.length - 1; i >= 0; i--) { code = fill("sequence.iteration", { node: node, element: node.elements[i], code: code }); } return fill("sequence", { node: node, code: code }); }, labeled: function(node) { return emit(node.expression); }, simple_and: emitSimple("simple_and"), simple_not: emitSimple("simple_not"), semantic_and: emitSimple("semantic_and"), semantic_not: emitSimple("semantic_not"), optional: emitSimple("optional"), zero_or_more: emitSimple("zero_or_more"), one_or_more: emitSimple("one_or_more"), action: emitSimple("action"), rule_ref: emitSimple("rule_ref"), literal: emitSimple("literal"), any: emitSimple("any"), "class": function(node) { var regexp; if (node.parts.length > 0) { regexp = '/^[' + (node.inverted ? '^' : '') + map(node.parts, function(part) { return part instanceof Array ? quoteForRegexpClass(part[0]) + '-' + quoteForRegexpClass(part[1]) : quoteForRegexpClass(part); }).join('') + ']/' + (node.ignoreCase ? 'i' : ''); } else { /* * Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so * we translate them into euqivalents it can handle. */ regexp = node.inverted ? '/^[\\S\\s]/' : '/^(?!)/'; } return fill("class", { node: node, regexp: regexp }); } }); return emit(ast); }; return PEG; })(); if (typeof module !== "undefined") { module.exports = PEG; } pegjs-0.7.0/VERSION0000644000175000017500000000000612206663530013147 0ustar danieldaniel0.7.0