1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2001-2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: FilterExpr.java,v 1.2.4.1 2005/09/12 10:22:50 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  25 
  26 import java.util.Vector;
  27 
  28 import com.sun.org.apache.bcel.internal.generic.ALOAD;
  29 import com.sun.org.apache.bcel.internal.generic.ASTORE;
  30 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  31 import com.sun.org.apache.bcel.internal.generic.ILOAD;
  32 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  33 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  34 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  35 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  36 import com.sun.org.apache.bcel.internal.generic.ISTORE;
  37 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  38 import com.sun.org.apache.bcel.internal.generic.NEW;
  39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
  42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  43 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  44 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  46 
  47 /**
  48  * @author Jacek Ambroziak
  49  * @author Santiago Pericas-Geertsen
  50  * @author Morten Jorgensen
  51  */
  52 class FilterExpr extends Expression {
  53 
  54     /**
  55      * Primary expression of this filter. I.e., 'e' in '(e)[p1]...[pn]'.
  56      */
  57     private Expression   _primary;
  58 
  59     /**
  60      * Array of predicates in '(e)[p1]...[pn]'.
  61      */
  62     private final Vector _predicates;
  63 
  64     public FilterExpr(Expression primary, Vector predicates) {
  65         _primary = primary;
  66         _predicates = predicates;
  67         primary.setParent(this);
  68     }
  69 
  70     protected Expression getExpr() {
  71         if (_primary instanceof CastExpr)
  72             return ((CastExpr)_primary).getExpr();
  73         else
  74             return _primary;
  75     }
  76 
  77     public void setParser(Parser parser) {
  78         super.setParser(parser);
  79         _primary.setParser(parser);
  80         if (_predicates != null) {
  81             final int n = _predicates.size();
  82             for (int i = 0; i < n; i++) {
  83                 final Expression exp = (Expression)_predicates.elementAt(i);
  84                 exp.setParser(parser);
  85                 exp.setParent(this);
  86             }
  87         }
  88     }
  89 
  90     public String toString() {
  91         return "filter-expr(" + _primary + ", " + _predicates + ")";
  92     }
  93 
  94     /**
  95      * Type check a FilterParentPath. If the filter is not a node-set add a
  96      * cast to node-set only if it is of reference type. This type coercion
  97      * is needed for expressions like $x where $x is a parameter reference.
  98      * All optimizations are turned off before type checking underlying
  99      * predicates.
 100      */
 101     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
 102         Type ptype = _primary.typeCheck(stable);
 103         boolean canOptimize = _primary instanceof KeyCall;
 104 
 105         if (ptype instanceof NodeSetType == false) {
 106             if (ptype instanceof ReferenceType)  {
 107                 _primary = new CastExpr(_primary, Type.NodeSet);
 108             }
 109             else {
 110                 throw new TypeCheckError(this);
 111             }
 112         }
 113 
 114         // Type check predicates and turn all optimizations off if appropriate
 115         int n = _predicates.size();
 116         for (int i = 0; i < n; i++) {
 117             Predicate pred = (Predicate) _predicates.elementAt(i);
 118 
 119             if (!canOptimize) {
 120                 pred.dontOptimize();
 121             }
 122             pred.typeCheck(stable);
 123         }
 124         return _type = Type.NodeSet;
 125     }
 126 
 127     /**
 128      * Translate a filter expression by pushing the appropriate iterator
 129      * onto the stack.
 130      */
 131     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 132         translateFilterExpr(classGen, methodGen, _predicates == null ? -1 : _predicates.size() - 1);
 133     }
 134 
 135     private void translateFilterExpr(ClassGenerator classGen,
 136                                      MethodGenerator methodGen,
 137                                      int predicateIndex) {
 138         if (predicateIndex >= 0) {
 139             translatePredicates(classGen, methodGen, predicateIndex);
 140         }
 141         else {
 142             _primary.translate(classGen, methodGen);
 143         }
 144     }
 145 
 146     /**
 147      * Translate a sequence of predicates. Each predicate is translated
 148      * by constructing an instance of <code>CurrentNodeListIterator</code>
 149      * which is initialized from another iterator (recursive call), a
 150      * filter and a closure (call to translate on the predicate) and "this".
 151      */
 152     public void translatePredicates(ClassGenerator classGen,
 153                                     MethodGenerator methodGen,
 154                                     int predicateIndex) {
 155         final ConstantPoolGen cpg = classGen.getConstantPool();
 156         final InstructionList il = methodGen.getInstructionList();
 157 
 158         // If not predicates left, translate primary expression
 159         if (predicateIndex < 0) {
 160             translateFilterExpr(classGen, methodGen, predicateIndex);
 161         }
 162         else {
 163             // Get the next predicate to be translated
 164             Predicate predicate = (Predicate) _predicates.get(predicateIndex--);
 165 
 166             // Translate the rest of the predicates from right to left
 167             translatePredicates(classGen, methodGen, predicateIndex);
 168 
 169             if (predicate.isNthPositionFilter()) {
 170                 int nthIteratorIdx = cpg.addMethodref(NTH_ITERATOR_CLASS,
 171                                        "<init>",
 172                                        "("+NODE_ITERATOR_SIG+"I)V");
 173 
 174                 // Backwards branches are prohibited if an uninitialized object
 175                 // is on the stack by section 4.9.4 of the JVM Specification,
 176                 // 2nd Ed.  We don't know whether this code might contain
 177                 // backwards branches, so we mustn't create the new object unti
 178 
 179                 // after we've created the suspect arguments to its constructor
 180 
 181                 // Instead we calculate the values of the arguments to the
 182                 // constructor first, store them in temporary variables, create
 183                 // the object and reload the arguments from the temporaries to
 184                 // avoid the problem.
 185                 LocalVariableGen iteratorTemp
 186                         = methodGen.addLocalVariable("filter_expr_tmp1",
 187                                          Util.getJCRefType(NODE_ITERATOR_SIG),
 188                                          null, null);
 189                 iteratorTemp.setStart(
 190                         il.append(new ASTORE(iteratorTemp.getIndex())));
 191 
 192                 predicate.translate(classGen, methodGen);
 193                 LocalVariableGen predicateValueTemp
 194                         = methodGen.addLocalVariable("filter_expr_tmp2",
 195                                          Util.getJCRefType("I"),
 196                                          null, null);
 197                 predicateValueTemp.setStart(
 198                         il.append(new ISTORE(predicateValueTemp.getIndex())));
 199 
 200                 il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS)));
 201                 il.append(DUP);
 202                 iteratorTemp.setEnd(
 203                         il.append(new ALOAD(iteratorTemp.getIndex())));
 204                 predicateValueTemp.setEnd(
 205                         il.append(new ILOAD(predicateValueTemp.getIndex())));
 206                 il.append(new INVOKESPECIAL(nthIteratorIdx));
 207             } else {
 208                     // Translate predicates from right to left
 209                 final int initCNLI = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR,
 210                                                       "<init>",
 211                                                       "("+NODE_ITERATOR_SIG+"Z"+
 212                                                       CURRENT_NODE_LIST_FILTER_SIG +
 213                                                       NODE_SIG+TRANSLET_SIG+")V");
 214 
 215                 // Backwards branches are prohibited if an uninitialized object is
 216                 // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
 217                 // We don't know whether this code might contain backwards branches,
 218                 // so we mustn't create the new object until after we've created
 219                 // the suspect arguments to its constructor.  Instead we calculate
 220                 // the values of the arguments to the constructor first, store them
 221                 // in temporary variables, create the object and reload the
 222                 // arguments from the temporaries to avoid the problem.
 223 
 224 
 225                 LocalVariableGen nodeIteratorTemp =
 226                     methodGen.addLocalVariable("filter_expr_tmp1",
 227                                                Util.getJCRefType(NODE_ITERATOR_SIG),
 228                                                null, null);
 229                 nodeIteratorTemp.setStart(
 230                         il.append(new ASTORE(nodeIteratorTemp.getIndex())));
 231 
 232                 predicate.translate(classGen, methodGen);
 233                 LocalVariableGen filterTemp =
 234                     methodGen.addLocalVariable("filter_expr_tmp2",
 235                                   Util.getJCRefType(CURRENT_NODE_LIST_FILTER_SIG),
 236                                   null, null);
 237                 filterTemp.setStart(il.append(new ASTORE(filterTemp.getIndex())));
 238 
 239                 // Create a CurrentNodeListIterator
 240                 il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
 241                 il.append(DUP);
 242 
 243                 // Initialize CurrentNodeListIterator
 244                 nodeIteratorTemp.setEnd(
 245                         il.append(new ALOAD(nodeIteratorTemp.getIndex())));
 246                 il.append(ICONST_1);
 247                 filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex())));
 248                 il.append(methodGen.loadCurrentNode());
 249                 il.append(classGen.loadTranslet());
 250                 il.append(new INVOKESPECIAL(initCNLI));
 251             }
 252         }
 253     }
 254 }