AST refactoring 4/6: Rewrite compilation to not extend the AST nodes

redux
David Majda 14 years ago
parent 5885a34dde
commit 41abb7ad92

@ -47,8 +47,8 @@ PEG.ArrayUtils = {
},
/*
* The code needs to be in sync with a code template in
* PEG.Grammar.Action.prototype.compile.
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
contains: function(array, value) {
/*
@ -90,8 +90,8 @@ 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 a code template in
* PEG.Grammar.Action.prototype.compile.
* The code needs to be in sync with th code template in the compilation
* function for "action" nodes.
*/
quote: function(s) {
/*
@ -447,234 +447,11 @@ PEG.Compiler = {
}
],
/*
* Generates a parser from a specified grammar AST and start rule. Throws
* |PEG.Grammar.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.
*/
compileParser: function(ast, startRule) {
/*
* This ensures that the same grammar and start rule always generate exactly
* the same parser.
*/
this._resetUniqueIdentifierCounters();
for (var i = 0; i < this._checks.length; i++) {
this._checks[i](ast, startRule);
}
var parseFunctionDefinitions = [];
for (var rule in ast) {
parseFunctionDefinitions.push(ast[rule].compile());
}
var source = this.formatCode(
"(function(){",
" /* Generated by PEG.js (http://pegjs.majda.cz/). */",
" ",
" var result = {",
" _startRule: ${startRule|string},",
" ",
/* This needs to be in sync with PEG.StringUtils.quote. */
" _quoteString: 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",
" + '\"';",
" },",
" ",
/* This needs to be in sync with PEG.ArrayUtils.contains. */
" _arrayContains: 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;",
" }",
" }",
" return false;",
" },",
" ",
" _matchFailed: function(failure) {",
" if (this._pos > this._rightmostMatchFailuresPos) {",
" this._rightmostMatchFailuresPos = this._pos;",
" this._rightmostMatchFailuresExpected = [];",
" }",
" ",
" if (!this._arrayContains(this._rightmostMatchFailuresExpected, failure)) {",
" this._rightmostMatchFailuresExpected.push(failure);",
" }",
" },",
" ",
" ${parseFunctionDefinitions}",
" ",
" /*",
" * 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.grammarParser.SyntaxError| describing the error.",
" */",
" parse: function(input) {",
" var that = this;",
" ",
" function initialize() {",
" that._input = input;",
" that._pos = 0;",
" that._rightmostMatchFailuresPos = 0;",
" that._rightmostMatchFailuresExpected = [];",
" that._cache = {};",
" }",
" ",
" function buildErrorMessage() {",
" function buildExpected(failuresExpected) {",
" switch (failuresExpected.length) {",
" case 0:",
" return 'end of input';",
" case 1:",
" return failuresExpected[0];",
" default:",
" failuresExpected.sort();",
" return failuresExpected.slice(0, failuresExpected.length - 1).join(', ')",
" + ' or '",
" + failuresExpected[failuresExpected.length - 1];",
" }",
" }",
" ",
" var expected = buildExpected(that._rightmostMatchFailuresExpected);",
" var pos = Math.max(that._pos, that._rightmostMatchFailuresPos);",
" var actual = pos < that._input.length",
" ? that._quoteString(that._input.charAt(pos))",
" : 'end of input';",
" ",
" return 'Expected ' + expected + ' but ' + actual + ' found.';",
" }",
" ",
" 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 input = that._input;",
" var pos = that._rightmostMatchFailuresPos;",
" var line = 1;",
" var column = 1;",
" var seenCR = false;",
" ",
" for (var i = 0; i < pos; 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 };",
" }",
" ",
" initialize();",
" ",
" var initialContext = {",
" reportMatchFailures: true",
" };",
" ",
" var result = this['_parse_' + this._startRule](initialContext);",
" ",
" /*",
" * The parser is now in one of the following three states:",
" *",
" * 1. The parser successfully parsed the whole input.",
" *",
" * - |result !== null|",
" * - |that._pos === input.length|",
" * - |that._rightmostMatchFailuresExpected.length| may or may not contain",
" * something",
" *",
" * 2. The parser successfully parsed only a part of the input.",
" *",
" * - |result !== null|",
" * - |that._pos < input.length|",
" * - |that._rightmostMatchFailuresExpected.length| may or may not contain",
" * something",
" *",
" * 3. The parser did not successfully parse any part of the input.",
" *",
" * - |result === null|",
" * - |that._pos === 0|",
" * - |that._rightmostMatchFailuresExpected.length| contains at least one failure",
" *",
" * All code following this comment (including called functions) must",
" * handle these states.",
" */",
" if (result === null || this._pos !== input.length) {",
" var errorPosition = computeErrorPosition();",
" throw new this.SyntaxError(",
" buildErrorMessage(),",
" 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(message, line, column) {",
" this.name = 'SyntaxError';",
" this.message = message;",
" this.line = line;",
" this.column = column;",
" };",
" ",
" result.SyntaxError.prototype = Error.prototype;",
" ",
" return result;",
"})()",
{
parseFunctionDefinitions: parseFunctionDefinitions.join("\n\n"),
startRule: startRule
}
);
var result = eval(source);
result._source = source;
return result;
}
};
PEG.Grammar.Rule.prototype.compile = function() {
_compileFunctions: {
rule: function(node) {
var resultVar = PEG.Compiler.generateUniqueIdentifier("result");
if (this.displayName !== null) {
if (node.displayName !== null) {
var setReportMatchFailuresCode = PEG.Compiler.formatCode(
"var savedReportMatchFailures = context.reportMatchFailures;",
"context.reportMatchFailures = false;"
@ -687,7 +464,7 @@ PEG.Grammar.Rule.prototype.compile = function() {
" this._matchFailed(${displayName|string});",
"}",
{
displayName: this.displayName,
displayName: node.displayName,
resultVar: resultVar
}
);
@ -720,26 +497,26 @@ PEG.Grammar.Rule.prototype.compile = function() {
" return ${resultVar};",
"},",
{
name: this.name,
name: node.name,
setReportMatchFailuresCode: setReportMatchFailuresCode,
restoreReportMatchFailuresCode: restoreReportMatchFailuresCode,
reportMatchFailureCode: reportMatchFailureCode,
code: this.expression.compile(resultVar),
code: PEG.Compiler.compileNode(node.expression, resultVar),
resultVar: resultVar
}
);
};
},
/*
* The contract for all code fragments generated by the following |compile|
* methods is as follows:
/*
* The contract for all code fragments generated by the following functions
* is as follows:
*
* * The code fragment should try to match a part of the input starting with the
* position indicated in |this._pos|. That position may point past the end of
* the input.
* * The code fragment should try to match a part of the input starting with
* the position indicated in |this._pos|. That position may point past the
* end of the input.
*
* * If the code fragment matches the input, it advances |this._pos| after the
* matched part of the input and sets variable with a name stored in
* * If the code fragment matches the input, it advances |this._pos| after
* the matched part of the input and sets variable with a name stored in
* |resultVar| to appropriate value, which is always non-null.
*
* * If the code fragment does not match the input, it does not change
@ -747,13 +524,13 @@ PEG.Grammar.Rule.prototype.compile = function() {
* |null|.
*/
PEG.Grammar.Choice.prototype.compile = function(resultVar) {
choice: function(node, resultVar) {
var code = PEG.Compiler.formatCode(
"var ${resultVar} = null;",
{ resultVar: resultVar }
);
for (var i = this.alternatives.length - 1; i >= 0; i--) {
for (var i = node.alternatives.length - 1; i >= 0; i--) {
var alternativeResultVar = PEG.Compiler.generateUniqueIdentifier("result");
code = PEG.Compiler.formatCode(
"${alternativeCode}",
@ -763,7 +540,7 @@ PEG.Grammar.Choice.prototype.compile = function(resultVar) {
" ${code};",
"}",
{
alternativeCode: this.alternatives[i].compile(alternativeResultVar),
alternativeCode: PEG.Compiler.compileNode(node.alternatives[i], alternativeResultVar),
alternativeResultVar: alternativeResultVar,
code: code,
resultVar: resultVar
@ -772,12 +549,12 @@ PEG.Grammar.Choice.prototype.compile = function(resultVar) {
}
return code;
};
},
PEG.Grammar.Sequence.prototype.compile = function(resultVar) {
sequence: function(node, resultVar) {
var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos");
var elementResultVars = PEG.ArrayUtils.map(this.elements, function() {
var elementResultVars = PEG.ArrayUtils.map(node.elements, function() {
return PEG.Compiler.generateUniqueIdentifier("result")
});
@ -789,7 +566,7 @@ PEG.Grammar.Sequence.prototype.compile = function(resultVar) {
}
);
for (var i = this.elements.length - 1; i >= 0; i--) {
for (var i = node.elements.length - 1; i >= 0; i--) {
code = PEG.Compiler.formatCode(
"${elementCode}",
"if (${elementResultVar} !== null) {",
@ -799,7 +576,7 @@ PEG.Grammar.Sequence.prototype.compile = function(resultVar) {
" this._pos = ${savedPosVar};",
"}",
{
elementCode: this.elements[i].compile(elementResultVars[i]),
elementCode: PEG.Compiler.compileNode(node.elements[i], elementResultVars[i]),
elementResultVar: elementResultVars[i],
code: code,
savedPosVar: savedPosVar,
@ -816,9 +593,9 @@ PEG.Grammar.Sequence.prototype.compile = function(resultVar) {
savedPosVar: savedPosVar
}
);
};
},
PEG.Grammar.AndPredicate.prototype.compile = function(resultVar) {
and_predicate: function(node, resultVar) {
var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos");
var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar");
var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result");
@ -836,16 +613,16 @@ PEG.Grammar.AndPredicate.prototype.compile = function(resultVar) {
" var ${resultVar} = null;",
"}",
{
expressionCode: this.expression.compile(expressionResultVar),
expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar),
expressionResultVar: expressionResultVar,
savedPosVar: savedPosVar,
savedReportMatchFailuresVar: savedReportMatchFailuresVar,
resultVar: resultVar
}
);
};
},
PEG.Grammar.NotPredicate.prototype.compile = function(resultVar) {
not_predicate: function(node, resultVar) {
var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos");
var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar");
var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result");
@ -863,30 +640,30 @@ PEG.Grammar.NotPredicate.prototype.compile = function(resultVar) {
" this._pos = ${savedPosVar};",
"}",
{
expressionCode: this.expression.compile(expressionResultVar),
expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar),
expressionResultVar: expressionResultVar,
savedPosVar: savedPosVar,
savedReportMatchFailuresVar: savedReportMatchFailuresVar,
resultVar: resultVar
}
);
};
},
PEG.Grammar.Optional.prototype.compile = function(resultVar) {
optional: function(node, resultVar) {
var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result");
return PEG.Compiler.formatCode(
"${expressionCode}",
"var ${resultVar} = ${expressionResultVar} !== null ? ${expressionResultVar} : '';",
{
expressionCode: this.expression.compile(expressionResultVar),
expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar),
expressionResultVar: expressionResultVar,
resultVar: resultVar
}
);
};
},
PEG.Grammar.ZeroOrMore.prototype.compile = function(resultVar) {
zero_or_more: function(node, resultVar) {
var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result");
return PEG.Compiler.formatCode(
@ -897,14 +674,14 @@ PEG.Grammar.ZeroOrMore.prototype.compile = function(resultVar) {
" ${expressionCode}",
"}",
{
expressionCode: this.expression.compile(expressionResultVar),
expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar),
expressionResultVar: expressionResultVar,
resultVar: resultVar
}
);
};
},
PEG.Grammar.OneOrMore.prototype.compile = function(resultVar) {
one_or_more: function(node, resultVar) {
var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result");
return PEG.Compiler.formatCode(
@ -919,17 +696,17 @@ PEG.Grammar.OneOrMore.prototype.compile = function(resultVar) {
" var ${resultVar} = null;",
"}",
{
expressionCode: this.expression.compile(expressionResultVar),
expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar),
expressionResultVar: expressionResultVar,
resultVar: resultVar
}
);
};
},
PEG.Grammar.Action.prototype.compile = function(resultVar) {
action: function(node, resultVar) {
/*
* In case of sequences, we splat their elements into function arguments one
* by one. Example:
* In case of sequences, we splat their elements into function arguments
* one by one. Example:
*
* start: "a" "b" "c" { alert(arguments.length) } // => 3
*
@ -938,9 +715,9 @@ PEG.Grammar.Action.prototype.compile = function(resultVar) {
var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result");
if (this.expression.type === "sequence") {
if (node.expression instanceof PEG.Grammar.Sequence) {
var params = PEG.ArrayUtils.map(
PEG.ArrayUtils.range(1, this.expression.elements.length + 1),
PEG.ArrayUtils.range(1, node.expression.elements.length + 1),
function(n) { return "$" + n; }
).join(", ");
@ -948,7 +725,7 @@ PEG.Grammar.Action.prototype.compile = function(resultVar) {
"(function(${params}) { ${action} }).apply(null, ${expressionResultVar})",
{
params: params,
action: this.action,
action: node.action,
expressionResultVar: expressionResultVar
}
);
@ -956,7 +733,7 @@ PEG.Grammar.Action.prototype.compile = function(resultVar) {
var invocationCode = PEG.Compiler.formatCode(
"(function($1) { ${action} })(${expressionResultVar})",
{
action: this.action,
action: node.action,
expressionResultVar: expressionResultVar
}
);
@ -968,25 +745,25 @@ PEG.Grammar.Action.prototype.compile = function(resultVar) {
" ? ${invocationCode}",
" : null;",
{
expressionCode: this.expression.compile(expressionResultVar),
expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar),
expressionResultVar: expressionResultVar,
invocationCode: invocationCode,
resultVar: resultVar
}
);
};
},
PEG.Grammar.RuleRef.prototype.compile = function(resultVar) {
rule_ref: function(node, resultVar) {
return PEG.Compiler.formatCode(
"var ${resultVar} = this.${ruleMethod}(context);",
{
ruleMethod: "_parse_" + this.name,
ruleMethod: "_parse_" + node.name,
resultVar: resultVar
}
);
};
},
PEG.Grammar.Literal.prototype.compile = function(resultVar) {
literal: function(node, resultVar) {
return PEG.Compiler.formatCode(
"if (this._input.substr(this._pos, ${length}) === ${value|string}) {",
" var ${resultVar} = ${value|string};",
@ -998,14 +775,14 @@ PEG.Grammar.Literal.prototype.compile = function(resultVar) {
" }",
"}",
{
value: this.value,
length: this.value.length,
value: node.value,
length: node.value.length,
resultVar: resultVar
}
);
};
},
PEG.Grammar.Any.prototype.compile = function(resultVar) {
any: function(node, resultVar) {
return PEG.Compiler.formatCode(
"if (this._input.length > this._pos) {",
" var ${resultVar} = this._input.charAt(this._pos);",
@ -1018,20 +795,19 @@ PEG.Grammar.Any.prototype.compile = function(resultVar) {
"}",
{ resultVar: resultVar }
);
};
},
PEG.Grammar.Class.prototype.compile = function(resultVar) {
"class": function(node, resultVar) {
/*
* Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so we
* translate them into euqivalents it can handle.
*/
if (this.characters === "") {
if (node.characters === "") {
var regexp = "/^(?!)/";
} else if (this.characters === "^") {
} else if (node.characters === "^") {
var regexp = "/^[\\S\\s]/";
} else {
var regexp = "/^[" + this.characters + "]/";
var regexp = "/^[" + node.characters + "]/";
}
return PEG.Compiler.formatCode(
@ -1045,11 +821,245 @@ PEG.Grammar.Class.prototype.compile = function(resultVar) {
" }",
"}",
{
characters: this.characters,
characters: node.characters,
regexp: regexp,
resultVar: resultVar
}
);
}
},
/*
* Compiles an AST node and returns the generated code. The |resultVar|
* parameter contains a name of variable in which the match result will be
* stored in the generated code.
*/
compileNode: function(node, resultVar) {
return this._compileFunctions[node.type](node, resultVar);
},
/*
* Generates a parser from a specified grammar AST and start rule. Throws
* |PEG.Grammar.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.
*/
compileParser: function(ast, startRule) {
/*
* This ensures that the same grammar and start rule always generate exactly
* the same parser.
*/
this._resetUniqueIdentifierCounters();
for (var i = 0; i < this._checks.length; i++) {
this._checks[i](ast, startRule);
}
var parseFunctionDefinitions = [];
for (var rule in ast) {
parseFunctionDefinitions.push(this.compileNode(ast[rule]));
}
var source = this.formatCode(
"(function(){",
" /* Generated by PEG.js (http://pegjs.majda.cz/). */",
" ",
" var result = {",
" _startRule: ${startRule|string},",
" ",
/* This needs to be in sync with PEG.StringUtils.quote. */
" _quoteString: 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",
" + '\"';",
" },",
" ",
/* This needs to be in sync with PEG.ArrayUtils.contains. */
" _arrayContains: 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;",
" }",
" }",
" return false;",
" },",
" ",
" _matchFailed: function(failure) {",
" if (this._pos > this._rightmostMatchFailuresPos) {",
" this._rightmostMatchFailuresPos = this._pos;",
" this._rightmostMatchFailuresExpected = [];",
" }",
" ",
" if (!this._arrayContains(this._rightmostMatchFailuresExpected, failure)) {",
" this._rightmostMatchFailuresExpected.push(failure);",
" }",
" },",
" ",
" ${parseFunctionDefinitions}",
" ",
" /*",
" * 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.grammarParser.SyntaxError| describing the error.",
" */",
" parse: function(input) {",
" var that = this;",
" ",
" function initialize() {",
" that._input = input;",
" that._pos = 0;",
" that._rightmostMatchFailuresPos = 0;",
" that._rightmostMatchFailuresExpected = [];",
" that._cache = {};",
" }",
" ",
" function buildErrorMessage() {",
" function buildExpected(failuresExpected) {",
" switch (failuresExpected.length) {",
" case 0:",
" return 'end of input';",
" case 1:",
" return failuresExpected[0];",
" default:",
" failuresExpected.sort();",
" return failuresExpected.slice(0, failuresExpected.length - 1).join(', ')",
" + ' or '",
" + failuresExpected[failuresExpected.length - 1];",
" }",
" }",
" ",
" var expected = buildExpected(that._rightmostMatchFailuresExpected);",
" var pos = Math.max(that._pos, that._rightmostMatchFailuresPos);",
" var actual = pos < that._input.length",
" ? that._quoteString(that._input.charAt(pos))",
" : 'end of input';",
" ",
" return 'Expected ' + expected + ' but ' + actual + ' found.';",
" }",
" ",
" 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 input = that._input;",
" var pos = that._rightmostMatchFailuresPos;",
" var line = 1;",
" var column = 1;",
" var seenCR = false;",
" ",
" for (var i = 0; i < pos; 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 };",
" }",
" ",
" initialize();",
" ",
" var initialContext = {",
" reportMatchFailures: true",
" };",
" ",
" var result = this['_parse_' + this._startRule](initialContext);",
" ",
" /*",
" * The parser is now in one of the following three states:",
" *",
" * 1. The parser successfully parsed the whole input.",
" *",
" * - |result !== null|",
" * - |that._pos === input.length|",
" * - |that._rightmostMatchFailuresExpected.length| may or may not contain",
" * something",
" *",
" * 2. The parser successfully parsed only a part of the input.",
" *",
" * - |result !== null|",
" * - |that._pos < input.length|",
" * - |that._rightmostMatchFailuresExpected.length| may or may not contain",
" * something",
" *",
" * 3. The parser did not successfully parse any part of the input.",
" *",
" * - |result === null|",
" * - |that._pos === 0|",
" * - |that._rightmostMatchFailuresExpected.length| contains at least one failure",
" *",
" * All code following this comment (including called functions) must",
" * handle these states.",
" */",
" if (result === null || this._pos !== input.length) {",
" var errorPosition = computeErrorPosition();",
" throw new this.SyntaxError(",
" buildErrorMessage(),",
" 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(message, line, column) {",
" this.name = 'SyntaxError';",
" this.message = message;",
" this.line = line;",
" this.column = column;",
" };",
" ",
" result.SyntaxError.prototype = Error.prototype;",
" ",
" return result;",
"})()",
{
parseFunctionDefinitions: parseFunctionDefinitions.join("\n\n"),
startRule: startRule
}
);
var result = eval(source);
result._source = source;
return result;
}
};
})();

Loading…
Cancel
Save