1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: Template.java,v 1.25 2004/02/24 03:55:48 zongaro Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import java.util.Vector;
  21. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  22. import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  23. import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  24. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  25. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  26. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  27. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NamedMethodGenerator;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  32. import com.sun.org.apache.xml.internal.utils.XMLChar;
  33. /**
  34. * @author Jacek Ambroziak
  35. * @author Santiago Pericas-Geertsen
  36. * @author Morten Jorgensen
  37. * @author Erwin Bolwidt <ejb@klomp.org>
  38. */
  39. public final class Template extends TopLevelElement {
  40. private QName _name; // The name of the template (if any)
  41. private QName _mode; // Mode in which this template is instantiated.
  42. private Pattern _pattern; // Matching pattern defined for this template.
  43. private double _priority; // Matching priority of this template.
  44. private int _position; // Position within stylesheet (prio. resolution)
  45. private boolean _disabled = false;
  46. private boolean _compiled = false;//make sure it is compiled only once
  47. private boolean _simplified = false;
  48. // True if this is a simple named template. A simple named
  49. // template is a template which only has a name but no match pattern.
  50. private boolean _isSimpleNamedTemplate = false;
  51. // The list of parameters in this template. This is only used
  52. // for simple named templates.
  53. private Vector _parameters = new Vector();
  54. public boolean hasParams() {
  55. return _parameters.size() > 0;
  56. }
  57. public boolean isSimplified() {
  58. return(_simplified);
  59. }
  60. public void setSimplified() {
  61. _simplified = true;
  62. }
  63. public boolean isSimpleNamedTemplate() {
  64. return _isSimpleNamedTemplate;
  65. }
  66. public void addParameter(Param param) {
  67. _parameters.addElement(param);
  68. }
  69. public Vector getParameters() {
  70. return _parameters;
  71. }
  72. public void disable() {
  73. _disabled = true;
  74. }
  75. public boolean disabled() {
  76. return(_disabled);
  77. }
  78. public double getPriority() {
  79. return _priority;
  80. }
  81. public int getPosition() {
  82. return(_position);
  83. }
  84. public boolean isNamed() {
  85. return _name != null;
  86. }
  87. public Pattern getPattern() {
  88. return _pattern;
  89. }
  90. public QName getName() {
  91. return _name;
  92. }
  93. public void setName(QName qname) {
  94. if (_name == null) _name = qname;
  95. }
  96. public QName getModeName() {
  97. return _mode;
  98. }
  99. /**
  100. * Compare this template to another. First checks priority, then position.
  101. */
  102. public int compareTo(Object template) {
  103. Template other = (Template)template;
  104. if (_priority > other._priority)
  105. return 1;
  106. else if (_priority < other._priority)
  107. return -1;
  108. else if (_position > other._position)
  109. return 1;
  110. else if (_position < other._position)
  111. return -1;
  112. else
  113. return 0;
  114. }
  115. public void display(int indent) {
  116. Util.println('\n');
  117. indent(indent);
  118. if (_name != null) {
  119. indent(indent);
  120. Util.println("name = " + _name);
  121. }
  122. else if (_pattern != null) {
  123. indent(indent);
  124. Util.println("match = " + _pattern.toString());
  125. }
  126. if (_mode != null) {
  127. indent(indent);
  128. Util.println("mode = " + _mode);
  129. }
  130. displayContents(indent + IndentIncrement);
  131. }
  132. private boolean resolveNamedTemplates(Template other, Parser parser) {
  133. if (other == null) return true;
  134. SymbolTable stable = parser.getSymbolTable();
  135. final int us = this.getImportPrecedence();
  136. final int them = other.getImportPrecedence();
  137. if (us > them) {
  138. other.disable();
  139. return true;
  140. }
  141. else if (us < them) {
  142. stable.addTemplate(other);
  143. this.disable();
  144. return true;
  145. }
  146. else {
  147. return false;
  148. }
  149. }
  150. private Stylesheet _stylesheet = null;
  151. public Stylesheet getStylesheet() {
  152. return _stylesheet;
  153. }
  154. public void parseContents(Parser parser) {
  155. final String name = getAttribute("name");
  156. final String mode = getAttribute("mode");
  157. final String match = getAttribute("match");
  158. final String priority = getAttribute("priority");
  159. _stylesheet = super.getStylesheet();
  160. if (name.length() > 0) {
  161. if (!XMLChar.isValidQName(name)) {
  162. ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
  163. parser.reportError(Constants.ERROR, err);
  164. }
  165. _name = parser.getQNameIgnoreDefaultNs(name);
  166. }
  167. if (mode.length() > 0) {
  168. if (!XMLChar.isValidQName(mode)) {
  169. ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this);
  170. parser.reportError(Constants.ERROR, err);
  171. }
  172. _mode = parser.getQNameIgnoreDefaultNs(mode);
  173. }
  174. if (match.length() > 0) {
  175. _pattern = parser.parsePattern(this, "match", null);
  176. }
  177. if (priority.length() > 0) {
  178. _priority = Double.parseDouble(priority);
  179. }
  180. else {
  181. if (_pattern != null)
  182. _priority = _pattern.getPriority();
  183. else
  184. _priority = Double.NaN;
  185. }
  186. _position = parser.getTemplateIndex();
  187. // Add the (named) template to the symbol table
  188. if (_name != null) {
  189. Template other = parser.getSymbolTable().addTemplate(this);
  190. if (!resolveNamedTemplates(other, parser)) {
  191. ErrorMsg err =
  192. new ErrorMsg(ErrorMsg.TEMPLATE_REDEF_ERR, _name, this);
  193. parser.reportError(Constants.ERROR, err);
  194. }
  195. // Is this a simple named template?
  196. if (_pattern == null && _mode == null) {
  197. _isSimpleNamedTemplate = true;
  198. }
  199. }
  200. if (_parent instanceof Stylesheet) {
  201. ((Stylesheet)_parent).addTemplate(this);
  202. }
  203. parser.setTemplate(this); // set current template
  204. parseChildren(parser);
  205. parser.setTemplate(null); // clear template
  206. }
  207. /**
  208. * When the parser realises that it is dealign with a simplified stylesheet
  209. * it will create an empty Stylesheet object with the root element of the
  210. * stylesheet (a LiteralElement object) as its only child. The Stylesheet
  211. * object will then create this Template object and invoke this method to
  212. * force some specific behaviour. What we need to do is:
  213. * o) create a pattern matching on the root node
  214. * o) add the LRE root node (the only child of the Stylesheet) as our
  215. * only child node
  216. * o) set the empty Stylesheet as our parent
  217. * o) set this template as the Stylesheet's only child
  218. */
  219. public void parseSimplified(Stylesheet stylesheet, Parser parser) {
  220. _stylesheet = stylesheet;
  221. setParent(stylesheet);
  222. _name = null;
  223. _mode = null;
  224. _priority = Double.NaN;
  225. _pattern = parser.parsePattern(this, "/");
  226. final Vector contents = _stylesheet.getContents();
  227. final SyntaxTreeNode root = (SyntaxTreeNode)contents.elementAt(0);
  228. if (root instanceof LiteralElement) {
  229. addElement(root);
  230. root.setParent(this);
  231. contents.set(0, this);
  232. parser.setTemplate(this);
  233. root.parseContents(parser);
  234. parser.setTemplate(null);
  235. }
  236. }
  237. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  238. if (_pattern != null) {
  239. _pattern.typeCheck(stable);
  240. }
  241. return typeCheckContents(stable);
  242. }
  243. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  244. final ConstantPoolGen cpg = classGen.getConstantPool();
  245. final InstructionList il = methodGen.getInstructionList();
  246. if (_disabled) return;
  247. // bug fix #4433133, add a call to named template from applyTemplates
  248. String className = classGen.getClassName();
  249. if (_compiled && isNamed()){
  250. String methodName = Util.escape(_name.toString());
  251. il.append(classGen.loadTranslet());
  252. il.append(methodGen.loadDOM());
  253. il.append(methodGen.loadIterator());
  254. il.append(methodGen.loadHandler());
  255. il.append(methodGen.loadCurrentNode());
  256. il.append(new INVOKEVIRTUAL(cpg.addMethodref(className,
  257. methodName,
  258. "("
  259. + DOM_INTF_SIG
  260. + NODE_ITERATOR_SIG
  261. + TRANSLET_OUTPUT_SIG
  262. + "I)V")));
  263. return;
  264. }
  265. if (_compiled) return;
  266. _compiled = true;
  267. // %OPT% Special handling for simple named templates.
  268. if (_isSimpleNamedTemplate && methodGen instanceof NamedMethodGenerator) {
  269. int numParams = _parameters.size();
  270. NamedMethodGenerator namedMethodGen = (NamedMethodGenerator)methodGen;
  271. // Update load/store instructions to access Params from the stack
  272. for (int i = 0; i < numParams; i++) {
  273. Param param = (Param)_parameters.elementAt(i);
  274. param.setLoadInstruction(namedMethodGen.loadParameter(i));
  275. param.setStoreInstruction(namedMethodGen.storeParameter(i));
  276. }
  277. }
  278. translateContents(classGen, methodGen);
  279. il.setPositions(true);
  280. }
  281. }