diff --git a/lib/compiler.js b/lib/compiler.js index cb348ab..a4008ef 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -198,6 +198,8 @@ PEG.Grammar.Choice = function(alternatives) { this._alternatives = alternatives; }; +PEG.Grammar.Optional = function(element) { this._element = element; }; + PEG.Grammar.ZeroOrMore = function(element) { this._element = element; }; PEG.Grammar.OneOrMore = function(element) { this._element = element; }; @@ -243,6 +245,9 @@ PEG.Grammar.extendNodes("checkReferencedRulesExist", { }); }, + Optional: + function(grammar) { this._element.checkReferencedRulesExist(grammar); }, + ZeroOrMore: function(grammar) { this._element.checkReferencedRulesExist(grammar); }, @@ -295,6 +300,11 @@ PEG.Grammar.extendNodes("checkNoLeftRecursion", { }); }, + Optional: + function(grammar, appliedRules) { + this._element.checkNoLeftRecursion(grammar, appliedRules); + }, + ZeroOrMore: function(grammar, appliedRules) { this._element.checkNoLeftRecursion(grammar, appliedRules); @@ -862,6 +872,20 @@ PEG.Grammar.Choice.prototype.compile = function(resultVar) { return code; }; +PEG.Grammar.Optional.prototype.compile = function(resultVar) { + var elementResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + return PEG.Compiler.formatCode( + "${elementCode}", + "var ${resultVar} = ${elementResultVar} !== null ? ${elementResultVar} : '';", + { + elementCode: this._element.compile(elementResultVar), + elementResultVar: elementResultVar, + resultVar: resultVar + } + ); +}; + PEG.Grammar.ZeroOrMore.prototype.compile = function(resultVar) { var elementResultVar = PEG.Compiler.generateUniqueIdentifier("result"); diff --git a/lib/metagrammar.js b/lib/metagrammar.js index 867c330..d76f9d6 100644 --- a/lib/metagrammar.js +++ b/lib/metagrammar.js @@ -426,9 +426,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos9; } var result50 = result51 !== null - ? (function() { - return new PEG.Grammar.Choice([(arguments[0]), new PEG.Grammar.Literal("")]); - }).apply(this, result51) + ? (function() { return new PEG.Grammar.Optional((arguments[0])); }).apply(this, result51) : null; if (result50 !== null) { var result40 = result50; @@ -1920,32 +1918,15 @@ PEG.grammarParser = (function(){ } if (result195 !== null) { if (this._input.substr(this._pos, 1) === "^") { - var result204 = "^"; + var result203 = "^"; this._pos += 1; } else { - var result204 = null; + var result203 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("^")); } } - if (result204 !== null) { - var result196 = result204; - } else { - if (this._input.substr(this._pos, 0) === "") { - var result203 = ""; - this._pos += 0; - } else { - var result203 = null; - if (context.reportMatchFailures) { - this._matchFailed(this._quoteString("")); - } - } - if (result203 !== null) { - var result196 = result203; - } else { - var result196 = null;; - }; - } + var result196 = result203 !== null ? result203 : ''; if (result196 !== null) { var result197 = []; var result202 = this._parse_classCharacterRange(context); @@ -2036,34 +2017,34 @@ PEG.grammarParser = (function(){ var savedPos35 = this._pos; - var result207 = this._parse_bracketDelimitedCharacter(context); - if (result207 !== null) { + var result206 = this._parse_bracketDelimitedCharacter(context); + if (result206 !== null) { if (this._input.substr(this._pos, 1) === "-") { - var result208 = "-"; + var result207 = "-"; this._pos += 1; } else { - var result208 = null; + var result207 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("-")); } } - if (result208 !== null) { - var result209 = this._parse_bracketDelimitedCharacter(context); - if (result209 !== null) { - var result206 = [result207, result208, result209]; + if (result207 !== null) { + var result208 = this._parse_bracketDelimitedCharacter(context); + if (result208 !== null) { + var result205 = [result206, result207, result208]; } else { - var result206 = null; + var result205 = null; this._pos = savedPos35; } } else { - var result206 = null; + var result205 = null; this._pos = savedPos35; } } else { - var result206 = null; + var result205 = null; this._pos = savedPos35; } - var result205 = result206 !== null + var result204 = result205 !== null ? (function() { if ((arguments[0]).charCodeAt(0) > (arguments[2]).charCodeAt(0)) { throw new this.SyntaxError( @@ -2078,16 +2059,16 @@ PEG.grammarParser = (function(){ return PEG.RegExpUtils.quoteForClass((arguments[0])) + "-" + PEG.RegExpUtils.quoteForClass((arguments[2])); - }).apply(this, result206) + }).apply(this, result205) : null; this._cache[cacheKey] = { nextPos: this._pos, - result: result205 + result: result204 }; - return result205; + return result204; }, _parse_classCharacter: function(context) { @@ -2101,20 +2082,20 @@ PEG.grammarParser = (function(){ var pos = this._pos; - var result211 = this._parse_bracketDelimitedCharacter(context); - var result210 = result211 !== null + var result210 = this._parse_bracketDelimitedCharacter(context); + var result209 = result210 !== null ? (function() { return PEG.RegExpUtils.quoteForClass((arguments[0])); - }).call(this, result211) + }).call(this, result210) : null; this._cache[cacheKey] = { nextPos: this._pos, - result: result210 + result: result209 }; - return result210; + return result209; }, _parse_bracketDelimitedCharacter: function(context) { @@ -2128,31 +2109,31 @@ PEG.grammarParser = (function(){ var pos = this._pos; - var result218 = this._parse_simpleBracketDelimitedCharacter(context); - if (result218 !== null) { - var result212 = result218; + var result217 = this._parse_simpleBracketDelimitedCharacter(context); + if (result217 !== null) { + var result211 = result217; } else { - var result217 = this._parse_simpleEscapeSequence(context); - if (result217 !== null) { - var result212 = result217; + var result216 = this._parse_simpleEscapeSequence(context); + if (result216 !== null) { + var result211 = result216; } else { - var result216 = this._parse_zeroEscapeSequence(context); - if (result216 !== null) { - var result212 = result216; + var result215 = this._parse_zeroEscapeSequence(context); + if (result215 !== null) { + var result211 = result215; } else { - var result215 = this._parse_hexEscapeSequence(context); - if (result215 !== null) { - var result212 = result215; + var result214 = this._parse_hexEscapeSequence(context); + if (result214 !== null) { + var result211 = result214; } else { - var result214 = this._parse_unicodeEscapeSequence(context); - if (result214 !== null) { - var result212 = result214; + var result213 = this._parse_unicodeEscapeSequence(context); + if (result213 !== null) { + var result211 = result213; } else { - var result213 = this._parse_eolEscapeSequence(context); - if (result213 !== null) { - var result212 = result213; + var result212 = this._parse_eolEscapeSequence(context); + if (result212 !== null) { + var result211 = result212; } else { - var result212 = null;; + var result211 = null;; }; }; }; @@ -2164,9 +2145,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result212 + result: result211 }; - return result212; + return result211; }, _parse_simpleBracketDelimitedCharacter: function(context) { @@ -2185,75 +2166,75 @@ PEG.grammarParser = (function(){ var savedReportMatchFailuresVar3 = context.reportMatchFailures; context.reportMatchFailures = false; if (this._input.substr(this._pos, 1) === "]") { - var result226 = "]"; + var result225 = "]"; this._pos += 1; } else { - var result226 = null; + var result225 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("]")); } } - if (result226 !== null) { - var result223 = result226; + if (result225 !== null) { + var result222 = result225; } else { if (this._input.substr(this._pos, 1) === "\\") { - var result225 = "\\"; + var result224 = "\\"; this._pos += 1; } else { - var result225 = null; + var result224 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\\")); } } - if (result225 !== null) { - var result223 = result225; + if (result224 !== null) { + var result222 = result224; } else { - var result224 = this._parse_eolChar(context); - if (result224 !== null) { - var result223 = result224; + var result223 = this._parse_eolChar(context); + if (result223 !== null) { + var result222 = result223; } else { - var result223 = null;; + var result222 = null;; }; }; } context.reportMatchFailures = savedReportMatchFailuresVar3; - if (result223 === null) { - var result221 = ''; + if (result222 === null) { + var result220 = ''; } else { - var result221 = null; + var result220 = null; this._pos = savedPos37; } - if (result221 !== null) { + if (result220 !== null) { if (this._input.length > this._pos) { - var result222 = this._input.charAt(this._pos); + var result221 = this._input.charAt(this._pos); this._pos++; } else { - var result222 = null; + var result221 = null; if (context.reportMatchFailures) { this._matchFailed('any character'); } } - if (result222 !== null) { - var result220 = [result221, result222]; + if (result221 !== null) { + var result219 = [result220, result221]; } else { - var result220 = null; + var result219 = null; this._pos = savedPos36; } } else { - var result220 = null; + var result219 = null; this._pos = savedPos36; } - var result219 = result220 !== null - ? (function() { return (arguments[1]); }).apply(this, result220) + var result218 = result219 !== null + ? (function() { return (arguments[1]); }).apply(this, result219) : null; this._cache[cacheKey] = { nextPos: this._pos, - result: result219 + result: result218 }; - return result219; + return result218; }, _parse_simpleEscapeSequence: function(context) { @@ -2269,87 +2250,87 @@ PEG.grammarParser = (function(){ var savedPos38 = this._pos; if (this._input.substr(this._pos, 1) === "\\") { - var result229 = "\\"; + var result228 = "\\"; this._pos += 1; } else { - var result229 = null; + var result228 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\\")); } } - if (result229 !== null) { + if (result228 !== null) { var savedPos39 = this._pos; var savedReportMatchFailuresVar4 = context.reportMatchFailures; context.reportMatchFailures = false; - var result236 = this._parse_digit(context); - if (result236 !== null) { - var result232 = result236; + var result235 = this._parse_digit(context); + if (result235 !== null) { + var result231 = result235; } else { if (this._input.substr(this._pos, 1) === "x") { - var result235 = "x"; + var result234 = "x"; this._pos += 1; } else { - var result235 = null; + var result234 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("x")); } } - if (result235 !== null) { - var result232 = result235; + if (result234 !== null) { + var result231 = result234; } else { if (this._input.substr(this._pos, 1) === "u") { - var result234 = "u"; + var result233 = "u"; this._pos += 1; } else { - var result234 = null; + var result233 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("u")); } } - if (result234 !== null) { - var result232 = result234; + if (result233 !== null) { + var result231 = result233; } else { - var result233 = this._parse_eolChar(context); - if (result233 !== null) { - var result232 = result233; + var result232 = this._parse_eolChar(context); + if (result232 !== null) { + var result231 = result232; } else { - var result232 = null;; + var result231 = null;; }; }; }; } context.reportMatchFailures = savedReportMatchFailuresVar4; - if (result232 === null) { - var result230 = ''; + if (result231 === null) { + var result229 = ''; } else { - var result230 = null; + var result229 = null; this._pos = savedPos39; } - if (result230 !== null) { + if (result229 !== null) { if (this._input.length > this._pos) { - var result231 = this._input.charAt(this._pos); + var result230 = this._input.charAt(this._pos); this._pos++; } else { - var result231 = null; + var result230 = null; if (context.reportMatchFailures) { this._matchFailed('any character'); } } - if (result231 !== null) { - var result228 = [result229, result230, result231]; + if (result230 !== null) { + var result227 = [result228, result229, result230]; } else { - var result228 = null; + var result227 = null; this._pos = savedPos38; } } else { - var result228 = null; + var result227 = null; this._pos = savedPos38; } } else { - var result228 = null; + var result227 = null; this._pos = savedPos38; } - var result227 = result228 !== null + var result226 = result227 !== null ? (function() { return (arguments[2]) .replace("b", "\b") @@ -2358,16 +2339,16 @@ PEG.grammarParser = (function(){ .replace("r", "\r") .replace("t", "\t") .replace("v", "\x0B") // IE does not recognize "\v". - }).apply(this, result228) + }).apply(this, result227) : null; this._cache[cacheKey] = { nextPos: this._pos, - result: result227 + result: result226 }; - return result227; + return result226; }, _parse_zeroEscapeSequence: function(context) { @@ -2383,47 +2364,47 @@ PEG.grammarParser = (function(){ var savedPos40 = this._pos; if (this._input.substr(this._pos, 2) === "\\0") { - var result239 = "\\0"; + var result238 = "\\0"; this._pos += 2; } else { - var result239 = null; + var result238 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\\0")); } } - if (result239 !== null) { + if (result238 !== null) { var savedPos41 = this._pos; var savedReportMatchFailuresVar5 = context.reportMatchFailures; context.reportMatchFailures = false; - var result241 = this._parse_digit(context); + var result240 = this._parse_digit(context); context.reportMatchFailures = savedReportMatchFailuresVar5; - if (result241 === null) { - var result240 = ''; + if (result240 === null) { + var result239 = ''; } else { - var result240 = null; + var result239 = null; this._pos = savedPos41; } - if (result240 !== null) { - var result238 = [result239, result240]; + if (result239 !== null) { + var result237 = [result238, result239]; } else { - var result238 = null; + var result237 = null; this._pos = savedPos40; } } else { - var result238 = null; + var result237 = null; this._pos = savedPos40; } - var result237 = result238 !== null - ? (function() { return "\0"; }).apply(this, result238) + var result236 = result237 !== null + ? (function() { return "\0"; }).apply(this, result237) : null; this._cache[cacheKey] = { nextPos: this._pos, - result: result237 + result: result236 }; - return result237; + return result236; }, _parse_hexEscapeSequence: function(context) { @@ -2439,45 +2420,45 @@ PEG.grammarParser = (function(){ var savedPos42 = this._pos; if (this._input.substr(this._pos, 2) === "\\x") { - var result244 = "\\x"; + var result243 = "\\x"; this._pos += 2; } else { - var result244 = null; + var result243 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\\x")); } } - if (result244 !== null) { - var result245 = this._parse_hexDigit(context); - if (result245 !== null) { - var result246 = this._parse_hexDigit(context); - if (result246 !== null) { - var result243 = [result244, result245, result246]; + if (result243 !== null) { + var result244 = this._parse_hexDigit(context); + if (result244 !== null) { + var result245 = this._parse_hexDigit(context); + if (result245 !== null) { + var result242 = [result243, result244, result245]; } else { - var result243 = null; + var result242 = null; this._pos = savedPos42; } } else { - var result243 = null; + var result242 = null; this._pos = savedPos42; } } else { - var result243 = null; + var result242 = null; this._pos = savedPos42; } - var result242 = result243 !== null + var result241 = result242 !== null ? (function() { return String.fromCharCode(parseInt("0x" + (arguments[1]) + (arguments[2]))); - }).apply(this, result243) + }).apply(this, result242) : null; this._cache[cacheKey] = { nextPos: this._pos, - result: result242 + result: result241 }; - return result242; + return result241; }, _parse_unicodeEscapeSequence: function(context) { @@ -2493,57 +2474,57 @@ PEG.grammarParser = (function(){ var savedPos43 = this._pos; if (this._input.substr(this._pos, 2) === "\\u") { - var result249 = "\\u"; + var result248 = "\\u"; this._pos += 2; } else { - var result249 = null; + var result248 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\\u")); } } - if (result249 !== null) { - var result250 = this._parse_hexDigit(context); - if (result250 !== null) { - var result251 = this._parse_hexDigit(context); - if (result251 !== null) { - var result252 = this._parse_hexDigit(context); - if (result252 !== null) { - var result253 = this._parse_hexDigit(context); - if (result253 !== null) { - var result248 = [result249, result250, result251, result252, result253]; + if (result248 !== null) { + var result249 = this._parse_hexDigit(context); + if (result249 !== null) { + var result250 = this._parse_hexDigit(context); + if (result250 !== null) { + var result251 = this._parse_hexDigit(context); + if (result251 !== null) { + var result252 = this._parse_hexDigit(context); + if (result252 !== null) { + var result247 = [result248, result249, result250, result251, result252]; } else { - var result248 = null; + var result247 = null; this._pos = savedPos43; } } else { - var result248 = null; + var result247 = null; this._pos = savedPos43; } } else { - var result248 = null; + var result247 = null; this._pos = savedPos43; } } else { - var result248 = null; + var result247 = null; this._pos = savedPos43; } } else { - var result248 = null; + var result247 = null; this._pos = savedPos43; } - var result247 = result248 !== null + var result246 = result247 !== null ? (function() { return String.fromCharCode(parseInt("0x" + (arguments[1]) + (arguments[2]) + (arguments[3]) + (arguments[4]))); - }).apply(this, result248) + }).apply(this, result247) : null; this._cache[cacheKey] = { nextPos: this._pos, - result: result247 + result: result246 }; - return result247; + return result246; }, _parse_eolEscapeSequence: function(context) { @@ -2559,37 +2540,37 @@ PEG.grammarParser = (function(){ var savedPos44 = this._pos; if (this._input.substr(this._pos, 1) === "\\") { - var result256 = "\\"; + var result255 = "\\"; this._pos += 1; } else { - var result256 = null; + var result255 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\\")); } } - if (result256 !== null) { - var result257 = this._parse_eol(context); - if (result257 !== null) { - var result255 = [result256, result257]; + if (result255 !== null) { + var result256 = this._parse_eol(context); + if (result256 !== null) { + var result254 = [result255, result256]; } else { - var result255 = null; + var result254 = null; this._pos = savedPos44; } } else { - var result255 = null; + var result254 = null; this._pos = savedPos44; } - var result254 = result255 !== null - ? (function() { return (arguments[1]); }).apply(this, result255) + var result253 = result254 !== null + ? (function() { return (arguments[1]); }).apply(this, result254) : null; this._cache[cacheKey] = { nextPos: this._pos, - result: result254 + result: result253 }; - return result254; + return result253; }, _parse_digit: function(context) { @@ -2604,10 +2585,10 @@ PEG.grammarParser = (function(){ if (this._input.substr(this._pos).match(/^[0-9]/) !== null) { - var result258 = this._input.charAt(this._pos); + var result257 = this._input.charAt(this._pos); this._pos++; } else { - var result258 = null; + var result257 = null; if (context.reportMatchFailures) { this._matchFailed('[' + "0-9" + ']'); } @@ -2617,9 +2598,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result258 + result: result257 }; - return result258; + return result257; }, _parse_hexDigit: function(context) { @@ -2634,10 +2615,10 @@ PEG.grammarParser = (function(){ if (this._input.substr(this._pos).match(/^[0-9a-fA-F]/) !== null) { - var result259 = this._input.charAt(this._pos); + var result258 = this._input.charAt(this._pos); this._pos++; } else { - var result259 = null; + var result258 = null; if (context.reportMatchFailures) { this._matchFailed('[' + "0-9a-fA-F" + ']'); } @@ -2647,9 +2628,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result259 + result: result258 }; - return result259; + return result258; }, _parse_letter: function(context) { @@ -2663,15 +2644,15 @@ PEG.grammarParser = (function(){ var pos = this._pos; - var result262 = this._parse_lowerCaseLetter(context); - if (result262 !== null) { - var result260 = result262; + var result261 = this._parse_lowerCaseLetter(context); + if (result261 !== null) { + var result259 = result261; } else { - var result261 = this._parse_upperCaseLetter(context); - if (result261 !== null) { - var result260 = result261; + var result260 = this._parse_upperCaseLetter(context); + if (result260 !== null) { + var result259 = result260; } else { - var result260 = null;; + var result259 = null;; }; } @@ -2679,9 +2660,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result260 + result: result259 }; - return result260; + return result259; }, _parse_lowerCaseLetter: function(context) { @@ -2696,10 +2677,10 @@ PEG.grammarParser = (function(){ if (this._input.substr(this._pos).match(/^[a-z]/) !== null) { - var result263 = this._input.charAt(this._pos); + var result262 = this._input.charAt(this._pos); this._pos++; } else { - var result263 = null; + var result262 = null; if (context.reportMatchFailures) { this._matchFailed('[' + "a-z" + ']'); } @@ -2709,9 +2690,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result263 + result: result262 }; - return result263; + return result262; }, _parse_upperCaseLetter: function(context) { @@ -2726,10 +2707,10 @@ PEG.grammarParser = (function(){ if (this._input.substr(this._pos).match(/^[A-Z]/) !== null) { - var result264 = this._input.charAt(this._pos); + var result263 = this._input.charAt(this._pos); this._pos++; } else { - var result264 = null; + var result263 = null; if (context.reportMatchFailures) { this._matchFailed('[' + "A-Z" + ']'); } @@ -2739,9 +2720,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result264 + result: result263 }; - return result264; + return result263; }, _parse___: function(context) { @@ -2755,38 +2736,38 @@ PEG.grammarParser = (function(){ var pos = this._pos; - var result265 = []; - var result269 = this._parse_whitespace(context); - if (result269 !== null) { - var result266 = result269; + var result264 = []; + var result268 = this._parse_whitespace(context); + if (result268 !== null) { + var result265 = result268; } else { - var result268 = this._parse_eol(context); - if (result268 !== null) { - var result266 = result268; + var result267 = this._parse_eol(context); + if (result267 !== null) { + var result265 = result267; } else { - var result267 = this._parse_comment(context); - if (result267 !== null) { - var result266 = result267; + var result266 = this._parse_comment(context); + if (result266 !== null) { + var result265 = result266; } else { - var result266 = null;; + var result265 = null;; }; }; } - while (result266 !== null) { - result265.push(result266); - var result269 = this._parse_whitespace(context); - if (result269 !== null) { - var result266 = result269; + while (result265 !== null) { + result264.push(result265); + var result268 = this._parse_whitespace(context); + if (result268 !== null) { + var result265 = result268; } else { - var result268 = this._parse_eol(context); - if (result268 !== null) { - var result266 = result268; + var result267 = this._parse_eol(context); + if (result267 !== null) { + var result265 = result267; } else { - var result267 = this._parse_comment(context); - if (result267 !== null) { - var result266 = result267; + var result266 = this._parse_comment(context); + if (result266 !== null) { + var result265 = result266; } else { - var result266 = null;; + var result265 = null;; }; }; } @@ -2796,9 +2777,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result265 + result: result264 }; - return result265; + return result264; }, _parse_comment: function(context) { @@ -2813,27 +2794,27 @@ PEG.grammarParser = (function(){ var savedReportMatchFailures = context.reportMatchFailures; context.reportMatchFailures = false; - var result272 = this._parse_singleLineComment(context); - if (result272 !== null) { - var result270 = result272; + var result271 = this._parse_singleLineComment(context); + if (result271 !== null) { + var result269 = result271; } else { - var result271 = this._parse_multiLineComment(context); - if (result271 !== null) { - var result270 = result271; + var result270 = this._parse_multiLineComment(context); + if (result270 !== null) { + var result269 = result270; } else { - var result270 = null;; + var result269 = null;; }; } context.reportMatchFailures = savedReportMatchFailures; - if (context.reportMatchFailures && result270 === null) { + if (context.reportMatchFailures && result269 === null) { this._matchFailed("comment"); } this._cache[cacheKey] = { nextPos: this._pos, - result: result270 + result: result269 }; - return result270; + return result269; }, _parse_singleLineComment: function(context) { @@ -2849,91 +2830,91 @@ PEG.grammarParser = (function(){ var savedPos45 = this._pos; if (this._input.substr(this._pos, 2) === "//") { - var result274 = "//"; + var result273 = "//"; this._pos += 2; } else { - var result274 = null; + var result273 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("//")); } } - if (result274 !== null) { - var result275 = []; + if (result273 !== null) { + var result274 = []; var savedPos46 = this._pos; var savedPos47 = this._pos; var savedReportMatchFailuresVar6 = context.reportMatchFailures; context.reportMatchFailures = false; - var result279 = this._parse_eolChar(context); + var result278 = this._parse_eolChar(context); context.reportMatchFailures = savedReportMatchFailuresVar6; - if (result279 === null) { - var result277 = ''; + if (result278 === null) { + var result276 = ''; } else { - var result277 = null; + var result276 = null; this._pos = savedPos47; } - if (result277 !== null) { + if (result276 !== null) { if (this._input.length > this._pos) { - var result278 = this._input.charAt(this._pos); + var result277 = this._input.charAt(this._pos); this._pos++; } else { - var result278 = null; + var result277 = null; if (context.reportMatchFailures) { this._matchFailed('any character'); } } - if (result278 !== null) { - var result276 = [result277, result278]; + if (result277 !== null) { + var result275 = [result276, result277]; } else { - var result276 = null; + var result275 = null; this._pos = savedPos46; } } else { - var result276 = null; + var result275 = null; this._pos = savedPos46; } - while (result276 !== null) { - result275.push(result276); + while (result275 !== null) { + result274.push(result275); var savedPos46 = this._pos; var savedPos47 = this._pos; var savedReportMatchFailuresVar6 = context.reportMatchFailures; context.reportMatchFailures = false; - var result279 = this._parse_eolChar(context); + var result278 = this._parse_eolChar(context); context.reportMatchFailures = savedReportMatchFailuresVar6; - if (result279 === null) { - var result277 = ''; + if (result278 === null) { + var result276 = ''; } else { - var result277 = null; + var result276 = null; this._pos = savedPos47; } - if (result277 !== null) { + if (result276 !== null) { if (this._input.length > this._pos) { - var result278 = this._input.charAt(this._pos); + var result277 = this._input.charAt(this._pos); this._pos++; } else { - var result278 = null; + var result277 = null; if (context.reportMatchFailures) { this._matchFailed('any character'); } } - if (result278 !== null) { - var result276 = [result277, result278]; + if (result277 !== null) { + var result275 = [result276, result277]; } else { - var result276 = null; + var result275 = null; this._pos = savedPos46; } } else { - var result276 = null; + var result275 = null; this._pos = savedPos46; } } - if (result275 !== null) { - var result273 = [result274, result275]; + if (result274 !== null) { + var result272 = [result273, result274]; } else { - var result273 = null; + var result272 = null; this._pos = savedPos45; } } else { - var result273 = null; + var result272 = null; this._pos = savedPos45; } @@ -2941,9 +2922,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result273 + result: result272 }; - return result273; + return result272; }, _parse_multiLineComment: function(context) { @@ -2959,121 +2940,121 @@ PEG.grammarParser = (function(){ var savedPos48 = this._pos; if (this._input.substr(this._pos, 2) === "/*") { - var result281 = "/*"; + var result280 = "/*"; this._pos += 2; } else { - var result281 = null; + var result280 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("/*")); } } - if (result281 !== null) { - var result282 = []; + if (result280 !== null) { + var result281 = []; var savedPos49 = this._pos; var savedPos50 = this._pos; var savedReportMatchFailuresVar7 = context.reportMatchFailures; context.reportMatchFailures = false; if (this._input.substr(this._pos, 2) === "*/") { - var result287 = "*/"; + var result286 = "*/"; this._pos += 2; } else { - var result287 = null; + var result286 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("*/")); } } context.reportMatchFailures = savedReportMatchFailuresVar7; - if (result287 === null) { - var result285 = ''; + if (result286 === null) { + var result284 = ''; } else { - var result285 = null; + var result284 = null; this._pos = savedPos50; } - if (result285 !== null) { + if (result284 !== null) { if (this._input.length > this._pos) { - var result286 = this._input.charAt(this._pos); + var result285 = this._input.charAt(this._pos); this._pos++; } else { - var result286 = null; + var result285 = null; if (context.reportMatchFailures) { this._matchFailed('any character'); } } - if (result286 !== null) { - var result284 = [result285, result286]; + if (result285 !== null) { + var result283 = [result284, result285]; } else { - var result284 = null; + var result283 = null; this._pos = savedPos49; } } else { - var result284 = null; + var result283 = null; this._pos = savedPos49; } - while (result284 !== null) { - result282.push(result284); + while (result283 !== null) { + result281.push(result283); var savedPos49 = this._pos; var savedPos50 = this._pos; var savedReportMatchFailuresVar7 = context.reportMatchFailures; context.reportMatchFailures = false; if (this._input.substr(this._pos, 2) === "*/") { - var result287 = "*/"; + var result286 = "*/"; this._pos += 2; } else { - var result287 = null; + var result286 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("*/")); } } context.reportMatchFailures = savedReportMatchFailuresVar7; - if (result287 === null) { - var result285 = ''; + if (result286 === null) { + var result284 = ''; } else { - var result285 = null; + var result284 = null; this._pos = savedPos50; } - if (result285 !== null) { + if (result284 !== null) { if (this._input.length > this._pos) { - var result286 = this._input.charAt(this._pos); + var result285 = this._input.charAt(this._pos); this._pos++; } else { - var result286 = null; + var result285 = null; if (context.reportMatchFailures) { this._matchFailed('any character'); } } - if (result286 !== null) { - var result284 = [result285, result286]; + if (result285 !== null) { + var result283 = [result284, result285]; } else { - var result284 = null; + var result283 = null; this._pos = savedPos49; } } else { - var result284 = null; + var result283 = null; this._pos = savedPos49; } } - if (result282 !== null) { + if (result281 !== null) { if (this._input.substr(this._pos, 2) === "*/") { - var result283 = "*/"; + var result282 = "*/"; this._pos += 2; } else { - var result283 = null; + var result282 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("*/")); } } - if (result283 !== null) { - var result280 = [result281, result282, result283]; + if (result282 !== null) { + var result279 = [result280, result281, result282]; } else { - var result280 = null; + var result279 = null; this._pos = savedPos48; } } else { - var result280 = null; + var result279 = null; this._pos = savedPos48; } } else { - var result280 = null; + var result279 = null; this._pos = savedPos48; } @@ -3081,9 +3062,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result280 + result: result279 }; - return result280; + return result279; }, _parse_eol: function(context) { @@ -3099,81 +3080,81 @@ PEG.grammarParser = (function(){ var savedReportMatchFailures = context.reportMatchFailures; context.reportMatchFailures = false; if (this._input.substr(this._pos, 1) === "\n") { - var result293 = "\n"; + var result292 = "\n"; this._pos += 1; } else { - var result293 = null; + var result292 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\n")); } } - if (result293 !== null) { - var result288 = result293; + if (result292 !== null) { + var result287 = result292; } else { if (this._input.substr(this._pos, 2) === "\r\n") { - var result292 = "\r\n"; + var result291 = "\r\n"; this._pos += 2; } else { - var result292 = null; + var result291 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\r\n")); } } - if (result292 !== null) { - var result288 = result292; + if (result291 !== null) { + var result287 = result291; } else { if (this._input.substr(this._pos, 1) === "\r") { - var result291 = "\r"; + var result290 = "\r"; this._pos += 1; } else { - var result291 = null; + var result290 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\r")); } } - if (result291 !== null) { - var result288 = result291; + if (result290 !== null) { + var result287 = result290; } else { if (this._input.substr(this._pos, 1) === "\u2028") { - var result290 = "\u2028"; + var result289 = "\u2028"; this._pos += 1; } else { - var result290 = null; + var result289 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\u2028")); } } - if (result290 !== null) { - var result288 = result290; + if (result289 !== null) { + var result287 = result289; } else { if (this._input.substr(this._pos, 1) === "\u2029") { - var result289 = "\u2029"; + var result288 = "\u2029"; this._pos += 1; } else { - var result289 = null; + var result288 = null; if (context.reportMatchFailures) { this._matchFailed(this._quoteString("\u2029")); } } - if (result289 !== null) { - var result288 = result289; + if (result288 !== null) { + var result287 = result288; } else { - var result288 = null;; + var result287 = null;; }; }; }; }; } context.reportMatchFailures = savedReportMatchFailures; - if (context.reportMatchFailures && result288 === null) { + if (context.reportMatchFailures && result287 === null) { this._matchFailed("end of line"); } this._cache[cacheKey] = { nextPos: this._pos, - result: result288 + result: result287 }; - return result288; + return result287; }, _parse_eolChar: function(context) { @@ -3188,10 +3169,10 @@ PEG.grammarParser = (function(){ if (this._input.substr(this._pos).match(/^[\n\r\u2028\u2029]/) !== null) { - var result294 = this._input.charAt(this._pos); + var result293 = this._input.charAt(this._pos); this._pos++; } else { - var result294 = null; + var result293 = null; if (context.reportMatchFailures) { this._matchFailed('[' + "\\n\\r\\u2028\\u2029" + ']'); } @@ -3201,9 +3182,9 @@ PEG.grammarParser = (function(){ this._cache[cacheKey] = { nextPos: this._pos, - result: result294 + result: result293 }; - return result294; + return result293; }, _parse_whitespace: function(context) { @@ -3219,24 +3200,24 @@ PEG.grammarParser = (function(){ var savedReportMatchFailures = context.reportMatchFailures; context.reportMatchFailures = false; if (this._input.substr(this._pos).match(/^[   ᠎ -    ]/) !== null) { - var result295 = this._input.charAt(this._pos); + var result294 = this._input.charAt(this._pos); this._pos++; } else { - var result295 = null; + var result294 = null; if (context.reportMatchFailures) { this._matchFailed('[' + "   ᠎ -    " + ']'); } } context.reportMatchFailures = savedReportMatchFailures; - if (context.reportMatchFailures && result295 === null) { + if (context.reportMatchFailures && result294 === null) { this._matchFailed("whitespace"); } this._cache[cacheKey] = { nextPos: this._pos, - result: result295 + result: result294 }; - return result295; + return result294; }, /* diff --git a/lib/metagrammar.pegjs b/lib/metagrammar.pegjs index 2d355cf..82acfed 100644 --- a/lib/metagrammar.pegjs +++ b/lib/metagrammar.pegjs @@ -34,11 +34,9 @@ prefixed / suffixed suffixed - : primary question { - return new PEG.Grammar.Choice([$1, new PEG.Grammar.Literal("")]); - } - / primary star { return new PEG.Grammar.ZeroOrMore($1); } - / primary plus { return new PEG.Grammar.OneOrMore($1); } + : primary question { return new PEG.Grammar.Optional($1); } + / primary star { return new PEG.Grammar.ZeroOrMore($1); } + / primary plus { return new PEG.Grammar.OneOrMore($1); } / primary primary diff --git a/test/compiler-test.js b/test/compiler-test.js index 7cd8558..fb4899a 100644 --- a/test/compiler-test.js +++ b/test/compiler-test.js @@ -191,6 +191,7 @@ test("buildParser reports missing referenced rules", function() { 'start: "a" "b" missing', 'start: missing / "a" / "b"', 'start: "a" / "b" / missing', + 'start: missing?', 'start: missing*', 'start: missing+', 'start: &missing', @@ -214,6 +215,7 @@ test("buildParser reports left recursion", function() { 'start: start "a" "b"', 'start: start / "a" / "b"', 'start: "a" / "b" / start', + 'start: start?', 'start: start*', 'start: start+', 'start: &start', diff --git a/test/metagrammar-test.js b/test/metagrammar-test.js index 293f675..e73d159 100644 --- a/test/metagrammar-test.js +++ b/test/metagrammar-test.js @@ -17,12 +17,11 @@ global.grammarParserDoesNotParse = function(input) { module("Grammar Parser"); with (PEG.Grammar) { - var literalEmpty = new Literal(""); var literalAbcd = new Literal("abcd"); var literalEfgh = new Literal("efgh"); var literalIjkl = new Literal("ijkl"); - var choice = new Choice([literalAbcd, literalEmpty]); + var choice = new Optional(literalAbcd); var notAbcd = new NotPredicate(literalAbcd); var notEfgh = new NotPredicate(literalEfgh);