Browse Source

Simplify utility functions structure + do not export them as part of the PEG object

redux
David Majda 11 years ago
parent
commit
1279e87766
  1. 8
      src/checks.js
  2. 32
      src/emitter.js
  3. 128
      src/parser.js
  4. 14
      src/parser.pegjs
  5. 2
      src/passes.js
  6. 147
      src/utils.js
  7. 72
      test/compiler-test.js

8
src/checks.js

@ -13,9 +13,7 @@ PEG.compiler.checks = [
function checkExpression(node) { check(node.expression); }
function checkSubnodes(propertyName) {
return function(node) {
PEG.ArrayUtils.each(node[propertyName], check);
};
return function(node) { each(node[propertyName], check); };
}
var checkFunctions = {
@ -81,7 +79,7 @@ PEG.compiler.checks = [
choice:
function(node, appliedRules) {
PEG.ArrayUtils.each(node.alternatives, function(alternative) {
each(node.alternatives, function(alternative) {
check(alternative, appliedRules);
});
},
@ -105,7 +103,7 @@ PEG.compiler.checks = [
rule_ref:
function(node, appliedRules) {
if (PEG.ArrayUtils.contains(appliedRules, node.name)) {
if (contains(appliedRules, node.name)) {
throw new PEG.GrammarError(
"Left recursion detected for rule \"" + node.name + "\"."
);

32
src/emitter.js

@ -32,7 +32,7 @@ PEG.compiler.emitter = function(ast) {
*/
function formatCode() {
function interpolateVariablesInParts(parts) {
return PEG.ArrayUtils.map(parts, function(part) {
return map(parts, function(part) {
return part.replace(
/\$\{([a-zA-Z_][a-zA-Z0-9_]*)(\|([a-zA-Z_][a-zA-Z0-9_]*))?\}/g,
function(match, name, dummy, filter) {
@ -43,7 +43,7 @@ PEG.compiler.emitter = function(ast) {
if (filter !== undefined && filter != "") { // JavaScript engines differ here.
if (filter === "string") {
return PEG.StringUtils.quote(value);
return quote(value);
} else {
throw new Error("Unrecognized filter: \"" + filter + "\".");
}
@ -56,13 +56,13 @@ PEG.compiler.emitter = function(ast) {
}
function indentMultilineParts(parts) {
return PEG.ArrayUtils.map(parts, function(part) {
return map(parts, function(part) {
if (!/\n/.test(part)) { return part; }
var firstLineWhitespacePrefix = part.match(/^\s*/)[0];
var lines = part.split("\n");
var linesIndented = [lines[0]].concat(
PEG.ArrayUtils.map(lines.slice(1), function(line) {
map(lines.slice(1), function(line) {
return firstLineWhitespacePrefix + line;
})
);
@ -118,8 +118,8 @@ PEG.compiler.emitter = function(ast) {
" var rightmostMatchFailuresExpected = [];",
" var cache = {};",
" ",
/* This needs to be in sync with PEG.StringUtils.quote. */
" function quoteString(s) {",
/* 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,",
@ -136,8 +136,8 @@ PEG.compiler.emitter = function(ast) {
" + '\"';",
" }",
" ",
/* This needs to be in sync with PEG.ArrayUtils.contains. */
" function arrayContains(array, value) {",
/* This needs to be in sync with |contains| in utils.js. */
" function contains(array, value) {",
" /*",
" * Stupid IE does not have Array.prototype.indexOf, otherwise this",
" * function would be a one-liner.",
@ -161,7 +161,7 @@ PEG.compiler.emitter = function(ast) {
" rightmostMatchFailuresExpected = [];",
" }",
" ",
" if (!arrayContains(rightmostMatchFailuresExpected, failure)) {",
" if (!contains(rightmostMatchFailuresExpected, failure)) {",
" rightmostMatchFailuresExpected.push(failure);",
" }",
" }",
@ -186,7 +186,7 @@ PEG.compiler.emitter = function(ast) {
" var expected = buildExpected(rightmostMatchFailuresExpected);",
" var actualPos = Math.max(pos, rightmostMatchFailuresPos);",
" var actual = actualPos < input.length",
" ? quoteString(input.charAt(actualPos))",
" ? quote(input.charAt(actualPos))",
" : 'end of input';",
" ",
" return 'Expected ' + expected + ' but ' + actual + ' found.';",
@ -404,7 +404,7 @@ PEG.compiler.emitter = function(ast) {
sequence: function(node, resultVar) {
var savedPosVar = UID.next("savedPos");
var elementResultVars = PEG.ArrayUtils.map(node.elements, function() {
var elementResultVars = map(node.elements, function() {
return UID.next("result")
});
@ -647,7 +647,7 @@ PEG.compiler.emitter = function(ast) {
"} else {",
" var ${resultVar} = null;",
" if (context.reportMatchFailures) {",
" matchFailed(quoteString(${value|string}));",
" matchFailed(quote(${value|string}));",
" }",
"}",
{
@ -677,12 +677,12 @@ PEG.compiler.emitter = function(ast) {
if (node.parts.length > 0) {
var regexp = "/^["
+ (node.inverted ? "^" : "")
+ PEG.ArrayUtils.map(node.parts, function(part) {
+ map(node.parts, function(part) {
return part instanceof Array
? PEG.RegExpUtils.quoteForClass(part[0])
? quoteForRegexpClass(part[0])
+ "-"
+ PEG.RegExpUtils.quoteForClass(part[1])
: PEG.RegExpUtils.quoteForClass(part);
+ quoteForRegexpClass(part[1])
: quoteForRegexpClass(part);
}).join("")
+ "]/";
} else {

128
src/parser.js

@ -14,7 +14,7 @@ PEG.parser = (function(){
var rightmostMatchFailuresExpected = [];
var cache = {};
function quoteString(s) {
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,
@ -31,7 +31,7 @@ PEG.parser = (function(){
+ '"';
}
function arrayContains(array, value) {
function contains(array, value) {
/*
* Stupid IE does not have Array.prototype.indexOf, otherwise this
* function would be a one-liner.
@ -55,7 +55,7 @@ PEG.parser = (function(){
rightmostMatchFailuresExpected = [];
}
if (!arrayContains(rightmostMatchFailuresExpected, failure)) {
if (!contains(rightmostMatchFailuresExpected, failure)) {
rightmostMatchFailuresExpected.push(failure);
}
}
@ -102,7 +102,7 @@ PEG.parser = (function(){
var result0 = result1 !== null
? (function(initializer, rules) {
var rulesConverted = {};
PEG.ArrayUtils.each(rules, function(rule) { rulesConverted[rule.name] = rule; });
each(rules, function(rule) { rulesConverted[rule.name] = rule; });
return {
type: "grammar",
@ -186,7 +186,7 @@ PEG.parser = (function(){
} else {
var result8 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString(""));
matchFailed(quote(""));
}
}
if (result8 !== null) {
@ -301,7 +301,7 @@ PEG.parser = (function(){
var result0 = result1 !== null
? (function(head, tail) {
if (tail.length > 0) {
var alternatives = [head].concat(PEG.ArrayUtils.map(
var alternatives = [head].concat(map(
tail,
function(element) { return element[1]; }
));
@ -718,7 +718,7 @@ PEG.parser = (function(){
} else {
var result18 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString(""));
matchFailed(quote(""));
}
}
if (result18 !== null) {
@ -887,7 +887,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("{"));
matchFailed(quote("{"));
}
}
if (result2 !== null) {
@ -924,7 +924,7 @@ PEG.parser = (function(){
} else {
var result4 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("}"));
matchFailed(quote("}"));
}
}
if (result4 !== null) {
@ -1032,7 +1032,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("="));
matchFailed(quote("="));
}
}
if (result2 !== null) {
@ -1076,7 +1076,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString(":"));
matchFailed(quote(":"));
}
}
if (result2 !== null) {
@ -1120,7 +1120,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString(";"));
matchFailed(quote(";"));
}
}
if (result2 !== null) {
@ -1164,7 +1164,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("/"));
matchFailed(quote("/"));
}
}
if (result2 !== null) {
@ -1208,7 +1208,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("&"));
matchFailed(quote("&"));
}
}
if (result2 !== null) {
@ -1252,7 +1252,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("!"));
matchFailed(quote("!"));
}
}
if (result2 !== null) {
@ -1296,7 +1296,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("?"));
matchFailed(quote("?"));
}
}
if (result2 !== null) {
@ -1340,7 +1340,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("*"));
matchFailed(quote("*"));
}
}
if (result2 !== null) {
@ -1384,7 +1384,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("+"));
matchFailed(quote("+"));
}
}
if (result2 !== null) {
@ -1428,7 +1428,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("("));
matchFailed(quote("("));
}
}
if (result2 !== null) {
@ -1472,7 +1472,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString(")"));
matchFailed(quote(")"));
}
}
if (result2 !== null) {
@ -1516,7 +1516,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("."));
matchFailed(quote("."));
}
}
if (result2 !== null) {
@ -1565,7 +1565,7 @@ PEG.parser = (function(){
} else {
var result11 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("_"));
matchFailed(quote("_"));
}
}
if (result11 !== null) {
@ -1577,7 +1577,7 @@ PEG.parser = (function(){
} else {
var result10 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("$"));
matchFailed(quote("$"));
}
}
if (result10 !== null) {
@ -1603,7 +1603,7 @@ PEG.parser = (function(){
} else {
var result7 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("_"));
matchFailed(quote("_"));
}
}
if (result7 !== null) {
@ -1615,7 +1615,7 @@ PEG.parser = (function(){
} else {
var result6 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("$"));
matchFailed(quote("$"));
}
}
if (result6 !== null) {
@ -1642,7 +1642,7 @@ PEG.parser = (function(){
} else {
var result7 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("_"));
matchFailed(quote("_"));
}
}
if (result7 !== null) {
@ -1654,7 +1654,7 @@ PEG.parser = (function(){
} else {
var result6 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("$"));
matchFailed(quote("$"));
}
}
if (result6 !== null) {
@ -1764,7 +1764,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\""));
matchFailed(quote("\""));
}
}
if (result2 !== null) {
@ -1781,7 +1781,7 @@ PEG.parser = (function(){
} else {
var result4 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\""));
matchFailed(quote("\""));
}
}
if (result4 !== null) {
@ -1880,7 +1880,7 @@ PEG.parser = (function(){
} else {
var result7 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\""));
matchFailed(quote("\""));
}
}
if (result7 !== null) {
@ -1892,7 +1892,7 @@ PEG.parser = (function(){
} else {
var result6 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\\"));
matchFailed(quote("\\"));
}
}
if (result6 !== null) {
@ -1962,7 +1962,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("'"));
matchFailed(quote("'"));
}
}
if (result2 !== null) {
@ -1979,7 +1979,7 @@ PEG.parser = (function(){
} else {
var result4 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("'"));
matchFailed(quote("'"));
}
}
if (result4 !== null) {
@ -2078,7 +2078,7 @@ PEG.parser = (function(){
} else {
var result7 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("'"));
matchFailed(quote("'"));
}
}
if (result7 !== null) {
@ -2090,7 +2090,7 @@ PEG.parser = (function(){
} else {
var result6 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\\"));
matchFailed(quote("\\"));
}
}
if (result6 !== null) {
@ -2161,7 +2161,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("["));
matchFailed(quote("["));
}
}
if (result2 !== null) {
@ -2171,7 +2171,7 @@ PEG.parser = (function(){
} else {
var result10 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("^"));
matchFailed(quote("^"));
}
}
var result3 = result10 !== null ? result10 : '';
@ -2209,7 +2209,7 @@ PEG.parser = (function(){
} else {
var result5 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("]"));
matchFailed(quote("]"));
}
}
if (result5 !== null) {
@ -2238,14 +2238,10 @@ PEG.parser = (function(){
}
var result0 = result1 !== null
? (function(inverted, parts) {
partsConverted = PEG.ArrayUtils.map(parts, function(part) {
return part.data;
});
partsConverted = map(parts, function(part) { return part.data; });
rawText = "["
+ inverted
+ PEG.ArrayUtils.map(parts, function(part) {
return part.rawText;
}).join("")
+ map(parts, function(part) { return part.rawText; }).join("")
+ "]";
return {
@ -2287,7 +2283,7 @@ PEG.parser = (function(){
} else {
var result3 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("-"));
matchFailed(quote("-"));
}
}
if (result3 !== null) {
@ -2346,7 +2342,7 @@ PEG.parser = (function(){
return {
data: char_,
// FIXME: Get the raw text from the input directly.
rawText: PEG.RegExpUtils.quoteForClass(char_)
rawText: quoteForRegexpClass(char_)
};
})(result1)
: null;
@ -2429,7 +2425,7 @@ PEG.parser = (function(){
} else {
var result7 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("]"));
matchFailed(quote("]"));
}
}
if (result7 !== null) {
@ -2441,7 +2437,7 @@ PEG.parser = (function(){
} else {
var result6 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\\"));
matchFailed(quote("\\"));
}
}
if (result6 !== null) {
@ -2511,7 +2507,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\\"));
matchFailed(quote("\\"));
}
}
if (result2 !== null) {
@ -2528,7 +2524,7 @@ PEG.parser = (function(){
} else {
var result8 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("x"));
matchFailed(quote("x"));
}
}
if (result8 !== null) {
@ -2540,7 +2536,7 @@ PEG.parser = (function(){
} else {
var result7 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("u"));
matchFailed(quote("u"));
}
}
if (result7 !== null) {
@ -2623,7 +2619,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\\0"));
matchFailed(quote("\\0"));
}
}
if (result2 !== null) {
@ -2677,7 +2673,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\\x"));
matchFailed(quote("\\x"));
}
}
if (result2 !== null) {
@ -2729,7 +2725,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\\u"));
matchFailed(quote("\\u"));
}
}
if (result2 !== null) {
@ -2793,7 +2789,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\\"));
matchFailed(quote("\\"));
}
}
if (result2 !== null) {
@ -3067,7 +3063,7 @@ PEG.parser = (function(){
} else {
var result1 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("//"));
matchFailed(quote("//"));
}
}
if (result1 !== null) {
@ -3175,7 +3171,7 @@ PEG.parser = (function(){
} else {
var result1 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("/*"));
matchFailed(quote("/*"));
}
}
if (result1 !== null) {
@ -3190,7 +3186,7 @@ PEG.parser = (function(){
} else {
var result7 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("*/"));
matchFailed(quote("*/"));
}
}
context.reportMatchFailures = savedReportMatchFailuresVar0;
@ -3232,7 +3228,7 @@ PEG.parser = (function(){
} else {
var result7 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("*/"));
matchFailed(quote("*/"));
}
}
context.reportMatchFailures = savedReportMatchFailuresVar0;
@ -3270,7 +3266,7 @@ PEG.parser = (function(){
} else {
var result3 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("*/"));
matchFailed(quote("*/"));
}
}
if (result3 !== null) {
@ -3313,7 +3309,7 @@ PEG.parser = (function(){
} else {
var result5 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\n"));
matchFailed(quote("\n"));
}
}
if (result5 !== null) {
@ -3325,7 +3321,7 @@ PEG.parser = (function(){
} else {
var result4 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\r\n"));
matchFailed(quote("\r\n"));
}
}
if (result4 !== null) {
@ -3337,7 +3333,7 @@ PEG.parser = (function(){
} else {
var result3 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\r"));
matchFailed(quote("\r"));
}
}
if (result3 !== null) {
@ -3349,7 +3345,7 @@ PEG.parser = (function(){
} else {
var result2 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\u2028"));
matchFailed(quote("\u2028"));
}
}
if (result2 !== null) {
@ -3361,7 +3357,7 @@ PEG.parser = (function(){
} else {
var result1 = null;
if (context.reportMatchFailures) {
matchFailed(quoteString("\u2029"));
matchFailed(quote("\u2029"));
}
}
if (result1 !== null) {
@ -3462,7 +3458,7 @@ PEG.parser = (function(){
var expected = buildExpected(rightmostMatchFailuresExpected);
var actualPos = Math.max(pos, rightmostMatchFailuresPos);
var actual = actualPos < input.length
? quoteString(input.charAt(actualPos))
? quote(input.charAt(actualPos))
: 'end of input';
return 'Expected ' + expected + ' but ' + actual + ' found.';

14
src/parser.pegjs

@ -1,7 +1,7 @@
grammar
= __ initializer:initializer? rules:rule+ {
var rulesConverted = {};
PEG.ArrayUtils.each(rules, function(rule) { rulesConverted[rule.name] = rule; });
each(rules, function(rule) { rulesConverted[rule.name] = rule; });
return {
type: "grammar",
@ -35,7 +35,7 @@ expression
choice
= head:sequence tail:(slash sequence)* {
if (tail.length > 0) {
var alternatives = [head].concat(PEG.ArrayUtils.map(
var alternatives = [head].concat(map(
tail,
function(element) { return element[1]; }
));
@ -232,14 +232,10 @@ simpleSingleQuotedCharacter
class "character class"
= "[" inverted:"^"? parts:(classCharacterRange / classCharacter)* "]" __ {
partsConverted = PEG.ArrayUtils.map(parts, function(part) {
return part.data;
});
partsConverted = map(parts, function(part) { return part.data; });
rawText = "["
+ inverted
+ PEG.ArrayUtils.map(parts, function(part) {
return part.rawText;
}).join("")
+ map(parts, function(part) { return part.rawText; }).join("")
+ "]";
return {
@ -271,7 +267,7 @@ classCharacter
return {
data: char_,
// FIXME: Get the raw text from the input directly.
rawText: PEG.RegExpUtils.quoteForClass(char_)
rawText: quoteForRegexpClass(char_)
};
}

2
src/passes.js

@ -22,7 +22,7 @@ PEG.compiler.passes = [
function replaceInSubnodes(propertyName) {
return function(node, from, to) {
PEG.ArrayUtils.each(node[propertyName], function(node) {
each(node[propertyName], function(node) {
replace(node, from, to);
});
};

147
src/utils.js

@ -1,94 +1,75 @@
/* ===== PEG.ArrayUtils ===== */
/* Array manipulation utility functions. */
PEG.ArrayUtils = {
/*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
function contains(array, value) {
/*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
* Stupid IE does not have Array.prototype.indexOf, otherwise this function
* would be a one-liner.
*/
contains: function(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;
}
var length = array.length;
for (var i = 0; i < length; i++) {
if (array[i] === value) {
return true;
}
return false;
},
each: function(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++) {
callback(array[i]);
}
},
map: function(array, callback) {
var result = [];
var length = array.length;
for (var i = 0; i < length; i++) {
result[i] = callback(array[i]);
}
return result;
}
};
/* ===== PEG.StringUtils ===== */
/* String manipulation utility functions. */
return false;
}
PEG.StringUtils = {
/*
* Surrounds the string with quotes and escapes characters inside so that the
* result is a valid JavaScript string.
*
* The code needs to be in sync with th code template in the compilation
* function for "action" nodes.
*/
quote: function(s) {
/*
* ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
* literal except for the closing quote character, backslash, carriage
* return, line separator, paragraph separator, and line feed. Any character
* may appear in the form of an escape sequence.
*/
return '"' + s
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing quote character
.replace(/\r/g, '\\r') // carriage return
.replace(/\u2028/g, '\\u2028') // line separator
.replace(/\u2029/g, '\\u2029') // paragraph separator
.replace(/\n/g, '\\n') // line feed
+ '"';
function each(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++) {
callback(array[i]);
}
}
};
/* ===== PEG.RegExpUtils ===== */
/* RegExp manipulation utility functions. */
function map(array, callback) {
var result = [];
var length = array.length;
for (var i = 0; i < length; i++) {
result[i] = callback(array[i]);
}
return result;
}
PEG.RegExpUtils = {
/*
* Surrounds the string with quotes and escapes characters inside so that the
* result is a valid JavaScript string.
*
* The code needs to be in sync with th code template in the compilation
* function for "action" nodes.
*/
function quote(s) {
/*
* Escapes characters inside the string so that it can be used as a list of
* characters in a character class of a regular expression.
* 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.
*/
quoteForClass: function(s) {
/* Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1. */
return s
.replace(/\\/g, '\\\\') // backslash
.replace(/\0/g, '\\0') // null, IE needs this
.replace(/\//g, '\\/') // closing slash
.replace(/]/g, '\\]') // closing bracket
.replace(/-/g, '\\-') // dash
.replace(/\r/g, '\\r') // carriage return
.replace(/\u2028/g, '\\u2028') // line separator
.replace(/\u2029/g, '\\u2029') // paragraph separator
.replace(/\n/g, '\\n') // line feed
}
return '"' + s
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing quote character
.replace(/\r/g, '\\r') // carriage return
.replace(/\u2028/g, '\\u2028') // line separator
.replace(/\u2029/g, '\\u2029') // paragraph separator
.replace(/\n/g, '\\n') // line feed
+ '"';
};
/*
* 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. */
return s
.replace(/\\/g, '\\\\') // backslash
.replace(/\0/g, '\\0') // null, IE needs this
.replace(/\//g, '\\/') // closing slash
.replace(/]/g, '\\]') // closing bracket
.replace(/-/g, '\\-') // dash
.replace(/\r/g, '\\r') // carriage return
.replace(/\u2028/g, '\\u2028') // line separator
.replace(/\u2029/g, '\\u2029') // paragraph separator
.replace(/\n/g, '\\n') // line feed
}

72
test/compiler-test.js

@ -57,66 +57,6 @@ global.doesNotParseWithPos = function(parser, input, line, column) {
);
};
/* ===== PEG.ArrayUtils ===== */
module("PEG.ArrayUtils");
test("contains", function() {
ok(!PEG.ArrayUtils.contains([], 42));
ok(PEG.ArrayUtils.contains([1, 2, 3], 1));
ok(PEG.ArrayUtils.contains([1, 2, 3], 2));
ok(PEG.ArrayUtils.contains([1, 2, 3], 3));
ok(!PEG.ArrayUtils.contains([1, 2, 3], 42));
ok(!PEG.ArrayUtils.contains([1, 2, 3], "2")); // Does it use |===|?
});
test("each", function() {
var sum;
function increment(x) { sum += x; }
sum = 0;
PEG.ArrayUtils.each([], increment);
strictEqual(sum, 0);
sum = 0;
PEG.ArrayUtils.each([1, 2, 3], increment);
strictEqual(sum, 6);
});
test("map", function() {
function square(x) { return x * x; }
deepEqual(PEG.ArrayUtils.map([], square), []);
deepEqual(PEG.ArrayUtils.map([1, 2, 3], square), [1, 4, 9]);
});
/* ===== PEG.StringUtils ===== */
module("PEG.StringUtils");
test("quote", function() {
strictEqual(PEG.StringUtils.quote(""), '""');
strictEqual(PEG.StringUtils.quote("abcd"), '"abcd"');
strictEqual(
PEG.StringUtils.quote("\"\\\r\u2028\u2029\n\"\\\r\u2028\u2029\n"),
'"\\\"\\\\\\r\\u2028\\u2029\\n\\\"\\\\\\r\\u2028\\u2029\\n"'
);
});
/* ===== PEG.RegExpUtils ===== */
module("PEG.RegExpUtils");
test("quoteForClass", function() {
strictEqual(PEG.RegExpUtils.quoteForClass(""), '');
strictEqual(PEG.RegExpUtils.quoteForClass("abcd"), 'abcd');
strictEqual(
PEG.RegExpUtils.quoteForClass("\\\0/]-\r\u2028\u2029\n\\\0/]-\r\u2028\u2029\n"),
'\\\\\\0\\/\\]\\-\\r\\u2028\\u2029\\n\\\\\\0\\/\\]\\-\\r\\u2028\\u2029\\n'
);
});
/* ===== PEG ===== */
module("PEG");
@ -144,13 +84,13 @@ test("buildParser reports missing referenced rules", function() {
'start = missing { }'
];
PEG.ArrayUtils.each(grammars, function(grammar) {
for (var i = 0; i < grammars.length; i++) {
throws(
function() { PEG.buildParser(grammar); },
function() { PEG.buildParser(grammars[i]); },
PEG.GrammarError,
{ message: "Referenced rule \"missing\" does not exist." }
);
});
}
});
test("buildParser reports left recursion", function() {
@ -172,13 +112,13 @@ test("buildParser reports left recursion", function() {
'start = stop; stop = start'
];
PEG.ArrayUtils.each(grammars, function(grammar) {
for (var i = 0; i < grammars.length; i++) {
throws(
function() { PEG.buildParser(grammar); },
function() { PEG.buildParser(grammars[i]); },
PEG.GrammarError,
{ message: "Left recursion detected for rule \"start\"." }
);
});
}
});
test("buildParser allows custom start rule", function() {

Loading…
Cancel
Save