View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 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: ResultTreeType.java,v 1.2.4.1 2005/09/05 11:30:01 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
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.CHECKCAST;
29  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
30  import com.sun.org.apache.bcel.internal.generic.GETFIELD;
31  import com.sun.org.apache.bcel.internal.generic.IFEQ;
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.INVOKEVIRTUAL;
35  import com.sun.org.apache.bcel.internal.generic.Instruction;
36  import com.sun.org.apache.bcel.internal.generic.InstructionList;
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.bcel.internal.generic.PUSH;
40  import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
41  import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
42  
43  /**
44   * @author Jacek Ambroziak
45   * @author Santiago Pericas-Geertsen
46   * @author Morten Jorgensen
47   */
48  public final class ResultTreeType extends Type {
49      private final String _methodName;
50  
51      protected ResultTreeType() {
52          _methodName = null;
53      }
54  
55      public ResultTreeType(String methodName) {
56          _methodName = methodName;
57      }
58  
59      public String toString() {
60          return "result-tree";
61      }
62  
63      public boolean identicalTo(Type other) {
64          return (other instanceof ResultTreeType);
65      }
66  
67      public String toSignature() {
68          return DOM_INTF_SIG;
69      }
70  
71      public com.sun.org.apache.bcel.internal.generic.Type toJCType() {
72          return Util.getJCRefType(toSignature());
73      }
74  
75      public String getMethodName() {
76          return _methodName;
77      }
78  
79      public boolean implementedAsMethod() {
80          return _methodName != null;
81      }
82  
83      /**
84       * Translates a result tree to object of internal type <code>type</code>.
85       * The translation to int is undefined since result trees
86       * are always converted to reals in arithmetic expressions.
87       *
88       * @param classGen A BCEL class generator
89       * @param methodGen A BCEL method generator
90       * @param type An instance of the type to translate the result tree to
91       * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
92       */
93      public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
94                              Type type) {
95          if (type == Type.String) {
96              translateTo(classGen, methodGen, (StringType)type);
97          }
98          else if (type == Type.Boolean) {
99              translateTo(classGen, methodGen, (BooleanType)type);
100         }
101         else if (type == Type.Real) {
102             translateTo(classGen, methodGen, (RealType)type);
103         }
104         else if (type == Type.NodeSet) {
105             translateTo(classGen, methodGen, (NodeSetType)type);
106         }
107         else if (type == Type.Reference) {
108             translateTo(classGen, methodGen, (ReferenceType)type);
109         }
110         else if (type == Type.Object) {
111             translateTo(classGen, methodGen, (ObjectType) type);
112         }
113         else {
114             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
115                                         toString(), type.toString());
116             classGen.getParser().reportError(Constants.FATAL, err);
117         }
118     }
119 
120     /**
121      * Expects an result tree on the stack and pushes a boolean.
122      * Translates a result tree to a boolean by first converting it to string.
123      *
124      * @param classGen A BCEL class generator
125      * @param methodGen A BCEL method generator
126      * @param type An instance of BooleanType (any)
127      * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
128      */
129     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
130                             BooleanType type) {
131         // A result tree is always 'true' when converted to a boolean value,
132         // since the tree always has at least one node (the root).
133         final ConstantPoolGen cpg = classGen.getConstantPool();
134         final InstructionList il = methodGen.getInstructionList();
135         il.append(POP);      // don't need the DOM reference
136         il.append(ICONST_1); // push 'true' on the stack
137     }
138 
139     /**
140      * Expects an result tree on the stack and pushes a string.
141      *
142      * @param classGen A BCEL class generator
143      * @param methodGen A BCEL method generator
144      * @param type An instance of StringType (any)
145      * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
146      */
147     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
148                             StringType type) {
149         final ConstantPoolGen cpg = classGen.getConstantPool();
150         final InstructionList il = methodGen.getInstructionList();
151 
152         if (_methodName == null) {
153             int index = cpg.addInterfaceMethodref(DOM_INTF,
154                                                   "getStringValue",
155                                                   "()"+STRING_SIG);
156             il.append(new INVOKEINTERFACE(index, 1));
157         }
158         else {
159             final String className = classGen.getClassName();
160             final int current = methodGen.getLocalIndex("current");
161 
162             // Push required parameters
163             il.append(classGen.loadTranslet());
164             if (classGen.isExternal()) {
165                 il.append(new CHECKCAST(cpg.addClass(className)));
166             }
167             il.append(DUP);
168             il.append(new GETFIELD(cpg.addFieldref(className, "_dom",
169                                                    DOM_INTF_SIG)));
170 
171             // Create a new instance of a StringValueHandler
172             int index = cpg.addMethodref(STRING_VALUE_HANDLER, "<init>", "()V");
173             il.append(new NEW(cpg.addClass(STRING_VALUE_HANDLER)));
174             il.append(DUP);
175             il.append(DUP);
176             il.append(new INVOKESPECIAL(index));
177 
178             // Store new Handler into a local variable
179             final LocalVariableGen handler =
180                 methodGen.addLocalVariable("rt_to_string_handler",
181                                            Util.getJCRefType(STRING_VALUE_HANDLER_SIG),
182                                            null, null);
183             handler.setStart(il.append(new ASTORE(handler.getIndex())));
184 
185             // Call the method that implements this result tree
186             index = cpg.addMethodref(className, _methodName,
187                                      "("+DOM_INTF_SIG+TRANSLET_OUTPUT_SIG+")V");
188             il.append(new INVOKEVIRTUAL(index));
189 
190             // Restore new handler and call getValue()
191             handler.setEnd(il.append(new ALOAD(handler.getIndex())));
192             index = cpg.addMethodref(STRING_VALUE_HANDLER,
193                                      "getValue",
194                                      "()" + STRING_SIG);
195             il.append(new INVOKEVIRTUAL(index));
196         }
197     }
198 
199     /**
200      * Expects an result tree on the stack and pushes a real.
201      * Translates a result tree into a real by first converting it to string.
202      *
203      * @param classGen A BCEL class generator
204      * @param methodGen A BCEL method generator
205      * @param type An instance of RealType (any)
206      * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
207      */
208     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
209                             RealType type) {
210         translateTo(classGen, methodGen, Type.String);
211         Type.String.translateTo(classGen, methodGen, Type.Real);
212     }
213 
214     /**
215      * Expects a result tree on the stack and pushes a boxed result tree.
216      * Result trees are already boxed so the translation is just a NOP.
217      *
218      * @param classGen A BCEL class generator
219      * @param methodGen A BCEL method generator
220      * @param type An instance of ReferenceType (any)
221      * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
222      */
223     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
224                             ReferenceType type) {
225         final ConstantPoolGen cpg = classGen.getConstantPool();
226         final InstructionList il = methodGen.getInstructionList();
227 
228         if (_methodName == null) {
229             il.append(NOP);
230         }
231         else {
232             LocalVariableGen domBuilder, newDom;
233             final String className = classGen.getClassName();
234             final int current = methodGen.getLocalIndex("current");
235 
236             // Push required parameters
237             il.append(classGen.loadTranslet());
238             if (classGen.isExternal()) {
239                 il.append(new CHECKCAST(cpg.addClass(className)));
240             }
241             il.append(methodGen.loadDOM());
242 
243             // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes)
244             il.append(methodGen.loadDOM());
245             int index = cpg.addInterfaceMethodref(DOM_INTF,
246                                  "getResultTreeFrag",
247                                  "(IZ)" + DOM_INTF_SIG);
248             il.append(new PUSH(cpg, RTF_INITIAL_SIZE));
249             il.append(new PUSH(cpg, false));
250             il.append(new INVOKEINTERFACE(index,3));
251             il.append(DUP);
252 
253             // Store new DOM into a local variable
254             newDom = methodGen.addLocalVariable("rt_to_reference_dom",
255                                                 Util.getJCRefType(DOM_INTF_SIG),
256                                                 null, null);
257             il.append(new CHECKCAST(cpg.addClass(DOM_INTF_SIG)));
258             newDom.setStart(il.append(new ASTORE(newDom.getIndex())));
259 
260             // Overwrite old handler with DOM handler
261             index = cpg.addInterfaceMethodref(DOM_INTF,
262                                  "getOutputDomBuilder",
263                                  "()" + TRANSLET_OUTPUT_SIG);
264 
265             il.append(new INVOKEINTERFACE(index,1));
266             //index = cpg.addMethodref(DOM_IMPL,
267                 //                   "getOutputDomBuilder",
268                 //                   "()" + TRANSLET_OUTPUT_SIG);
269             //il.append(new INVOKEVIRTUAL(index));
270             il.append(DUP);
271             il.append(DUP);
272 
273             // Store DOM handler in a local in order to call endDocument()
274             domBuilder =
275                 methodGen.addLocalVariable("rt_to_reference_handler",
276                                            Util.getJCRefType(TRANSLET_OUTPUT_SIG),
277                                            null, null);
278             domBuilder.setStart(il.append(new ASTORE(domBuilder.getIndex())));
279 
280             // Call startDocument on the new handler
281             index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
282                                               "startDocument", "()V");
283             il.append(new INVOKEINTERFACE(index, 1));
284 
285             // Call the method that implements this result tree
286             index = cpg.addMethodref(className,
287                                      _methodName,
288                                      "("
289                                      + DOM_INTF_SIG
290                                      + TRANSLET_OUTPUT_SIG
291                                      +")V");
292             il.append(new INVOKEVIRTUAL(index));
293 
294             // Call endDocument on the DOM handler
295             domBuilder.setEnd(il.append(new ALOAD(domBuilder.getIndex())));
296             index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
297                                               "endDocument", "()V");
298             il.append(new INVOKEINTERFACE(index, 1));
299 
300             // Push the new DOM on the stack
301             newDom.setEnd(il.append(new ALOAD(newDom.getIndex())));
302         }
303     }
304 
305     /**
306      * Expects a result tree on the stack and pushes a node-set (iterator).
307      * Note that the produced iterator is an iterator for the DOM that
308      * contains the result tree, and not the DOM that is currently in use.
309      * This conversion here will therefore not directly work with elements
310      * such as <xsl:apply-templates> and <xsl:for-each> without the DOM
311      * parameter/variable being updates as well.
312      *
313      * @param classGen A BCEL class generator
314      * @param methodGen A BCEL method generator
315      * @param type An instance of NodeSetType (any)
316      * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
317      */
318     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
319                             NodeSetType type) {
320         final ConstantPoolGen cpg = classGen.getConstantPool();
321         final InstructionList il = methodGen.getInstructionList();
322 
323         // Put an extra copy of the result tree (DOM) on the stack
324         il.append(DUP);
325 
326         // DOM adapters containing a result tree are not initialised with
327         // translet-type to DOM-type mapping. This must be done now for
328         // XPath expressions and patterns to work for the iterator we create.
329         il.append(classGen.loadTranslet()); // get names array
330         il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
331                                                NAMES_INDEX,
332                                                NAMES_INDEX_SIG)));
333         il.append(classGen.loadTranslet()); // get uris array
334         il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
335                                                URIS_INDEX,
336                                                URIS_INDEX_SIG)));
337         il.append(classGen.loadTranslet()); // get types array
338         il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
339                                                TYPES_INDEX,
340                                                TYPES_INDEX_SIG)));
341         il.append(classGen.loadTranslet()); // get namespaces array
342         il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
343                                                NAMESPACE_INDEX,
344                                                NAMESPACE_INDEX_SIG)));
345         // Pass the type mappings to the DOM adapter
346         final int mapping = cpg.addInterfaceMethodref(DOM_INTF,
347                                                       "setupMapping",
348                                                       "(["+STRING_SIG+
349                                                       "["+STRING_SIG+
350                                                       "[I" +
351                                                       "["+STRING_SIG+")V");
352         il.append(new INVOKEINTERFACE(mapping, 5));
353         il.append(DUP);
354 
355         // Create an iterator for the root node of the DOM adapter
356         final int iter = cpg.addInterfaceMethodref(DOM_INTF,
357                                                    "getIterator",
358                                                    "()"+NODE_ITERATOR_SIG);
359         il.append(new INVOKEINTERFACE(iter, 1));
360     }
361 
362     /**
363      * Subsume result tree into ObjectType.
364      *
365      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
366      */
367     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
368                             ObjectType type) {
369         methodGen.getInstructionList().append(NOP);
370     }
371 
372     /**
373      * Translates a result tree into a non-synthesized boolean.
374      * It does not push a 0 or a 1 but instead returns branchhandle list
375      * to be appended to the false list.
376      *
377      * @param classGen A BCEL class generator
378      * @param methodGen A BCEL method generator
379      * @param type An instance of BooleanType (any)
380      * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized
381      */
382     public FlowList translateToDesynthesized(ClassGenerator classGen,
383                                              MethodGenerator methodGen,
384                                              BooleanType type) {
385         final InstructionList il = methodGen.getInstructionList();
386         translateTo(classGen, methodGen, Type.Boolean);
387         return new FlowList(il.append(new IFEQ(null)));
388     }
389 
390     /**
391      * Translates a result tree to a Java type denoted by <code>clazz</code>.
392      * Expects a result tree on the stack and pushes an object
393      * of the appropriate type after coercion. Result trees are translated
394      * to W3C Node or W3C NodeList and the translation is done
395      * via node-set type.
396      *
397      * @param classGen A BCEL class generator
398      * @param methodGen A BCEL method generator
399      * @param clazz An reference to the Class to translate to
400      * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
401      */
402     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
403                             Class clazz) {
404         final String className = clazz.getName();
405         final ConstantPoolGen cpg = classGen.getConstantPool();
406         final InstructionList il = methodGen.getInstructionList();
407 
408         if (className.equals("org.w3c.dom.Node")) {
409             translateTo(classGen, methodGen, Type.NodeSet);
410             int index = cpg.addInterfaceMethodref(DOM_INTF,
411                                                   MAKE_NODE,
412                                                   MAKE_NODE_SIG2);
413             il.append(new INVOKEINTERFACE(index, 2));
414         }
415         else if (className.equals("org.w3c.dom.NodeList")) {
416             translateTo(classGen, methodGen, Type.NodeSet);
417             int index = cpg.addInterfaceMethodref(DOM_INTF,
418                                                   MAKE_NODE_LIST,
419                                                   MAKE_NODE_LIST_SIG2);
420             il.append(new INVOKEINTERFACE(index, 2));
421         }
422         else if (className.equals("java.lang.Object")) {
423             il.append(NOP);
424         }
425         else if (className.equals("java.lang.String")) {
426             translateTo(classGen, methodGen, Type.String);
427         }
428         else {
429             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
430                                         toString(), className);
431             classGen.getParser().reportError(Constants.FATAL, err);
432         }
433     }
434 
435     /**
436      * Translates an object of this type to its boxed representation.
437      */
438     public void translateBox(ClassGenerator classGen,
439                              MethodGenerator methodGen) {
440         translateTo(classGen, methodGen, Type.Reference);
441     }
442 
443     /**
444      * Translates an object of this type to its unboxed representation.
445      */
446     public void translateUnBox(ClassGenerator classGen,
447                                MethodGenerator methodGen) {
448         methodGen.getInstructionList().append(NOP);
449     }
450 
451     /**
452      * Returns the class name of an internal type's external representation.
453      */
454     public String getClassName() {
455         return(DOM_INTF);
456     }
457 
458     public Instruction LOAD(int slot) {
459         return new ALOAD(slot);
460     }
461 
462     public Instruction STORE(int slot) {
463         return new ASTORE(slot);
464     }
465 }