View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2005 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: ParentLocationPath.java,v 1.2.4.1 2005/09/12 10:56:30 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import com.sun.org.apache.bcel.internal.generic.ALOAD;
27  import com.sun.org.apache.bcel.internal.generic.ASTORE;
28  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
29  import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
30  import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
31  import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
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.bcel.internal.generic.NEW;
35  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
36  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
37  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
38  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
39  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
40  import com.sun.org.apache.xml.internal.dtm.Axis;
41  import com.sun.org.apache.xml.internal.dtm.DTM;
42  
43  /**
44   * @author Jacek Ambroziak
45   * @author Santiago Pericas-Geertsen
46   */
47  final class ParentLocationPath extends RelativeLocationPath {
48      private Expression _step;
49      private final RelativeLocationPath _path;
50      private Type stype;
51      private boolean _orderNodes = false;
52      private boolean _axisMismatch = false;
53  
54      public ParentLocationPath(RelativeLocationPath path, Expression step) {
55          _path = path;
56          _step = step;
57          _path.setParent(this);
58          _step.setParent(this);
59  
60          if (_step instanceof Step) {
61              _axisMismatch = checkAxisMismatch();
62          }
63      }
64  
65      public void setAxis(int axis) {
66          _path.setAxis(axis);
67      }
68  
69      public int getAxis() {
70          return _path.getAxis();
71      }
72  
73      public RelativeLocationPath getPath() {
74          return(_path);
75      }
76  
77      public Expression getStep() {
78          return(_step);
79      }
80  
81      public void setParser(Parser parser) {
82          super.setParser(parser);
83          _step.setParser(parser);
84          _path.setParser(parser);
85      }
86  
87      public String toString() {
88          return "ParentLocationPath(" + _path + ", " + _step + ')';
89      }
90  
91      public Type typeCheck(SymbolTable stable) throws TypeCheckError {
92          stype = _step.typeCheck(stable);
93          _path.typeCheck(stable);
94  
95          if (_axisMismatch) enableNodeOrdering();
96  
97          return _type = Type.NodeSet;
98      }
99  
100     public void enableNodeOrdering() {
101         SyntaxTreeNode parent = getParent();
102         if (parent instanceof ParentLocationPath)
103             ((ParentLocationPath)parent).enableNodeOrdering();
104         else {
105             _orderNodes = true;
106         }
107     }
108 
109     /**
110      * This method is used to determine if this parent location path is a
111      * combination of two step's with axes that will create duplicate or
112      * unordered nodes.
113      */
114     public boolean checkAxisMismatch() {
115 
116         int left = _path.getAxis();
117         int right = ((Step)_step).getAxis();
118 
119         if (((left == Axis.ANCESTOR) || (left == Axis.ANCESTORORSELF)) &&
120             ((right == Axis.CHILD) ||
121              (right == Axis.DESCENDANT) ||
122              (right == Axis.DESCENDANTORSELF) ||
123              (right == Axis.PARENT) ||
124              (right == Axis.PRECEDING) ||
125              (right == Axis.PRECEDINGSIBLING)))
126             return true;
127 
128         if ((left == Axis.CHILD) &&
129             (right == Axis.ANCESTOR) ||
130             (right == Axis.ANCESTORORSELF) ||
131             (right == Axis.PARENT) ||
132             (right == Axis.PRECEDING))
133             return true;
134 
135         if ((left == Axis.DESCENDANT) || (left == Axis.DESCENDANTORSELF))
136             return true;
137 
138         if (((left == Axis.FOLLOWING) || (left == Axis.FOLLOWINGSIBLING)) &&
139             ((right == Axis.FOLLOWING) ||
140              (right == Axis.PARENT) ||
141              (right == Axis.PRECEDING) ||
142              (right == Axis.PRECEDINGSIBLING)))
143             return true;
144 
145         if (((left == Axis.PRECEDING) || (left == Axis.PRECEDINGSIBLING)) &&
146             ((right == Axis.DESCENDANT) ||
147              (right == Axis.DESCENDANTORSELF) ||
148              (right == Axis.FOLLOWING) ||
149              (right == Axis.FOLLOWINGSIBLING) ||
150              (right == Axis.PARENT) ||
151              (right == Axis.PRECEDING) ||
152              (right == Axis.PRECEDINGSIBLING)))
153             return true;
154 
155         if ((right == Axis.FOLLOWING) && (left == Axis.CHILD)) {
156             // Special case for '@*/following::*' expressions. The resulting
157             // iterator is initialised with the parent's first child, and this
158             // can cause duplicates in the output if the parent has more than
159             // one attribute that matches the left step.
160             if (_path instanceof Step) {
161                 int type = ((Step)_path).getNodeType();
162                 if (type == DTM.ATTRIBUTE_NODE) return true;
163             }
164         }
165 
166         return false;
167     }
168 
169     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
170 
171         // Compile path iterator
172         _path.translate(classGen, methodGen); // iterator on stack....
173 
174         translateStep(classGen, methodGen);
175     }
176 
177     public void translateStep(ClassGenerator classGen, MethodGenerator methodGen) {
178         final ConstantPoolGen cpg = classGen.getConstantPool();
179         final InstructionList il = methodGen.getInstructionList();
180 
181         // Backwards branches are prohibited if an uninitialized object is
182         // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
183         // We don't know whether this code might contain backwards branches
184         // so we mustn't create the new object until after we've created
185         // the suspect arguments to its constructor.  Instead we calculate
186         // the values of the arguments to the constructor first, store them
187         // in temporary variables, create the object and reload the
188         // arguments from the temporaries to avoid the problem.
189 
190         LocalVariableGen pathTemp
191                 = methodGen.addLocalVariable("parent_location_path_tmp1",
192                                          Util.getJCRefType(NODE_ITERATOR_SIG),
193                                          null, null);
194         pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex())));
195 
196         _step.translate(classGen, methodGen);
197         LocalVariableGen stepTemp
198                 = methodGen.addLocalVariable("parent_location_path_tmp2",
199                                          Util.getJCRefType(NODE_ITERATOR_SIG),
200                                          null, null);
201         stepTemp.setStart(il.append(new ASTORE(stepTemp.getIndex())));
202 
203         // Create new StepIterator
204         final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS,
205                                             "<init>",
206                                             "("
207                                             +NODE_ITERATOR_SIG
208                                             +NODE_ITERATOR_SIG
209                                             +")V");
210         il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS)));
211         il.append(DUP);
212 
213         pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex())));
214         stepTemp.setEnd(il.append(new ALOAD(stepTemp.getIndex())));
215 
216         // Initialize StepIterator with iterators from the stack
217         il.append(new INVOKESPECIAL(initSI));
218 
219         // This is a special case for the //* path with or without predicates
220         Expression stp = _step;
221         if (stp instanceof ParentLocationPath)
222             stp = ((ParentLocationPath)stp).getStep();
223 
224         if ((_path instanceof Step) && (stp instanceof Step)) {
225             final int path = ((Step)_path).getAxis();
226             final int step = ((Step)stp).getAxis();
227             if ((path == Axis.DESCENDANTORSELF && step == Axis.CHILD) ||
228                 (path == Axis.PRECEDING        && step == Axis.PARENT)) {
229                 final int incl = cpg.addMethodref(NODE_ITERATOR_BASE,
230                                                   "includeSelf",
231                                                   "()" + NODE_ITERATOR_SIG);
232                 il.append(new INVOKEVIRTUAL(incl));
233             }
234         }
235 
236         /*
237          * If this pattern contains a sequence of descendant iterators we
238          * run the risk of returning the same node several times. We put
239          * a new iterator on top of the existing one to assure node order
240          * and prevent returning a single node multiple times.
241          */
242         if (_orderNodes) {
243             final int order = cpg.addInterfaceMethodref(DOM_INTF,
244                                                         ORDER_ITERATOR,
245                                                         ORDER_ITERATOR_SIG);
246             il.append(methodGen.loadDOM());
247             il.append(SWAP);
248             il.append(methodGen.loadContextNode());
249             il.append(new INVOKEINTERFACE(order, 3));
250         }
251     }
252 }