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