diff --git a/lib/compiler.js b/lib/compiler.js index 06ae83b..6a14076 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -43,6 +43,20 @@ PEG.buildParser = function(grammar, startRule) { /* Array manipulation utility functions. */ PEG.ArrayUtils = { + /* Like Python's |range|, but without |step|. */ + range: function(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; + }, + /* * The code needs to be in sync with a code template in * PEG.Grammar.Action.prototype.compile. @@ -194,6 +208,10 @@ PEG.Grammar.Any = function() {}; PEG.Grammar.Sequence = function(elements) { this._elements = elements; }; +PEG.Grammar.Sequence.prototype = { + getElements: function() { return this._elements; } +}; + PEG.Grammar.Choice = function(alternatives) { this._alternatives = alternatives; }; @@ -991,28 +1009,34 @@ PEG.Grammar.RuleRef.prototype.compile = function(resultVar) { }; PEG.Grammar.Action.prototype.compile = function(resultVar) { - var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); - - var actionCode = this._action.replace( - /\$(\d+)/g, - function(match, digits) { - return PEG.Compiler.formatCode( - "(arguments[${index}])", - { index: parseInt(digits) - 1 } - ); - } - ) - var actionFunction = PEG.Compiler.formatCode( - "function() { ${actionCode} }", - { actionCode: actionCode } - ); - /* * In case of sequences, we splat their elements into function arguments one * by one. Example: * - * start: "a" "b" "c" { alert(arguments.length) } // => "3" + * start: "a" "b" "c" { alert(arguments.length) } // => 3 + * + * This behavior is reflected in this function. */ + + var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + var paramCount = this._expression instanceof PEG.Grammar.Sequence + ? this._expression.getElements().length + : 1; + + var params = PEG.ArrayUtils.map( + PEG.ArrayUtils.range(1, paramCount + 1), + function(n) { return "$" + n; } + ).join(", "); + + var actionFunction = PEG.Compiler.formatCode( + "function(${params}) { ${action} }", + { + params: params, + action: this._action + } + ); + var invokeFunctionName = this._expression instanceof PEG.Grammar.Sequence ? "apply" : "call"; diff --git a/lib/metagrammar.js b/lib/metagrammar.js index d76f9d6..96c8134 100644 --- a/lib/metagrammar.js +++ b/lib/metagrammar.js @@ -81,9 +81,9 @@ PEG.grammarParser = (function(){ this._pos = savedPos0; } var result0 = result1 !== null - ? (function() { + ? (function($1, $2) { var result = {}; - PEG.ArrayUtils.each((arguments[1]), function(rule) { result[rule.getName()] = rule; }); + PEG.ArrayUtils.each($2, function(rule) { result[rule.getName()] = rule; }); return result; }).apply(this, result1) : null; @@ -153,8 +153,8 @@ PEG.grammarParser = (function(){ this._pos = savedPos1; } var result5 = result6 !== null - ? (function() { - return new PEG.Grammar.Rule((arguments[0]), (arguments[1]) !== "" ? (arguments[1]) : null, (arguments[3])); + ? (function($1, $2, $3, $4) { + return new PEG.Grammar.Rule($1, $2 !== "" ? $2 : null, $4); }).apply(this, result6) : null; @@ -246,13 +246,13 @@ PEG.grammarParser = (function(){ this._pos = savedPos2; } var result14 = result15 !== null - ? (function() { - return (arguments[1]).length > 0 - ? new PEG.Grammar.Choice([(arguments[0])].concat(PEG.ArrayUtils.map( - (arguments[1]), + ? (function($1, $2) { + return $2.length > 0 + ? new PEG.Grammar.Choice([$1].concat(PEG.ArrayUtils.map( + $2, function(element) { return element[1]; } ))) - : (arguments[0]); + : $1; }).apply(this, result15) : null; @@ -296,10 +296,10 @@ PEG.grammarParser = (function(){ this._pos = savedPos4; } var result25 = result26 !== null - ? (function() { + ? (function($1, $2) { return new PEG.Grammar.Action( - (arguments[0]).length != 1 ? new PEG.Grammar.Sequence((arguments[0])) : (arguments[0])[0], - (arguments[1]) + $1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0], + $2 ); }).apply(this, result26) : null; @@ -313,7 +313,7 @@ PEG.grammarParser = (function(){ var result24 = this._parse_prefixed(context); } var result22 = result23 !== null - ? (function() { return (arguments[0]).length != 1 ? new PEG.Grammar.Sequence((arguments[0])) : (arguments[0])[0]; }).call(this, result23) + ? (function($1) { return $1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0]; }).call(this, result23) : null; if (result22 !== null) { var result21 = result22; @@ -357,7 +357,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos6; } var result36 = result37 !== null - ? (function() { return new PEG.Grammar.AndPredicate((arguments[1])); }).apply(this, result37) + ? (function($1, $2) { return new PEG.Grammar.AndPredicate($2); }).apply(this, result37) : null; if (result36 !== null) { var result30 = result36; @@ -377,7 +377,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos5; } var result32 = result33 !== null - ? (function() { return new PEG.Grammar.NotPredicate((arguments[1])); }).apply(this, result33) + ? (function($1, $2) { return new PEG.Grammar.NotPredicate($2); }).apply(this, result33) : null; if (result32 !== null) { var result30 = result32; @@ -426,7 +426,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos9; } var result50 = result51 !== null - ? (function() { return new PEG.Grammar.Optional((arguments[0])); }).apply(this, result51) + ? (function($1, $2) { return new PEG.Grammar.Optional($1); }).apply(this, result51) : null; if (result50 !== null) { var result40 = result50; @@ -446,7 +446,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos8; } var result46 = result47 !== null - ? (function() { return new PEG.Grammar.ZeroOrMore((arguments[0])); }).apply(this, result47) + ? (function($1, $2) { return new PEG.Grammar.ZeroOrMore($1); }).apply(this, result47) : null; if (result46 !== null) { var result40 = result46; @@ -466,7 +466,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos7; } var result42 = result43 !== null - ? (function() { return new PEG.Grammar.OneOrMore((arguments[0])); }).apply(this, result43) + ? (function($1, $2) { return new PEG.Grammar.OneOrMore($1); }).apply(this, result43) : null; if (result42 !== null) { var result40 = result42; @@ -557,28 +557,28 @@ PEG.grammarParser = (function(){ this._pos = savedPos11; } var result66 = result67 !== null - ? (function() { return new PEG.Grammar.RuleRef((arguments[0])); }).apply(this, result67) + ? (function($1, $2) { return new PEG.Grammar.RuleRef($1); }).apply(this, result67) : null; if (result66 !== null) { var result54 = result66; } else { var result65 = this._parse_literal(context); var result64 = result65 !== null - ? (function() { return new PEG.Grammar.Literal((arguments[0])); }).call(this, result65) + ? (function($1) { return new PEG.Grammar.Literal($1); }).call(this, result65) : null; if (result64 !== null) { var result54 = result64; } else { var result63 = this._parse_dot(context); var result62 = result63 !== null - ? (function() { return new PEG.Grammar.Any(); }).call(this, result63) + ? (function($1) { return new PEG.Grammar.Any(); }).call(this, result63) : null; if (result62 !== null) { var result54 = result62; } else { var result61 = this._parse_class(context); var result60 = result61 !== null - ? (function() { return new PEG.Grammar.Class((arguments[0])); }).call(this, result61) + ? (function($1) { return new PEG.Grammar.Class($1); }).call(this, result61) : null; if (result60 !== null) { var result54 = result60; @@ -604,7 +604,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos10; } var result55 = result56 !== null - ? (function() { return (arguments[1]); }).apply(this, result56) + ? (function($1, $2, $3) { return $2; }).apply(this, result56) : null; if (result55 !== null) { var result54 = result55; @@ -652,7 +652,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos14; } var result75 = result76 !== null - ? (function() { return (arguments[0]).substr(1, (arguments[0]).length - 2); }).apply(this, result76) + ? (function($1, $2) { return $1.substr(1, $1.length - 2); }).apply(this, result76) : null; context.reportMatchFailures = savedReportMatchFailures; if (context.reportMatchFailures && result75 === null) { @@ -739,7 +739,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos15; } var result79 = result80 !== null - ? (function() { return (arguments[0]) + (arguments[1]).join("") + (arguments[2]); }).apply(this, result80) + ? (function($1, $2, $3) { return $1 + $2.join("") + $3; }).apply(this, result80) : null; @@ -773,7 +773,7 @@ PEG.grammarParser = (function(){ var result88 = null; } var result87 = result88 !== null - ? (function() { return (arguments[0]).join(""); }).call(this, result88) + ? (function($1) { return $1.join(""); }).call(this, result88) : null; @@ -806,7 +806,7 @@ PEG.grammarParser = (function(){ } } var result90 = result91 !== null - ? (function() { return (arguments[0]); }).call(this, result91) + ? (function($1) { return $1; }).call(this, result91) : null; @@ -852,7 +852,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos16; } var result92 = result93 !== null - ? (function() { return (arguments[0]); }).apply(this, result93) + ? (function($1, $2) { return $1; }).apply(this, result93) : null; @@ -898,7 +898,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos17; } var result96 = result97 !== null - ? (function() { return (arguments[0]); }).apply(this, result97) + ? (function($1, $2) { return $1; }).apply(this, result97) : null; @@ -944,7 +944,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos18; } var result100 = result101 !== null - ? (function() { return (arguments[0]); }).apply(this, result101) + ? (function($1, $2) { return $1; }).apply(this, result101) : null; @@ -990,7 +990,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos19; } var result104 = result105 !== null - ? (function() { return (arguments[0]); }).apply(this, result105) + ? (function($1, $2) { return $1; }).apply(this, result105) : null; @@ -1036,7 +1036,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos20; } var result108 = result109 !== null - ? (function() { return (arguments[0]); }).apply(this, result109) + ? (function($1, $2) { return $1; }).apply(this, result109) : null; @@ -1082,7 +1082,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos21; } var result112 = result113 !== null - ? (function() { return (arguments[0]); }).apply(this, result113) + ? (function($1, $2) { return $1; }).apply(this, result113) : null; @@ -1128,7 +1128,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos22; } var result116 = result117 !== null - ? (function() { return (arguments[0]); }).apply(this, result117) + ? (function($1, $2) { return $1; }).apply(this, result117) : null; @@ -1174,7 +1174,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos23; } var result120 = result121 !== null - ? (function() { return (arguments[0]); }).apply(this, result121) + ? (function($1, $2) { return $1; }).apply(this, result121) : null; @@ -1220,7 +1220,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos24; } var result124 = result125 !== null - ? (function() { return (arguments[0]); }).apply(this, result125) + ? (function($1, $2) { return $1; }).apply(this, result125) : null; @@ -1266,7 +1266,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos25; } var result128 = result129 !== null - ? (function() { return (arguments[0]); }).apply(this, result129) + ? (function($1, $2) { return $1; }).apply(this, result129) : null; @@ -1419,8 +1419,8 @@ PEG.grammarParser = (function(){ this._pos = savedPos26; } var result132 = result133 !== null - ? (function() { - return (arguments[0]) + (arguments[1]).join(""); + ? (function($1, $2, $3) { + return $1 + $2.join(""); }).apply(this, result133) : null; context.reportMatchFailures = savedReportMatchFailures; @@ -1472,7 +1472,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos27; } var result145 = result146 !== null - ? (function() { return (arguments[0]); }).apply(this, result146) + ? (function($1, $2) { return $1; }).apply(this, result146) : null; context.reportMatchFailures = savedReportMatchFailures; if (context.reportMatchFailures && result145 === null) { @@ -1539,7 +1539,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos28; } var result151 = result152 !== null - ? (function() { return (arguments[1]).join(""); }).apply(this, result152) + ? (function($1, $2, $3) { return $2.join(""); }).apply(this, result152) : null; @@ -1678,7 +1678,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos29; } var result164 = result165 !== null - ? (function() { return (arguments[1]); }).apply(this, result165) + ? (function($1, $2) { return $2; }).apply(this, result165) : null; @@ -1743,7 +1743,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos31; } var result172 = result173 !== null - ? (function() { return (arguments[1]).join(""); }).apply(this, result173) + ? (function($1, $2, $3) { return $2.join(""); }).apply(this, result173) : null; @@ -1882,7 +1882,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos32; } var result185 = result186 !== null - ? (function() { return (arguments[1]); }).apply(this, result186) + ? (function($1, $2) { return $2; }).apply(this, result186) : null; @@ -1989,8 +1989,8 @@ PEG.grammarParser = (function(){ this._pos = savedPos34; } var result193 = result194 !== null - ? (function() { - return (arguments[1]) + (arguments[2]).join(""); + ? (function($1, $2, $3, $4, $5) { + return $2 + $3.join(""); }).apply(this, result194) : null; context.reportMatchFailures = savedReportMatchFailures; @@ -2045,20 +2045,20 @@ PEG.grammarParser = (function(){ this._pos = savedPos35; } var result204 = result205 !== null - ? (function() { - if ((arguments[0]).charCodeAt(0) > (arguments[2]).charCodeAt(0)) { + ? (function($1, $2, $3) { + if ($1.charCodeAt(0) > $3.charCodeAt(0)) { throw new this.SyntaxError( "Invalid character range: " - + PEG.RegExpUtils.quoteForClass((arguments[0])) + + PEG.RegExpUtils.quoteForClass($1) + "-" - + PEG.RegExpUtils.quoteForClass((arguments[2])) + + PEG.RegExpUtils.quoteForClass($3) + "." ); } - return PEG.RegExpUtils.quoteForClass((arguments[0])) + return PEG.RegExpUtils.quoteForClass($1) + "-" - + PEG.RegExpUtils.quoteForClass((arguments[2])); + + PEG.RegExpUtils.quoteForClass($3); }).apply(this, result205) : null; @@ -2084,8 +2084,8 @@ PEG.grammarParser = (function(){ var result210 = this._parse_bracketDelimitedCharacter(context); var result209 = result210 !== null - ? (function() { - return PEG.RegExpUtils.quoteForClass((arguments[0])); + ? (function($1) { + return PEG.RegExpUtils.quoteForClass($1); }).call(this, result210) : null; @@ -2225,7 +2225,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos36; } var result218 = result219 !== null - ? (function() { return (arguments[1]); }).apply(this, result219) + ? (function($1, $2) { return $2; }).apply(this, result219) : null; @@ -2331,8 +2331,8 @@ PEG.grammarParser = (function(){ this._pos = savedPos38; } var result226 = result227 !== null - ? (function() { - return (arguments[2]) + ? (function($1, $2, $3) { + return $3 .replace("b", "\b") .replace("f", "\f") .replace("n", "\n") @@ -2395,7 +2395,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos40; } var result236 = result237 !== null - ? (function() { return "\0"; }).apply(this, result237) + ? (function($1, $2) { return "\0"; }).apply(this, result237) : null; @@ -2447,8 +2447,8 @@ PEG.grammarParser = (function(){ this._pos = savedPos42; } var result241 = result242 !== null - ? (function() { - return String.fromCharCode(parseInt("0x" + (arguments[1]) + (arguments[2]))); + ? (function($1, $2, $3) { + return String.fromCharCode(parseInt("0x" + $2 + $3)); }).apply(this, result242) : null; @@ -2513,8 +2513,8 @@ PEG.grammarParser = (function(){ this._pos = savedPos43; } var result246 = result247 !== null - ? (function() { - return String.fromCharCode(parseInt("0x" + (arguments[1]) + (arguments[2]) + (arguments[3]) + (arguments[4]))); + ? (function($1, $2, $3, $4, $5) { + return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5)); }).apply(this, result247) : null; @@ -2561,7 +2561,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos44; } var result253 = result254 !== null - ? (function() { return (arguments[1]); }).apply(this, result254) + ? (function($1, $2) { return $2; }).apply(this, result254) : null; diff --git a/test/compiler-test.js b/test/compiler-test.js index fb4899a..654ec58 100644 --- a/test/compiler-test.js +++ b/test/compiler-test.js @@ -61,6 +61,21 @@ global.doesNotParseWithPos = function(parser, input, line, column) { module("PEG.ArrayUtils"); +test("range", function() { + deepEqual(PEG.ArrayUtils.range(-1), []); + deepEqual(PEG.ArrayUtils.range(0), []); + deepEqual(PEG.ArrayUtils.range(1), [0]); + deepEqual(PEG.ArrayUtils.range(2), [0, 1]); + deepEqual(PEG.ArrayUtils.range(3), [0, 1, 2]); + + deepEqual(PEG.ArrayUtils.range(0, -1), []); + deepEqual(PEG.ArrayUtils.range(0, 0), []); + deepEqual(PEG.ArrayUtils.range(0, 1), [0]); + deepEqual(PEG.ArrayUtils.range(0, 2), [0, 1]); + deepEqual(PEG.ArrayUtils.range(0, 3), [0, 1, 2]); + deepEqual(PEG.ArrayUtils.range(-3, 0), [-3, -2, -1]); +}); + test("contains", function() { ok(!PEG.ArrayUtils.contains([], 42));