1 /*
2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  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 com.sun.org.apache.bcel.internal.generic.BranchHandle;
27 import com.sun.org.apache.bcel.internal.generic.GOTO;
28 import com.sun.org.apache.bcel.internal.generic.IFEQ;
29 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
30 import com.sun.org.apache.bcel.internal.generic.InstructionList;
31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
37 import java.util.Enumeration;
38 import java.util.Iterator;
39 import java.util.Vector;
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      */
display(int indent)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      */
translate(ClassGenerator classGen, MethodGenerator methodGen)62     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
63         final Vector whenElements = new Vector();
64         Otherwise otherwise = null;
65         Iterator<SyntaxTreeNode> 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.hasNext()) {
73             SyntaxTreeNode element = elements.next();
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 }
169