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