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 }