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