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: NodeType.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.BranchHandle; 025 import org.apache.bcel.generic.CHECKCAST; 026 import org.apache.bcel.generic.ConstantPoolGen; 027 import org.apache.bcel.generic.GETFIELD; 028 import org.apache.bcel.generic.GOTO; 029 import org.apache.bcel.generic.IFEQ; 030 import org.apache.bcel.generic.ILOAD; 031 import org.apache.bcel.generic.INVOKEINTERFACE; 032 import org.apache.bcel.generic.INVOKESPECIAL; 033 import org.apache.bcel.generic.ISTORE; 034 import org.apache.bcel.generic.Instruction; 035 import org.apache.bcel.generic.InstructionList; 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 import org.apache.xalan.xsltc.compiler.NodeTest; 041 042 /** 043 * @author Jacek Ambroziak 044 * @author Santiago Pericas-Geertsen 045 */ 046 public final class NodeType extends Type { 047 private final int _type; 048 049 protected NodeType() { 050 this(NodeTest.ANODE); 051 } 052 053 protected NodeType(int type) { 054 _type = type; 055 } 056 057 public int getType() { 058 return _type; 059 } 060 061 public String toString() { 062 return "node-type"; 063 } 064 065 public boolean identicalTo(Type other) { 066 return other instanceof NodeType; 067 } 068 069 public int hashCode() { 070 return _type; 071 } 072 073 public String toSignature() { 074 return "I"; 075 } 076 077 public org.apache.bcel.generic.Type toJCType() { 078 return org.apache.bcel.generic.Type.INT; 079 } 080 081 /** 082 * Translates a node into an object of internal type <code>type</code>. 083 * The translation to int is undefined since nodes are always converted 084 * to reals in arithmetic expressions. 085 * 086 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 087 */ 088 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 089 Type type) { 090 if (type == Type.String) { 091 translateTo(classGen, methodGen, (StringType) type); 092 } 093 else if (type == Type.Boolean) { 094 translateTo(classGen, methodGen, (BooleanType) type); 095 } 096 else if (type == Type.Real) { 097 translateTo(classGen, methodGen, (RealType) type); 098 } 099 else if (type == Type.NodeSet) { 100 translateTo(classGen, methodGen, (NodeSetType) type); 101 } 102 else if (type == Type.Reference) { 103 translateTo(classGen, methodGen, (ReferenceType) type); 104 } 105 else if (type == Type.Object) { 106 translateTo(classGen, methodGen, (ObjectType) type); 107 } 108 else { 109 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 110 toString(), type.toString()); 111 classGen.getParser().reportError(Constants.FATAL, err); 112 } 113 } 114 115 /** 116 * Expects a node on the stack and pushes its string value. 117 * 118 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 119 */ 120 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 121 StringType type) { 122 final ConstantPoolGen cpg = classGen.getConstantPool(); 123 final InstructionList il = methodGen.getInstructionList(); 124 125 switch (_type) { 126 case NodeTest.ROOT: 127 case NodeTest.ELEMENT: 128 il.append(methodGen.loadDOM()); 129 il.append(SWAP); // dom ref must be below node index 130 int index = cpg.addInterfaceMethodref(DOM_INTF, 131 GET_ELEMENT_VALUE, 132 GET_ELEMENT_VALUE_SIG); 133 il.append(new INVOKEINTERFACE(index, 2)); 134 break; 135 136 case NodeTest.ANODE: 137 case NodeTest.COMMENT: 138 case NodeTest.ATTRIBUTE: 139 case NodeTest.PI: 140 il.append(methodGen.loadDOM()); 141 il.append(SWAP); // dom ref must be below node index 142 index = cpg.addInterfaceMethodref(DOM_INTF, 143 GET_NODE_VALUE, 144 GET_NODE_VALUE_SIG); 145 il.append(new INVOKEINTERFACE(index, 2)); 146 break; 147 148 default: 149 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 150 toString(), type.toString()); 151 classGen.getParser().reportError(Constants.FATAL, err); 152 break; 153 } 154 } 155 156 /** 157 * Translates a node into a synthesized boolean. 158 * If the expression is "@attr", 159 * then "true" is pushed iff "attr" is an attribute of the current node. 160 * If the expression is ".", the result is always "true". 161 * 162 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 163 */ 164 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 165 BooleanType type) { 166 final InstructionList il = methodGen.getInstructionList(); 167 FlowList falsel = translateToDesynthesized(classGen, methodGen, type); 168 il.append(ICONST_1); 169 final BranchHandle truec = il.append(new GOTO(null)); 170 falsel.backPatch(il.append(ICONST_0)); 171 truec.setTarget(il.append(NOP)); 172 } 173 174 /** 175 * Expects a node on the stack and pushes a real. 176 * First the node is converted to string, and from string to real. 177 * 178 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 179 */ 180 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 181 RealType type) { 182 translateTo(classGen, methodGen, Type.String); 183 Type.String.translateTo(classGen, methodGen, Type.Real); 184 } 185 186 /** 187 * Expects a node on the stack and pushes a singleton node-set. Singleton 188 * iterators are already started after construction. 189 * 190 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 191 */ 192 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 193 NodeSetType type) { 194 ConstantPoolGen cpg = classGen.getConstantPool(); 195 InstructionList il = methodGen.getInstructionList(); 196 197 // Create a new instance of SingletonIterator 198 il.append(new NEW(cpg.addClass(SINGLETON_ITERATOR))); 199 il.append(DUP_X1); 200 il.append(SWAP); 201 final int init = cpg.addMethodref(SINGLETON_ITERATOR, "<init>", 202 "(" + NODE_SIG +")V"); 203 il.append(new INVOKESPECIAL(init)); 204 } 205 206 /** 207 * Subsume Node into ObjectType. 208 * 209 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 210 */ 211 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 212 ObjectType type) { 213 methodGen.getInstructionList().append(NOP); 214 } 215 216 /** 217 * Translates a node into a non-synthesized boolean. It does not push a 218 * 0 or a 1 but instead returns branchhandle list to be appended to the 219 * false list. 220 * 221 * @see org.apache.xalan.xsltc.compiler.util.Type#translateToDesynthesized 222 */ 223 public FlowList translateToDesynthesized(ClassGenerator classGen, 224 MethodGenerator methodGen, 225 BooleanType type) { 226 final InstructionList il = methodGen.getInstructionList(); 227 return new FlowList(il.append(new IFEQ(null))); 228 } 229 230 /** 231 * Expects a node on the stack and pushes a boxed node. Boxed nodes 232 * are represented by an instance of <code>org.apache.xalan.xsltc.dom.Node</code>. 233 * 234 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 235 */ 236 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 237 ReferenceType type) { 238 final ConstantPoolGen cpg = classGen.getConstantPool(); 239 final InstructionList il = methodGen.getInstructionList(); 240 il.append(new NEW(cpg.addClass(RUNTIME_NODE_CLASS))); 241 il.append(DUP_X1); 242 il.append(SWAP); 243 il.append(new PUSH(cpg, _type)); 244 il.append(new INVOKESPECIAL(cpg.addMethodref(RUNTIME_NODE_CLASS, 245 "<init>", "(II)V"))); 246 } 247 248 /** 249 * Translates a node into the Java type denoted by <code>clazz</code>. 250 * Expects a node on the stack and pushes an object of the appropriate 251 * type after coercion. 252 */ 253 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 254 Class clazz) { 255 final ConstantPoolGen cpg = classGen.getConstantPool(); 256 final InstructionList il = methodGen.getInstructionList(); 257 258 String className = clazz.getName(); 259 if (className.equals("java.lang.String")) { 260 translateTo(classGen, methodGen, Type.String); 261 return; 262 } 263 264 il.append(methodGen.loadDOM()); 265 il.append(SWAP); // dom ref must be below node index 266 267 if (className.equals("org.w3c.dom.Node") || 268 className.equals("java.lang.Object")) { 269 int index = cpg.addInterfaceMethodref(DOM_INTF, 270 MAKE_NODE, 271 MAKE_NODE_SIG); 272 il.append(new INVOKEINTERFACE(index, 2)); 273 } 274 else if (className.equals("org.w3c.dom.NodeList")) { 275 int index = cpg.addInterfaceMethodref(DOM_INTF, 276 MAKE_NODE_LIST, 277 MAKE_NODE_LIST_SIG); 278 il.append(new INVOKEINTERFACE(index, 2)); 279 } 280 else { 281 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 282 toString(), className); 283 classGen.getParser().reportError(Constants.FATAL, err); 284 } 285 } 286 287 /** 288 * Translates an object of this type to its boxed representation. 289 */ 290 public void translateBox(ClassGenerator classGen, 291 MethodGenerator methodGen) { 292 translateTo(classGen, methodGen, Type.Reference); 293 } 294 295 /** 296 * Translates an object of this type to its unboxed representation. 297 */ 298 public void translateUnBox(ClassGenerator classGen, 299 MethodGenerator methodGen) { 300 final ConstantPoolGen cpg = classGen.getConstantPool(); 301 final InstructionList il = methodGen.getInstructionList(); 302 il.append(new CHECKCAST(cpg.addClass(RUNTIME_NODE_CLASS))); 303 il.append(new GETFIELD(cpg.addFieldref(RUNTIME_NODE_CLASS, 304 NODE_FIELD, 305 NODE_FIELD_SIG))); 306 } 307 308 /** 309 * Returns the class name of an internal type's external representation. 310 */ 311 public String getClassName() { 312 return(RUNTIME_NODE_CLASS); 313 } 314 315 public Instruction LOAD(int slot) { 316 return new ILOAD(slot); 317 } 318 319 public Instruction STORE(int slot) { 320 return new ISTORE(slot); 321 } 322 } 323