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: SyntaxTreeNode.java 1225842 2011-12-30 15:14:35Z mrglavas $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import java.util.Enumeration;
025 import java.util.Hashtable;
026 import java.util.Vector;
027
028 import org.apache.bcel.generic.ANEWARRAY;
029 import org.apache.bcel.generic.BasicType;
030 import org.apache.bcel.generic.CHECKCAST;
031 import org.apache.bcel.generic.ConstantPoolGen;
032 import org.apache.bcel.generic.DUP_X1;
033 import org.apache.bcel.generic.GETFIELD;
034 import org.apache.bcel.generic.ICONST;
035 import org.apache.bcel.generic.INVOKEINTERFACE;
036 import org.apache.bcel.generic.INVOKESPECIAL;
037 import org.apache.bcel.generic.INVOKEVIRTUAL;
038 import org.apache.bcel.generic.InstructionList;
039 import org.apache.bcel.generic.NEW;
040 import org.apache.bcel.generic.NEWARRAY;
041 import org.apache.bcel.generic.PUSH;
042 import org.apache.xalan.xsltc.DOM;
043 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
044 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
045 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
046 import org.apache.xalan.xsltc.compiler.util.Type;
047 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
048 import org.apache.xalan.xsltc.runtime.AttributeList;
049 import org.xml.sax.Attributes;
050
051
052
053 /**
054 * @author Jacek Ambroziak
055 * @author Santiago Pericas-Geertsen
056 * @author G. Todd Miller
057 * @author Morten Jorensen
058 * @author Erwin Bolwidt <ejb@klomp.org>
059 * @author John Howard <JohnH@schemasoft.com>
060 */
061 public abstract class SyntaxTreeNode implements Constants {
062
063 // Reference to the AST parser
064 private Parser _parser;
065
066 // AST navigation pointers
067 protected SyntaxTreeNode _parent; // Parent node
068 private Stylesheet _stylesheet; // Stylesheet ancestor node
069 private Template _template; // Template ancestor node
070 private final Vector _contents = new Vector(2); // Child nodes
071
072 // Element description data
073 protected QName _qname; // The element QName
074 private int _line; // Source file line number
075 protected AttributeList _attributes = null; // Attributes of this element
076 private Hashtable _prefixMapping = null; // Namespace declarations
077
078 public static final int UNKNOWN_STYLESHEET_NODE_ID = -1;
079
080 // Records whether this node or any descendant needs to know the
081 // in-scope namespaces at transform-time
082 private int _nodeIDForStylesheetNSLookup = UNKNOWN_STYLESHEET_NODE_ID;
083
084 // Sentinel - used to denote unrecognised syntaxt tree nodes.
085 static final SyntaxTreeNode Dummy = new AbsolutePathPattern(null);
086
087 // These two are used for indenting nodes in the AST (debug output)
088 protected static final int IndentIncrement = 4;
089 private static final char[] _spaces =
090 " ".toCharArray();
091
092 /**
093 * Creates a new SyntaxTreeNode with a 'null' QName and no source file
094 * line number reference.
095 */
096 public SyntaxTreeNode() {
097 _line = 0;
098 _qname = null;
099 }
100
101 /**
102 * Creates a new SyntaxTreeNode with a 'null' QName.
103 * @param line Source file line number reference
104 */
105 public SyntaxTreeNode(int line) {
106 _line = line;
107 _qname = null;
108 }
109
110 /**
111 * Creates a new SyntaxTreeNode with no source file line number reference.
112 * @param uri The element's namespace URI
113 * @param prefix The element's namespace prefix
114 * @param local The element's local name
115 */
116 public SyntaxTreeNode(String uri, String prefix, String local) {
117 _line = 0;
118 setQName(uri, prefix, local);
119 }
120
121 /**
122 * Set the source file line number for this element
123 * @param line The source file line number.
124 */
125 protected final void setLineNumber(int line) {
126 _line = line;
127 }
128
129 /**
130 * Get the source file line number for this element. If unavailable, lookup
131 * in ancestors.
132 *
133 * @return The source file line number.
134 */
135 public final int getLineNumber() {
136 if (_line > 0) return _line;
137 SyntaxTreeNode parent = getParent();
138 return (parent != null) ? parent.getLineNumber() : 0;
139 }
140
141 /**
142 * Set the QName for the syntax tree node.
143 * @param qname The QName for the syntax tree node
144 */
145 protected void setQName(QName qname) {
146 _qname = qname;
147 }
148
149 /**
150 * Set the QName for the SyntaxTreeNode
151 * @param uri The element's namespace URI
152 * @param prefix The element's namespace prefix
153 * @param local The element's local name
154 */
155 protected void setQName(String uri, String prefix, String localname) {
156 _qname = new QName(uri, prefix, localname);
157 }
158
159 /**
160 * Set the QName for the SyntaxTreeNode
161 * @param qname The QName for the syntax tree node
162 */
163 protected QName getQName() {
164 return(_qname);
165 }
166
167 /**
168 * Set the attributes for this SyntaxTreeNode.
169 * @param attributes Attributes for the element. Must be passed in as an
170 * implementation of org.xml.sax.Attributes.
171 */
172 protected void setAttributes(AttributeList attributes) {
173 _attributes = attributes;
174 }
175
176 /**
177 * Returns a value for an attribute from the source element.
178 * @param qname The QName of the attribute to return.
179 * @return The value of the attribute of name 'qname'.
180 */
181 protected String getAttribute(String qname) {
182 if (_attributes == null) {
183 return EMPTYSTRING;
184 }
185 final String value = _attributes.getValue(qname);
186 return (value == null || value.equals(EMPTYSTRING)) ?
187 EMPTYSTRING : value;
188 }
189
190 protected String getAttribute(String prefix, String localName) {
191 return getAttribute(prefix + ':' + localName);
192 }
193
194 protected boolean hasAttribute(String qname) {
195 return (_attributes != null && _attributes.getValue(qname) != null);
196 }
197
198 protected void addAttribute(String qname, String value) {
199 _attributes.add(qname, value);
200 }
201
202 /**
203 * Returns a list of all attributes declared for the element represented by
204 * this syntax tree node.
205 * @return Attributes for this syntax tree node
206 */
207 protected Attributes getAttributes() {
208 return(_attributes);
209 }
210
211 /**
212 * Sets the prefix mapping for the namespaces that were declared in this
213 * element. This does not include all prefix mappings in scope, so one
214 * may have to check ancestor elements to get all mappings that are in
215 * in scope. The prefixes must be passed in as a Hashtable that maps
216 * namespace prefixes (String objects) to namespace URIs (also String).
217 * @param mapping The Hashtable containing the mappings.
218 */
219 protected void setPrefixMapping(Hashtable mapping) {
220 _prefixMapping = mapping;
221 }
222
223 /**
224 * Returns a Hashtable containing the prefix mappings that were declared
225 * for this element. This does not include all prefix mappings in scope,
226 * so one may have to check ancestor elements to get all mappings that are
227 * in in scope.
228 * @return Prefix mappings (for this element only).
229 */
230 protected Hashtable getPrefixMapping() {
231 return _prefixMapping;
232 }
233
234 /**
235 * Adds a single prefix mapping to this syntax tree node.
236 * @param prefix Namespace prefix.
237 * @param uri Namespace URI.
238 */
239 protected void addPrefixMapping(String prefix, String uri) {
240 if (_prefixMapping == null)
241 _prefixMapping = new Hashtable();
242 _prefixMapping.put(prefix, uri);
243 }
244
245 /**
246 * Returns any namespace URI that is in scope for a given prefix. This
247 * method checks namespace mappings for this element, and if necessary
248 * for ancestor elements as well (ie. if the prefix maps to an URI in this
249 * scope then you'll definately get the URI from this method).
250 * @param prefix Namespace prefix.
251 * @return Namespace URI.
252 */
253 protected String lookupNamespace(String prefix) {
254 // Initialise the output (default is 'null' for undefined)
255 String uri = null;
256
257 // First look up the prefix/uri mapping in our own hashtable...
258 if (_prefixMapping != null)
259 uri = (String)_prefixMapping.get(prefix);
260 // ... but if we can't find it there we ask our parent for the mapping
261 if ((uri == null) && (_parent != null)) {
262 uri = _parent.lookupNamespace(prefix);
263 if ((prefix == Constants.EMPTYSTRING) && (uri == null))
264 uri = Constants.EMPTYSTRING;
265 }
266 // ... and then we return whatever URI we've got.
267 return(uri);
268 }
269
270 /**
271 * Returns any namespace prefix that is mapped to a prefix in the current
272 * scope. This method checks namespace mappings for this element, and if
273 * necessary for ancestor elements as well (ie. if the URI is declared
274 * within the current scope then you'll definately get the prefix from
275 * this method). Note that this is a very slow method and consequentially
276 * it should only be used strictly when needed.
277 * @param uri Namespace URI.
278 * @return Namespace prefix.
279 */
280 protected String lookupPrefix(String uri) {
281 // Initialise the output (default is 'null' for undefined)
282 String prefix = null;
283
284 // First look up the prefix/uri mapping in our own hashtable...
285 if ((_prefixMapping != null) &&
286 (_prefixMapping.contains(uri))) {
287 Enumeration prefixes = _prefixMapping.keys();
288 while (prefixes.hasMoreElements()) {
289 prefix = (String)prefixes.nextElement();
290 String mapsTo = (String)_prefixMapping.get(prefix);
291 if (mapsTo.equals(uri)) return(prefix);
292 }
293 }
294 // ... but if we can't find it there we ask our parent for the mapping
295 else if (_parent != null) {
296 prefix = _parent.lookupPrefix(uri);
297 if ((uri == Constants.EMPTYSTRING) && (prefix == null))
298 prefix = Constants.EMPTYSTRING;
299 }
300 return(prefix);
301 }
302
303 /**
304 * Set this node's parser. The parser (the XSLT parser) gives this
305 * syntax tree node access to the symbol table and XPath parser.
306 * @param parser The XSLT parser.
307 */
308 protected void setParser(Parser parser) {
309 _parser = parser;
310 }
311
312 /**
313 * Returns this node's XSLT parser.
314 * @return The XSLT parser.
315 */
316 public final Parser getParser() {
317 return _parser;
318 }
319
320 /**
321 * Set this syntax tree node's parent node
322 * @param parent The parent node.
323 */
324 protected void setParent(SyntaxTreeNode parent) {
325 if (_parent == null)
326 _parent = parent;
327 }
328
329 /**
330 * Returns this syntax tree node's parent node.
331 * @return The parent syntax tree node.
332 */
333 protected final SyntaxTreeNode getParent() {
334 return _parent;
335 }
336
337 /**
338 * Returns 'true' if this syntax tree node is the Sentinal node.
339 * @return 'true' if this syntax tree node is the Sentinal node.
340 */
341 protected final boolean isDummy() {
342 return this == Dummy;
343 }
344
345 /**
346 * Get the import precedence of this element. The import precedence equals
347 * the import precedence of the stylesheet in which this element occured.
348 * @return The import precedence of this syntax tree node.
349 */
350 protected int getImportPrecedence() {
351 Stylesheet stylesheet = getStylesheet();
352 if (stylesheet == null) return Integer.MIN_VALUE;
353 return stylesheet.getImportPrecedence();
354 }
355
356 /**
357 * Get the Stylesheet node that represents the <xsl:stylesheet/> element
358 * that this node occured under.
359 * @return The Stylesheet ancestor node of this node.
360 */
361 public Stylesheet getStylesheet() {
362 if (_stylesheet == null) {
363 SyntaxTreeNode parent = this;
364 while (parent != null) {
365 if (parent instanceof Stylesheet)
366 return((Stylesheet)parent);
367 parent = parent.getParent();
368 }
369 _stylesheet = (Stylesheet)parent;
370 }
371 return(_stylesheet);
372 }
373
374 /**
375 * Get the Template node that represents the <xsl:template/> element
376 * that this node occured under. Note that this method will return 'null'
377 * for nodes that represent top-level elements.
378 * @return The Template ancestor node of this node or 'null'.
379 */
380 protected Template getTemplate() {
381 if (_template == null) {
382 SyntaxTreeNode parent = this;
383 while ((parent != null) && (!(parent instanceof Template)))
384 parent = parent.getParent();
385 _template = (Template)parent;
386 }
387 return(_template);
388 }
389
390 /**
391 * Returns a reference to the XSLTC (XSLT compiler) in use.
392 * @return XSLTC - XSLT compiler.
393 */
394 protected final XSLTC getXSLTC() {
395 return _parser.getXSLTC();
396 }
397
398 /**
399 * Returns the XSLT parser's symbol table.
400 * @return Symbol table.
401 */
402 protected final SymbolTable getSymbolTable() {
403 return (_parser == null) ? null : _parser.getSymbolTable();
404 }
405
406 /**
407 * Parse the contents of this syntax tree nodes (child nodes, XPath
408 * expressions, patterns and functions). The default behaviour is to parser
409 * the syntax tree node's children (since there are no common expressions,
410 * patterns, etc. that can be handled in this base class.
411 * @param parser reference to the XSLT parser
412 */
413 public void parseContents(Parser parser) {
414 parseChildren(parser);
415 }
416
417 /**
418 * Parse all children of this syntax tree node. This method is normally
419 * called by the parseContents() method.
420 * @param parser reference to the XSLT parser
421 */
422 protected final void parseChildren(Parser parser) {
423
424 Vector locals = null; // only create when needed
425
426 final int count = _contents.size();
427 for (int i=0; i<count; i++) {
428 SyntaxTreeNode child = (SyntaxTreeNode)_contents.elementAt(i);
429 parser.getSymbolTable().setCurrentNode(child);
430 child.parseContents(parser);
431 // if variable or parameter, add it to scope
432 final QName varOrParamName = updateScope(parser, child);
433 if (varOrParamName != null) {
434 if (locals == null) {
435 locals = new Vector(2);
436 }
437 locals.addElement(varOrParamName);
438 }
439 }
440
441 parser.getSymbolTable().setCurrentNode(this);
442
443 // after the last element, remove any locals from scope
444 if (locals != null) {
445 final int nLocals = locals.size();
446 for (int i = 0; i < nLocals; i++) {
447 parser.removeVariable((QName)locals.elementAt(i));
448 }
449 }
450 }
451
452 /**
453 * Add a node to the current scope and return name of a variable or
454 * parameter if the node represents a variable or a parameter.
455 */
456 protected QName updateScope(Parser parser, SyntaxTreeNode node) {
457 if (node instanceof Variable) {
458 final Variable var = (Variable)node;
459 parser.addVariable(var);
460 return var.getName();
461 }
462 else if (node instanceof Param) {
463 final Param param = (Param)node;
464 parser.addParameter(param);
465 return param.getName();
466 }
467 else {
468 return null;
469 }
470 }
471
472 /**
473 * Type check the children of this node. The type check phase may add
474 * coercions (CastExpr) to the AST.
475 * @param stable The compiler/parser's symbol table
476 */
477 public abstract Type typeCheck(SymbolTable stable) throws TypeCheckError;
478
479 /**
480 * Call typeCheck() on all child syntax tree nodes.
481 * @param stable The compiler/parser's symbol table
482 */
483 protected Type typeCheckContents(SymbolTable stable) throws TypeCheckError {
484 final int n = elementCount();
485 for (int i = 0; i < n; i++) {
486 SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i);
487 item.typeCheck(stable);
488 }
489 return Type.Void;
490 }
491
492 /**
493 * Translate this abstract syntax tree node into JVM bytecodes.
494 * @param classGen BCEL Java class generator
495 * @param methodGen BCEL Java method generator
496 */
497 public abstract void translate(ClassGenerator classGen,
498 MethodGenerator methodGen);
499
500 /**
501 * Call translate() on all child syntax tree nodes.
502 * @param classGen BCEL Java class generator
503 * @param methodGen BCEL Java method generator
504 */
505 protected void translateContents(ClassGenerator classGen,
506 MethodGenerator methodGen) {
507 // Call translate() on all child nodes
508 final int n = elementCount();
509
510 for (int i = 0; i < n; i++) {
511 methodGen.markChunkStart();
512 final SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i);
513 item.translate(classGen, methodGen);
514 methodGen.markChunkEnd();
515 }
516
517 // After translation, unmap any registers for any variables/parameters
518 // that were declared in this scope. Performing this unmapping in the
519 // same AST scope as the declaration deals with the problems of
520 // references falling out-of-scope inside the for-each element.
521 // (the cause of which being 'lazy' register allocation for references)
522 for (int i = 0; i < n; i++) {
523 if( _contents.elementAt(i) instanceof VariableBase) {
524 final VariableBase var = (VariableBase)_contents.elementAt(i);
525 var.unmapRegister(methodGen);
526 }
527 }
528 }
529
530 /**
531 * Return true if the node represents a simple RTF.
532 *
533 * A node is a simple RTF if all children only produce Text value.
534 *
535 * @param node A node
536 * @return true if the node content can be considered as a simple RTF.
537 */
538 private boolean isSimpleRTF(SyntaxTreeNode node) {
539
540 Vector contents = node.getContents();
541 for (int i = 0; i < contents.size(); i++) {
542 SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i);
543 if (!isTextElement(item, false))
544 return false;
545 }
546
547 return true;
548 }
549
550 /**
551 * Return true if the node represents an adaptive RTF.
552 *
553 * A node is an adaptive RTF if each children is a Text element
554 * or it is <xsl:call-template> or <xsl:apply-templates>.
555 *
556 * @param node A node
557 * @return true if the node content can be considered as an adaptive RTF.
558 */
559 private boolean isAdaptiveRTF(SyntaxTreeNode node) {
560
561 Vector contents = node.getContents();
562 for (int i = 0; i < contents.size(); i++) {
563 SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i);
564 if (!isTextElement(item, true))
565 return false;
566 }
567
568 return true;
569 }
570
571 /**
572 * Return true if the node only produces Text content.
573 *
574 * A node is a Text element if it is Text, xsl:value-of, xsl:number,
575 * or a combination of these nested in a control instruction (xsl:if or
576 * xsl:choose).
577 *
578 * If the doExtendedCheck flag is true, xsl:call-template and xsl:apply-templates
579 * are also considered as Text elements.
580 *
581 * @param node A node
582 * @param doExtendedCheck If this flag is true, <xsl:call-template> and
583 * <xsl:apply-templates> are also considered as Text elements.
584 *
585 * @return true if the node of Text type
586 */
587 private boolean isTextElement(SyntaxTreeNode node, boolean doExtendedCheck) {
588 if (node instanceof ValueOf || node instanceof Number
589 || node instanceof Text)
590 {
591 return true;
592 }
593 else if (node instanceof If) {
594 return doExtendedCheck ? isAdaptiveRTF(node) : isSimpleRTF(node);
595 }
596 else if (node instanceof Choose) {
597 Vector contents = node.getContents();
598 for (int i = 0; i < contents.size(); i++) {
599 SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i);
600 if (item instanceof Text ||
601 ((item instanceof When || item instanceof Otherwise)
602 && ((doExtendedCheck && isAdaptiveRTF(item))
603 || (!doExtendedCheck && isSimpleRTF(item)))))
604 continue;
605 else
606 return false;
607 }
608 return true;
609 }
610 else if (doExtendedCheck &&
611 (node instanceof CallTemplate
612 || node instanceof ApplyTemplates))
613 return true;
614 else
615 return false;
616 }
617
618 /**
619 * Utility method used by parameters and variables to store result trees
620 * @param classGen BCEL Java class generator
621 * @param methodGen BCEL Java method generator
622 */
623 protected void compileResultTree(ClassGenerator classGen,
624 MethodGenerator methodGen)
625 {
626 final ConstantPoolGen cpg = classGen.getConstantPool();
627 final InstructionList il = methodGen.getInstructionList();
628 final Stylesheet stylesheet = classGen.getStylesheet();
629
630 boolean isSimple = isSimpleRTF(this);
631 boolean isAdaptive = false;
632 if (!isSimple) {
633 isAdaptive = isAdaptiveRTF(this);
634 }
635
636 int rtfType = isSimple ? DOM.SIMPLE_RTF
637 : (isAdaptive ? DOM.ADAPTIVE_RTF : DOM.TREE_RTF);
638
639 // Save the current handler base on the stack
640 il.append(methodGen.loadHandler());
641
642 final String DOM_CLASS = classGen.getDOMClass();
643
644 // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes)
645 //int index = cpg.addMethodref(DOM_IMPL, "<init>", "(I)V");
646 //il.append(new NEW(cpg.addClass(DOM_IMPL)));
647
648 il.append(methodGen.loadDOM());
649 int index = cpg.addInterfaceMethodref(DOM_INTF,
650 "getResultTreeFrag",
651 "(IIZ)" + DOM_INTF_SIG);
652 il.append(new PUSH(cpg, RTF_INITIAL_SIZE));
653 il.append(new PUSH(cpg, rtfType));
654 il.append(new PUSH(cpg, stylesheet.callsNodeset()));
655 il.append(new INVOKEINTERFACE(index,4));
656
657 il.append(DUP);
658
659 // Overwrite old handler with DOM handler
660 index = cpg.addInterfaceMethodref(DOM_INTF,
661 "getOutputDomBuilder",
662 "()" + TRANSLET_OUTPUT_SIG);
663
664 il.append(new INVOKEINTERFACE(index,1));
665 il.append(DUP);
666 il.append(methodGen.storeHandler());
667
668 // Call startDocument on the new handler
669 il.append(methodGen.startDocument());
670
671 // Instantiate result tree fragment
672 translateContents(classGen, methodGen);
673
674 // Call endDocument on the new handler
675 il.append(methodGen.loadHandler());
676 il.append(methodGen.endDocument());
677
678 // Check if we need to wrap the DOMImpl object in a DOMAdapter object.
679 // DOMAdapter is not needed if the RTF is a simple RTF and the nodeset()
680 // function is not used.
681 if (stylesheet.callsNodeset()
682 && !DOM_CLASS.equals(DOM_IMPL_CLASS)) {
683 // new org.apache.xalan.xsltc.dom.DOMAdapter(DOMImpl,String[]);
684 index = cpg.addMethodref(DOM_ADAPTER_CLASS,
685 "<init>",
686 "("+DOM_INTF_SIG+
687 "["+STRING_SIG+
688 "["+STRING_SIG+
689 "[I"+
690 "["+STRING_SIG+")V");
691 il.append(new NEW(cpg.addClass(DOM_ADAPTER_CLASS)));
692 il.append(new DUP_X1());
693 il.append(SWAP);
694
695 /*
696 * Give the DOM adapter an empty type mapping if the nodeset
697 * extension function is never called.
698 */
699 if (!stylesheet.callsNodeset()) {
700 il.append(new ICONST(0));
701 il.append(new ANEWARRAY(cpg.addClass(STRING)));
702 il.append(DUP);
703 il.append(DUP);
704 il.append(new ICONST(0));
705 il.append(new NEWARRAY(BasicType.INT));
706 il.append(SWAP);
707 il.append(new INVOKESPECIAL(index));
708 }
709 else {
710 // Push name arrays on the stack
711 il.append(ALOAD_0);
712 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
713 NAMES_INDEX,
714 NAMES_INDEX_SIG)));
715 il.append(ALOAD_0);
716 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
717 URIS_INDEX,
718 URIS_INDEX_SIG)));
719 il.append(ALOAD_0);
720 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
721 TYPES_INDEX,
722 TYPES_INDEX_SIG)));
723 il.append(ALOAD_0);
724 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
725 NAMESPACE_INDEX,
726 NAMESPACE_INDEX_SIG)));
727
728 // Initialized DOM adapter
729 il.append(new INVOKESPECIAL(index));
730
731 // Add DOM adapter to MultiDOM class by calling addDOMAdapter()
732 il.append(DUP);
733 il.append(methodGen.loadDOM());
734 il.append(new CHECKCAST(cpg.addClass(classGen.getDOMClass())));
735 il.append(SWAP);
736 index = cpg.addMethodref(MULTI_DOM_CLASS,
737 "addDOMAdapter",
738 "(" + DOM_ADAPTER_SIG + ")I");
739 il.append(new INVOKEVIRTUAL(index));
740 il.append(POP); // ignore mask returned by addDOMAdapter
741 }
742 }
743
744 // Restore old handler base from stack
745 il.append(SWAP);
746 il.append(methodGen.storeHandler());
747 }
748
749 /**
750 * Retrieve an ID to identify the namespaces in scope at this point in the
751 * stylesheet
752 * @return An <code>int</code> representing the node ID or <code>-1</code>
753 * if no namespace declarations are in scope
754 */
755 protected final int getNodeIDForStylesheetNSLookup() {
756 if (_nodeIDForStylesheetNSLookup == UNKNOWN_STYLESHEET_NODE_ID) {
757 Hashtable prefixMapping = getPrefixMapping();
758 int parentNodeID =
759 (_parent != null) ? _parent.getNodeIDForStylesheetNSLookup()
760 : UNKNOWN_STYLESHEET_NODE_ID;
761
762 // If this node in the stylesheet has no namespace declarations of
763 // its own, use the ID of the nearest ancestor element that does
764 // have namespace declarations.
765 if (prefixMapping == null) {
766 _nodeIDForStylesheetNSLookup = parentNodeID;
767 } else {
768 // Inform the XSLTC object that we'll need to know about this
769 // node's namespace declarations.
770 _nodeIDForStylesheetNSLookup =
771 getXSLTC().registerStylesheetPrefixMappingForRuntime(
772 prefixMapping, parentNodeID);
773 }
774 }
775
776 return _nodeIDForStylesheetNSLookup;
777 }
778 /**
779 * Returns true if this expression/instruction depends on the context. By
780 * default, every expression/instruction depends on the context unless it
781 * overrides this method. Currently used to determine if result trees are
782 * compiled using procedures or little DOMs (result tree fragments).
783 * @return 'true' if this node depends on the context.
784 */
785 protected boolean contextDependent() {
786 return true;
787 }
788
789 /**
790 * Return true if any of the expressions/instructions in the contents of
791 * this node is context dependent.
792 * @return 'true' if the contents of this node is context dependent.
793 */
794 protected boolean dependentContents() {
795 final int n = elementCount();
796 for (int i = 0; i < n; i++) {
797 final SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i);
798 if (item.contextDependent()) {
799 return true;
800 }
801 }
802 return false;
803 }
804
805 /**
806 * Adds a child node to this syntax tree node.
807 * @param element is the new child node.
808 */
809 protected final void addElement(SyntaxTreeNode element) {
810 _contents.addElement(element);
811 element.setParent(this);
812 }
813
814 /**
815 * Inserts the first child node of this syntax tree node. The existing
816 * children are shifted back one position.
817 * @param element is the new child node.
818 */
819 protected final void setFirstElement(SyntaxTreeNode element) {
820 _contents.insertElementAt(element,0);
821 element.setParent(this);
822 }
823
824 /**
825 * Removed a child node of this syntax tree node.
826 * @param element is the child node to remove.
827 */
828 protected final void removeElement(SyntaxTreeNode element) {
829 _contents.remove(element);
830 element.setParent(null);
831 }
832
833 /**
834 * Returns a Vector containing all the child nodes of this node.
835 * @return A Vector containing all the child nodes of this node.
836 */
837 protected final Vector getContents() {
838 return _contents;
839 }
840
841 /**
842 * Tells you if this node has any child nodes.
843 * @return 'true' if this node has any children.
844 */
845 protected final boolean hasContents() {
846 return elementCount() > 0;
847 }
848
849 /**
850 * Returns the number of children this node has.
851 * @return Number of child nodes.
852 */
853 protected final int elementCount() {
854 return _contents.size();
855 }
856
857 /**
858 * Returns an Enumeration of all child nodes of this node.
859 * @return An Enumeration of all child nodes of this node.
860 */
861 protected final Enumeration elements() {
862 return _contents.elements();
863 }
864
865 /**
866 * Returns a child node at a given position.
867 * @param pos The child node's position.
868 * @return The child node.
869 */
870 protected final Object elementAt(int pos) {
871 return _contents.elementAt(pos);
872 }
873
874 /**
875 * Returns this element's last child
876 * @return The child node.
877 */
878 protected final SyntaxTreeNode lastChild() {
879 if (_contents.size() == 0) return null;
880 return (SyntaxTreeNode)_contents.lastElement();
881 }
882
883 /**
884 * Displays the contents of this syntax tree node (to stdout).
885 * This method is intended for debugging _only_, and should be overridden
886 * by all syntax tree node implementations.
887 * @param indent Indentation level for syntax tree levels.
888 */
889 public void display(int indent) {
890 displayContents(indent);
891 }
892
893 /**
894 * Displays the contents of this syntax tree node (to stdout).
895 * This method is intended for debugging _only_ !!!
896 * @param indent Indentation level for syntax tree levels.
897 */
898 protected void displayContents(int indent) {
899 final int n = elementCount();
900 for (int i = 0; i < n; i++) {
901 SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i);
902 item.display(indent);
903 }
904 }
905
906 /**
907 * Set the indentation level for debug output.
908 * @param indent Indentation level for syntax tree levels.
909 */
910 protected final void indent(int indent) {
911 System.out.print(new String(_spaces, 0, indent));
912 }
913
914 /**
915 * Report an error to the parser.
916 * @param element The element in which the error occured (normally 'this'
917 * but it could also be an expression/pattern/etc.)
918 * @param parser The XSLT parser to report the error to.
919 * @param error The error code (from util/ErrorMsg).
920 * @param message Any additional error message.
921 */
922 protected void reportError(SyntaxTreeNode element, Parser parser,
923 String errorCode, String message) {
924 final ErrorMsg error = new ErrorMsg(errorCode, message, element);
925 parser.reportError(Constants.ERROR, error);
926 }
927
928 /**
929 * Report a recoverable error to the parser.
930 * @param element The element in which the error occured (normally 'this'
931 * but it could also be an expression/pattern/etc.)
932 * @param parser The XSLT parser to report the error to.
933 * @param error The error code (from util/ErrorMsg).
934 * @param message Any additional error message.
935 */
936 protected void reportWarning(SyntaxTreeNode element, Parser parser,
937 String errorCode, String message) {
938 final ErrorMsg error = new ErrorMsg(errorCode, message, element);
939 parser.reportError(Constants.WARNING, error);
940 }
941
942 }