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 }