Implemented generic AST node extension mechanism.

redux
David Majda 14 years ago
parent 1aa3d8e07e
commit 714512f232

@ -57,7 +57,31 @@ PEG.buildParser = function(grammar, startRule) {
/* Namespace with grammar AST nodes. */ /* Namespace with grammar AST nodes. */
PEG.Grammar = {}; PEG.Grammar = {
/*
* Extends specified AST node classes with a function named |name|. The
* definition of the function is different for each node class and it is
* specified in the |functions| object, which contains the functions keyed by
* unqualified AST node names.
*
* Example:
*
* PEG.Grammar.extendNodes("foo", {
* Literal: function() { return 1; },
* Class: function() { return 2; }
* });
*
* This is is equivalent to:
*
* PEG.Grammar.Literal.prototype.foo = function() { return 1; };
* PEG.Grammar.Class.prototype.foo = function() { return 2; };
*/
extendNodes: function(name, functions) {
for (var nodeName in functions) {
PEG.Grammar[nodeName].prototype[name] = functions[nodeName];
}
}
};
/* ===== PEG.Grammar.GrammarError ===== */ /* ===== PEG.Grammar.GrammarError ===== */
@ -109,88 +133,99 @@ PEG.Grammar.Action = function(expression, action) {
/* ===== Referenced Rule Existence Checks ===== */ /* ===== Referenced Rule Existence Checks ===== */
PEG.Grammar.Rule.prototype.checkReferencedRulesExist = function(grammar) { PEG.Grammar.extendNodes("checkReferencedRulesExist", {
this._expression.checkReferencedRulesExist(grammar); Rule:
}; function(grammar) {
this._expression.checkReferencedRulesExist(grammar);
},
PEG.Grammar.Literal.prototype.checkReferencedRulesExist = nop; Literal: nop,
Class: nop,
Any: nop,
PEG.Grammar.Class.prototype.checkReferencedRulesExist = nop; Sequence:
function(grammar) {
PEG.ArrayUtils.each(this._elements, function(element) {
element.checkReferencedRulesExist(grammar);
});
},
PEG.Grammar.Any.prototype.checkReferencedRulesExist = nop; Choice:
function(grammar) {
PEG.ArrayUtils.each(this._alternatives, function(alternative) {
alternative.checkReferencedRulesExist(grammar);
});
},
PEG.Grammar.Sequence.prototype.checkReferencedRulesExist = function(grammar) { ZeroOrMore:
PEG.ArrayUtils.each(this._elements, function(element) { function(grammar) { this._element.checkReferencedRulesExist(grammar); },
element.checkReferencedRulesExist(grammar);
});
};
PEG.Grammar.Choice.prototype.checkReferencedRulesExist = function(grammar) { NotPredicate:
PEG.ArrayUtils.each(this._alternatives, function(alternative) { function(grammar) { this._expression.checkReferencedRulesExist(grammar); },
alternative.checkReferencedRulesExist(grammar);
});
};
PEG.Grammar.ZeroOrMore.prototype.checkReferencedRulesExist = function(grammar) { RuleRef:
this._element.checkReferencedRulesExist(grammar); function(grammar) {
}; if (grammar[this._name] === undefined) {
throw new PEG.Grammar.GrammarError(
"Referenced rule \"" + this._name + "\" does not exist."
);
}
},
PEG.Grammar.NotPredicate.prototype.checkReferencedRulesExist = function(grammar) { Action:
this._expression.checkReferencedRulesExist(grammar); function(grammar) { this._expression.checkReferencedRulesExist(grammar); }
}; });
PEG.Grammar.RuleRef.prototype.checkReferencedRulesExist = function(grammar) {
if (grammar[this._name] === undefined) {
throw new PEG.Grammar.GrammarError("Referenced rule \"" + this._name + "\" does not exist.");
}
};
PEG.Grammar.Action.prototype.checkReferencedRulesExist = function(grammar) {
this._expression.checkReferencedRulesExist(grammar);
};
/* ===== Left Recursion Checks ===== */ /* ===== Left Recursion Checks ===== */
PEG.Grammar.Rule.prototype.checkNoLeftRecursion = function(grammar, appliedRules) { PEG.Grammar.extendNodes("checkNoLeftRecursion", {
this._expression.checkNoLeftRecursion(grammar, appliedRules.concat(this._name)); Rule:
}; function(grammar, appliedRules) {
this._expression.checkNoLeftRecursion(grammar, appliedRules.concat(this._name));
PEG.Grammar.Literal.prototype.checkNoLeftRecursion = nop; },
PEG.Grammar.Class.prototype.checkNoLeftRecursion = nop;
PEG.Grammar.Any.prototype.checkNoLeftRecursion = nop;
PEG.Grammar.Sequence.prototype.checkNoLeftRecursion = function(grammar, appliedRules) { Literal: nop,
if (this._elements.length > 0) { Class: nop,
this._elements[0].checkNoLeftRecursion(grammar, appliedRules); Any: nop,
}
};
PEG.Grammar.Choice.prototype.checkNoLeftRecursion = function(grammar, appliedRules) {
PEG.ArrayUtils.each(this._alternatives, function(alternative) {
alternative.checkNoLeftRecursion(grammar, appliedRules);
});
};
PEG.Grammar.ZeroOrMore.prototype.checkNoLeftRecursion = function(grammar, appliedRules) { Sequence:
this._element.checkNoLeftRecursion(grammar, appliedRules); function(grammar, appliedRules) {
}; if (this._elements.length > 0) {
this._elements[0].checkNoLeftRecursion(grammar, appliedRules);
PEG.Grammar.NotPredicate.prototype.checkNoLeftRecursion = function(grammar, appliedRules) { }
this._expression.checkNoLeftRecursion(grammar, appliedRules); },
};
PEG.Grammar.RuleRef.prototype.checkNoLeftRecursion = function(grammar, appliedRules) { Choice:
if (appliedRules.indexOf(this._name) !== -1) { function(grammar, appliedRules) {
throw new PEG.Grammar.GrammarError("Left recursion detected for rule \"" + this._name + "\"."); PEG.ArrayUtils.each(this._alternatives, function(alternative) {
} alternative.checkNoLeftRecursion(grammar, appliedRules);
grammar[this._name].checkNoLeftRecursion(grammar, appliedRules); });
}; },
ZeroOrMore:
function(grammar, appliedRules) {
this._element.checkNoLeftRecursion(grammar, appliedRules);
},
NotPredicate:
function(grammar, appliedRules) {
this._expression.checkNoLeftRecursion(grammar, appliedRules);
},
RuleRef:
function(grammar, appliedRules) {
if (appliedRules.indexOf(this._name) !== -1) {
throw new PEG.Grammar.GrammarError("Left recursion detected for rule \"" + this._name + "\".");
}
grammar[this._name].checkNoLeftRecursion(grammar, appliedRules);
},
PEG.Grammar.Action.prototype.checkNoLeftRecursion = function(grammar, appliedRules) { Action:
this._expression.checkNoLeftRecursion(grammar, appliedRules); function(grammar, appliedRules) {
}; this._expression.checkNoLeftRecursion(grammar, appliedRules);
}
});
/* ===== PEG.Compiler ===== */ /* ===== PEG.Compiler ===== */

Loading…
Cancel
Save