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: Template.java 1225842 2011-12-30 15:14:35Z mrglavas $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import java.util.Vector;
025
026 import org.apache.bcel.generic.ConstantPoolGen;
027 import org.apache.bcel.generic.INVOKEVIRTUAL;
028 import org.apache.bcel.generic.InstructionList;
029 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
030 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
031 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
032 import org.apache.xalan.xsltc.compiler.util.NamedMethodGenerator;
033 import org.apache.xalan.xsltc.compiler.util.Type;
034 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
035 import org.apache.xalan.xsltc.compiler.util.Util;
036 import org.apache.xml.utils.XML11Char;
037
038
039 /**
040 * @author Jacek Ambroziak
041 * @author Santiago Pericas-Geertsen
042 * @author Morten Jorgensen
043 * @author Erwin Bolwidt <ejb@klomp.org>
044 */
045 public final class Template extends TopLevelElement {
046
047 private QName _name; // The name of the template (if any)
048 private QName _mode; // Mode in which this template is instantiated.
049 private Pattern _pattern; // Matching pattern defined for this template.
050 private double _priority; // Matching priority of this template.
051 private int _position; // Position within stylesheet (prio. resolution)
052 private boolean _disabled = false;
053 private boolean _compiled = false;//make sure it is compiled only once
054 private boolean _simplified = false;
055
056 // True if this is a simple named template. A simple named
057 // template is a template which only has a name but no match pattern.
058 private boolean _isSimpleNamedTemplate = false;
059
060 // The list of parameters in this template. This is only used
061 // for simple named templates.
062 private Vector _parameters = new Vector();
063
064 public boolean hasParams() {
065 return _parameters.size() > 0;
066 }
067
068 public boolean isSimplified() {
069 return(_simplified);
070 }
071
072 public void setSimplified() {
073 _simplified = true;
074 }
075
076 public boolean isSimpleNamedTemplate() {
077 return _isSimpleNamedTemplate;
078 }
079
080 public void addParameter(Param param) {
081 _parameters.addElement(param);
082 }
083
084 public Vector getParameters() {
085 return _parameters;
086 }
087
088 public void disable() {
089 _disabled = true;
090 }
091
092 public boolean disabled() {
093 return(_disabled);
094 }
095
096 public double getPriority() {
097 return _priority;
098 }
099
100 public int getPosition() {
101 return(_position);
102 }
103
104 public boolean isNamed() {
105 return _name != null;
106 }
107
108 public Pattern getPattern() {
109 return _pattern;
110 }
111
112 public QName getName() {
113 return _name;
114 }
115
116 public void setName(QName qname) {
117 if (_name == null) _name = qname;
118 }
119
120 public QName getModeName() {
121 return _mode;
122 }
123
124 /**
125 * Compare this template to another. First checks priority, then position.
126 */
127 public int compareTo(Object template) {
128 Template other = (Template)template;
129 if (_priority > other._priority)
130 return 1;
131 else if (_priority < other._priority)
132 return -1;
133 else if (_position > other._position)
134 return 1;
135 else if (_position < other._position)
136 return -1;
137 else
138 return 0;
139 }
140
141 public void display(int indent) {
142 Util.println('\n');
143 indent(indent);
144 if (_name != null) {
145 indent(indent);
146 Util.println("name = " + _name);
147 }
148 else if (_pattern != null) {
149 indent(indent);
150 Util.println("match = " + _pattern.toString());
151 }
152 if (_mode != null) {
153 indent(indent);
154 Util.println("mode = " + _mode);
155 }
156 displayContents(indent + IndentIncrement);
157 }
158
159 private boolean resolveNamedTemplates(Template other, Parser parser) {
160
161 if (other == null) return true;
162
163 SymbolTable stable = parser.getSymbolTable();
164
165 final int us = this.getImportPrecedence();
166 final int them = other.getImportPrecedence();
167
168 if (us > them) {
169 other.disable();
170 return true;
171 }
172 else if (us < them) {
173 stable.addTemplate(other);
174 this.disable();
175 return true;
176 }
177 else {
178 return false;
179 }
180 }
181
182 private Stylesheet _stylesheet = null;
183
184 public Stylesheet getStylesheet() {
185 return _stylesheet;
186 }
187
188 public void parseContents(Parser parser) {
189
190 final String name = getAttribute("name");
191 final String mode = getAttribute("mode");
192 final String match = getAttribute("match");
193 final String priority = getAttribute("priority");
194
195 _stylesheet = super.getStylesheet();
196
197 if (name.length() > 0) {
198 if (!XML11Char.isXML11ValidQName(name)) {
199 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
200 parser.reportError(Constants.ERROR, err);
201 }
202 _name = parser.getQNameIgnoreDefaultNs(name);
203 }
204
205 if (mode.length() > 0) {
206 if (!XML11Char.isXML11ValidQName(mode)) {
207 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this);
208 parser.reportError(Constants.ERROR, err);
209 }
210 _mode = parser.getQNameIgnoreDefaultNs(mode);
211 }
212
213 if (match.length() > 0) {
214 _pattern = parser.parsePattern(this, "match", null);
215 }
216
217 if (priority.length() > 0) {
218 _priority = Double.parseDouble(priority);
219 }
220 else {
221 if (_pattern != null)
222 _priority = _pattern.getPriority();
223 else
224 _priority = Double.NaN;
225 }
226
227 _position = parser.getTemplateIndex();
228
229 // Add the (named) template to the symbol table
230 if (_name != null) {
231 Template other = parser.getSymbolTable().addTemplate(this);
232 if (!resolveNamedTemplates(other, parser)) {
233 ErrorMsg err =
234 new ErrorMsg(ErrorMsg.TEMPLATE_REDEF_ERR, _name, this);
235 parser.reportError(Constants.ERROR, err);
236 }
237 // Is this a simple named template?
238 if (_pattern == null && _mode == null) {
239 _isSimpleNamedTemplate = true;
240 }
241 }
242
243 if (_parent instanceof Stylesheet) {
244 ((Stylesheet)_parent).addTemplate(this);
245 }
246
247 parser.setTemplate(this); // set current template
248 parseChildren(parser);
249 parser.setTemplate(null); // clear template
250 }
251
252 /**
253 * When the parser realises that it is dealign with a simplified stylesheet
254 * it will create an empty Stylesheet object with the root element of the
255 * stylesheet (a LiteralElement object) as its only child. The Stylesheet
256 * object will then create this Template object and invoke this method to
257 * force some specific behaviour. What we need to do is:
258 * o) create a pattern matching on the root node
259 * o) add the LRE root node (the only child of the Stylesheet) as our
260 * only child node
261 * o) set the empty Stylesheet as our parent
262 * o) set this template as the Stylesheet's only child
263 */
264 public void parseSimplified(Stylesheet stylesheet, Parser parser) {
265
266 _stylesheet = stylesheet;
267 setParent(stylesheet);
268
269 _name = null;
270 _mode = null;
271 _priority = Double.NaN;
272 _pattern = parser.parsePattern(this, "/");
273
274 final Vector contents = _stylesheet.getContents();
275 final SyntaxTreeNode root = (SyntaxTreeNode)contents.elementAt(0);
276
277 if (root instanceof LiteralElement) {
278 addElement(root);
279 root.setParent(this);
280 contents.set(0, this);
281 parser.setTemplate(this);
282 root.parseContents(parser);
283 parser.setTemplate(null);
284 }
285 }
286
287 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
288 if (_pattern != null) {
289 _pattern.typeCheck(stable);
290 }
291
292 return typeCheckContents(stable);
293 }
294
295 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
296 final ConstantPoolGen cpg = classGen.getConstantPool();
297 final InstructionList il = methodGen.getInstructionList();
298
299 if (_disabled) return;
300 // bug fix #4433133, add a call to named template from applyTemplates
301 String className = classGen.getClassName();
302
303 if (_compiled && isNamed()){
304 String methodName = Util.escape(_name.toString());
305 il.append(classGen.loadTranslet());
306 il.append(methodGen.loadDOM());
307 il.append(methodGen.loadIterator());
308 il.append(methodGen.loadHandler());
309 il.append(methodGen.loadCurrentNode());
310 il.append(new INVOKEVIRTUAL(cpg.addMethodref(className,
311 methodName,
312 "("
313 + DOM_INTF_SIG
314 + NODE_ITERATOR_SIG
315 + TRANSLET_OUTPUT_SIG
316 + "I)V")));
317 return;
318 }
319
320 if (_compiled) return;
321 _compiled = true;
322
323 // %OPT% Special handling for simple named templates.
324 if (_isSimpleNamedTemplate && methodGen instanceof NamedMethodGenerator) {
325 int numParams = _parameters.size();
326 NamedMethodGenerator namedMethodGen = (NamedMethodGenerator)methodGen;
327
328 // Update load/store instructions to access Params from the stack
329 for (int i = 0; i < numParams; i++) {
330 Param param = (Param)_parameters.elementAt(i);
331 param.setLoadInstruction(namedMethodGen.loadParameter(i));
332 param.setStoreInstruction(namedMethodGen.storeParameter(i));
333 }
334 }
335
336 translateContents(classGen, methodGen);
337 il.setPositions(true);
338 }
339
340 }