001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: Choose.java 1225842 2011-12-30 15:14:35Z mrglavas $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import java.util.ArrayList; 025 import java.util.Enumeration; 026 import java.util.Iterator; 027 import java.util.List; 028 029 import org.apache.bcel.generic.BranchHandle; 030 import org.apache.bcel.generic.GOTO; 031 import org.apache.bcel.generic.IFEQ; 032 import org.apache.bcel.generic.InstructionHandle; 033 import org.apache.bcel.generic.InstructionList; 034 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 035 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 036 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 037 import org.apache.xalan.xsltc.compiler.util.Type; 038 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 039 import org.apache.xalan.xsltc.compiler.util.Util; 040 041 /** 042 * @author Jacek Ambroziak 043 * @author Santiago Pericas-Geertsen 044 * @author Morten Jorgensen 045 */ 046 final class Choose extends Instruction { 047 048 /** 049 * Display the element contents (a lot of when's and an otherwise) 050 */ 051 public void display(int indent) { 052 indent(indent); 053 Util.println("Choose"); 054 indent(indent + IndentIncrement); 055 displayContents(indent + IndentIncrement); 056 } 057 058 /** 059 * Translate this Choose element. Generate a test-chain for the various 060 * <xsl:when> elements and default to the <xsl:otherwise> if present. 061 */ 062 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 063 final List whenElements = new ArrayList(); 064 Otherwise otherwise = null; 065 Enumeration elements = elements(); 066 067 // These two are for reporting errors only 068 ErrorMsg error = null; 069 final int line = getLineNumber(); 070 071 // Traverse all child nodes - must be either When or Otherwise 072 while (elements.hasMoreElements()) { 073 Object element = elements.nextElement(); 074 // Add a When child element 075 if (element instanceof When) { 076 whenElements.add(element); 077 } 078 // Add an Otherwise child element 079 else if (element instanceof Otherwise) { 080 if (otherwise == null) { 081 otherwise = (Otherwise)element; 082 } 083 else { 084 error = new ErrorMsg(ErrorMsg.MULTIPLE_OTHERWISE_ERR, this); 085 getParser().reportError(Constants.ERROR, error); 086 } 087 } 088 else if (element instanceof Text) { 089 ((Text)element).ignore(); 090 } 091 // It is an error if we find some other element here 092 else { 093 error = new ErrorMsg(ErrorMsg.WHEN_ELEMENT_ERR, this); 094 getParser().reportError(Constants.ERROR, error); 095 } 096 } 097 098 // Make sure that there is at least one <xsl:when> element 099 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 List exitHandles = new ArrayList(); 111 InstructionHandle exit = null; 112 113 Iterator whens = whenElements.iterator(); 114 while (whens.hasNext()) { 115 final When when = (When)whens.next(); 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.add(il.append(new GOTO(null))); 145 if (whens.hasNext() || 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 Iterator exitGotos = exitHandles.iterator(); 163 while (exitGotos.hasNext()) { 164 BranchHandle gotoExit = (BranchHandle)exitGotos.next(); 165 gotoExit.setTarget(exit); 166 } 167 } 168 }