1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *     http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 /*
  22  * $Id: Choose.java,v 1.2.4.1 2005/09/01 12:00:14 pvedula Exp $
  23  */
  24 
  25 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  26 
  27 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  28 import com.sun.org.apache.bcel.internal.generic.GOTO;
  29 import com.sun.org.apache.bcel.internal.generic.IFEQ;
  30 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  31 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  38 import java.util.ArrayList;
  39 import java.util.Collections;
  40 import java.util.Enumeration;
  41 import java.util.Iterator;
  42 import java.util.List;
  43 
  44 /**
  45  * @author Jacek Ambroziak
  46  * @author Santiago Pericas-Geertsen
  47  * @author Morten Jorgensen
  48  */
  49 final class Choose extends Instruction {
  50 
  51     /**
  52      * Display the element contents (a lot of when's and an otherwise)
  53      */
  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      */
  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 }