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: NodeSetType.java,v 1.2.4.1 2005/09/05 11:21:45 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.BranchHandle;
29 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
30 import com.sun.org.apache.bcel.internal.generic.GOTO;
31 import com.sun.org.apache.bcel.internal.generic.IFLT;
32 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
33 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
34 import com.sun.org.apache.bcel.internal.generic.Instruction;
35 import com.sun.org.apache.bcel.internal.generic.InstructionList;
36 import com.sun.org.apache.bcel.internal.generic.PUSH;
37 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
38 import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
39 
40 /**
41  * @author Jacek Ambroziak
42  * @author Santiago Pericas-Geertsen
43  */
44 public final class NodeSetType extends Type {
NodeSetType()45     protected NodeSetType() {}
46 
toString()47     public String toString() {
48         return "node-set";
49     }
50 
identicalTo(Type other)51     public boolean identicalTo(Type other) {
52         return this == other;
53     }
54 
toSignature()55     public String toSignature() {
56         return NODE_ITERATOR_SIG;
57     }
58 
toJCType()59     public com.sun.org.apache.bcel.internal.generic.Type toJCType() {
60         return new com.sun.org.apache.bcel.internal.generic.ObjectType(NODE_ITERATOR);
61     }
62 
63     /**
64      * Translates a node-set into an object of internal type
65      * <code>type</code>. The translation to int is undefined
66      * since node-sets are always converted to
67      * reals in arithmetic expressions.
68      *
69      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
70      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, Type type)71     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
72                             Type type) {
73         if (type == Type.String) {
74             translateTo(classGen, methodGen, (StringType) type);
75         }
76         else if (type == Type.Boolean) {
77             translateTo(classGen, methodGen, (BooleanType) type);
78         }
79         else if (type == Type.Real) {
80             translateTo(classGen, methodGen, (RealType) type);
81         }
82         else if (type == Type.Node) {
83             translateTo(classGen, methodGen, (NodeType) type);
84         }
85         else if (type == Type.Reference) {
86             translateTo(classGen, methodGen, (ReferenceType) type);
87         }
88         else if (type == Type.Object) {
89             translateTo(classGen, methodGen, (ObjectType) type);
90         }
91         else {
92             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
93                                         toString(), type.toString());
94             classGen.getParser().reportError(Constants.FATAL, err);
95         }
96     }
97 
98     /**
99      * Translates an external Java Class into an internal type.
100      * Expects the Java object on the stack, pushes the internal type
101      */
translateFrom(ClassGenerator classGen, MethodGenerator methodGen, Class clazz)102     public void translateFrom(ClassGenerator classGen,
103         MethodGenerator methodGen, Class clazz)
104     {
105 
106         InstructionList il = methodGen.getInstructionList();
107         ConstantPoolGen cpg = classGen.getConstantPool();
108         if (clazz.getName().equals("org.w3c.dom.NodeList")) {
109            // w3c NodeList is on the stack from the external Java function call.
110            // call BasisFunction to consume NodeList and leave Iterator on
111            //    the stack.
112            il.append(classGen.loadTranslet());   // push translet onto stack
113            il.append(methodGen.loadDOM());       // push DOM onto stack
114            final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
115                                         "nodeList2Iterator",
116                                         "("
117                                          + "Lorg/w3c/dom/NodeList;"
118                                          + TRANSLET_INTF_SIG
119                                          + DOM_INTF_SIG
120                                          + ")" + NODE_ITERATOR_SIG );
121            il.append(new INVOKESTATIC(convert));
122         }
123         else if (clazz.getName().equals("org.w3c.dom.Node")) {
124            // w3c Node is on the stack from the external Java function call.
125            // call BasisLibrary.node2Iterator() to consume Node and leave
126            // Iterator on the stack.
127            il.append(classGen.loadTranslet());   // push translet onto stack
128            il.append(methodGen.loadDOM());       // push DOM onto stack
129            final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
130                                         "node2Iterator",
131                                         "("
132                                          + "Lorg/w3c/dom/Node;"
133                                          + TRANSLET_INTF_SIG
134                                          + DOM_INTF_SIG
135                                          + ")" + NODE_ITERATOR_SIG );
136            il.append(new INVOKESTATIC(convert));
137         }
138         else {
139             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
140                 toString(), clazz.getName());
141             classGen.getParser().reportError(Constants.FATAL, err);
142         }
143     }
144 
145 
146     /**
147      * Translates a node-set into a synthesized boolean.
148      * The boolean value of a node-set is "true" if non-empty
149      * and "false" otherwise. Notice that the
150      * function getFirstNode() is called in translateToDesynthesized().
151      *
152      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
153      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)154     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
155                             BooleanType type) {
156         final InstructionList il = methodGen.getInstructionList();
157         FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
158         il.append(ICONST_1);
159         final BranchHandle truec = il.append(new GOTO(null));
160         falsel.backPatch(il.append(ICONST_0));
161         truec.setTarget(il.append(NOP));
162     }
163 
164     /**
165      * Translates a node-set into a string. The string value of a node-set is
166      * value of its first element.
167      *
168      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
169      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, StringType type)170     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
171                             StringType type) {
172         final InstructionList il = methodGen.getInstructionList();
173         getFirstNode(classGen, methodGen);
174         il.append(DUP);
175         final BranchHandle falsec = il.append(new IFLT(null));
176         Type.Node.translateTo(classGen, methodGen, type);
177         final BranchHandle truec = il.append(new GOTO(null));
178         falsec.setTarget(il.append(POP));
179         il.append(new PUSH(classGen.getConstantPool(), ""));
180         truec.setTarget(il.append(NOP));
181     }
182 
183     /**
184      * Expects a node-set on the stack and pushes a real.
185      * First the node-set is converted to string, and from string to real.
186      *
187      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
188      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, RealType type)189     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
190                             RealType type) {
191         translateTo(classGen, methodGen, Type.String);
192         Type.String.translateTo(classGen, methodGen, Type.Real);
193     }
194 
195     /**
196      * Expects a node-set on the stack and pushes a node.
197      *
198      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
199      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, NodeType type)200     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
201                             NodeType type) {
202         getFirstNode(classGen, methodGen);
203     }
204 
205     /**
206      * Subsume node-set into ObjectType.
207      *
208      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
209      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, ObjectType type)210     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
211                             ObjectType type) {
212             methodGen.getInstructionList().append(NOP);
213     }
214 
215     /**
216      * Translates a node-set into a non-synthesized boolean. It does not
217      * push a 0 or a 1 but instead returns branchhandle list to be appended
218      * to the false list.
219      *
220      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized
221      */
translateToDesynthesized(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)222     public FlowList translateToDesynthesized(ClassGenerator classGen,
223                                              MethodGenerator methodGen,
224                                              BooleanType type) {
225         final InstructionList il = methodGen.getInstructionList();
226         getFirstNode(classGen, methodGen);
227         return new FlowList(il.append(new IFLT(null)));
228     }
229 
230     /**
231      * Expects a node-set on the stack and pushes a boxed node-set.
232      * Node sets are already boxed so the translation is just a NOP.
233      *
234      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
235      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, ReferenceType type)236     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
237                             ReferenceType type) {
238         methodGen.getInstructionList().append(NOP);
239     }
240 
241     /**
242      * Translates a node-set into the Java type denoted by <code>clazz</code>.
243      * Expects a node-set on the stack and pushes an object of the appropriate
244      * type after coercion.
245      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, Class clazz)246     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
247                             Class clazz) {
248         final ConstantPoolGen cpg = classGen.getConstantPool();
249         final InstructionList il = methodGen.getInstructionList();
250         final String className = clazz.getName();
251 
252         il.append(methodGen.loadDOM());
253         il.append(SWAP);
254 
255         if (className.equals("org.w3c.dom.Node")) {
256             int index = cpg.addInterfaceMethodref(DOM_INTF,
257                                                   MAKE_NODE,
258                                                   MAKE_NODE_SIG2);
259             il.append(new INVOKEINTERFACE(index, 2));
260         }
261         else if (className.equals("org.w3c.dom.NodeList") ||
262                  className.equals("java.lang.Object")) {
263             int index = cpg.addInterfaceMethodref(DOM_INTF,
264                                                   MAKE_NODE_LIST,
265                                                   MAKE_NODE_LIST_SIG2);
266             il.append(new INVOKEINTERFACE(index, 2));
267         }
268         else if (className.equals("java.lang.String")) {
269             int next = cpg.addInterfaceMethodref(NODE_ITERATOR,
270                                                  "next", "()I");
271             int index = cpg.addInterfaceMethodref(DOM_INTF,
272                                                  GET_NODE_VALUE,
273                                                  "(I)"+STRING_SIG);
274 
275             // Get next node from the iterator
276             il.append(new INVOKEINTERFACE(next, 1));
277             // Get the node's string value (from the DOM)
278             il.append(new INVOKEINTERFACE(index, 2));
279 
280         }
281         else {
282             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
283                                         toString(), className);
284             classGen.getParser().reportError(Constants.FATAL, err);
285         }
286     }
287 
288     /**
289      * Some type conversions require gettting the first node from the node-set.
290      * This function is defined to avoid code repetition.
291      */
getFirstNode(ClassGenerator classGen, MethodGenerator methodGen)292     private void getFirstNode(ClassGenerator classGen, MethodGenerator methodGen) {
293         final ConstantPoolGen cpg = classGen.getConstantPool();
294         final InstructionList il = methodGen.getInstructionList();
295         il.append(new INVOKEINTERFACE(cpg.addInterfaceMethodref(NODE_ITERATOR,
296                                                                 NEXT,
297                                                                 NEXT_SIG), 1));
298     }
299 
300     /**
301      * Translates an object of this type to its boxed representation.
302      */
translateBox(ClassGenerator classGen, MethodGenerator methodGen)303     public void translateBox(ClassGenerator classGen,
304                              MethodGenerator methodGen) {
305         translateTo(classGen, methodGen, Type.Reference);
306     }
307 
308     /**
309      * Translates an object of this type to its unboxed representation.
310      */
translateUnBox(ClassGenerator classGen, MethodGenerator methodGen)311     public void translateUnBox(ClassGenerator classGen,
312                                MethodGenerator methodGen) {
313         methodGen.getInstructionList().append(NOP);
314     }
315 
316     /**
317      * Returns the class name of an internal type's external representation.
318      */
getClassName()319     public String getClassName() {
320         return(NODE_ITERATOR);
321     }
322 
323 
LOAD(int slot)324     public Instruction LOAD(int slot) {
325         return new ALOAD(slot);
326     }
327 
STORE(int slot)328     public Instruction STORE(int slot) {
329         return new ASTORE(slot);
330     }
331 }
332