1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: NodeSetType.java,v 1.17 2004/02/16 22:26:44 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
  20. import com.sun.org.apache.bcel.internal.generic.ALOAD;
  21. import com.sun.org.apache.bcel.internal.generic.ASTORE;
  22. import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  23. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  24. import com.sun.org.apache.bcel.internal.generic.GOTO;
  25. import com.sun.org.apache.bcel.internal.generic.IFLT;
  26. import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  27. import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  28. import com.sun.org.apache.bcel.internal.generic.Instruction;
  29. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  30. import com.sun.org.apache.bcel.internal.generic.PUSH;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
  32. import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
  33. /**
  34. * @author Jacek Ambroziak
  35. * @author Santiago Pericas-Geertsen
  36. */
  37. public final class NodeSetType extends Type {
  38. protected NodeSetType() {}
  39. public String toString() {
  40. return "node-set";
  41. }
  42. public boolean identicalTo(Type other) {
  43. return this == other;
  44. }
  45. public String toSignature() {
  46. return NODE_ITERATOR_SIG;
  47. }
  48. public com.sun.org.apache.bcel.internal.generic.Type toJCType() {
  49. return new com.sun.org.apache.bcel.internal.generic.ObjectType(NODE_ITERATOR);
  50. }
  51. /**
  52. * Translates a node-set into an object of internal type
  53. * <code>type</code>. The translation to int is undefined
  54. * since node-sets are always converted to
  55. * reals in arithmetic expressions.
  56. *
  57. * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  58. */
  59. public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  60. Type type) {
  61. if (type == Type.String) {
  62. translateTo(classGen, methodGen, (StringType) type);
  63. }
  64. else if (type == Type.Boolean) {
  65. translateTo(classGen, methodGen, (BooleanType) type);
  66. }
  67. else if (type == Type.Real) {
  68. translateTo(classGen, methodGen, (RealType) type);
  69. }
  70. else if (type == Type.Node) {
  71. translateTo(classGen, methodGen, (NodeType) type);
  72. }
  73. else if (type == Type.Reference) {
  74. translateTo(classGen, methodGen, (ReferenceType) type);
  75. }
  76. else if (type == Type.Object) {
  77. translateTo(classGen, methodGen, (ObjectType) type);
  78. }
  79. else {
  80. ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
  81. toString(), type.toString());
  82. classGen.getParser().reportError(Constants.FATAL, err);
  83. }
  84. }
  85. /**
  86. * Translates an external Java Class into an internal type.
  87. * Expects the Java object on the stack, pushes the internal type
  88. */
  89. public void translateFrom(ClassGenerator classGen,
  90. MethodGenerator methodGen, Class clazz)
  91. {
  92. InstructionList il = methodGen.getInstructionList();
  93. ConstantPoolGen cpg = classGen.getConstantPool();
  94. if (clazz.getName().equals("org.w3c.dom.NodeList")) {
  95. // w3c NodeList is on the stack from the external Java function call.
  96. // call BasisFunction to consume NodeList and leave Iterator on
  97. // the stack.
  98. il.append(classGen.loadTranslet()); // push translet onto stack
  99. il.append(methodGen.loadDOM()); // push DOM onto stack
  100. final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
  101. "nodeList2Iterator",
  102. "("
  103. + "Lorg/w3c/dom/NodeList;"
  104. + TRANSLET_INTF_SIG
  105. + DOM_INTF_SIG
  106. + ")" + NODE_ITERATOR_SIG );
  107. il.append(new INVOKESTATIC(convert));
  108. }
  109. else if (clazz.getName().equals("org.w3c.dom.Node")) {
  110. // w3c Node is on the stack from the external Java function call.
  111. // call BasisLibrary.node2Iterator() to consume Node and leave
  112. // Iterator on the stack.
  113. il.append(classGen.loadTranslet()); // push translet onto stack
  114. il.append(methodGen.loadDOM()); // push DOM onto stack
  115. final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
  116. "node2Iterator",
  117. "("
  118. + "Lorg/w3c/dom/Node;"
  119. + TRANSLET_INTF_SIG
  120. + DOM_INTF_SIG
  121. + ")" + NODE_ITERATOR_SIG );
  122. il.append(new INVOKESTATIC(convert));
  123. }
  124. else {
  125. ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
  126. toString(), clazz.getName());
  127. classGen.getParser().reportError(Constants.FATAL, err);
  128. }
  129. }
  130. /**
  131. * Translates a node-set into a synthesized boolean.
  132. * The boolean value of a node-set is "true" if non-empty
  133. * and "false" otherwise. Notice that the
  134. * function getFirstNode() is called in translateToDesynthesized().
  135. *
  136. * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  137. */
  138. public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  139. BooleanType type) {
  140. final InstructionList il = methodGen.getInstructionList();
  141. FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
  142. il.append(ICONST_1);
  143. final BranchHandle truec = il.append(new GOTO(null));
  144. falsel.backPatch(il.append(ICONST_0));
  145. truec.setTarget(il.append(NOP));
  146. }
  147. /**
  148. * Translates a node-set into a string. The string value of a node-set is
  149. * value of its first element.
  150. *
  151. * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  152. */
  153. public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  154. StringType type) {
  155. final InstructionList il = methodGen.getInstructionList();
  156. getFirstNode(classGen, methodGen);
  157. il.append(DUP);
  158. final BranchHandle falsec = il.append(new IFLT(null));
  159. Type.Node.translateTo(classGen, methodGen, type);
  160. final BranchHandle truec = il.append(new GOTO(null));
  161. falsec.setTarget(il.append(POP));
  162. il.append(new PUSH(classGen.getConstantPool(), ""));
  163. truec.setTarget(il.append(NOP));
  164. }
  165. /**
  166. * Expects a node-set on the stack and pushes a real.
  167. * First the node-set is converted to string, and from string to real.
  168. *
  169. * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  170. */
  171. public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  172. RealType type) {
  173. translateTo(classGen, methodGen, Type.String);
  174. Type.String.translateTo(classGen, methodGen, Type.Real);
  175. }
  176. /**
  177. * Expects a node-set on the stack and pushes a node.
  178. *
  179. * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  180. */
  181. public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  182. NodeType type) {
  183. getFirstNode(classGen, methodGen);
  184. }
  185. /**
  186. * Subsume node-set into ObjectType.
  187. *
  188. * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  189. */
  190. public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  191. ObjectType type) {
  192. methodGen.getInstructionList().append(NOP);
  193. }
  194. /**
  195. * Translates a node-set into a non-synthesized boolean. It does not
  196. * push a 0 or a 1 but instead returns branchhandle list to be appended
  197. * to the false list.
  198. *
  199. * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized
  200. */
  201. public FlowList translateToDesynthesized(ClassGenerator classGen,
  202. MethodGenerator methodGen,
  203. BooleanType type) {
  204. final InstructionList il = methodGen.getInstructionList();
  205. getFirstNode(classGen, methodGen);
  206. return new FlowList(il.append(new IFLT(null)));
  207. }
  208. /**
  209. * Expects a node-set on the stack and pushes a boxed node-set.
  210. * Node sets are already boxed so the translation is just a NOP.
  211. *
  212. * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  213. */
  214. public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  215. ReferenceType type) {
  216. methodGen.getInstructionList().append(NOP);
  217. }
  218. /**
  219. * Translates a node-set into the Java type denoted by <code>clazz</code>.
  220. * Expects a node-set on the stack and pushes an object of the appropriate
  221. * type after coercion.
  222. */
  223. public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  224. Class clazz) {
  225. final ConstantPoolGen cpg = classGen.getConstantPool();
  226. final InstructionList il = methodGen.getInstructionList();
  227. final String className = clazz.getName();
  228. il.append(methodGen.loadDOM());
  229. il.append(SWAP);
  230. if (className.equals("org.w3c.dom.Node")) {
  231. int index = cpg.addInterfaceMethodref(DOM_INTF,
  232. MAKE_NODE,
  233. MAKE_NODE_SIG2);
  234. il.append(new INVOKEINTERFACE(index, 2));
  235. }
  236. else if (className.equals("org.w3c.dom.NodeList") ||
  237. className.equals("java.lang.Object")) {
  238. int index = cpg.addInterfaceMethodref(DOM_INTF,
  239. MAKE_NODE_LIST,
  240. MAKE_NODE_LIST_SIG2);
  241. il.append(new INVOKEINTERFACE(index, 2));
  242. }
  243. else if (className.equals("java.lang.String")) {
  244. int next = cpg.addInterfaceMethodref(NODE_ITERATOR,
  245. "next", "()I");
  246. int index = cpg.addInterfaceMethodref(DOM_INTF,
  247. GET_NODE_VALUE,
  248. "(I)"+STRING_SIG);
  249. // Get next node from the iterator
  250. il.append(new INVOKEINTERFACE(next, 1));
  251. // Get the node's string value (from the DOM)
  252. il.append(new INVOKEINTERFACE(index, 2));
  253. }
  254. else {
  255. ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
  256. toString(), className);
  257. classGen.getParser().reportError(Constants.FATAL, err);
  258. }
  259. }
  260. /**
  261. * Some type conversions require gettting the first node from the node-set.
  262. * This function is defined to avoid code repetition.
  263. */
  264. private void getFirstNode(ClassGenerator classGen, MethodGenerator methodGen) {
  265. final ConstantPoolGen cpg = classGen.getConstantPool();
  266. final InstructionList il = methodGen.getInstructionList();
  267. il.append(new INVOKEINTERFACE(cpg.addInterfaceMethodref(NODE_ITERATOR,
  268. NEXT,
  269. NEXT_SIG), 1));
  270. }
  271. /**
  272. * Translates an object of this type to its boxed representation.
  273. */
  274. public void translateBox(ClassGenerator classGen,
  275. MethodGenerator methodGen) {
  276. translateTo(classGen, methodGen, Type.Reference);
  277. }
  278. /**
  279. * Translates an object of this type to its unboxed representation.
  280. */
  281. public void translateUnBox(ClassGenerator classGen,
  282. MethodGenerator methodGen) {
  283. methodGen.getInstructionList().append(NOP);
  284. }
  285. /**
  286. * Returns the class name of an internal type's external representation.
  287. */
  288. public String getClassName() {
  289. return(NODE_ITERATOR);
  290. }
  291. public Instruction LOAD(int slot) {
  292. return new ALOAD(slot);
  293. }
  294. public Instruction STORE(int slot) {
  295. return new ASTORE(slot);
  296. }
  297. }