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