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      * 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 }