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