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 }