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