001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: AncestorPattern.java 468650 2006-10-28 07:03:30Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import org.apache.bcel.generic.BranchHandle; 025 import org.apache.bcel.generic.ConstantPoolGen; 026 import org.apache.bcel.generic.GOTO; 027 import org.apache.bcel.generic.IFLT; 028 import org.apache.bcel.generic.ILOAD; 029 import org.apache.bcel.generic.INVOKEINTERFACE; 030 import org.apache.bcel.generic.ISTORE; 031 import org.apache.bcel.generic.InstructionHandle; 032 import org.apache.bcel.generic.InstructionList; 033 import org.apache.bcel.generic.LocalVariableGen; 034 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 035 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 036 import org.apache.xalan.xsltc.compiler.util.Type; 037 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 038 import org.apache.xalan.xsltc.compiler.util.Util; 039 040 /** 041 * @author Jacek Ambroziak 042 * @author Santiago Pericas-Geertsen 043 * @author Erwin Bolwidt <ejb@klomp.org> 044 */ 045 final class AncestorPattern extends RelativePathPattern { 046 047 private final Pattern _left; // may be null 048 private final RelativePathPattern _right; 049 private InstructionHandle _loop; 050 051 public AncestorPattern(RelativePathPattern right) { 052 this(null, right); 053 } 054 055 public AncestorPattern(Pattern left, RelativePathPattern right) { 056 _left = left; 057 (_right = right).setParent(this); 058 if (left != null) { 059 left.setParent(this); 060 } 061 } 062 063 public InstructionHandle getLoopHandle() { 064 return _loop; 065 } 066 067 public void setParser(Parser parser) { 068 super.setParser(parser); 069 if (_left != null) { 070 _left.setParser(parser); 071 } 072 _right.setParser(parser); 073 } 074 075 public boolean isWildcard() { 076 //!!! can be wildcard 077 return false; 078 } 079 080 public StepPattern getKernelPattern() { 081 return _right.getKernelPattern(); 082 } 083 084 public void reduceKernelPattern() { 085 _right.reduceKernelPattern(); 086 } 087 088 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 089 if (_left != null) { 090 _left.typeCheck(stable); 091 } 092 return _right.typeCheck(stable); 093 } 094 095 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 096 InstructionHandle parent; 097 final ConstantPoolGen cpg = classGen.getConstantPool(); 098 final InstructionList il = methodGen.getInstructionList(); 099 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 org.apache.bcel.generic.Instruction loadLocal = 109 new ILOAD(local.getIndex()); 110 final org.apache.bcel.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 }