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: 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 {
45      protected NodeSetType() {}
46  
47      public String toString() {
48          return "node-set";
49      }
50  
51      public boolean identicalTo(Type other) {
52          return this == other;
53      }
54  
55      public String toSignature() {
56          return NODE_ITERATOR_SIG;
57      }
58  
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       */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
319     public String getClassName() {
320         return(NODE_ITERATOR);
321     }
322 
323 
324     public Instruction LOAD(int slot) {
325         return new ALOAD(slot);
326     }
327 
328     public Instruction STORE(int slot) {
329         return new ASTORE(slot);
330     }
331 }