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