View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: Choose.java,v 1.2.4.1 2005/09/01 12:00:14 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import java.util.Enumeration;
27  import java.util.Vector;
28  
29  import com.sun.org.apache.bcel.internal.generic.BranchHandle;
30  import com.sun.org.apache.bcel.internal.generic.GOTO;
31  import com.sun.org.apache.bcel.internal.generic.IFEQ;
32  import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
33  import com.sun.org.apache.bcel.internal.generic.InstructionList;
34  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
35  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
36  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
37  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
38  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
39  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
40  
41  /**
42   * @author Jacek Ambroziak
43   * @author Santiago Pericas-Geertsen
44   * @author Morten Jorgensen
45   */
46  final class Choose extends Instruction {
47  
48      /**
49       * Display the element contents (a lot of when's and an otherwise)
50       */
51      public void display(int indent) {
52          indent(indent);
53          Util.println("Choose");
54          indent(indent + IndentIncrement);
55          displayContents(indent + IndentIncrement);
56      }
57  
58      /**
59       * Translate this Choose element. Generate a test-chain for the various
60       * <xsl:when> elements and default to the <xsl:otherwise> if present.
61       */
62      public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
63          final Vector whenElements = new Vector();
64          Otherwise otherwise = null;
65          Enumeration elements = elements();
66  
67          // These two are for reporting errors only
68          ErrorMsg error = null;
69          final int line = getLineNumber();
70  
71          // Traverse all child nodes - must be either When or Otherwise
72          while (elements.hasMoreElements()) {
73              Object element = elements.nextElement();
74              // Add a When child element
75              if (element instanceof When) {
76                  whenElements.addElement(element);
77              }
78              // Add an Otherwise child element
79              else if (element instanceof Otherwise) {
80                  if (otherwise == null) {
81                      otherwise = (Otherwise)element;
82                  }
83                  else {
84                      error = new ErrorMsg(ErrorMsg.MULTIPLE_OTHERWISE_ERR, this);
85                      getParser().reportError(Constants.ERROR, error);
86                  }
87              }
88              else if (element instanceof Text) {
89                  ((Text)element).ignore();
90              }
91              // It is an error if we find some other element here
92              else {
93                  error = new ErrorMsg(ErrorMsg.WHEN_ELEMENT_ERR, this);
94                  getParser().reportError(Constants.ERROR, error);
95              }
96          }
97  
98          // Make sure that there is at least one <xsl:when> element
99          if (whenElements.size() == 0) {
100             error = new ErrorMsg(ErrorMsg.MISSING_WHEN_ERR, this);
101             getParser().reportError(Constants.ERROR, error);
102             return;
103         }
104 
105         InstructionList il = methodGen.getInstructionList();
106 
107         // next element will hold a handle to the beginning of next
108         // When/Otherwise if test on current When fails
109         BranchHandle nextElement = null;
110         Vector exitHandles = new Vector();
111         InstructionHandle exit = null;
112 
113         Enumeration whens = whenElements.elements();
114         while (whens.hasMoreElements()) {
115             final When when = (When)whens.nextElement();
116             final Expression test = when.getTest();
117 
118             InstructionHandle truec = il.getEnd();
119 
120             if (nextElement != null)
121                 nextElement.setTarget(il.append(NOP));
122             test.translateDesynthesized(classGen, methodGen);
123 
124             if (test instanceof FunctionCall) {
125                 FunctionCall call = (FunctionCall)test;
126                 try {
127                     Type type = call.typeCheck(getParser().getSymbolTable());
128                     if (type != Type.Boolean) {
129                         test._falseList.add(il.append(new IFEQ(null)));
130                     }
131                 }
132                 catch (TypeCheckError e) {
133                     // handled later!
134                 }
135             }
136             // remember end of condition
137             truec = il.getEnd();
138 
139             // The When object should be ignored completely in case it tests
140             // for the support of a non-available element
141             if (!when.ignore()) when.translateContents(classGen, methodGen);
142 
143             // goto exit after executing the body of when
144             exitHandles.addElement(il.append(new GOTO(null)));
145             if (whens.hasMoreElements() || otherwise != null) {
146                 nextElement = il.append(new GOTO(null));
147                 test.backPatchFalseList(nextElement);
148             }
149             else
150                 test.backPatchFalseList(exit = il.append(NOP));
151             test.backPatchTrueList(truec.getNext());
152         }
153 
154         // Translate any <xsl:otherwise> element
155         if (otherwise != null) {
156             nextElement.setTarget(il.append(NOP));
157             otherwise.translateContents(classGen, methodGen);
158             exit = il.append(NOP);
159         }
160 
161         // now that end is known set targets of exit gotos
162         Enumeration exitGotos = exitHandles.elements();
163         while (exitGotos.hasMoreElements()) {
164             BranchHandle gotoExit = (BranchHandle)exitGotos.nextElement();
165             gotoExit.setTarget(exit);
166         }
167     }
168 }