001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: NodeSetType.java 468649 2006-10-28 07:00:55Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler.util; 023 024 import org.apache.bcel.generic.ALOAD; 025 import org.apache.bcel.generic.ASTORE; 026 import org.apache.bcel.generic.BranchHandle; 027 import org.apache.bcel.generic.ConstantPoolGen; 028 import org.apache.bcel.generic.GOTO; 029 import org.apache.bcel.generic.IFLT; 030 import org.apache.bcel.generic.INVOKEINTERFACE; 031 import org.apache.bcel.generic.INVOKESTATIC; 032 import org.apache.bcel.generic.Instruction; 033 import org.apache.bcel.generic.InstructionList; 034 import org.apache.bcel.generic.PUSH; 035 import org.apache.xalan.xsltc.compiler.Constants; 036 import org.apache.xalan.xsltc.compiler.FlowList; 037 038 /** 039 * @author Jacek Ambroziak 040 * @author Santiago Pericas-Geertsen 041 */ 042 public final class NodeSetType extends Type { 043 protected NodeSetType() {} 044 045 public String toString() { 046 return "node-set"; 047 } 048 049 public boolean identicalTo(Type other) { 050 return this == other; 051 } 052 053 public String toSignature() { 054 return NODE_ITERATOR_SIG; 055 } 056 057 public org.apache.bcel.generic.Type toJCType() { 058 return new org.apache.bcel.generic.ObjectType(NODE_ITERATOR); 059 } 060 061 /** 062 * Translates a node-set into an object of internal type 063 * <code>type</code>. The translation to int is undefined 064 * since node-sets are always converted to 065 * reals in arithmetic expressions. 066 * 067 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 068 */ 069 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 070 Type type) { 071 if (type == Type.String) { 072 translateTo(classGen, methodGen, (StringType) type); 073 } 074 else if (type == Type.Boolean) { 075 translateTo(classGen, methodGen, (BooleanType) type); 076 } 077 else if (type == Type.Real) { 078 translateTo(classGen, methodGen, (RealType) type); 079 } 080 else if (type == Type.Node) { 081 translateTo(classGen, methodGen, (NodeType) type); 082 } 083 else if (type == Type.Reference) { 084 translateTo(classGen, methodGen, (ReferenceType) type); 085 } 086 else if (type == Type.Object) { 087 translateTo(classGen, methodGen, (ObjectType) type); 088 } 089 else { 090 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 091 toString(), type.toString()); 092 classGen.getParser().reportError(Constants.FATAL, err); 093 } 094 } 095 096 /** 097 * Translates an external Java Class into an internal type. 098 * Expects the Java object on the stack, pushes the internal type 099 */ 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 org.apache.xalan.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 org.apache.xalan.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 org.apache.xalan.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 org.apache.xalan.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 org.apache.xalan.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 org.apache.xalan.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 org.apache.xalan.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 }