1 /*
2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  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 package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
22 
23 import com.sun.org.apache.bcel.internal.generic.ALOAD;
24 import com.sun.org.apache.bcel.internal.generic.ASTORE;
25 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
27 import com.sun.org.apache.bcel.internal.generic.GOTO;
28 import com.sun.org.apache.bcel.internal.generic.IFLT;
29 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
30 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
31 import com.sun.org.apache.bcel.internal.generic.Instruction;
32 import com.sun.org.apache.bcel.internal.generic.InstructionList;
33 import com.sun.org.apache.bcel.internal.generic.PUSH;
34 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
35 import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
36 
37 /**
38  * @author Jacek Ambroziak
39  * @author Santiago Pericas-Geertsen
40  * @LastModified: Oct 2017
41  */
42 public final class NodeSetType extends Type {
NodeSetType()43     protected NodeSetType() {}
44 
toString()45     public String toString() {
46         return "node-set";
47     }
48 
identicalTo(Type other)49     public boolean identicalTo(Type other) {
50         return this == other;
51     }
52 
toSignature()53     public String toSignature() {
54         return NODE_ITERATOR_SIG;
55     }
56 
toJCType()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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, Type type)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      */
translateFrom(ClassGenerator classGen, MethodGenerator methodGen, Class<?> clazz)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, StringType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, RealType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, NodeType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, ObjectType type)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      */
translateToDesynthesized(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, ReferenceType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, Class<?> clazz)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      */
getFirstNode(ClassGenerator classGen, MethodGenerator methodGen)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      */
translateBox(ClassGenerator classGen, MethodGenerator methodGen)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      */
translateUnBox(ClassGenerator classGen, MethodGenerator methodGen)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      */
getClassName()317     public String getClassName() {
318         return(NODE_ITERATOR);
319     }
320 
321 
LOAD(int slot)322     public Instruction LOAD(int slot) {
323         return new ALOAD(slot);
324     }
325 
STORE(int slot)326     public Instruction STORE(int slot) {
327         return new ASTORE(slot);
328     }
329 }
330