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 }