1 /*
2  * Copyright (c) 2015, 2017, 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.ArrayList;
38 import java.util.Collections;
39 import java.util.Enumeration;
40 import java.util.Iterator;
41 import java.util.List;
42 
43 /**
44  * @author Jacek Ambroziak
45  * @author Santiago Pericas-Geertsen
46  * @author Morten Jorgensen
47  * @LastModified: Oct 2017
48  */
49 final class Choose extends Instruction {
50 
51     /**
52      * Display the element contents (a lot of when's and an otherwise)
53      */
display(int indent)54     public void display(int indent) {
55         indent(indent);
56         Util.println("Choose");
57         indent(indent + IndentIncrement);
58         displayContents(indent + IndentIncrement);
59     }
60 
61     /**
62      * Translate this Choose element. Generate a test-chain for the various
63      * <xsl:when> elements and default to the <xsl:otherwise> if present.
64      */
translate(ClassGenerator classGen, MethodGenerator methodGen)65     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
66         final List<SyntaxTreeNode> whenElements = new ArrayList<>();
67         Otherwise otherwise = null;
68         Iterator<SyntaxTreeNode> elements = elements();
69 
70         // These two are for reporting errors only
71         ErrorMsg error = null;
72         final int line = getLineNumber();
73 
74         // Traverse all child nodes - must be either When or Otherwise
75         while (elements.hasNext()) {
76             SyntaxTreeNode element = elements.next();
77             // Add a When child element
78             if (element instanceof When) {
79                 whenElements.add(element);
80             }
81             // Add an Otherwise child element
82             else if (element instanceof Otherwise) {
83                 if (otherwise == null) {
84                     otherwise = (Otherwise)element;
85                 }
86                 else {
87                     error = new ErrorMsg(ErrorMsg.MULTIPLE_OTHERWISE_ERR, this);
88                     getParser().reportError(Constants.ERROR, error);
89                 }
90             }
91             else if (element instanceof Text) {
92                 ((Text)element).ignore();
93             }
94             // It is an error if we find some other element here
95             else {
96                 error = new ErrorMsg(ErrorMsg.WHEN_ELEMENT_ERR, this);
97                 getParser().reportError(Constants.ERROR, error);
98             }
99         }
100 
101         // Make sure that there is at least one <xsl:when> element
102         if (whenElements.size() == 0) {
103             error = new ErrorMsg(ErrorMsg.MISSING_WHEN_ERR, this);
104             getParser().reportError(Constants.ERROR, error);
105             return;
106         }
107 
108         InstructionList il = methodGen.getInstructionList();
109 
110         // next element will hold a handle to the beginning of next
111         // When/Otherwise if test on current When fails
112         BranchHandle nextElement = null;
113         List<InstructionHandle> exitHandles = new ArrayList<>();
114         InstructionHandle exit = null;
115 
116         Enumeration<SyntaxTreeNode> whens = Collections.enumeration(whenElements);
117         while (whens.hasMoreElements()) {
118             final When when = (When)whens.nextElement();
119             final Expression test = when.getTest();
120 
121             InstructionHandle truec = il.getEnd();
122 
123             if (nextElement != null)
124                 nextElement.setTarget(il.append(NOP));
125             test.translateDesynthesized(classGen, methodGen);
126 
127             if (test instanceof FunctionCall) {
128                 FunctionCall call = (FunctionCall)test;
129                 try {
130                     Type type = call.typeCheck(getParser().getSymbolTable());
131                     if (type != Type.Boolean) {
132                         test._falseList.add(il.append(new IFEQ(null)));
133                     }
134                 }
135                 catch (TypeCheckError e) {
136                     // handled later!
137                 }
138             }
139             // remember end of condition
140             truec = il.getEnd();
141 
142             // The When object should be ignored completely in case it tests
143             // for the support of a non-available element
144             if (!when.ignore()) when.translateContents(classGen, methodGen);
145 
146             // goto exit after executing the body of when
147             exitHandles.add(il.append(new GOTO(null)));
148             if (whens.hasMoreElements() || otherwise != null) {
149                 nextElement = il.append(new GOTO(null));
150                 test.backPatchFalseList(nextElement);
151             }
152             else
153                 test.backPatchFalseList(exit = il.append(NOP));
154             test.backPatchTrueList(truec.getNext());
155         }
156 
157         // Translate any <xsl:otherwise> element
158         if (otherwise != null) {
159             nextElement.setTarget(il.append(NOP));
160             otherwise.translateContents(classGen, methodGen);
161             exit = il.append(NOP);
162         }
163 
164         // now that end is known set targets of exit gotos
165         Enumeration<InstructionHandle> exitGotos = Collections.enumeration(exitHandles);
166         while (exitGotos.hasMoreElements()) {
167             BranchHandle gotoExit = (BranchHandle)exitGotos.nextElement();
168             gotoExit.setTarget(exit);
169         }
170     }
171 }
172