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.
pegjs/src/compiler/passes/compute-var-indices.js

126 lines
3.7 KiB
JavaScript

/*
* Computes indices of variables used for storing match results and parse
* positions in generated code. These variables are organized as two stacks.
* The following will hold after running this pass:
*
* * All nodes except "grammar" and "rule" nodes will have a |resultIndex|
* property. It will contain an index of the variable that will store a
* match result of the expression represented by the node in generated code.
*
* * Some nodes will have a |posIndex| property. It will contain an index of
* the variable that will store a parse position in generated code.
*
* * All "rule" nodes will contain |resultIndices| and |posIndices|
* properties. They will contain a list of values of |resultIndex| and
* |posIndex| properties used in rule's subnodes. (This is useful to declare
* variables in generated code.)
*/
PEG.compiler.passes.computeVarIndices = function(ast) {
function computeLeaf(node, index) {
node.resultIndex = index.result;
return { result: 0, pos: 0 };
}
function computeFromExpression(delta) {
return function(node, index) {
var depth = compute(
node.expression,
{
result: index.result + delta.result,
pos: index.pos + delta.pos
}
);
node.resultIndex = index.result;
if (delta.pos !== 0) {
node.posIndex = index.pos;
}
return {
result: depth.result + delta.result,
pos: depth.pos + delta.pos
};
};
}
var compute = buildNodeVisitor({
grammar:
function(node, index) {
each(node.rules, function(node) {
compute(node, index);
});
},
rule:
function(node, index) {
var depth = compute(node.expression, index);
node.resultIndex = index.result;
node.resultIndices = range(depth.result + 1);
node.posIndices = range(depth.pos);
},
named: computeFromExpression({ result: 0, pos: 0 }),
choice:
function(node, index) {
var depths = map(node.alternatives, function(alternative) {
return compute(alternative, index);
});
node.resultIndex = index.result;
return {
result: Math.max.apply(null, pluck(depths, "result")),
pos: Math.max.apply(null, pluck(depths, "pos"))
};
},
action: computeFromExpression({ result: 0, pos: 1 }),
sequence:
function(node, index) {
var depths = map(node.elements, function(element, i) {
return compute(
element,
{ result: index.result + i, pos: index.pos + 1 }
);
});
node.resultIndex = index.result;
node.posIndex = index.pos;
return {
result:
node.elements.length > 0
? Math.max.apply(
null,
map(depths, function(d, i) { return i + d.result; })
)
: 0,
pos:
node.elements.length > 0
? 1 + Math.max.apply(null, pluck(depths, "pos"))
: 1
};
},
labeled: computeFromExpression({ result: 0, pos: 0 }),
simple_and: computeFromExpression({ result: 0, pos: 1 }),
simple_not: computeFromExpression({ result: 0, pos: 1 }),
semantic_and: computeLeaf,
semantic_not: computeLeaf,
optional: computeFromExpression({ result: 0, pos: 0 }),
zero_or_more: computeFromExpression({ result: 1, pos: 0 }),
one_or_more: computeFromExpression({ result: 1, pos: 0 }),
rule_ref: computeLeaf,
literal: computeLeaf,
"class": computeLeaf,
any: computeLeaf
});
compute(ast, { result: 0, pos: 0 });
};