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 
  21 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  22 
  23 import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
  24 import com.sun.org.apache.bcel.internal.generic.BasicType;
  25 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
  26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  27 import com.sun.org.apache.bcel.internal.generic.DUP_X1;
  28 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
  29 import com.sun.org.apache.bcel.internal.generic.ICONST;
  30 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  31 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  32 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  33 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  34 import com.sun.org.apache.bcel.internal.generic.NEW;
  35 import com.sun.org.apache.bcel.internal.generic.NEWARRAY;
  36 import com.sun.org.apache.bcel.internal.generic.PUSH;
  37 import com.sun.org.apache.xalan.internal.xsltc.DOM;
  38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  43 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  44 import java.util.ArrayList;
  45 import java.util.HashMap;
  46 import java.util.Iterator;
  47 import java.util.List;
  48 import java.util.Map;
  49 import org.xml.sax.Attributes;
  50 import 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  */
  61 public 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      * Return true if the node represents a simple RTF.
 528      *
 529      * A node is a simple RTF if all children only produce Text value.
 530      *
 531      * @param node A node
 532      * @return true if the node content can be considered as a simple RTF.
 533      */
 534     private boolean isSimpleRTF(SyntaxTreeNode node) {
 535 
 536         List<SyntaxTreeNode> contents = node.getContents();
 537         if (!contents.stream().noneMatch((item) -> (!isTextElement(item, false)))) {
 538                 return false;
 539         }
 540 
 541         return true;
 542     }
 543 
 544      /**
 545      * Return true if the node represents an adaptive RTF.
 546      *
 547      * A node is an adaptive RTF if each children is a Text element
 548      * or it is <xsl:call-template> or <xsl:apply-templates>.
 549      *
 550      * @param node A node
 551      * @return true if the node content can be considered as an adaptive RTF.
 552      */
 553     private boolean isAdaptiveRTF(SyntaxTreeNode node) {
 554 
 555         List<SyntaxTreeNode> contents = node.getContents();
 556         for (SyntaxTreeNode item : contents) {
 557             if (!isTextElement(item, true))
 558                 return false;
 559         }
 560 
 561         return true;
 562     }
 563 
 564     /**
 565      * Return true if the node only produces Text content.
 566      *
 567      * A node is a Text element if it is Text, xsl:value-of, xsl:number,
 568      * or a combination of these nested in a control instruction (xsl:if or
 569      * xsl:choose).
 570      *
 571      * If the doExtendedCheck flag is true, xsl:call-template and xsl:apply-templates
 572      * are also considered as Text elements.
 573      *
 574      * @param node A node
 575      * @param doExtendedCheck If this flag is true, <xsl:call-template> and
 576      * <xsl:apply-templates> are also considered as Text elements.
 577      *
 578      * @return true if the node of Text type
 579      */
 580     private boolean isTextElement(SyntaxTreeNode node, boolean doExtendedCheck) {
 581         if (node instanceof ValueOf || node instanceof Number
 582             || node instanceof Text)
 583         {
 584             return true;
 585         }
 586         else if (node instanceof If) {
 587             return doExtendedCheck ? isAdaptiveRTF(node) : isSimpleRTF(node);
 588         }
 589         else if (node instanceof Choose) {
 590             List<SyntaxTreeNode> contents = node.getContents();
 591             for (SyntaxTreeNode item : contents) {
 592                 if (item instanceof Text ||
 593                      ((item instanceof When || item instanceof Otherwise)
 594                      && ((doExtendedCheck && isAdaptiveRTF(item))
 595                          || (!doExtendedCheck && isSimpleRTF(item)))))
 596                     continue;
 597                 else
 598                     return false;
 599             }
 600             return true;
 601         }
 602         else if (doExtendedCheck &&
 603                   (node instanceof CallTemplate
 604                    || node instanceof ApplyTemplates))
 605             return true;
 606         else
 607             return false;
 608     }
 609 
 610     /**
 611      * Utility method used by parameters and variables to store result trees
 612      * @param classGen BCEL Java class generator
 613      * @param methodGen BCEL Java method generator
 614      */
 615     protected void compileResultTree(ClassGenerator classGen,
 616                                      MethodGenerator methodGen)
 617     {
 618         final ConstantPoolGen cpg = classGen.getConstantPool();
 619         final InstructionList il = methodGen.getInstructionList();
 620         final Stylesheet stylesheet = classGen.getStylesheet();
 621 
 622         boolean isSimple = isSimpleRTF(this);
 623         boolean isAdaptive = false;
 624         if (!isSimple) {
 625             isAdaptive = isAdaptiveRTF(this);
 626         }
 627 
 628         int rtfType = isSimple ? DOM.SIMPLE_RTF
 629                                : (isAdaptive ? DOM.ADAPTIVE_RTF : DOM.TREE_RTF);
 630 
 631         // Save the current handler base on the stack
 632         il.append(methodGen.loadHandler());
 633 
 634         final String DOM_CLASS = classGen.getDOMClass();
 635 
 636         // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes)
 637         //int index = cpg.addMethodref(DOM_IMPL, "<init>", "(I)V");
 638         //il.append(new NEW(cpg.addClass(DOM_IMPL)));
 639 
 640         il.append(methodGen.loadDOM());
 641         int index = cpg.addInterfaceMethodref(DOM_INTF,
 642                                  "getResultTreeFrag",
 643                                  "(IIZ)" + DOM_INTF_SIG);
 644         il.append(new PUSH(cpg, RTF_INITIAL_SIZE));
 645         il.append(new PUSH(cpg, rtfType));
 646         il.append(new PUSH(cpg, stylesheet.callsNodeset()));
 647         il.append(new INVOKEINTERFACE(index,4));
 648 
 649         il.append(DUP);
 650 
 651         // Overwrite old handler with DOM handler
 652         index = cpg.addInterfaceMethodref(DOM_INTF,
 653                                  "getOutputDomBuilder",
 654                                  "()" + TRANSLET_OUTPUT_SIG);
 655 
 656         il.append(new INVOKEINTERFACE(index,1));
 657         il.append(DUP);
 658         il.append(methodGen.storeHandler());
 659 
 660         // Call startDocument on the new handler
 661         il.append(methodGen.startDocument());
 662 
 663         // Instantiate result tree fragment
 664         translateContents(classGen, methodGen);
 665 
 666         // Call endDocument on the new handler
 667         il.append(methodGen.loadHandler());
 668         il.append(methodGen.endDocument());
 669 
 670         // Check if we need to wrap the DOMImpl object in a DOMAdapter object.
 671         // DOMAdapter is not needed if the RTF is a simple RTF and the nodeset()
 672         // function is not used.
 673         if (stylesheet.callsNodeset()
 674             && !DOM_CLASS.equals(DOM_IMPL_CLASS)) {
 675             // new com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter(DOMImpl,String[]);
 676             index = cpg.addMethodref(DOM_ADAPTER_CLASS,
 677                                      "<init>",
 678                                      "("+DOM_INTF_SIG+
 679                                      "["+STRING_SIG+
 680                                      "["+STRING_SIG+
 681                                      "[I"+
 682                                      "["+STRING_SIG+")V");
 683             il.append(new NEW(cpg.addClass(DOM_ADAPTER_CLASS)));
 684             il.append(new DUP_X1());
 685             il.append(SWAP);
 686 
 687             /*
 688              * Give the DOM adapter an empty type mapping if the nodeset
 689              * extension function is never called.
 690              */
 691             if (!stylesheet.callsNodeset()) {
 692                 il.append(new ICONST(0));
 693                 il.append(new ANEWARRAY(cpg.addClass(STRING)));
 694                 il.append(DUP);
 695                 il.append(DUP);
 696                 il.append(new ICONST(0));
 697                 il.append(new NEWARRAY(BasicType.INT));
 698                 il.append(SWAP);
 699                 il.append(new INVOKESPECIAL(index));
 700             }
 701             else {
 702                 // Push name arrays on the stack
 703                 il.append(ALOAD_0);
 704                 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
 705                                            NAMES_INDEX,
 706                                            NAMES_INDEX_SIG)));
 707                 il.append(ALOAD_0);
 708                 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
 709                                            URIS_INDEX,
 710                                            URIS_INDEX_SIG)));
 711                 il.append(ALOAD_0);
 712                 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
 713                                            TYPES_INDEX,
 714                                            TYPES_INDEX_SIG)));
 715                 il.append(ALOAD_0);
 716                 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
 717                                            NAMESPACE_INDEX,
 718                                            NAMESPACE_INDEX_SIG)));
 719 
 720                 // Initialized DOM adapter
 721                 il.append(new INVOKESPECIAL(index));
 722 
 723                 // Add DOM adapter to MultiDOM class by calling addDOMAdapter()
 724                 il.append(DUP);
 725                 il.append(methodGen.loadDOM());
 726                 il.append(new CHECKCAST(cpg.addClass(classGen.getDOMClass())));
 727                 il.append(SWAP);
 728                 index = cpg.addMethodref(MULTI_DOM_CLASS,
 729                                          "addDOMAdapter",
 730                                          "(" + DOM_ADAPTER_SIG + ")I");
 731                 il.append(new INVOKEVIRTUAL(index));
 732                 il.append(POP);         // ignore mask returned by addDOMAdapter
 733             }
 734         }
 735 
 736         // Restore old handler base from stack
 737         il.append(SWAP);
 738         il.append(methodGen.storeHandler());
 739     }
 740 
 741     /**
 742      * Returns true if this expression/instruction depends on the context. By
 743      * default, every expression/instruction depends on the context unless it
 744      * overrides this method. Currently used to determine if result trees are
 745      * compiled using procedures or little DOMs (result tree fragments).
 746      * @return 'true' if this node depends on the context.
 747      */
 748     protected boolean contextDependent() {
 749         return true;
 750     }
 751 
 752     /**
 753      * Return true if any of the expressions/instructions in the contents of
 754      * this node is context dependent.
 755      * @return 'true' if the contents of this node is context dependent.
 756      */
 757     protected boolean dependentContents() {
 758         for (SyntaxTreeNode item : _contents) {
 759             if (item.contextDependent()) {
 760                 return true;
 761             }
 762         }
 763         return false;
 764     }
 765 
 766     /**
 767      * Adds a child node to this syntax tree node.
 768      * @param element is the new child node.
 769      */
 770     protected final void addElement(SyntaxTreeNode element) {
 771         _contents.add(element);
 772         element.setParent(this);
 773     }
 774 
 775     /**
 776      * Inserts the first child node of this syntax tree node. The existing
 777      * children are shifted back one position.
 778      * @param element is the new child node.
 779      */
 780     protected final void setFirstElement(SyntaxTreeNode element) {
 781         _contents.add(0, element);
 782         element.setParent(this);
 783     }
 784 
 785     /**
 786      * Removed a child node of this syntax tree node.
 787      * @param element is the child node to remove.
 788      */
 789     protected final void removeElement(SyntaxTreeNode element) {
 790         _contents.remove(element);
 791         element.setParent(null);
 792     }
 793 
 794     /**
 795      * Returns a List containing all the child nodes of this node.
 796      * @return A List containing all the child nodes of this node.
 797      */
 798     protected final List<SyntaxTreeNode> getContents() {
 799         return _contents;
 800     }
 801 
 802     /**
 803      * Tells you if this node has any child nodes.
 804      * @return 'true' if this node has any children.
 805      */
 806     protected final boolean hasContents() {
 807         return elementCount() > 0;
 808     }
 809 
 810     /**
 811      * Returns the number of children this node has.
 812      * @return Number of child nodes.
 813      */
 814     protected final int elementCount() {
 815         return _contents.size();
 816     }
 817 
 818     /**
 819      * Returns an Iterator of all child nodes of this node.
 820      * @return An Iterator of all child nodes of this node.
 821      */
 822     protected final Iterator<SyntaxTreeNode> elements() {
 823         return _contents.iterator();
 824     }
 825 
 826     /**
 827      * Returns a child node at a given position.
 828      * @param pos The child node's position.
 829      * @return The child node.
 830      */
 831     protected final SyntaxTreeNode elementAt(int pos) {
 832         return _contents.get(pos);
 833     }
 834 
 835     /**
 836      * Returns this element's last child
 837      * @return The child node.
 838      */
 839     protected final SyntaxTreeNode lastChild() {
 840         if (_contents.isEmpty()) return null;
 841         return (SyntaxTreeNode)_contents.get(_contents.size() - 1);
 842     }
 843 
 844     /**
 845      * Displays the contents of this syntax tree node (to stdout).
 846      * This method is intended for debugging _only_, and should be overridden
 847      * by all syntax tree node implementations.
 848      * @param indent Indentation level for syntax tree levels.
 849      */
 850     public void display(int indent) {
 851         displayContents(indent);
 852     }
 853 
 854     /**
 855      * Displays the contents of this syntax tree node (to stdout).
 856      * This method is intended for debugging _only_ !!!
 857      * @param indent Indentation level for syntax tree levels.
 858      */
 859     protected void displayContents(int indent) {
 860         for (SyntaxTreeNode item : _contents) {
 861             item.display(indent);
 862         }
 863     }
 864 
 865     /**
 866      * Set the indentation level for debug output.
 867      * @param indent Indentation level for syntax tree levels.
 868      */
 869     protected final void indent(int indent) {
 870         System.out.print(new String(_spaces, 0, indent));
 871     }
 872 
 873     /**
 874      * Report an error to the parser.
 875      * @param element The element in which the error occured (normally 'this'
 876      * but it could also be an expression/pattern/etc.)
 877      * @param parser The XSLT parser to report the error to.
 878      * @param error The error code (from util/ErrorMsg).
 879      * @param message Any additional error message.
 880      */
 881     protected void reportError(SyntaxTreeNode element, Parser parser,
 882                                String errorCode, String message) {
 883         final ErrorMsg error = new ErrorMsg(errorCode, message, element);
 884         parser.reportError(Constants.ERROR, error);
 885     }
 886 
 887     /**
 888      * Report a recoverable error to the parser.
 889      * @param element The element in which the error occured (normally 'this'
 890      * but it could also be an expression/pattern/etc.)
 891      * @param parser The XSLT parser to report the error to.
 892      * @param error The error code (from util/ErrorMsg).
 893      * @param message Any additional error message.
 894      */
 895     protected  void reportWarning(SyntaxTreeNode element, Parser parser,
 896                                   String errorCode, String message) {
 897         final ErrorMsg error = new ErrorMsg(errorCode, message, element);
 898         parser.reportError(Constants.WARNING, error);
 899     }
 900 
 901 }