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: FilterExpr.java,v 1.2.4.1 2005/09/12 10:22:50 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import java.util.Vector;
27  
28  import com.sun.org.apache.bcel.internal.generic.ALOAD;
29  import com.sun.org.apache.bcel.internal.generic.ASTORE;
30  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
31  import com.sun.org.apache.bcel.internal.generic.ILOAD;
32  import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
33  import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
34  import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
35  import com.sun.org.apache.bcel.internal.generic.InstructionList;
36  import com.sun.org.apache.bcel.internal.generic.ISTORE;
37  import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
38  import com.sun.org.apache.bcel.internal.generic.NEW;
39  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
40  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
41  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
42  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
43  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
44  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
45  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
46  
47  /**
48   * @author Jacek Ambroziak
49   * @author Santiago Pericas-Geertsen
50   * @author Morten Jorgensen
51   */
52  class FilterExpr extends Expression {
53  
54      /**
55       * Primary expression of this filter. I.e., 'e' in '(e)[p1]...[pn]'.
56       */
57      private Expression   _primary;
58  
59      /**
60       * Array of predicates in '(e)[p1]...[pn]'.
61       */
62      private final Vector _predicates;
63  
64      public FilterExpr(Expression primary, Vector predicates) {
65          _primary = primary;
66          _predicates = predicates;
67          primary.setParent(this);
68      }
69  
70      protected Expression getExpr() {
71          if (_primary instanceof CastExpr)
72              return ((CastExpr)_primary).getExpr();
73          else
74              return _primary;
75      }
76  
77      public void setParser(Parser parser) {
78          super.setParser(parser);
79          _primary.setParser(parser);
80          if (_predicates != null) {
81              final int n = _predicates.size();
82              for (int i = 0; i < n; i++) {
83                  final Expression exp = (Expression)_predicates.elementAt(i);
84                  exp.setParser(parser);
85                  exp.setParent(this);
86              }
87          }
88      }
89  
90      public String toString() {
91          return "filter-expr(" + _primary + ", " + _predicates + ")";
92      }
93  
94      /**
95       * Type check a FilterParentPath. If the filter is not a node-set add a
96       * cast to node-set only if it is of reference type. This type coercion
97       * is needed for expressions like $x where $x is a parameter reference.
98       * All optimizations are turned off before type checking underlying
99       * predicates.
100      */
101     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
102         Type ptype = _primary.typeCheck(stable);
103         boolean canOptimize = _primary instanceof KeyCall;
104 
105         if (ptype instanceof NodeSetType == false) {
106             if (ptype instanceof ReferenceType)  {
107                 _primary = new CastExpr(_primary, Type.NodeSet);
108             }
109             else {
110                 throw new TypeCheckError(this);
111             }
112         }
113 
114         // Type check predicates and turn all optimizations off if appropriate
115         int n = _predicates.size();
116         for (int i = 0; i < n; i++) {
117             Predicate pred = (Predicate) _predicates.elementAt(i);
118 
119             if (!canOptimize) {
120                 pred.dontOptimize();
121             }
122             pred.typeCheck(stable);
123         }
124         return _type = Type.NodeSet;
125     }
126 
127     /**
128      * Translate a filter expression by pushing the appropriate iterator
129      * onto the stack.
130      */
131     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
132         translateFilterExpr(classGen, methodGen, _predicates == null ? -1 : _predicates.size() - 1);
133     }
134 
135     private void translateFilterExpr(ClassGenerator classGen,
136                                      MethodGenerator methodGen,
137                                      int predicateIndex) {
138         if (predicateIndex >= 0) {
139             translatePredicates(classGen, methodGen, predicateIndex);
140         }
141         else {
142             _primary.translate(classGen, methodGen);
143         }
144     }
145 
146     /**
147      * Translate a sequence of predicates. Each predicate is translated
148      * by constructing an instance of <code>CurrentNodeListIterator</code>
149      * which is initialized from another iterator (recursive call), a
150      * filter and a closure (call to translate on the predicate) and "this".
151      */
152     public void translatePredicates(ClassGenerator classGen,
153                                     MethodGenerator methodGen,
154                                     int predicateIndex) {
155         final ConstantPoolGen cpg = classGen.getConstantPool();
156         final InstructionList il = methodGen.getInstructionList();
157 
158         // If not predicates left, translate primary expression
159         if (predicateIndex < 0) {
160             translateFilterExpr(classGen, methodGen, predicateIndex);
161         }
162         else {
163             // Get the next predicate to be translated
164             Predicate predicate = (Predicate) _predicates.get(predicateIndex--);
165 
166             // Translate the rest of the predicates from right to left
167             translatePredicates(classGen, methodGen, predicateIndex);
168 
169             if (predicate.isNthPositionFilter()) {
170                 int nthIteratorIdx = cpg.addMethodref(NTH_ITERATOR_CLASS,
171                                        "<init>",
172                                        "("+NODE_ITERATOR_SIG+"I)V");
173 
174                 // Backwards branches are prohibited if an uninitialized object
175                 // is on the stack by section 4.9.4 of the JVM Specification,
176                 // 2nd Ed.  We don't know whether this code might contain
177                 // backwards branches, so we mustn't create the new object unti
178 
179                 // after we've created the suspect arguments to its constructor
180 
181                 // Instead we calculate the values of the arguments to the
182                 // constructor first, store them in temporary variables, create
183                 // the object and reload the arguments from the temporaries to
184                 // avoid the problem.
185                 LocalVariableGen iteratorTemp
186                         = methodGen.addLocalVariable("filter_expr_tmp1",
187                                          Util.getJCRefType(NODE_ITERATOR_SIG),
188                                          null, null);
189                 iteratorTemp.setStart(
190                         il.append(new ASTORE(iteratorTemp.getIndex())));
191 
192                 predicate.translate(classGen, methodGen);
193                 LocalVariableGen predicateValueTemp
194                         = methodGen.addLocalVariable("filter_expr_tmp2",
195                                          Util.getJCRefType("I"),
196                                          null, null);
197                 predicateValueTemp.setStart(
198                         il.append(new ISTORE(predicateValueTemp.getIndex())));
199 
200                 il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS)));
201                 il.append(DUP);
202                 iteratorTemp.setEnd(
203                         il.append(new ALOAD(iteratorTemp.getIndex())));
204                 predicateValueTemp.setEnd(
205                         il.append(new ILOAD(predicateValueTemp.getIndex())));
206                 il.append(new INVOKESPECIAL(nthIteratorIdx));
207             } else {
208                     // Translate predicates from right to left
209                 final int initCNLI = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR,
210                                                       "<init>",
211                                                       "("+NODE_ITERATOR_SIG+"Z"+
212                                                       CURRENT_NODE_LIST_FILTER_SIG +
213                                                       NODE_SIG+TRANSLET_SIG+")V");
214 
215                 // Backwards branches are prohibited if an uninitialized object is
216                 // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
217                 // We don't know whether this code might contain backwards branches,
218                 // so we mustn't create the new object until after we've created
219                 // the suspect arguments to its constructor.  Instead we calculate
220                 // the values of the arguments to the constructor first, store them
221                 // in temporary variables, create the object and reload the
222                 // arguments from the temporaries to avoid the problem.
223 
224 
225                 LocalVariableGen nodeIteratorTemp =
226                     methodGen.addLocalVariable("filter_expr_tmp1",
227                                                Util.getJCRefType(NODE_ITERATOR_SIG),
228                                                null, null);
229                 nodeIteratorTemp.setStart(
230                         il.append(new ASTORE(nodeIteratorTemp.getIndex())));
231 
232                 predicate.translate(classGen, methodGen);
233                 LocalVariableGen filterTemp =
234                     methodGen.addLocalVariable("filter_expr_tmp2",
235                                   Util.getJCRefType(CURRENT_NODE_LIST_FILTER_SIG),
236                                   null, null);
237                 filterTemp.setStart(il.append(new ASTORE(filterTemp.getIndex())));
238 
239                 // Create a CurrentNodeListIterator
240                 il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
241                 il.append(DUP);
242 
243                 // Initialize CurrentNodeListIterator
244                 nodeIteratorTemp.setEnd(
245                         il.append(new ALOAD(nodeIteratorTemp.getIndex())));
246                 il.append(ICONST_1);
247                 filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex())));
248                 il.append(methodGen.loadCurrentNode());
249                 il.append(classGen.loadTranslet());
250                 il.append(new INVOKESPECIAL(initCNLI));
251             }
252         }
253     }
254 }