You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.8 KiB
JavaScript
110 lines
2.8 KiB
JavaScript
/*
|
|
* This pass walks through the AST and tracks what labels are visible at each
|
|
* point. For "action", "semantic_and" and "semantic_or" nodes it computes
|
|
* parameter names and values for the function used in generated code. (In the
|
|
* emitter, user's code is wrapped into a function that is immediately executed.
|
|
* Its parameter names correspond to visible labels and its parameter values to
|
|
* their captured values). Implicitly, this pass defines scoping rules for
|
|
* labels.
|
|
*
|
|
* After running this pass, all "action", "semantic_and" and "semantic_or" nodes
|
|
* will have a |params| property containing an object mapping parameter names to
|
|
* the expressions that will be used as their values.
|
|
*/
|
|
PEG.compiler.passes.computeParams = function(ast) {
|
|
var envs = [];
|
|
|
|
function scoped(f) {
|
|
envs.push({});
|
|
f();
|
|
envs.pop();
|
|
}
|
|
|
|
function nop() {}
|
|
|
|
function computeForScopedExpression(node) {
|
|
scoped(function() { compute(node.expression); });
|
|
}
|
|
|
|
function computeParams(node) {
|
|
var env = envs[envs.length - 1], params = {}, name;
|
|
|
|
for (name in env) {
|
|
params[name] = env[name];
|
|
}
|
|
node.params = params;
|
|
}
|
|
|
|
var compute = buildNodeVisitor({
|
|
grammar:
|
|
function(node) {
|
|
each(node.rules, compute);
|
|
},
|
|
|
|
rule: computeForScopedExpression,
|
|
named:
|
|
function(node) {
|
|
compute(node.expression);
|
|
},
|
|
|
|
choice:
|
|
function(node) {
|
|
scoped(function() { each(node.alternatives, compute); });
|
|
},
|
|
|
|
action:
|
|
function(node) {
|
|
scoped(function() {
|
|
compute(node.expression);
|
|
computeParams(node);
|
|
});
|
|
},
|
|
|
|
sequence:
|
|
function(node) {
|
|
var env = envs[envs.length - 1], name;
|
|
|
|
function fixup(name) {
|
|
each(pluck(node.elements, "resultIndex"), function(resultIndex, i) {
|
|
if (env[name].resultIndex === resultIndex) {
|
|
env[name] = {
|
|
resultIndex: node.resultIndex,
|
|
subindices: [i].concat(env[name].subindices)
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
each(node.elements, compute);
|
|
|
|
for (name in env) {
|
|
fixup(name);
|
|
}
|
|
},
|
|
|
|
labeled:
|
|
function(node) {
|
|
envs[envs.length - 1][node.label] = {
|
|
resultIndex: node.resultIndex,
|
|
subindices: []
|
|
};
|
|
|
|
scoped(function() { compute(node.expression); });
|
|
},
|
|
|
|
simple_and: computeForScopedExpression,
|
|
simple_not: computeForScopedExpression,
|
|
semantic_and: computeParams,
|
|
semantic_not: computeParams,
|
|
optional: computeForScopedExpression,
|
|
zero_or_more: computeForScopedExpression,
|
|
one_or_more: computeForScopedExpression,
|
|
rule_ref: nop,
|
|
literal: nop,
|
|
"class": nop,
|
|
any: nop
|
|
});
|
|
|
|
compute(ast);
|
|
};
|