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.BranchHandle;
  25 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  26 import com.sun.org.apache.bcel.internal.generic.GOTO;
  27 import com.sun.org.apache.bcel.internal.generic.IFLT;
  28 import com.sun.org.apache.bcel.internal.generic.ILOAD;
  29 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  30 import com.sun.org.apache.bcel.internal.generic.ISTORE;
  31 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  32 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  33 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  39 
  40 /**
  41  * @author Jacek Ambroziak
  42  * @author Santiago Pericas-Geertsen
  43  * @author Erwin Bolwidt <ejb@klomp.org>
  44  */
  45 final class AncestorPattern extends RelativePathPattern {
  46 
  47     private final Pattern _left;        // may be null
  48     private final RelativePathPattern _right;
  49     private InstructionHandle _loop;
  50 
  51     public AncestorPattern(RelativePathPattern right) {
  52         this(null, right);
  53     }
  54 
  55     public AncestorPattern(Pattern left, RelativePathPattern right) {
  56         _left = left;
  57         (_right = right).setParent(this);
  58         if (left != null) {
  59             left.setParent(this);
  60         }
  61     }
  62 
  63     public InstructionHandle getLoopHandle() {
  64         return _loop;
  65     }
  66 
  67     public void setParser(Parser parser) {
  68         super.setParser(parser);
  69         if (_left != null) {
  70             _left.setParser(parser);
  71         }
  72         _right.setParser(parser);
  73     }
  74 
  75     public boolean isWildcard() {
  76         //!!! can be wildcard
  77         return false;
  78     }
  79 
  80     public StepPattern getKernelPattern() {
  81         return _right.getKernelPattern();
  82     }
  83 
  84     public void reduceKernelPattern() {
  85         _right.reduceKernelPattern();
  86     }
  87 
  88     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  89         if (_left != null) {
  90             _left.typeCheck(stable);
  91         }
  92         return _right.typeCheck(stable);
  93     }
  94 
  95     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  96         InstructionHandle parent;
  97         final ConstantPoolGen cpg = classGen.getConstantPool();
  98         final InstructionList il = methodGen.getInstructionList();
  99 
 100         /*
 101          * The scope of this local var must be the entire method since
 102          * a another pattern may decide to jump back into the loop
 103          */
 104         final LocalVariableGen local =
 105             methodGen.addLocalVariable2("app", Util.getJCRefType(NODE_SIG),
 106                                         il.getEnd());
 107 
 108         final com.sun.org.apache.bcel.internal.generic.Instruction loadLocal =
 109             new ILOAD(local.getIndex());
 110         final com.sun.org.apache.bcel.internal.generic.Instruction storeLocal =
 111             new ISTORE(local.getIndex());
 112 
 113         if (_right instanceof StepPattern) {
 114             il.append(DUP);
 115             il.append(storeLocal);
 116             _right.translate(classGen, methodGen);
 117             il.append(methodGen.loadDOM());
 118             il.append(loadLocal);
 119         }
 120         else {
 121             _right.translate(classGen, methodGen);
 122 
 123             if (_right instanceof AncestorPattern) {
 124                 il.append(methodGen.loadDOM());
 125                 il.append(SWAP);
 126             }
 127         }
 128 
 129         if (_left != null) {
 130             final int getParent = cpg.addInterfaceMethodref(DOM_INTF,
 131                                                             GET_PARENT,
 132                                                             GET_PARENT_SIG);
 133             parent = il.append(new INVOKEINTERFACE(getParent, 2));
 134 
 135             il.append(DUP);
 136             il.append(storeLocal);
 137             _falseList.add(il.append(new IFLT(null)));
 138             il.append(loadLocal);
 139 
 140             _left.translate(classGen, methodGen);
 141 
 142             final SyntaxTreeNode p = getParent();
 143             if (p == null || p instanceof Instruction ||
 144                 p instanceof TopLevelElement)
 145             {
 146                 // do nothing
 147             }
 148             else {
 149                 il.append(loadLocal);
 150             }
 151 
 152             final BranchHandle exit = il.append(new GOTO(null));
 153             _loop = il.append(methodGen.loadDOM());
 154             il.append(loadLocal);
 155             local.setEnd(_loop);
 156             il.append(new GOTO(parent));
 157             exit.setTarget(il.append(NOP));
 158             _left.backPatchFalseList(_loop);
 159 
 160             _trueList.append(_left._trueList);
 161         }
 162         else {
 163             il.append(POP2);
 164         }
 165 
 166         /*
 167          * If _right is an ancestor pattern, backpatch this pattern's false
 168          * list to the loop that searches for more ancestors.
 169          */
 170         if (_right instanceof AncestorPattern) {
 171             final AncestorPattern ancestor = (AncestorPattern) _right;
 172             _falseList.backPatch(ancestor.getLoopHandle());    // clears list
 173         }
 174 
 175         _trueList.append(_right._trueList);
 176         _falseList.append(_right._falseList);
 177     }
 178 
 179     public String toString() {
 180         return "AncestorPattern(" + _left + ", " + _right + ')';
 181     }
 182 }