1 /*
2  * Copyright (c) 2015, 2017, 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.InstructionHandle;
26 import com.sun.org.apache.bcel.internal.generic.InstructionList;
27 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
28 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NamedMethodGenerator;
31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
34 import com.sun.org.apache.xml.internal.utils.XML11Char;
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 
39 /**
40  * @author Jacek Ambroziak
41  * @author Santiago Pericas-Geertsen
42  * @author Morten Jorgensen
43  * @author Erwin Bolwidt <ejb@klomp.org>
44  * @LastModified: Oct 2017
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 List<Param> _parameters = new ArrayList<>();
64 
hasParams()65     public boolean hasParams() {
66         return _parameters.size() > 0;
67     }
68 
isSimplified()69     public boolean isSimplified() {
70         return(_simplified);
71     }
72 
setSimplified()73     public void setSimplified() {
74         _simplified = true;
75     }
76 
isSimpleNamedTemplate()77     public boolean isSimpleNamedTemplate() {
78         return _isSimpleNamedTemplate;
79     }
80 
addParameter(Param param)81     public void addParameter(Param param) {
82         _parameters.add(param);
83     }
84 
getParameters()85     public List<Param> getParameters() {
86         return _parameters;
87     }
88 
disable()89     public void disable() {
90         _disabled = true;
91     }
92 
disabled()93     public boolean disabled() {
94         return(_disabled);
95     }
96 
getPriority()97     public double getPriority() {
98         return _priority;
99     }
100 
getPosition()101     public int getPosition() {
102         return(_position);
103     }
104 
isNamed()105     public boolean isNamed() {
106         return _name != null;
107     }
108 
getPattern()109     public Pattern getPattern() {
110         return _pattern;
111     }
112 
getName()113     public QName getName() {
114         return _name;
115     }
116 
setName(QName qname)117     public void setName(QName qname) {
118         if (_name == null) _name = qname;
119     }
120 
getModeName()121     public QName getModeName() {
122         return _mode;
123     }
124 
125     /**
126      * Compare this template to another. First checks priority, then position.
127      */
compareTo(Object template)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 
display(int indent)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 
resolveNamedTemplates(Template other, Parser parser)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 
getStylesheet()185     public Stylesheet getStylesheet() {
186         return _stylesheet;
187     }
188 
parseContents(Parser parser)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      */
parseSimplified(Stylesheet stylesheet, Parser parser)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 
typeCheck(SymbolTable stable)288     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
289         if (_pattern != null) {
290             _pattern.typeCheck(stable);
291         }
292 
293         return typeCheckContents(stable);
294     }
295 
translate(ClassGenerator classGen, MethodGenerator methodGen)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 = _parameters.get(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 }
342