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: ResultTreeType.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.CHECKCAST; 027 import org.apache.bcel.generic.ConstantPoolGen; 028 import org.apache.bcel.generic.GETFIELD; 029 import org.apache.bcel.generic.IFEQ; 030 import org.apache.bcel.generic.INVOKEINTERFACE; 031 import org.apache.bcel.generic.INVOKESPECIAL; 032 import org.apache.bcel.generic.INVOKEVIRTUAL; 033 import org.apache.bcel.generic.Instruction; 034 import org.apache.bcel.generic.InstructionList; 035 import org.apache.bcel.generic.LocalVariableGen; 036 import org.apache.bcel.generic.NEW; 037 import org.apache.bcel.generic.PUSH; 038 import org.apache.xalan.xsltc.compiler.Constants; 039 import org.apache.xalan.xsltc.compiler.FlowList; 040 041 /** 042 * @author Jacek Ambroziak 043 * @author Santiago Pericas-Geertsen 044 * @author Morten Jorgensen 045 */ 046 public final class ResultTreeType extends Type { 047 private final String _methodName; 048 049 protected ResultTreeType() { 050 _methodName = null; 051 } 052 053 public ResultTreeType(String methodName) { 054 _methodName = methodName; 055 } 056 057 public String toString() { 058 return "result-tree"; 059 } 060 061 public boolean identicalTo(Type other) { 062 return (other instanceof ResultTreeType); 063 } 064 065 public String toSignature() { 066 return DOM_INTF_SIG; 067 } 068 069 public org.apache.bcel.generic.Type toJCType() { 070 return Util.getJCRefType(toSignature()); 071 } 072 073 public String getMethodName() { 074 return _methodName; 075 } 076 077 public boolean implementedAsMethod() { 078 return _methodName != null; 079 } 080 081 /** 082 * Translates a result tree to object of internal type <code>type</code>. 083 * The translation to int is undefined since result trees 084 * are always converted to reals in arithmetic expressions. 085 * 086 * @param classGen A BCEL class generator 087 * @param methodGen A BCEL method generator 088 * @param type An instance of the type to translate the result tree to 089 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 090 */ 091 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 092 Type type) { 093 if (type == Type.String) { 094 translateTo(classGen, methodGen, (StringType)type); 095 } 096 else if (type == Type.Boolean) { 097 translateTo(classGen, methodGen, (BooleanType)type); 098 } 099 else if (type == Type.Real) { 100 translateTo(classGen, methodGen, (RealType)type); 101 } 102 else if (type == Type.NodeSet) { 103 translateTo(classGen, methodGen, (NodeSetType)type); 104 } 105 else if (type == Type.Reference) { 106 translateTo(classGen, methodGen, (ReferenceType)type); 107 } 108 else if (type == Type.Object) { 109 translateTo(classGen, methodGen, (ObjectType) type); 110 } 111 else { 112 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 113 toString(), type.toString()); 114 classGen.getParser().reportError(Constants.FATAL, err); 115 } 116 } 117 118 /** 119 * Expects an result tree on the stack and pushes a boolean. 120 * Translates a result tree to a boolean by first converting it to string. 121 * 122 * @param classGen A BCEL class generator 123 * @param methodGen A BCEL method generator 124 * @param type An instance of BooleanType (any) 125 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 126 */ 127 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 128 BooleanType type) { 129 // A result tree is always 'true' when converted to a boolean value, 130 // since the tree always has at least one node (the root). 131 final ConstantPoolGen cpg = classGen.getConstantPool(); 132 final InstructionList il = methodGen.getInstructionList(); 133 il.append(POP); // don't need the DOM reference 134 il.append(ICONST_1); // push 'true' on the stack 135 } 136 137 /** 138 * Expects an result tree on the stack and pushes a string. 139 * 140 * @param classGen A BCEL class generator 141 * @param methodGen A BCEL method generator 142 * @param type An instance of StringType (any) 143 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 144 */ 145 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 146 StringType type) { 147 final ConstantPoolGen cpg = classGen.getConstantPool(); 148 final InstructionList il = methodGen.getInstructionList(); 149 150 if (_methodName == null) { 151 int index = cpg.addInterfaceMethodref(DOM_INTF, 152 "getStringValue", 153 "()"+STRING_SIG); 154 il.append(new INVOKEINTERFACE(index, 1)); 155 } 156 else { 157 final String className = classGen.getClassName(); 158 final int current = methodGen.getLocalIndex("current"); 159 160 // Push required parameters 161 il.append(classGen.loadTranslet()); 162 if (classGen.isExternal()) { 163 il.append(new CHECKCAST(cpg.addClass(className))); 164 } 165 il.append(DUP); 166 il.append(new GETFIELD(cpg.addFieldref(className, "_dom", 167 DOM_INTF_SIG))); 168 169 // Create a new instance of a StringValueHandler 170 int index = cpg.addMethodref(STRING_VALUE_HANDLER, "<init>", "()V"); 171 il.append(new NEW(cpg.addClass(STRING_VALUE_HANDLER))); 172 il.append(DUP); 173 il.append(DUP); 174 il.append(new INVOKESPECIAL(index)); 175 176 // Store new Handler into a local variable 177 final LocalVariableGen handler = 178 methodGen.addLocalVariable("rt_to_string_handler", 179 Util.getJCRefType(STRING_VALUE_HANDLER_SIG), 180 null, null); 181 handler.setStart(il.append(new ASTORE(handler.getIndex()))); 182 183 // Call the method that implements this result tree 184 index = cpg.addMethodref(className, _methodName, 185 "("+DOM_INTF_SIG+TRANSLET_OUTPUT_SIG+")V"); 186 il.append(new INVOKEVIRTUAL(index)); 187 188 // Restore new handler and call getValue() 189 handler.setEnd(il.append(new ALOAD(handler.getIndex()))); 190 index = cpg.addMethodref(STRING_VALUE_HANDLER, 191 "getValue", 192 "()" + STRING_SIG); 193 il.append(new INVOKEVIRTUAL(index)); 194 } 195 } 196 197 /** 198 * Expects an result tree on the stack and pushes a real. 199 * Translates a result tree into a real by first converting it to string. 200 * 201 * @param classGen A BCEL class generator 202 * @param methodGen A BCEL method generator 203 * @param type An instance of RealType (any) 204 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 205 */ 206 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 207 RealType type) { 208 translateTo(classGen, methodGen, Type.String); 209 Type.String.translateTo(classGen, methodGen, Type.Real); 210 } 211 212 /** 213 * Expects a result tree on the stack and pushes a boxed result tree. 214 * Result trees are already boxed so the translation is just a NOP. 215 * 216 * @param classGen A BCEL class generator 217 * @param methodGen A BCEL method generator 218 * @param type An instance of ReferenceType (any) 219 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 220 */ 221 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 222 ReferenceType type) { 223 final ConstantPoolGen cpg = classGen.getConstantPool(); 224 final InstructionList il = methodGen.getInstructionList(); 225 226 if (_methodName == null) { 227 il.append(NOP); 228 } 229 else { 230 LocalVariableGen domBuilder, newDom; 231 final String className = classGen.getClassName(); 232 final int current = methodGen.getLocalIndex("current"); 233 234 // Push required parameters 235 il.append(classGen.loadTranslet()); 236 if (classGen.isExternal()) { 237 il.append(new CHECKCAST(cpg.addClass(className))); 238 } 239 il.append(methodGen.loadDOM()); 240 241 // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes) 242 il.append(methodGen.loadDOM()); 243 int index = cpg.addInterfaceMethodref(DOM_INTF, 244 "getResultTreeFrag", 245 "(IZ)" + DOM_INTF_SIG); 246 il.append(new PUSH(cpg, RTF_INITIAL_SIZE)); 247 il.append(new PUSH(cpg, false)); 248 il.append(new INVOKEINTERFACE(index,3)); 249 il.append(DUP); 250 251 // Store new DOM into a local variable 252 newDom = methodGen.addLocalVariable("rt_to_reference_dom", 253 Util.getJCRefType(DOM_INTF_SIG), 254 null, null); 255 il.append(new CHECKCAST(cpg.addClass(DOM_INTF_SIG))); 256 newDom.setStart(il.append(new ASTORE(newDom.getIndex()))); 257 258 // Overwrite old handler with DOM handler 259 index = cpg.addInterfaceMethodref(DOM_INTF, 260 "getOutputDomBuilder", 261 "()" + TRANSLET_OUTPUT_SIG); 262 263 il.append(new INVOKEINTERFACE(index,1)); 264 //index = cpg.addMethodref(DOM_IMPL, 265 // "getOutputDomBuilder", 266 // "()" + TRANSLET_OUTPUT_SIG); 267 //il.append(new INVOKEVIRTUAL(index)); 268 il.append(DUP); 269 il.append(DUP); 270 271 // Store DOM handler in a local in order to call endDocument() 272 domBuilder = 273 methodGen.addLocalVariable("rt_to_reference_handler", 274 Util.getJCRefType(TRANSLET_OUTPUT_SIG), 275 null, null); 276 domBuilder.setStart(il.append(new ASTORE(domBuilder.getIndex()))); 277 278 // Call startDocument on the new handler 279 index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 280 "startDocument", "()V"); 281 il.append(new INVOKEINTERFACE(index, 1)); 282 283 // Call the method that implements this result tree 284 index = cpg.addMethodref(className, 285 _methodName, 286 "(" 287 + DOM_INTF_SIG 288 + TRANSLET_OUTPUT_SIG 289 +")V"); 290 il.append(new INVOKEVIRTUAL(index)); 291 292 // Call endDocument on the DOM handler 293 domBuilder.setEnd(il.append(new ALOAD(domBuilder.getIndex()))); 294 index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 295 "endDocument", "()V"); 296 il.append(new INVOKEINTERFACE(index, 1)); 297 298 // Push the new DOM on the stack 299 newDom.setEnd(il.append(new ALOAD(newDom.getIndex()))); 300 } 301 } 302 303 /** 304 * Expects a result tree on the stack and pushes a node-set (iterator). 305 * Note that the produced iterator is an iterator for the DOM that 306 * contains the result tree, and not the DOM that is currently in use. 307 * This conversion here will therefore not directly work with elements 308 * such as <xsl:apply-templates> and <xsl:for-each> without the DOM 309 * parameter/variable being updates as well. 310 * 311 * @param classGen A BCEL class generator 312 * @param methodGen A BCEL method generator 313 * @param type An instance of NodeSetType (any) 314 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 315 */ 316 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 317 NodeSetType type) { 318 final ConstantPoolGen cpg = classGen.getConstantPool(); 319 final InstructionList il = methodGen.getInstructionList(); 320 321 // Put an extra copy of the result tree (DOM) on the stack 322 il.append(DUP); 323 324 // DOM adapters containing a result tree are not initialised with 325 // translet-type to DOM-type mapping. This must be done now for 326 // XPath expressions and patterns to work for the iterator we create. 327 il.append(classGen.loadTranslet()); // get names array 328 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 329 NAMES_INDEX, 330 NAMES_INDEX_SIG))); 331 il.append(classGen.loadTranslet()); // get uris array 332 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 333 URIS_INDEX, 334 URIS_INDEX_SIG))); 335 il.append(classGen.loadTranslet()); // get types array 336 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 337 TYPES_INDEX, 338 TYPES_INDEX_SIG))); 339 il.append(classGen.loadTranslet()); // get namespaces array 340 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 341 NAMESPACE_INDEX, 342 NAMESPACE_INDEX_SIG))); 343 // Pass the type mappings to the DOM adapter 344 final int mapping = cpg.addInterfaceMethodref(DOM_INTF, 345 "setupMapping", 346 "(["+STRING_SIG+ 347 "["+STRING_SIG+ 348 "[I" + 349 "["+STRING_SIG+")V"); 350 il.append(new INVOKEINTERFACE(mapping, 5)); 351 il.append(DUP); 352 353 // Create an iterator for the root node of the DOM adapter 354 final int iter = cpg.addInterfaceMethodref(DOM_INTF, 355 "getIterator", 356 "()"+NODE_ITERATOR_SIG); 357 il.append(new INVOKEINTERFACE(iter, 1)); 358 } 359 360 /** 361 * Subsume result tree into ObjectType. 362 * 363 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 364 */ 365 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 366 ObjectType type) { 367 methodGen.getInstructionList().append(NOP); 368 } 369 370 /** 371 * Translates a result tree into a non-synthesized boolean. 372 * It does not push a 0 or a 1 but instead returns branchhandle list 373 * to be appended to the false list. 374 * 375 * @param classGen A BCEL class generator 376 * @param methodGen A BCEL method generator 377 * @param type An instance of BooleanType (any) 378 * @see org.apache.xalan.xsltc.compiler.util.Type#translateToDesynthesized 379 */ 380 public FlowList translateToDesynthesized(ClassGenerator classGen, 381 MethodGenerator methodGen, 382 BooleanType type) { 383 final InstructionList il = methodGen.getInstructionList(); 384 translateTo(classGen, methodGen, Type.Boolean); 385 return new FlowList(il.append(new IFEQ(null))); 386 } 387 388 /** 389 * Translates a result tree to a Java type denoted by <code>clazz</code>. 390 * Expects a result tree on the stack and pushes an object 391 * of the appropriate type after coercion. Result trees are translated 392 * to W3C Node or W3C NodeList and the translation is done 393 * via node-set type. 394 * 395 * @param classGen A BCEL class generator 396 * @param methodGen A BCEL method generator 397 * @param clazz An reference to the Class to translate to 398 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 399 */ 400 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 401 Class clazz) { 402 final String className = clazz.getName(); 403 final ConstantPoolGen cpg = classGen.getConstantPool(); 404 final InstructionList il = methodGen.getInstructionList(); 405 406 if (className.equals("org.w3c.dom.Node")) { 407 translateTo(classGen, methodGen, Type.NodeSet); 408 int index = cpg.addInterfaceMethodref(DOM_INTF, 409 MAKE_NODE, 410 MAKE_NODE_SIG2); 411 il.append(new INVOKEINTERFACE(index, 2)); 412 } 413 else if (className.equals("org.w3c.dom.NodeList")) { 414 translateTo(classGen, methodGen, Type.NodeSet); 415 int index = cpg.addInterfaceMethodref(DOM_INTF, 416 MAKE_NODE_LIST, 417 MAKE_NODE_LIST_SIG2); 418 il.append(new INVOKEINTERFACE(index, 2)); 419 } 420 else if (className.equals("java.lang.Object")) { 421 il.append(NOP); 422 } 423 else if (className.equals("java.lang.String")) { 424 translateTo(classGen, methodGen, Type.String); 425 } 426 else { 427 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 428 toString(), className); 429 classGen.getParser().reportError(Constants.FATAL, err); 430 } 431 } 432 433 /** 434 * Translates an object of this type to its boxed representation. 435 */ 436 public void translateBox(ClassGenerator classGen, 437 MethodGenerator methodGen) { 438 translateTo(classGen, methodGen, Type.Reference); 439 } 440 441 /** 442 * Translates an object of this type to its unboxed representation. 443 */ 444 public void translateUnBox(ClassGenerator classGen, 445 MethodGenerator methodGen) { 446 methodGen.getInstructionList().append(NOP); 447 } 448 449 /** 450 * Returns the class name of an internal type's external representation. 451 */ 452 public String getClassName() { 453 return(DOM_INTF); 454 } 455 456 public Instruction LOAD(int slot) { 457 return new ALOAD(slot); 458 } 459 460 public Instruction STORE(int slot) { 461 return new ASTORE(slot); 462 } 463 }