1 /* 2 * Copyright (c) 2015, 2016, 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 package com.sun.org.apache.xalan.internal.xsltc.compiler; 22 23 import java.util.Vector; 24 25 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 26 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 27 import com.sun.org.apache.bcel.internal.generic.InstructionHandle; 28 import com.sun.org.apache.bcel.internal.generic.InstructionList; 29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NamedMethodGenerator; 33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 36 import com.sun.org.apache.xml.internal.utils.XML11Char; 37 import java.util.List; 38 39 40 /** 41 * @author Jacek Ambroziak 42 * @author Santiago Pericas-Geertsen 43 * @author Morten Jorgensen 44 * @author Erwin Bolwidt <ejb@klomp.org> 45 */ 46 public final class Template extends TopLevelElement { 47 48 private QName _name; // The name of the template (if any) 49 private QName _mode; // Mode in which this template is instantiated. 50 private Pattern _pattern; // Matching pattern defined for this template. 51 private double _priority; // Matching priority of this template. 52 private int _position; // Position within stylesheet (prio. resolution) 53 private boolean _disabled = false; 54 private boolean _compiled = false;//make sure it is compiled only once 55 private boolean _simplified = false; 56 57 // True if this is a simple named template. A simple named 58 // template is a template which only has a name but no match pattern. 59 private boolean _isSimpleNamedTemplate = false; 60 61 // The list of parameters in this template. This is only used 62 // for simple named templates. 63 private Vector<Param> _parameters = new Vector<>(); 64 65 public boolean hasParams() { 66 return _parameters.size() > 0; 67 } 68 69 public boolean isSimplified() { 70 return(_simplified); 71 } 72 73 public void setSimplified() { 74 _simplified = true; 75 } 76 77 public boolean isSimpleNamedTemplate() { 78 return _isSimpleNamedTemplate; 79 } 80 81 public void addParameter(Param param) { 82 _parameters.addElement(param); 83 } 84 85 public Vector<Param> getParameters() { 86 return _parameters; 87 } 88 89 public void disable() { 90 _disabled = true; 91 } 92 93 public boolean disabled() { 94 return(_disabled); 95 } 96 97 public double getPriority() { 98 return _priority; 99 } 100 101 public int getPosition() { 102 return(_position); 103 } 104 105 public boolean isNamed() { 106 return _name != null; 107 } 108 109 public Pattern getPattern() { 110 return _pattern; 111 } 112 113 public QName getName() { 114 return _name; 115 } 116 117 public void setName(QName qname) { 118 if (_name == null) _name = qname; 119 } 120 121 public QName getModeName() { 122 return _mode; 123 } 124 125 /** 126 * Compare this template to another. First checks priority, then position. 127 */ 128 public int compareTo(Object template) { 129 Template other = (Template)template; 130 if (_priority > other._priority) 131 return 1; 132 else if (_priority < other._priority) 133 return -1; 134 else if (_position > other._position) 135 return 1; 136 else if (_position < other._position) 137 return -1; 138 else 139 return 0; 140 } 141 142 public void display(int indent) { 143 Util.println('\n'); 144 indent(indent); 145 if (_name != null) { 146 indent(indent); 147 Util.println("name = " + _name); 148 } 149 else if (_pattern != null) { 150 indent(indent); 151 Util.println("match = " + _pattern.toString()); 152 } 153 if (_mode != null) { 154 indent(indent); 155 Util.println("mode = " + _mode); 156 } 157 displayContents(indent + IndentIncrement); 158 } 159 160 private boolean resolveNamedTemplates(Template other, Parser parser) { 161 162 if (other == null) return true; 163 164 SymbolTable stable = parser.getSymbolTable(); 165 166 final int us = this.getImportPrecedence(); 167 final int them = other.getImportPrecedence(); 168 169 if (us > them) { 170 other.disable(); 171 return true; 172 } 173 else if (us < them) { 174 stable.addTemplate(other); 175 this.disable(); 176 return true; 177 } 178 else { 179 return false; 180 } 181 } 182 183 private Stylesheet _stylesheet = null; 184 185 public Stylesheet getStylesheet() { 186 return _stylesheet; 187 } 188 189 public void parseContents(Parser parser) { 190 191 final String name = getAttribute("name"); 192 final String mode = getAttribute("mode"); 193 final String match = getAttribute("match"); 194 final String priority = getAttribute("priority"); 195 196 _stylesheet = super.getStylesheet(); 197 198 if (name.length() > 0) { 199 if (!XML11Char.isXML11ValidQName(name)) { 200 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this); 201 parser.reportError(Constants.ERROR, err); 202 } 203 _name = parser.getQNameIgnoreDefaultNs(name); 204 } 205 206 if (mode.length() > 0) { 207 if (!XML11Char.isXML11ValidQName(mode)) { 208 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this); 209 parser.reportError(Constants.ERROR, err); 210 } 211 _mode = parser.getQNameIgnoreDefaultNs(mode); 212 } 213 214 if (match.length() > 0) { 215 _pattern = parser.parsePattern(this, "match", null); 216 } 217 218 if (priority.length() > 0) { 219 _priority = Double.parseDouble(priority); 220 } 221 else { 222 if (_pattern != null) 223 _priority = _pattern.getPriority(); 224 else 225 _priority = Double.NaN; 226 } 227 228 _position = parser.getTemplateIndex(); 229 230 // Add the (named) template to the symbol table 231 if (_name != null) { 232 Template other = parser.getSymbolTable().addTemplate(this); 233 if (!resolveNamedTemplates(other, parser)) { 234 ErrorMsg err = 235 new ErrorMsg(ErrorMsg.TEMPLATE_REDEF_ERR, _name, this); 236 parser.reportError(Constants.ERROR, err); 237 } 238 // Is this a simple named template? 239 if (_pattern == null && _mode == null) { 240 _isSimpleNamedTemplate = true; 241 } 242 } 243 244 if (_parent instanceof Stylesheet) { 245 ((Stylesheet)_parent).addTemplate(this); 246 } 247 248 parser.setTemplate(this); // set current template 249 parseChildren(parser); 250 parser.setTemplate(null); // clear template 251 } 252 253 /** 254 * When the parser realises that it is dealign with a simplified stylesheet 255 * it will create an empty Stylesheet object with the root element of the 256 * stylesheet (a LiteralElement object) as its only child. The Stylesheet 257 * object will then create this Template object and invoke this method to 258 * force some specific behaviour. What we need to do is: 259 * o) create a pattern matching on the root node 260 * o) add the LRE root node (the only child of the Stylesheet) as our 261 * only child node 262 * o) set the empty Stylesheet as our parent 263 * o) set this template as the Stylesheet's only child 264 */ 265 public void parseSimplified(Stylesheet stylesheet, Parser parser) { 266 267 _stylesheet = stylesheet; 268 setParent(stylesheet); 269 270 _name = null; 271 _mode = null; 272 _priority = Double.NaN; 273 _pattern = parser.parsePattern(this, "/"); 274 275 final List<SyntaxTreeNode> contents = _stylesheet.getContents(); 276 final SyntaxTreeNode root = contents.get(0); 277 278 if (root instanceof LiteralElement) { 279 addElement(root); 280 root.setParent(this); 281 contents.set(0, this); 282 parser.setTemplate(this); 283 root.parseContents(parser); 284 parser.setTemplate(null); 285 } 286 } 287 288 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 289 if (_pattern != null) { 290 _pattern.typeCheck(stable); 291 } 292 293 return typeCheckContents(stable); 294 } 295 296 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 297 final ConstantPoolGen cpg = classGen.getConstantPool(); 298 final InstructionList il = methodGen.getInstructionList(); 299 300 if (_disabled) return; 301 // bug fix #4433133, add a call to named template from applyTemplates 302 String className = classGen.getClassName(); 303 304 if (_compiled && isNamed()){ 305 String methodName = Util.escape(_name.toString()); 306 il.append(classGen.loadTranslet()); 307 il.append(methodGen.loadDOM()); 308 il.append(methodGen.loadIterator()); 309 il.append(methodGen.loadHandler()); 310 il.append(methodGen.loadCurrentNode()); 311 il.append(new INVOKEVIRTUAL(cpg.addMethodref(className, 312 methodName, 313 "(" 314 + DOM_INTF_SIG 315 + NODE_ITERATOR_SIG 316 + TRANSLET_OUTPUT_SIG 317 + "I)V"))); 318 return; 319 } 320 321 if (_compiled) return; 322 _compiled = true; 323 324 // %OPT% Special handling for simple named templates. 325 if (_isSimpleNamedTemplate && methodGen instanceof NamedMethodGenerator) { 326 int numParams = _parameters.size(); 327 NamedMethodGenerator namedMethodGen = (NamedMethodGenerator)methodGen; 328 329 // Update load/store instructions to access Params from the stack 330 for (int i = 0; i < numParams; i++) { 331 Param param = (Param)_parameters.elementAt(i); 332 param.setLoadInstruction(namedMethodGen.loadParameter(i)); 333 param.setStoreInstruction(namedMethodGen.storeParameter(i)); 334 } 335 } 336 337 translateContents(classGen, methodGen); 338 il.setPositions(true); 339 } 340 341 }