001: /*
002: * Copyright 2001-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: Template.java,v 1.26 2005/03/23 17:54:04 ytalwar Exp $
018: */
019:
020: package org.apache.xalan.xsltc.compiler;
021:
022: import java.util.Vector;
023:
024: import org.apache.bcel.generic.ConstantPoolGen;
025: import org.apache.bcel.generic.INVOKEVIRTUAL;
026: import org.apache.bcel.generic.InstructionHandle;
027: import org.apache.bcel.generic.InstructionList;
028: import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
029: import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
030: import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
031: import org.apache.xalan.xsltc.compiler.util.NamedMethodGenerator;
032: import org.apache.xalan.xsltc.compiler.util.Type;
033: import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
034: import org.apache.xalan.xsltc.compiler.util.Util;
035: import org.apache.xml.utils.XML11Char;
036:
037: /**
038: * @author Jacek Ambroziak
039: * @author Santiago Pericas-Geertsen
040: * @author Morten Jorgensen
041: * @author Erwin Bolwidt <ejb@klomp.org>
042: */
043: public final class Template extends TopLevelElement {
044:
045: private QName _name; // The name of the template (if any)
046: private QName _mode; // Mode in which this template is instantiated.
047: private Pattern _pattern; // Matching pattern defined for this template.
048: private double _priority; // Matching priority of this template.
049: private int _position; // Position within stylesheet (prio. resolution)
050: private boolean _disabled = false;
051: private boolean _compiled = false;//make sure it is compiled only once
052: private boolean _simplified = false;
053:
054: // True if this is a simple named template. A simple named
055: // template is a template which only has a name but no match pattern.
056: private boolean _isSimpleNamedTemplate = false;
057:
058: // The list of parameters in this template. This is only used
059: // for simple named templates.
060: private Vector _parameters = new Vector();
061:
062: public boolean hasParams() {
063: return _parameters.size() > 0;
064: }
065:
066: public boolean isSimplified() {
067: return (_simplified);
068: }
069:
070: public void setSimplified() {
071: _simplified = true;
072: }
073:
074: public boolean isSimpleNamedTemplate() {
075: return _isSimpleNamedTemplate;
076: }
077:
078: public void addParameter(Param param) {
079: _parameters.addElement(param);
080: }
081:
082: public Vector getParameters() {
083: return _parameters;
084: }
085:
086: public void disable() {
087: _disabled = true;
088: }
089:
090: public boolean disabled() {
091: return (_disabled);
092: }
093:
094: public double getPriority() {
095: return _priority;
096: }
097:
098: public int getPosition() {
099: return (_position);
100: }
101:
102: public boolean isNamed() {
103: return _name != null;
104: }
105:
106: public Pattern getPattern() {
107: return _pattern;
108: }
109:
110: public QName getName() {
111: return _name;
112: }
113:
114: public void setName(QName qname) {
115: if (_name == null)
116: _name = qname;
117: }
118:
119: public QName getModeName() {
120: return _mode;
121: }
122:
123: /**
124: * Compare this template to another. First checks priority, then position.
125: */
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:
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: } else if (_pattern != null) {
147: indent(indent);
148: Util.println("match = " + _pattern.toString());
149: }
150: if (_mode != null) {
151: indent(indent);
152: Util.println("mode = " + _mode);
153: }
154: displayContents(indent + IndentIncrement);
155: }
156:
157: private boolean resolveNamedTemplates(Template other, Parser parser) {
158:
159: if (other == null)
160: 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: } else if (us < them) {
171: stable.addTemplate(other);
172: this .disable();
173: return true;
174: } else {
175: return false;
176: }
177: }
178:
179: private Stylesheet _stylesheet = null;
180:
181: public Stylesheet getStylesheet() {
182: return _stylesheet;
183: }
184:
185: public void parseContents(Parser parser) {
186:
187: final String name = getAttribute("name");
188: final String mode = getAttribute("mode");
189: final String match = getAttribute("match");
190: final String priority = getAttribute("priority");
191:
192: _stylesheet = super .getStylesheet();
193:
194: if (name.length() > 0) {
195: if (!XML11Char.isXML11ValidQName(name)) {
196: ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR,
197: name, this );
198: parser.reportError(Constants.ERROR, err);
199: }
200: _name = parser.getQNameIgnoreDefaultNs(name);
201: }
202:
203: if (mode.length() > 0) {
204: if (!XML11Char.isXML11ValidQName(mode)) {
205: ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR,
206: 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: } else {
219: if (_pattern != null)
220: _priority = _pattern.getPriority();
221: else
222: _priority = Double.NaN;
223: }
224:
225: _position = parser.getTemplateIndex();
226:
227: // Add the (named) template to the symbol table
228: if (_name != null) {
229: Template other = parser.getSymbolTable().addTemplate(this );
230: if (!resolveNamedTemplates(other, parser)) {
231: ErrorMsg err = new ErrorMsg(
232: ErrorMsg.TEMPLATE_REDEF_ERR, _name, this );
233: parser.reportError(Constants.ERROR, err);
234: }
235: // Is this a simple named template?
236: if (_pattern == null && _mode == null) {
237: _isSimpleNamedTemplate = true;
238: }
239: }
240:
241: if (_parent instanceof Stylesheet) {
242: ((Stylesheet) _parent).addTemplate(this );
243: }
244:
245: parser.setTemplate(this ); // set current template
246: parseChildren(parser);
247: parser.setTemplate(null); // clear template
248: }
249:
250: /**
251: * When the parser realises that it is dealign with a simplified stylesheet
252: * it will create an empty Stylesheet object with the root element of the
253: * stylesheet (a LiteralElement object) as its only child. The Stylesheet
254: * object will then create this Template object and invoke this method to
255: * force some specific behaviour. What we need to do is:
256: * o) create a pattern matching on the root node
257: * o) add the LRE root node (the only child of the Stylesheet) as our
258: * only child node
259: * o) set the empty Stylesheet as our parent
260: * o) set this template as the Stylesheet's only child
261: */
262: public void parseSimplified(Stylesheet stylesheet, Parser parser) {
263:
264: _stylesheet = stylesheet;
265: setParent(stylesheet);
266:
267: _name = null;
268: _mode = null;
269: _priority = Double.NaN;
270: _pattern = parser.parsePattern(this , "/");
271:
272: final Vector contents = _stylesheet.getContents();
273: final SyntaxTreeNode root = (SyntaxTreeNode) contents
274: .elementAt(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:
286: public Type typeCheck(SymbolTable stable) throws TypeCheckError {
287: if (_pattern != null) {
288: _pattern.typeCheck(stable);
289: }
290:
291: return typeCheckContents(stable);
292: }
293:
294: public void translate(ClassGenerator classGen,
295: MethodGenerator methodGen) {
296: final ConstantPoolGen cpg = classGen.getConstantPool();
297: final InstructionList il = methodGen.getInstructionList();
298:
299: if (_disabled)
300: 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, "(" + DOM_INTF_SIG + NODE_ITERATOR_SIG
313: + TRANSLET_OUTPUT_SIG + "I)V")));
314: return;
315: }
316:
317: if (_compiled)
318: return;
319: _compiled = true;
320:
321: // %OPT% Special handling for simple named templates.
322: if (_isSimpleNamedTemplate
323: && 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
331: .loadParameter(i));
332: param.setStoreInstruction(namedMethodGen
333: .storeParameter(i));
334: }
335: }
336:
337: translateContents(classGen, methodGen);
338: il.setPositions(true);
339: }
340:
341: }
|