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 }