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: FilterParentPath.java,v 1.2.4.1 2005/09/12 10:24:55 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.NodeSetType;
38  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
39  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
40  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
41  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
42  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
43  
44  /**
45   * @author Jacek Ambroziak
46   * @author Santiago Pericas-Geertsen
47   */
48  final class FilterParentPath extends Expression {
49  
50      private Expression _filterExpr;
51      private Expression _path;
52      private boolean _hasDescendantAxis = false;
53  
54      public FilterParentPath(Expression filterExpr, Expression path) {
55          (_path = path).setParent(this);
56          (_filterExpr = filterExpr).setParent(this);
57      }
58  
59      public void setParser(Parser parser) {
60          super.setParser(parser);
61          _filterExpr.setParser(parser);
62          _path.setParser(parser);
63      }
64  
65      public String toString() {
66          return "FilterParentPath(" + _filterExpr + ", " + _path + ')';
67      }
68  
69      public void setDescendantAxis() {
70          _hasDescendantAxis = true;
71      }
72  
73      /**
74       * Type check a FilterParentPath. If the filter is not a node-set add a
75       * cast to node-set only if it is of reference type. This type coercion is
76       * needed for expressions like $x/LINE where $x is a parameter reference.
77       */
78      public Type typeCheck(SymbolTable stable) throws TypeCheckError {
79          final Type ftype = _filterExpr.typeCheck(stable);
80          if (ftype instanceof NodeSetType == false) {
81              if (ftype instanceof ReferenceType)  {
82                  _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
83              }
84              /*
85              else if (ftype instanceof ResultTreeType)  {
86                  _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
87              }
88              */
89              else if (ftype instanceof NodeType)  {
90                  _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
91              }
92              else {
93                  throw new TypeCheckError(this);
94              }
95          }
96  
97          // Wrap single node path in a node set
98          final Type ptype = _path.typeCheck(stable);
99          if (!(ptype instanceof NodeSetType)) {
100             _path = new CastExpr(_path, Type.NodeSet);
101         }
102 
103         return _type = Type.NodeSet;
104     }
105 
106     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
107         final ConstantPoolGen cpg = classGen.getConstantPool();
108         final InstructionList il = methodGen.getInstructionList();
109         // Create new StepIterator
110         final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS,
111                                             "<init>",
112                                             "("
113                                             +NODE_ITERATOR_SIG
114                                             +NODE_ITERATOR_SIG
115                                             +")V");
116 
117         // Backwards branches are prohibited if an uninitialized object is
118         // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
119         // We don't know whether this code might contain backwards branches,
120         // so we mustn't create the new object until after we've created
121         // the suspect arguments to its constructor.  Instead we calculate
122         // the values of the arguments to the constructor first, store them
123         // in temporary variables, create the object and reload the
124         // arguments from the temporaries to avoid the problem.
125 
126         // Recursively compile 2 iterators
127         _filterExpr.translate(classGen, methodGen);
128         LocalVariableGen filterTemp =
129                 methodGen.addLocalVariable("filter_parent_path_tmp1",
130                                            Util.getJCRefType(NODE_ITERATOR_SIG),
131                                            null, null);
132         filterTemp.setStart(il.append(new ASTORE(filterTemp.getIndex())));
133 
134         _path.translate(classGen, methodGen);
135         LocalVariableGen pathTemp =
136                 methodGen.addLocalVariable("filter_parent_path_tmp2",
137                                            Util.getJCRefType(NODE_ITERATOR_SIG),
138                                            null, null);
139         pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex())));
140 
141         il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS)));
142         il.append(DUP);
143         filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex())));
144         pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex())));
145 
146         // Initialize StepIterator with iterators from the stack
147         il.append(new INVOKESPECIAL(initSI));
148 
149         // This is a special case for the //* path with or without predicates
150         if (_hasDescendantAxis) {
151             final int incl = cpg.addMethodref(NODE_ITERATOR_BASE,
152                                               "includeSelf",
153                                               "()" + NODE_ITERATOR_SIG);
154             il.append(new INVOKEVIRTUAL(incl));
155         }
156 
157         SyntaxTreeNode parent = getParent();
158 
159         boolean parentAlreadyOrdered =
160             (parent instanceof RelativeLocationPath)
161                 || (parent instanceof FilterParentPath)
162                 || (parent instanceof KeyCall)
163                 || (parent instanceof CurrentCall)
164                 || (parent instanceof DocumentCall);
165 
166         if (!parentAlreadyOrdered) {
167             final int order = cpg.addInterfaceMethodref(DOM_INTF,
168                                                         ORDER_ITERATOR,
169                                                         ORDER_ITERATOR_SIG);
170             il.append(methodGen.loadDOM());
171             il.append(SWAP);
172             il.append(methodGen.loadContextNode());
173             il.append(new INVOKEINTERFACE(order, 3));
174         }
175     }
176 }