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: Choose.java,v 1.9 2004/02/16 22:24:29 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import java.util.Enumeration;
  21. import java.util.Vector;
  22. import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  23. import com.sun.org.apache.bcel.internal.generic.GOTO;
  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.ClassGenerator;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  32. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  33. /**
  34. * @author Jacek Ambroziak
  35. * @author Santiago Pericas-Geertsen
  36. * @author Morten Jorgensen
  37. */
  38. final class Choose extends Instruction {
  39. /**
  40. * Display the element contents (a lot of when's and an otherwise)
  41. */
  42. public void display(int indent) {
  43. indent(indent);
  44. Util.println("Choose");
  45. indent(indent + IndentIncrement);
  46. displayContents(indent + IndentIncrement);
  47. }
  48. /**
  49. * Translate this Choose element. Generate a test-chain for the various
  50. * <xsl:when> elements and default to the <xsl:otherwise> if present.
  51. */
  52. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  53. final Vector whenElements = new Vector();
  54. Otherwise otherwise = null;
  55. Enumeration elements = elements();
  56. // These two are for reporting errors only
  57. ErrorMsg error = null;
  58. final int line = getLineNumber();
  59. // Traverse all child nodes - must be either When or Otherwise
  60. while (elements.hasMoreElements()) {
  61. Object element = elements.nextElement();
  62. // Add a When child element
  63. if (element instanceof When) {
  64. whenElements.addElement(element);
  65. }
  66. // Add an Otherwise child element
  67. else if (element instanceof Otherwise) {
  68. if (otherwise == null) {
  69. otherwise = (Otherwise)element;
  70. }
  71. else {
  72. error = new ErrorMsg(ErrorMsg.MULTIPLE_OTHERWISE_ERR, this);
  73. getParser().reportError(Constants.ERROR, error);
  74. }
  75. }
  76. else if (element instanceof Text) {
  77. ((Text)element).ignore();
  78. }
  79. // It is an error if we find some other element here
  80. else {
  81. error = new ErrorMsg(ErrorMsg.WHEN_ELEMENT_ERR, this);
  82. getParser().reportError(Constants.ERROR, error);
  83. }
  84. }
  85. // Make sure that there is at least one <xsl:when> element
  86. if (whenElements.size() == 0) {
  87. error = new ErrorMsg(ErrorMsg.MISSING_WHEN_ERR, this);
  88. getParser().reportError(Constants.ERROR, error);
  89. return;
  90. }
  91. InstructionList il = methodGen.getInstructionList();
  92. // next element will hold a handle to the beginning of next
  93. // When/Otherwise if test on current When fails
  94. BranchHandle nextElement = null;
  95. Vector exitHandles = new Vector();
  96. InstructionHandle exit = null;
  97. Enumeration whens = whenElements.elements();
  98. while (whens.hasMoreElements()) {
  99. final When when = (When)whens.nextElement();
  100. final Expression test = when.getTest();
  101. InstructionHandle truec = il.getEnd();
  102. if (nextElement != null)
  103. nextElement.setTarget(il.append(NOP));
  104. test.translateDesynthesized(classGen, methodGen);
  105. if (test instanceof FunctionCall) {
  106. FunctionCall call = (FunctionCall)test;
  107. try {
  108. Type type = call.typeCheck(getParser().getSymbolTable());
  109. if (type != Type.Boolean) {
  110. test._falseList.add(il.append(new IFEQ(null)));
  111. }
  112. }
  113. catch (TypeCheckError e) {
  114. // handled later!
  115. }
  116. }
  117. // remember end of condition
  118. truec = il.getEnd();
  119. // The When object should be ignored completely in case it tests
  120. // for the support of a non-available element
  121. if (!when.ignore()) when.translateContents(classGen, methodGen);
  122. // goto exit after executing the body of when
  123. exitHandles.addElement(il.append(new GOTO(null)));
  124. if (whens.hasMoreElements() || otherwise != null) {
  125. nextElement = il.append(new GOTO(null));
  126. test.backPatchFalseList(nextElement);
  127. }
  128. else
  129. test.backPatchFalseList(exit = il.append(NOP));
  130. test.backPatchTrueList(truec.getNext());
  131. }
  132. // Translate any <xsl:otherwise> element
  133. if (otherwise != null) {
  134. nextElement.setTarget(il.append(NOP));
  135. otherwise.translateContents(classGen, methodGen);
  136. exit = il.append(NOP);
  137. }
  138. // now that end is known set targets of exit gotos
  139. Enumeration exitGotos = exitHandles.elements();
  140. while (exitGotos.hasMoreElements()) {
  141. BranchHandle gotoExit = (BranchHandle)exitGotos.nextElement();
  142. gotoExit.setTarget(exit);
  143. }
  144. }
  145. }