/* * reserved comment block * DO NOT REMOVE OR ALTER! */ /* * Copyright 2001-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: FilterExpr.java,v 1.2.4.1 2005/09/12 10:22:50 pvedula Exp $ */ package com.sun.org.apache.xalan.internal.xsltc.compiler; import java.util.Vector; import com.sun.org.apache.bcel.internal.generic.ALOAD; import com.sun.org.apache.bcel.internal.generic.ASTORE; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.NEW; import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC; import com.sun.org.apache.bcel.internal.generic.InstructionList; import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.bcel.internal.generic.NEW; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; /** * @author Jacek Ambroziak * @author Santiago Pericas-Geertsen * @author Morten Jorgensen */ class FilterExpr extends Expression { /** * Primary expression of this filter. I.e., 'e' in '(e)[p1]...[pn]'. */ private Expression _primary; /** * Array of predicates in '(e)[p1]...[pn]'. */ private final Vector _predicates; public FilterExpr(Expression primary, Vector predicates) { _primary = primary; _predicates = predicates; primary.setParent(this); } protected Expression getExpr() { if (_primary instanceof CastExpr) return ((CastExpr)_primary).getExpr(); else return _primary; } public void setParser(Parser parser) { super.setParser(parser); _primary.setParser(parser); if (_predicates != null) { final int n = _predicates.size(); for (int i = 0; i < n; i++) { final Expression exp = (Expression)_predicates.elementAt(i); exp.setParser(parser); exp.setParent(this); } } } public String toString() { return "filter-expr(" + _primary + ", " + _predicates + ")"; } /** * Type check a FilterParentPath. If the filter is not a node-set add a * cast to node-set only if it is of reference type. This type coercion * is needed for expressions like $x where $x is a parameter reference. * All optimizations are turned off before type checking underlying * predicates. */ public Type typeCheck(SymbolTable stable) throws TypeCheckError { Type ptype = _primary.typeCheck(stable); if (ptype instanceof NodeSetType == false) { if (ptype instanceof ReferenceType) { _primary = new CastExpr(_primary, Type.NodeSet); } else { throw new TypeCheckError(this); } } // Type check predicates and turn all optimizations off int n = _predicates.size(); for (int i = 0; i < n; i++) { Predicate pred = (Predicate) _predicates.elementAt(i); pred.dontOptimize(); pred.typeCheck(stable); } return _type = Type.NodeSet; } /** * Translate a filter expression by pushing the appropriate iterator * onto the stack. */ public void translate(ClassGenerator classGen, MethodGenerator methodGen) { translateFilterExpr(classGen, methodGen, _predicates == null ? -1 : _predicates.size() - 1); } private void translateFilterExpr(ClassGenerator classGen, MethodGenerator methodGen, int predicateIndex) { if (predicateIndex >= 0) { translatePredicates(classGen, methodGen, predicateIndex); } else { _primary.translate(classGen, methodGen); } } /** * Translate a sequence of predicates. Each predicate is translated * by constructing an instance of <code>CurrentNodeListIterator</code> * which is initialized from another iterator (recursive call), 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(); // If not predicates left, translate primary expression if (predicateIndex < 0) { translateFilterExpr(classGen, methodGen, predicateIndex); } else { // Translate predicates from right to left final int initCNLI = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR, "<init>", "("+NODE_ITERATOR_SIG+"Z"+ 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. // Get the next predicate to be translated Predicate predicate = (Predicate) _predicates.get(predicateIndex--); // Translate the rest of the predicates from right to left translatePredicates(classGen, methodGen, predicateIndex); LocalVariableGen nodeIteratorTemp = methodGen.addLocalVariable("filter_expr_tmp1", Util.getJCRefType(NODE_ITERATOR_SIG), il.getEnd(), null); il.append(new ASTORE(nodeIteratorTemp.getIndex())); predicate.translate(classGen, methodGen); LocalVariableGen filterTemp = methodGen.addLocalVariable("filter_expr_tmp2", Util.getJCRefType(CURRENT_NODE_LIST_FILTER_SIG), il.getEnd(), null); il.append(new ASTORE(filterTemp.getIndex())); // Create a CurrentNodeListIterator il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR))); il.append(DUP); // Initialize CurrentNodeListIterator il.append(new ALOAD(nodeIteratorTemp.getIndex())); il.append(ICONST_1); il.append(new ALOAD(filterTemp.getIndex())); il.append(methodGen.loadCurrentNode()); il.append(classGen.loadTranslet()); il.append(new INVOKESPECIAL(initCNLI)); } } }