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 }