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