diff --git a/lib/compiler.js b/lib/compiler.js index d1aa173..cb348ab 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -202,6 +202,10 @@ PEG.Grammar.ZeroOrMore = function(element) { this._element = element; }; PEG.Grammar.OneOrMore = function(element) { this._element = element; }; +PEG.Grammar.AndPredicate = function(expression) { + this._expression = expression; +}; + PEG.Grammar.NotPredicate = function(expression) { this._expression = expression; }; @@ -245,6 +249,9 @@ PEG.Grammar.extendNodes("checkReferencedRulesExist", { OneOrMore: function(grammar) { this._element.checkReferencedRulesExist(grammar); }, + AndPredicate: + function(grammar) { this._expression.checkReferencedRulesExist(grammar); }, + NotPredicate: function(grammar) { this._expression.checkReferencedRulesExist(grammar); }, @@ -298,6 +305,11 @@ PEG.Grammar.extendNodes("checkNoLeftRecursion", { this._element.checkNoLeftRecursion(grammar, appliedRules); }, + AndPredicate: + function(grammar, appliedRules) { + this._expression.checkNoLeftRecursion(grammar, appliedRules); + }, + NotPredicate: function(grammar, appliedRules) { this._expression.checkNoLeftRecursion(grammar, appliedRules); @@ -917,6 +929,33 @@ PEG.Grammar.NotPredicate.prototype.compile = function(resultVar) { ); }; +PEG.Grammar.AndPredicate.prototype.compile = function(resultVar) { + var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos"); + var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar"); + var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + return PEG.Compiler.formatCode( + "var ${savedPosVar} = this._pos;", + "var ${savedReportMatchFailuresVar} = context.reportMatchFailures;", + "context.reportMatchFailures = false;", + "${expressionCode}", + "context.reportMatchFailures = ${savedReportMatchFailuresVar};", + "if (${expressionResultVar} !== null) {", + " var ${resultVar} = '';", + " this._pos = ${savedPosVar};", + "} else {", + " var ${resultVar} = null;", + "}", + { + expressionCode: this._expression.compile(expressionResultVar), + expressionResultVar: expressionResultVar, + savedPosVar: savedPosVar, + savedReportMatchFailuresVar: savedReportMatchFailuresVar, + resultVar: resultVar + } + ); +}; + PEG.Grammar.RuleRef.prototype.compile = function(resultVar) { return PEG.Compiler.formatCode( "var ${resultVar} = this.${ruleMethod}(context);", diff --git a/lib/metagrammar.js b/lib/metagrammar.js index 1fdd0e8..867c330 100644 --- a/lib/metagrammar.js +++ b/lib/metagrammar.js @@ -357,9 +357,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos6; } var result36 = result37 !== null - ? (function() { - return new PEG.Grammar.NotPredicate(new PEG.Grammar.NotPredicate((arguments[1]))); - }).apply(this, result37) + ? (function() { return new PEG.Grammar.AndPredicate((arguments[1])); }).apply(this, result37) : null; if (result36 !== null) { var result30 = result36; diff --git a/lib/metagrammar.pegjs b/lib/metagrammar.pegjs index ae5eea4..2d355cf 100644 --- a/lib/metagrammar.pegjs +++ b/lib/metagrammar.pegjs @@ -29,9 +29,7 @@ sequence / prefixed* { return $1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0]; } prefixed - : and suffixed { - return new PEG.Grammar.NotPredicate(new PEG.Grammar.NotPredicate($2)); - } + : and suffixed { return new PEG.Grammar.AndPredicate($2); } / not suffixed { return new PEG.Grammar.NotPredicate($2); } / suffixed diff --git a/test/compiler-test.js b/test/compiler-test.js index bbeb0b7..7cd8558 100644 --- a/test/compiler-test.js +++ b/test/compiler-test.js @@ -193,8 +193,8 @@ test("buildParser reports missing referenced rules", function() { 'start: "a" / "b" / missing', 'start: missing*', 'start: missing+', - 'start: !missing', 'start: &missing', + 'start: !missing', 'start: missing { }' ]; @@ -216,8 +216,8 @@ test("buildParser reports left recursion", function() { 'start: "a" / "b" / start', 'start: start*', 'start: start+', - 'start: !start', 'start: &start', + 'start: !start', 'start: start { }', /* Indirect */ diff --git a/test/metagrammar-test.js b/test/metagrammar-test.js index 9715799..293f675 100644 --- a/test/metagrammar-test.js +++ b/test/metagrammar-test.js @@ -137,10 +137,7 @@ with (PEG.Grammar) { /* Canonical prefixed is "!\"abcd\"". */ test("parses prefixed", function() { - grammarParserParses( - 'start: &"abcd"?', - oneRuleGrammar(new NotPredicate(new NotPredicate(choice))) - ); + grammarParserParses('start: &"abcd"?', oneRuleGrammar(new AndPredicate(choice))); grammarParserParses('start: !"abcd"?', oneRuleGrammar(new NotPredicate(choice))); grammarParserParses('start: "abcd"?', oneRuleGrammar(choice)); });