* a filter and a closure (call to translate on the predicate) and "this".
*/
public void translatePredicates(ClassGenerator classGen,
MethodGenerator methodGen,
int predicateIndex) {
final ConstantPoolGen cpg = classGen.getConstantPool();
final InstructionList il = methodGen.getInstructionList();
int idx = 0;
if (predicateIndex < 0) {
translateStep(classGen, methodGen, predicateIndex);
}
else {
final Predicate predicate = (Predicate) _predicates.get(predicateIndex--);
// Special case for predicates that can use the NodeValueIterator
// instead of an auxiliary class. Certain path/predicates pairs
// are translated into a base path, on top of which we place a
// node value iterator that tests for the desired value:
// foo[@attr = 'str'] -> foo/@attr + test(value='str')
// foo[bar = 'str'] -> foo/bar + test(value='str')
// foo/bar[. = 'str'] -> foo/bar + test(value='str')
if (predicate.isNodeValueTest()) {
Step step = predicate.getStep();
il.append(methodGen.loadDOM());
// If the predicate's Step is simply '.' we translate this Step
// and place the node test on top of the resulting iterator
if (step.isAbbreviatedDot()) {
translateStep(classGen, methodGen, predicateIndex);
il.append(new ICONST(DOM.RETURN_CURRENT));
}
// Otherwise we create a parent location path with this Step and
// the predicates Step, and place the node test on top of that
else {
ParentLocationPath path = new ParentLocationPath(this, step);
_parent = step._parent = path; // Force re-parenting
try {
path.typeCheck(getParser().getSymbolTable());
}
catch (TypeCheckError e) { }
translateStep(classGen, methodGen, predicateIndex);
path.translateStep(classGen, methodGen);
il.append(new ICONST(DOM.RETURN_PARENT));
}
predicate.translate(classGen, methodGen);
idx = cpg.addInterfaceMethodref(DOM_INTF,
GET_NODE_VALUE_ITERATOR,
GET_NODE_VALUE_ITERATOR_SIG);
il.append(new INVOKEINTERFACE(idx, 5));
}
// Handle '//*[n]' expression
else if (predicate.isNthDescendant()) {
il.append(methodGen.loadDOM());
// il.append(new ICONST(NodeTest.ELEMENT));
il.append(new PUSH(cpg, predicate.getPosType()));
predicate.translate(classGen, methodGen);
il.append(new ICONST(0));
idx = cpg.addInterfaceMethodref(DOM_INTF,
"getNthDescendant",
"(IIZ)"+NODE_ITERATOR_SIG);
il.append(new INVOKEINTERFACE(idx, 4));
}
// Handle 'elem[n]' expression
else if (predicate.isNthPositionFilter()) {
idx = cpg.addMethodref(NTH_ITERATOR_CLASS,
"<init>",
"("+NODE_ITERATOR_SIG+"I)V");
// Backwards branches are prohibited if an uninitialized object
// is on the stack by section 4.9.4 of the JVM Specification,
// 2nd Ed. We don't know whether this code might contain
// backwards branches, so we mustn't create the new object until
// after we've created the suspect arguments to its constructor.
// Instead we calculate the values of the arguments to the
// constructor first, store them in temporary variables, create
// the object and reload the arguments from the temporaries to
// avoid the problem.
translatePredicates(classGen, methodGen, predicateIndex); // recursive call
LocalVariableGen iteratorTemp
= methodGen.addLocalVariable("step_tmp1",
Util.getJCRefType(NODE_ITERATOR_SIG),
null, null);
iteratorTemp.setStart(
il.append(new ASTORE(iteratorTemp.getIndex())));
predicate.translate(classGen, methodGen);
LocalVariableGen predicateValueTemp
= methodGen.addLocalVariable("step_tmp2",
Util.getJCRefType("I"),
null, null);
predicateValueTemp.setStart(
il.append(new ISTORE(predicateValueTemp.getIndex())));
il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS)));
il.append(DUP);
iteratorTemp.setEnd(
il.append(new ALOAD(iteratorTemp.getIndex())));
predicateValueTemp.setEnd(
il.append(new ILOAD(predicateValueTemp.getIndex())));
il.append(new INVOKESPECIAL(idx));
}
else {
idx = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR,
"<init>",
"("
+ NODE_ITERATOR_SIG
+ CURRENT_NODE_LIST_FILTER_SIG
+ NODE_SIG
+ TRANSLET_SIG
+ ")V");
// Backwards branches are prohibited if an uninitialized object
// is on the stack by section 4.9.4 of the JVM Specification,
// 2nd Ed. We don't know whether this code might contain
// backwards branches, so we mustn't create the new object until
// after we've created the suspect arguments to its constructor.
// Instead we calculate the values of the arguments to the
// constructor first, store them in temporary variables, create
// the object and reload the arguments from the temporaries to
// avoid the problem.
translatePredicates(classGen, methodGen, predicateIndex); // recursive call
LocalVariableGen iteratorTemp
= methodGen.addLocalVariable("step_tmp1",
Util.getJCRefType(NODE_ITERATOR_SIG),
null, null);
iteratorTemp.setStart(
il.append(new ASTORE(iteratorTemp.getIndex())));
predicate.translateFilter(classGen, methodGen);
LocalVariableGen filterTemp
= methodGen.addLocalVariable("step_tmp2",
Util.getJCRefType(CURRENT_NODE_LIST_FILTER_SIG),
null, null);
filterTemp.setStart(
il.append(new ASTORE(filterTemp.getIndex())));
// create new CurrentNodeListIterator
il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
il.append(DUP);
iteratorTemp.setEnd(
il.append(new ALOAD(iteratorTemp.getIndex())));
filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex())));
il.append(methodGen.loadCurrentNode());
il.append(classGen.loadTranslet());
if (classGen.isExternal()) {
final String className = classGen.getClassName();
il.append(new CHECKCAST(cpg.addClass(className)));
}
il.append(new INVOKESPECIAL(idx));
}
}
}