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: Expression.java,v 1.20 2004/02/16 22:24:28 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import java.util.Vector;
  21. import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  22. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  23. import com.sun.org.apache.bcel.internal.generic.GOTO_W;
  24. import com.sun.org.apache.bcel.internal.generic.IFEQ;
  25. import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  26. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  27. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
  32. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
  33. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  34. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  35. /**
  36. * @author Jacek Ambroziak
  37. * @author Santiago Pericas-Geertsen
  38. * @author Morten Jorgensen
  39. * @author Erwin Bolwidt <ejb@klomp.org>
  40. */
  41. abstract class Expression extends SyntaxTreeNode {
  42. /**
  43. * The type of this expression. It is set after calling
  44. * <code>typeCheck()</code>.
  45. */
  46. protected Type _type;
  47. /**
  48. * Instruction handles that comprise the true list.
  49. */
  50. protected FlowList _trueList = new FlowList();
  51. /**
  52. * Instruction handles that comprise the false list.
  53. */
  54. protected FlowList _falseList = new FlowList();
  55. public Type getType() {
  56. return _type;
  57. }
  58. public abstract String toString();
  59. public boolean hasPositionCall() {
  60. return false; // default should be 'false' for StepPattern
  61. }
  62. public boolean hasLastCall() {
  63. return false;
  64. }
  65. /**
  66. * Returns an object representing the compile-time evaluation
  67. * of an expression. We are only using this for function-available
  68. * and element-available at this time.
  69. */
  70. public Object evaluateAtCompileTime() {
  71. return null;
  72. }
  73. /**
  74. * Type check all the children of this node.
  75. */
  76. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  77. return typeCheckContents(stable);
  78. }
  79. /**
  80. * Translate this node into JVM bytecodes.
  81. */
  82. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  83. ErrorMsg msg = new ErrorMsg(ErrorMsg.NOT_IMPLEMENTED_ERR,
  84. getClass(), this);
  85. getParser().reportError(FATAL, msg);
  86. }
  87. /**
  88. * Translate this node into a fresh instruction list.
  89. * The original instruction list is saved and restored.
  90. */
  91. public final InstructionList compile(ClassGenerator classGen,
  92. MethodGenerator methodGen) {
  93. final InstructionList result, save = methodGen.getInstructionList();
  94. methodGen.setInstructionList(result = new InstructionList());
  95. translate(classGen, methodGen);
  96. methodGen.setInstructionList(save);
  97. return result;
  98. }
  99. /**
  100. * Redefined by expressions of type boolean that use flow lists.
  101. */
  102. public void translateDesynthesized(ClassGenerator classGen,
  103. MethodGenerator methodGen) {
  104. translate(classGen, methodGen);
  105. if (_type instanceof BooleanType) {
  106. desynthesize(classGen, methodGen);
  107. }
  108. }
  109. /**
  110. * If this expression is of type node-set and it is not a variable
  111. * reference, then call setStartNode() passing the context node.
  112. */
  113. public void startIterator(ClassGenerator classGen,
  114. MethodGenerator methodGen) {
  115. // Ignore if type is not node-set
  116. if (_type instanceof NodeSetType == false) {
  117. return;
  118. }
  119. // setStartNode() should not be called if expr is a variable ref
  120. Expression expr = this;
  121. if (expr instanceof CastExpr) {
  122. expr = ((CastExpr) expr).getExpr();
  123. }
  124. if (expr instanceof VariableRefBase == false) {
  125. final InstructionList il = methodGen.getInstructionList();
  126. il.append(methodGen.loadContextNode());
  127. il.append(methodGen.setStartNode());
  128. }
  129. }
  130. /**
  131. * Synthesize a boolean expression, i.e., either push a 0 or 1 onto the
  132. * operand stack for the next statement to succeed. Returns the handle
  133. * of the instruction to be backpatched.
  134. */
  135. public void synthesize(ClassGenerator classGen, MethodGenerator methodGen) {
  136. final ConstantPoolGen cpg = classGen.getConstantPool();
  137. final InstructionList il = methodGen.getInstructionList();
  138. _trueList.backPatch(il.append(ICONST_1));
  139. final BranchHandle truec = il.append(new GOTO_W(null));
  140. _falseList.backPatch(il.append(ICONST_0));
  141. truec.setTarget(il.append(NOP));
  142. }
  143. public void desynthesize(ClassGenerator classGen,
  144. MethodGenerator methodGen) {
  145. final InstructionList il = methodGen.getInstructionList();
  146. _falseList.add(il.append(new IFEQ(null)));
  147. }
  148. public FlowList getFalseList() {
  149. return _falseList;
  150. }
  151. public FlowList getTrueList() {
  152. return _trueList;
  153. }
  154. public void backPatchFalseList(InstructionHandle ih) {
  155. _falseList.backPatch(ih);
  156. }
  157. public void backPatchTrueList(InstructionHandle ih) {
  158. _trueList.backPatch(ih);
  159. }
  160. /**
  161. * Search for a primop in the symbol table that matches the method type
  162. * <code>ctype</code>. Two methods match if they have the same arity.
  163. * If a primop is overloaded then the "closest match" is returned. The
  164. * first entry in the vector of primops that has the right arity is
  165. * considered to be the default one.
  166. */
  167. public MethodType lookupPrimop(SymbolTable stable, String op,
  168. MethodType ctype) {
  169. MethodType result = null;
  170. final Vector primop = stable.lookupPrimop(op);
  171. if (primop != null) {
  172. final int n = primop.size();
  173. int minDistance = Integer.MAX_VALUE;
  174. for (int i = 0; i < n; i++) {
  175. final MethodType ptype = (MethodType) primop.elementAt(i);
  176. // Skip if different arity
  177. if (ptype.argsCount() != ctype.argsCount()) {
  178. continue;
  179. }
  180. // The first method with the right arity is the default
  181. if (result == null) {
  182. result = ptype; // default method
  183. }
  184. // Check if better than last one found
  185. final int distance = ctype.distanceTo(ptype);
  186. if (distance < minDistance) {
  187. minDistance = distance;
  188. result = ptype;
  189. }
  190. }
  191. }
  192. return result;
  193. }
  194. }