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: ApplyTemplates.java 468650 2006-10-28 07:03:30Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import java.util.Enumeration; 025 import java.util.Vector; 026 027 import org.apache.bcel.generic.ConstantPoolGen; 028 import org.apache.bcel.generic.INVOKEINTERFACE; 029 import org.apache.bcel.generic.INVOKEVIRTUAL; 030 import org.apache.bcel.generic.InstructionList; 031 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 032 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 033 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 034 import org.apache.xalan.xsltc.compiler.util.NodeSetType; 035 import org.apache.xalan.xsltc.compiler.util.NodeType; 036 import org.apache.xalan.xsltc.compiler.util.ReferenceType; 037 import org.apache.xalan.xsltc.compiler.util.ResultTreeType; 038 import org.apache.xalan.xsltc.compiler.util.Type; 039 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 040 import org.apache.xalan.xsltc.compiler.util.Util; 041 import org.apache.xml.utils.XML11Char; 042 043 /** 044 * @author Jacek Ambroziak 045 * @author Santiago Pericas-Geertsen 046 */ 047 final class ApplyTemplates extends Instruction { 048 private Expression _select; 049 private Type _type = null; 050 private QName _modeName; 051 private String _functionName; 052 053 public void display(int indent) { 054 indent(indent); 055 Util.println("ApplyTemplates"); 056 indent(indent + IndentIncrement); 057 Util.println("select " + _select.toString()); 058 if (_modeName != null) { 059 indent(indent + IndentIncrement); 060 Util.println("mode " + _modeName); 061 } 062 } 063 064 public boolean hasWithParams() { 065 return hasContents(); 066 } 067 068 public void parseContents(Parser parser) { 069 final String select = getAttribute("select"); 070 final String mode = getAttribute("mode"); 071 072 if (select.length() > 0) { 073 _select = parser.parseExpression(this, "select", null); 074 075 } 076 077 if (mode.length() > 0) { 078 if (!XML11Char.isXML11ValidQName(mode)) { 079 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this); 080 parser.reportError(Constants.ERROR, err); 081 } 082 _modeName = parser.getQNameIgnoreDefaultNs(mode); 083 } 084 085 // instantiate Mode if needed, cache (apply temp) function name 086 _functionName = 087 parser.getTopLevelStylesheet().getMode(_modeName).functionName(); 088 parseChildren(parser);// with-params 089 } 090 091 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 092 if (_select != null) { 093 _type = _select.typeCheck(stable); 094 if (_type instanceof NodeType || _type instanceof ReferenceType) { 095 _select = new CastExpr(_select, Type.NodeSet); 096 _type = Type.NodeSet; 097 } 098 if (_type instanceof NodeSetType||_type instanceof ResultTreeType) { 099 typeCheckContents(stable); // with-params 100 return Type.Void; 101 } 102 throw new TypeCheckError(this); 103 } 104 else { 105 typeCheckContents(stable); // with-params 106 return Type.Void; 107 } 108 } 109 110 /** 111 * Translate call-template. A parameter frame is pushed only if 112 * some template in the stylesheet uses parameters. 113 */ 114 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 115 boolean setStartNodeCalled = false; 116 final Stylesheet stylesheet = classGen.getStylesheet(); 117 final ConstantPoolGen cpg = classGen.getConstantPool(); 118 final InstructionList il = methodGen.getInstructionList(); 119 final int current = methodGen.getLocalIndex("current"); 120 121 // check if sorting nodes is required 122 final Vector sortObjects = new Vector(); 123 final Enumeration children = elements(); 124 while (children.hasMoreElements()) { 125 final Object child = children.nextElement(); 126 if (child instanceof Sort) { 127 sortObjects.addElement(child); 128 } 129 } 130 131 // Push a new parameter frame 132 if (stylesheet.hasLocalParams() || hasContents()) { 133 il.append(classGen.loadTranslet()); 134 final int pushFrame = cpg.addMethodref(TRANSLET_CLASS, 135 PUSH_PARAM_FRAME, 136 PUSH_PARAM_FRAME_SIG); 137 il.append(new INVOKEVIRTUAL(pushFrame)); 138 // translate with-params 139 translateContents(classGen, methodGen); 140 } 141 142 143 il.append(classGen.loadTranslet()); 144 145 // The 'select' expression is a result-tree 146 if ((_type != null) && (_type instanceof ResultTreeType)) { 147 // <xsl:sort> cannot be applied to a result tree - issue warning 148 if (sortObjects.size() > 0) { 149 ErrorMsg err = new ErrorMsg(ErrorMsg.RESULT_TREE_SORT_ERR,this); 150 getParser().reportError(WARNING, err); 151 } 152 // Put the result tree (a DOM adapter) on the stack 153 _select.translate(classGen, methodGen); 154 // Get back the DOM and iterator (not just iterator!!!) 155 _type.translateTo(classGen, methodGen, Type.NodeSet); 156 } 157 else { 158 il.append(methodGen.loadDOM()); 159 160 // compute node iterator for applyTemplates 161 if (sortObjects.size() > 0) { 162 Sort.translateSortIterator(classGen, methodGen, 163 _select, sortObjects); 164 int setStartNode = cpg.addInterfaceMethodref(NODE_ITERATOR, 165 SET_START_NODE, 166 "(I)"+ 167 NODE_ITERATOR_SIG); 168 il.append(methodGen.loadCurrentNode()); 169 il.append(new INVOKEINTERFACE(setStartNode,2)); 170 setStartNodeCalled = true; 171 } 172 else { 173 if (_select == null) 174 Mode.compileGetChildren(classGen, methodGen, current); 175 else 176 _select.translate(classGen, methodGen); 177 } 178 } 179 180 if (_select != null && !setStartNodeCalled) { 181 _select.startIterator(classGen, methodGen); 182 } 183 184 //!!! need to instantiate all needed modes 185 final String className = classGen.getStylesheet().getClassName(); 186 il.append(methodGen.loadHandler()); 187 final String applyTemplatesSig = classGen.getApplyTemplatesSig(); 188 final int applyTemplates = cpg.addMethodref(className, 189 _functionName, 190 applyTemplatesSig); 191 il.append(new INVOKEVIRTUAL(applyTemplates)); 192 193 // Pop parameter frame 194 if (stylesheet.hasLocalParams() || hasContents()) { 195 il.append(classGen.loadTranslet()); 196 final int popFrame = cpg.addMethodref(TRANSLET_CLASS, 197 POP_PARAM_FRAME, 198 POP_PARAM_FRAME_SIG); 199 il.append(new INVOKEVIRTUAL(popFrame)); 200 } 201 } 202 }