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