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    }