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    }