Add location information to AST nodes

This will allow to add location information to |GrammarError| exceptions
thrown in various passes.
redux
David Majda 9 years ago
parent d1fe86683b
commit 89146915ce

@ -35,10 +35,13 @@ module.exports = (function() {
return { return {
type: "grammar", type: "grammar",
initializer: extractOptional(initializer, 0), initializer: extractOptional(initializer, 0),
rules: extractList(rules, 0) rules: extractList(rules, 0),
location: location()
}; };
}, },
peg$c1 = function(code) { return { type: "initializer", code: code }; }, peg$c1 = function(code) {
return { type: "initializer", code: code, location: location() };
},
peg$c2 = "=", peg$c2 = "=",
peg$c3 = { type: "literal", value: "=", description: "\"=\"" }, peg$c3 = { type: "literal", value: "=", description: "\"=\"" },
peg$c4 = function(name, displayName, expression) { peg$c4 = function(name, displayName, expression) {
@ -49,35 +52,59 @@ module.exports = (function() {
? { ? {
type: "named", type: "named",
name: displayName[0], name: displayName[0],
expression: expression expression: expression,
location: location()
} }
: expression : expression,
location: location()
}; };
}, },
peg$c5 = "/", peg$c5 = "/",
peg$c6 = { type: "literal", value: "/", description: "\"/\"" }, peg$c6 = { type: "literal", value: "/", description: "\"/\"" },
peg$c7 = function(first, rest) { peg$c7 = function(first, rest) {
return rest.length > 0 return rest.length > 0
? { type: "choice", alternatives: buildList(first, rest, 3) } ? {
type: "choice",
alternatives: buildList(first, rest, 3),
location: location()
}
: first; : first;
}, },
peg$c8 = function(expression, code) { peg$c8 = function(expression, code) {
return code !== null return code !== null
? { type: "action", expression: expression, code: code[1] } ? {
type: "action",
expression: expression,
code: code[1],
location: location()
}
: expression; : expression;
}, },
peg$c9 = function(first, rest) { peg$c9 = function(first, rest) {
return rest.length > 0 return rest.length > 0
? { type: "sequence", elements: buildList(first, rest, 1) } ? {
type: "sequence",
elements: buildList(first, rest, 1),
location: location()
}
: first; : first;
}, },
peg$c10 = ":", peg$c10 = ":",
peg$c11 = { type: "literal", value: ":", description: "\":\"" }, peg$c11 = { type: "literal", value: ":", description: "\":\"" },
peg$c12 = function(label, expression) { peg$c12 = function(label, expression) {
return { type: "labeled", label: label, expression: expression }; return {
type: "labeled",
label: label,
expression: expression,
location: location()
};
}, },
peg$c13 = function(operator, expression) { peg$c13 = function(operator, expression) {
return { type: OPS_TO_PREFIXED_TYPES[operator], expression: expression }; return {
type: OPS_TO_PREFIXED_TYPES[operator],
expression: expression,
location: location()
};
}, },
peg$c14 = "$", peg$c14 = "$",
peg$c15 = { type: "literal", value: "$", description: "\"$\"" }, peg$c15 = { type: "literal", value: "$", description: "\"$\"" },
@ -86,7 +113,11 @@ module.exports = (function() {
peg$c18 = "!", peg$c18 = "!",
peg$c19 = { type: "literal", value: "!", description: "\"!\"" }, peg$c19 = { type: "literal", value: "!", description: "\"!\"" },
peg$c20 = function(expression, operator) { peg$c20 = function(expression, operator) {
return { type: OPS_TO_SUFFIXED_TYPES[operator], expression: expression }; return {
type: OPS_TO_SUFFIXED_TYPES[operator],
expression: expression,
location: location()
};
}, },
peg$c21 = "?", peg$c21 = "?",
peg$c22 = { type: "literal", value: "?", description: "\"?\"" }, peg$c22 = { type: "literal", value: "?", description: "\"?\"" },
@ -100,10 +131,14 @@ module.exports = (function() {
peg$c30 = { type: "literal", value: ")", description: "\")\"" }, peg$c30 = { type: "literal", value: ")", description: "\")\"" },
peg$c31 = function(expression) { return expression; }, peg$c31 = function(expression) { return expression; },
peg$c32 = function(name) { peg$c32 = function(name) {
return { type: "rule_ref", name: name }; return { type: "rule_ref", name: name, location: location() };
}, },
peg$c33 = function(operator, code) { peg$c33 = function(operator, code) {
return { type: OPS_TO_SEMANTIC_PREDICATE_TYPES[operator], code: code }; return {
type: OPS_TO_SEMANTIC_PREDICATE_TYPES[operator],
code: code,
location: location()
};
}, },
peg$c34 = { type: "any", description: "any character" }, peg$c34 = { type: "any", description: "any character" },
peg$c35 = { type: "other", description: "whitespace" }, peg$c35 = { type: "other", description: "whitespace" },
@ -155,7 +190,12 @@ module.exports = (function() {
peg$c81 = "i", peg$c81 = "i",
peg$c82 = { type: "literal", value: "i", description: "\"i\"" }, peg$c82 = { type: "literal", value: "i", description: "\"i\"" },
peg$c83 = function(value, ignoreCase) { peg$c83 = function(value, ignoreCase) {
return { type: "literal", value: value, ignoreCase: ignoreCase !== null }; return {
type: "literal",
value: value,
ignoreCase: ignoreCase !== null,
location: location()
};
}, },
peg$c84 = { type: "other", description: "string" }, peg$c84 = { type: "other", description: "string" },
peg$c85 = "\"", peg$c85 = "\"",
@ -177,7 +217,8 @@ module.exports = (function() {
parts: filterEmptyStrings(parts), parts: filterEmptyStrings(parts),
inverted: inverted !== null, inverted: inverted !== null,
ignoreCase: ignoreCase !== null, ignoreCase: ignoreCase !== null,
rawText: text() rawText: text(),
location: location()
}; };
}, },
peg$c99 = "-", peg$c99 = "-",
@ -226,7 +267,7 @@ module.exports = (function() {
peg$c132 = { type: "class", value: "[0-9a-f]i", description: "[0-9a-f]i" }, peg$c132 = { type: "class", value: "[0-9a-f]i", description: "[0-9a-f]i" },
peg$c133 = ".", peg$c133 = ".",
peg$c134 = { type: "literal", value: ".", description: "\".\"" }, peg$c134 = { type: "literal", value: ".", description: "\".\"" },
peg$c135 = function() { return { type: "any" }; }, peg$c135 = function() { return { type: "any", location: location() }; },
peg$c136 = { type: "other", description: "code block" }, peg$c136 = { type: "other", description: "code block" },
peg$c137 = "{", peg$c137 = "{",
peg$c138 = { type: "literal", value: "{", description: "\"{\"" }, peg$c138 = { type: "literal", value: "{", description: "\"{\"" },

@ -98,6 +98,74 @@ describe("PEG.js grammar parser", function() {
rules: [ruleA, ruleB] rules: [ruleA, ruleB]
}; };
var stripLocation = (function() {
function buildVisitor(functions) {
return function(node) {
return functions[node.type].apply(null, arguments);
};
}
function stripLeaf(node) {
delete node.location;
}
function stripExpression(node) {
delete node.location;
strip(node.expression);
}
function stripChildren(property) {
return function(node) {
var i;
delete node.location;
for (i = 0; i < node[property].length; i++) {
strip(node[property][i]);
}
};
}
var strip = buildVisitor({
grammar: function(node) {
var i;
delete node.location;
if (node.initializer) {
strip(node.initializer);
}
for (i = 0; i < node.rules.length; i++) {
strip(node.rules[i]);
}
},
initializer: stripLeaf,
rule: stripExpression,
named: stripExpression,
choice: stripChildren("alternatives"),
action: stripExpression,
sequence: stripChildren("elements"),
labeled: stripExpression,
text: stripExpression,
simple_and: stripExpression,
simple_not: stripExpression,
optional: stripExpression,
zero_or_more: stripExpression,
one_or_more: stripExpression,
semantic_and: stripLeaf,
semantic_not: stripLeaf,
rule_ref: stripLeaf,
literal: stripLeaf,
"class": stripLeaf,
any: stripLeaf
});
return strip;
})();
beforeEach(function() { beforeEach(function() {
this.addMatchers({ this.addMatchers({
toParseAs: function(expected) { toParseAs: function(expected) {
@ -106,6 +174,8 @@ describe("PEG.js grammar parser", function() {
try { try {
result = PEG.parser.parse(this.actual); result = PEG.parser.parse(this.actual);
stripLocation(result);
this.message = function() { this.message = function() {
return "Expected " + jasmine.pp(this.actual) + " " return "Expected " + jasmine.pp(this.actual) + " "
+ (this.isNot ? "not " : "") + (this.isNot ? "not " : "")
@ -132,6 +202,8 @@ describe("PEG.js grammar parser", function() {
try { try {
result = PEG.parser.parse(this.actual); result = PEG.parser.parse(this.actual);
stripLocation(result);
this.message = function() { this.message = function() {
return "Expected " + jasmine.pp(this.actual) + " to fail to parse" return "Expected " + jasmine.pp(this.actual) + " to fail to parse"
+ (details ? " with details " + jasmine.pp(details) : "") + ", " + (details ? " with details " + jasmine.pp(details) : "") + ", "

@ -79,12 +79,15 @@ Grammar
return { return {
type: "grammar", type: "grammar",
initializer: extractOptional(initializer, 0), initializer: extractOptional(initializer, 0),
rules: extractList(rules, 0) rules: extractList(rules, 0),
location: location()
}; };
} }
Initializer Initializer
= code:CodeBlock EOS { return { type: "initializer", code: code }; } = code:CodeBlock EOS {
return { type: "initializer", code: code, location: location() };
}
Rule Rule
= name:IdentifierName __ = name:IdentifierName __
@ -99,9 +102,11 @@ Rule
? { ? {
type: "named", type: "named",
name: displayName[0], name: displayName[0],
expression: expression expression: expression,
location: location()
} }
: expression : expression,
location: location()
}; };
} }
@ -111,33 +116,55 @@ Expression
ChoiceExpression ChoiceExpression
= first:ActionExpression rest:(__ "/" __ ActionExpression)* { = first:ActionExpression rest:(__ "/" __ ActionExpression)* {
return rest.length > 0 return rest.length > 0
? { type: "choice", alternatives: buildList(first, rest, 3) } ? {
type: "choice",
alternatives: buildList(first, rest, 3),
location: location()
}
: first; : first;
} }
ActionExpression ActionExpression
= expression:SequenceExpression code:(__ CodeBlock)? { = expression:SequenceExpression code:(__ CodeBlock)? {
return code !== null return code !== null
? { type: "action", expression: expression, code: code[1] } ? {
type: "action",
expression: expression,
code: code[1],
location: location()
}
: expression; : expression;
} }
SequenceExpression SequenceExpression
= first:LabeledExpression rest:(__ LabeledExpression)* { = first:LabeledExpression rest:(__ LabeledExpression)* {
return rest.length > 0 return rest.length > 0
? { type: "sequence", elements: buildList(first, rest, 1) } ? {
type: "sequence",
elements: buildList(first, rest, 1),
location: location()
}
: first; : first;
} }
LabeledExpression LabeledExpression
= label:Identifier __ ":" __ expression:PrefixedExpression { = label:Identifier __ ":" __ expression:PrefixedExpression {
return { type: "labeled", label: label, expression: expression }; return {
type: "labeled",
label: label,
expression: expression,
location: location()
};
} }
/ PrefixedExpression / PrefixedExpression
PrefixedExpression PrefixedExpression
= operator:PrefixedOperator __ expression:SuffixedExpression { = operator:PrefixedOperator __ expression:SuffixedExpression {
return { type: OPS_TO_PREFIXED_TYPES[operator], expression: expression }; return {
type: OPS_TO_PREFIXED_TYPES[operator],
expression: expression,
location: location()
};
} }
/ SuffixedExpression / SuffixedExpression
@ -148,7 +175,11 @@ PrefixedOperator
SuffixedExpression SuffixedExpression
= expression:PrimaryExpression __ operator:SuffixedOperator { = expression:PrimaryExpression __ operator:SuffixedOperator {
return { type: OPS_TO_SUFFIXED_TYPES[operator], expression: expression }; return {
type: OPS_TO_SUFFIXED_TYPES[operator],
expression: expression,
location: location()
};
} }
/ PrimaryExpression / PrimaryExpression
@ -167,12 +198,16 @@ PrimaryExpression
RuleReferenceExpression RuleReferenceExpression
= name:IdentifierName !(__ (StringLiteral __)? "=") { = name:IdentifierName !(__ (StringLiteral __)? "=") {
return { type: "rule_ref", name: name }; return { type: "rule_ref", name: name, location: location() };
} }
SemanticPredicateExpression SemanticPredicateExpression
= operator:SemanticPredicateOperator __ code:CodeBlock { = operator:SemanticPredicateOperator __ code:CodeBlock {
return { type: OPS_TO_SEMANTIC_PREDICATE_TYPES[operator], code: code }; return {
type: OPS_TO_SEMANTIC_PREDICATE_TYPES[operator],
code: code,
location: location()
};
} }
SemanticPredicateOperator SemanticPredicateOperator
@ -306,7 +341,12 @@ BooleanLiteral
LiteralMatcher "literal" LiteralMatcher "literal"
= value:StringLiteral ignoreCase:"i"? { = value:StringLiteral ignoreCase:"i"? {
return { type: "literal", value: value, ignoreCase: ignoreCase !== null }; return {
type: "literal",
value: value,
ignoreCase: ignoreCase !== null,
location: location()
};
} }
StringLiteral "string" StringLiteral "string"
@ -335,7 +375,8 @@ CharacterClassMatcher "character class"
parts: filterEmptyStrings(parts), parts: filterEmptyStrings(parts),
inverted: inverted !== null, inverted: inverted !== null,
ignoreCase: ignoreCase !== null, ignoreCase: ignoreCase !== null,
rawText: text() rawText: text(),
location: location()
}; };
} }
@ -405,7 +446,7 @@ HexDigit
= [0-9a-f]i = [0-9a-f]i
AnyMatcher AnyMatcher
= "." { return { type: "any" }; } = "." { return { type: "any", location: location() }; }
CodeBlock "code block" CodeBlock "code block"
= "{" code:Code "}" { return code; } = "{" code:Code "}" { return code; }

Loading…
Cancel
Save