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