1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  23 
  24 import com.sun.org.apache.bcel.internal.generic.ALOAD;
  25 import com.sun.org.apache.bcel.internal.generic.ASTORE;
  26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  27 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  28 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  29 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  30 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  31 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  32 import com.sun.org.apache.bcel.internal.generic.NEW;
  33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
  37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  41 
  42 /**
  43  * @author Jacek Ambroziak
  44  * @author Santiago Pericas-Geertsen
  45  */
  46 final class FilterParentPath extends Expression {
  47 
  48     private Expression _filterExpr;
  49     private Expression _path;
  50     private boolean _hasDescendantAxis = false;
  51 
  52     public FilterParentPath(Expression filterExpr, Expression path) {
  53         (_path = path).setParent(this);
  54         (_filterExpr = filterExpr).setParent(this);
  55     }
  56 
  57     public void setParser(Parser parser) {
  58         super.setParser(parser);
  59         _filterExpr.setParser(parser);
  60         _path.setParser(parser);
  61     }
  62 
  63     public String toString() {
  64         return "FilterParentPath(" + _filterExpr + ", " + _path + ')';
  65     }
  66 
  67     public void setDescendantAxis() {
  68         _hasDescendantAxis = true;
  69     }
  70 
  71     /**
  72      * Type check a FilterParentPath. If the filter is not a node-set add a
  73      * cast to node-set only if it is of reference type. This type coercion is
  74      * needed for expressions like $x/LINE where $x is a parameter reference.
  75      */
  76     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  77         final Type ftype = _filterExpr.typeCheck(stable);
  78         if (ftype instanceof NodeSetType == false) {
  79             if (ftype instanceof ReferenceType)  {
  80                 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
  81             }
  82             /*
  83             else if (ftype instanceof ResultTreeType)  {
  84                 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
  85             }
  86             */
  87             else if (ftype instanceof NodeType)  {
  88                 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
  89             }
  90             else {
  91                 throw new TypeCheckError(this);
  92             }
  93         }
  94 
  95         // Wrap single node path in a node set
  96         final Type ptype = _path.typeCheck(stable);
  97         if (!(ptype instanceof NodeSetType)) {
  98             _path = new CastExpr(_path, Type.NodeSet);
  99         }
 100 
 101         return _type = Type.NodeSet;
 102     }
 103 
 104     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 105         final ConstantPoolGen cpg = classGen.getConstantPool();
 106         final InstructionList il = methodGen.getInstructionList();
 107         // Create new StepIterator
 108         final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS,
 109                                             "<init>",
 110                                             "("
 111                                             +NODE_ITERATOR_SIG
 112                                             +NODE_ITERATOR_SIG
 113                                             +")V");
 114 
 115         // Backwards branches are prohibited if an uninitialized object is
 116         // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
 117         // We don't know whether this code might contain backwards branches,
 118         // so we mustn't create the new object until after we've created
 119         // the suspect arguments to its constructor.  Instead we calculate
 120         // the values of the arguments to the constructor first, store them
 121         // in temporary variables, create the object and reload the
 122         // arguments from the temporaries to avoid the problem.
 123 
 124         // Recursively compile 2 iterators
 125         _filterExpr.translate(classGen, methodGen);
 126         LocalVariableGen filterTemp =
 127                 methodGen.addLocalVariable("filter_parent_path_tmp1",
 128                                            Util.getJCRefType(NODE_ITERATOR_SIG),
 129                                            null, null);
 130         filterTemp.setStart(il.append(new ASTORE(filterTemp.getIndex())));
 131 
 132         _path.translate(classGen, methodGen);
 133         LocalVariableGen pathTemp =
 134                 methodGen.addLocalVariable("filter_parent_path_tmp2",
 135                                            Util.getJCRefType(NODE_ITERATOR_SIG),
 136                                            null, null);
 137         pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex())));
 138 
 139         il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS)));
 140         il.append(DUP);
 141         filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex())));
 142         pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex())));
 143 
 144         // Initialize StepIterator with iterators from the stack
 145         il.append(new INVOKESPECIAL(initSI));
 146 
 147         // This is a special case for the //* path with or without predicates
 148         if (_hasDescendantAxis) {
 149             final int incl = cpg.addMethodref(NODE_ITERATOR_BASE,
 150                                               "includeSelf",
 151                                               "()" + NODE_ITERATOR_SIG);
 152             il.append(new INVOKEVIRTUAL(incl));
 153         }
 154 
 155         SyntaxTreeNode parent = getParent();
 156 
 157         boolean parentAlreadyOrdered =
 158             (parent instanceof RelativeLocationPath)
 159                 || (parent instanceof FilterParentPath)
 160                 || (parent instanceof KeyCall)
 161                 || (parent instanceof CurrentCall)
 162                 || (parent instanceof DocumentCall);
 163 
 164         if (!parentAlreadyOrdered) {
 165             final int order = cpg.addInterfaceMethodref(DOM_INTF,
 166                                                         ORDER_ITERATOR,
 167                                                         ORDER_ITERATOR_SIG);
 168             il.append(methodGen.loadDOM());
 169             il.append(SWAP);
 170             il.append(methodGen.loadContextNode());
 171             il.append(new INVOKEINTERFACE(order, 3));
 172         }
 173     }
 174 }