001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: SyntaxTreeNode.java 1225842 2011-12-30 15:14:35Z mrglavas $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import java.util.Enumeration; 025 import java.util.Hashtable; 026 import java.util.Vector; 027 028 import org.apache.bcel.generic.ANEWARRAY; 029 import org.apache.bcel.generic.BasicType; 030 import org.apache.bcel.generic.CHECKCAST; 031 import org.apache.bcel.generic.ConstantPoolGen; 032 import org.apache.bcel.generic.DUP_X1; 033 import org.apache.bcel.generic.GETFIELD; 034 import org.apache.bcel.generic.ICONST; 035 import org.apache.bcel.generic.INVOKEINTERFACE; 036 import org.apache.bcel.generic.INVOKESPECIAL; 037 import org.apache.bcel.generic.INVOKEVIRTUAL; 038 import org.apache.bcel.generic.InstructionList; 039 import org.apache.bcel.generic.NEW; 040 import org.apache.bcel.generic.NEWARRAY; 041 import org.apache.bcel.generic.PUSH; 042 import org.apache.xalan.xsltc.DOM; 043 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 044 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 045 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 046 import org.apache.xalan.xsltc.compiler.util.Type; 047 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 048 import org.apache.xalan.xsltc.runtime.AttributeList; 049 import org.xml.sax.Attributes; 050 051 052 053 /** 054 * @author Jacek Ambroziak 055 * @author Santiago Pericas-Geertsen 056 * @author G. Todd Miller 057 * @author Morten Jorensen 058 * @author Erwin Bolwidt <ejb@klomp.org> 059 * @author John Howard <JohnH@schemasoft.com> 060 */ 061 public abstract class SyntaxTreeNode implements Constants { 062 063 // Reference to the AST parser 064 private Parser _parser; 065 066 // AST navigation pointers 067 protected SyntaxTreeNode _parent; // Parent node 068 private Stylesheet _stylesheet; // Stylesheet ancestor node 069 private Template _template; // Template ancestor node 070 private final Vector _contents = new Vector(2); // Child nodes 071 072 // Element description data 073 protected QName _qname; // The element QName 074 private int _line; // Source file line number 075 protected AttributeList _attributes = null; // Attributes of this element 076 private Hashtable _prefixMapping = null; // Namespace declarations 077 078 public static final int UNKNOWN_STYLESHEET_NODE_ID = -1; 079 080 // Records whether this node or any descendant needs to know the 081 // in-scope namespaces at transform-time 082 private int _nodeIDForStylesheetNSLookup = UNKNOWN_STYLESHEET_NODE_ID; 083 084 // Sentinel - used to denote unrecognised syntaxt tree nodes. 085 static final SyntaxTreeNode Dummy = new AbsolutePathPattern(null); 086 087 // These two are used for indenting nodes in the AST (debug output) 088 protected static final int IndentIncrement = 4; 089 private static final char[] _spaces = 090 " ".toCharArray(); 091 092 /** 093 * Creates a new SyntaxTreeNode with a 'null' QName and no source file 094 * line number reference. 095 */ 096 public SyntaxTreeNode() { 097 _line = 0; 098 _qname = null; 099 } 100 101 /** 102 * Creates a new SyntaxTreeNode with a 'null' QName. 103 * @param line Source file line number reference 104 */ 105 public SyntaxTreeNode(int line) { 106 _line = line; 107 _qname = null; 108 } 109 110 /** 111 * Creates a new SyntaxTreeNode with no source file line number reference. 112 * @param uri The element's namespace URI 113 * @param prefix The element's namespace prefix 114 * @param local The element's local name 115 */ 116 public SyntaxTreeNode(String uri, String prefix, String local) { 117 _line = 0; 118 setQName(uri, prefix, local); 119 } 120 121 /** 122 * Set the source file line number for this element 123 * @param line The source file line number. 124 */ 125 protected final void setLineNumber(int line) { 126 _line = line; 127 } 128 129 /** 130 * Get the source file line number for this element. If unavailable, lookup 131 * in ancestors. 132 * 133 * @return The source file line number. 134 */ 135 public final int getLineNumber() { 136 if (_line > 0) return _line; 137 SyntaxTreeNode parent = getParent(); 138 return (parent != null) ? parent.getLineNumber() : 0; 139 } 140 141 /** 142 * Set the QName for the syntax tree node. 143 * @param qname The QName for the syntax tree node 144 */ 145 protected void setQName(QName qname) { 146 _qname = qname; 147 } 148 149 /** 150 * Set the QName for the SyntaxTreeNode 151 * @param uri The element's namespace URI 152 * @param prefix The element's namespace prefix 153 * @param local The element's local name 154 */ 155 protected void setQName(String uri, String prefix, String localname) { 156 _qname = new QName(uri, prefix, localname); 157 } 158 159 /** 160 * Set the QName for the SyntaxTreeNode 161 * @param qname The QName for the syntax tree node 162 */ 163 protected QName getQName() { 164 return(_qname); 165 } 166 167 /** 168 * Set the attributes for this SyntaxTreeNode. 169 * @param attributes Attributes for the element. Must be passed in as an 170 * implementation of org.xml.sax.Attributes. 171 */ 172 protected void setAttributes(AttributeList attributes) { 173 _attributes = attributes; 174 } 175 176 /** 177 * Returns a value for an attribute from the source element. 178 * @param qname The QName of the attribute to return. 179 * @return The value of the attribute of name 'qname'. 180 */ 181 protected String getAttribute(String qname) { 182 if (_attributes == null) { 183 return EMPTYSTRING; 184 } 185 final String value = _attributes.getValue(qname); 186 return (value == null || value.equals(EMPTYSTRING)) ? 187 EMPTYSTRING : value; 188 } 189 190 protected String getAttribute(String prefix, String localName) { 191 return getAttribute(prefix + ':' + localName); 192 } 193 194 protected boolean hasAttribute(String qname) { 195 return (_attributes != null && _attributes.getValue(qname) != null); 196 } 197 198 protected void addAttribute(String qname, String value) { 199 _attributes.add(qname, value); 200 } 201 202 /** 203 * Returns a list of all attributes declared for the element represented by 204 * this syntax tree node. 205 * @return Attributes for this syntax tree node 206 */ 207 protected Attributes getAttributes() { 208 return(_attributes); 209 } 210 211 /** 212 * Sets the prefix mapping for the namespaces that were declared in this 213 * element. This does not include all prefix mappings in scope, so one 214 * may have to check ancestor elements to get all mappings that are in 215 * in scope. The prefixes must be passed in as a Hashtable that maps 216 * namespace prefixes (String objects) to namespace URIs (also String). 217 * @param mapping The Hashtable containing the mappings. 218 */ 219 protected void setPrefixMapping(Hashtable mapping) { 220 _prefixMapping = mapping; 221 } 222 223 /** 224 * Returns a Hashtable containing the prefix mappings that were declared 225 * for this element. This does not include all prefix mappings in scope, 226 * so one may have to check ancestor elements to get all mappings that are 227 * in in scope. 228 * @return Prefix mappings (for this element only). 229 */ 230 protected Hashtable getPrefixMapping() { 231 return _prefixMapping; 232 } 233 234 /** 235 * Adds a single prefix mapping to this syntax tree node. 236 * @param prefix Namespace prefix. 237 * @param uri Namespace URI. 238 */ 239 protected void addPrefixMapping(String prefix, String uri) { 240 if (_prefixMapping == null) 241 _prefixMapping = new Hashtable(); 242 _prefixMapping.put(prefix, uri); 243 } 244 245 /** 246 * Returns any namespace URI that is in scope for a given prefix. This 247 * method checks namespace mappings for this element, and if necessary 248 * for ancestor elements as well (ie. if the prefix maps to an URI in this 249 * scope then you'll definately get the URI from this method). 250 * @param prefix Namespace prefix. 251 * @return Namespace URI. 252 */ 253 protected String lookupNamespace(String prefix) { 254 // Initialise the output (default is 'null' for undefined) 255 String uri = null; 256 257 // First look up the prefix/uri mapping in our own hashtable... 258 if (_prefixMapping != null) 259 uri = (String)_prefixMapping.get(prefix); 260 // ... but if we can't find it there we ask our parent for the mapping 261 if ((uri == null) && (_parent != null)) { 262 uri = _parent.lookupNamespace(prefix); 263 if ((prefix == Constants.EMPTYSTRING) && (uri == null)) 264 uri = Constants.EMPTYSTRING; 265 } 266 // ... and then we return whatever URI we've got. 267 return(uri); 268 } 269 270 /** 271 * Returns any namespace prefix that is mapped to a prefix in the current 272 * scope. This method checks namespace mappings for this element, and if 273 * necessary for ancestor elements as well (ie. if the URI is declared 274 * within the current scope then you'll definately get the prefix from 275 * this method). Note that this is a very slow method and consequentially 276 * it should only be used strictly when needed. 277 * @param uri Namespace URI. 278 * @return Namespace prefix. 279 */ 280 protected String lookupPrefix(String uri) { 281 // Initialise the output (default is 'null' for undefined) 282 String prefix = null; 283 284 // First look up the prefix/uri mapping in our own hashtable... 285 if ((_prefixMapping != null) && 286 (_prefixMapping.contains(uri))) { 287 Enumeration prefixes = _prefixMapping.keys(); 288 while (prefixes.hasMoreElements()) { 289 prefix = (String)prefixes.nextElement(); 290 String mapsTo = (String)_prefixMapping.get(prefix); 291 if (mapsTo.equals(uri)) return(prefix); 292 } 293 } 294 // ... but if we can't find it there we ask our parent for the mapping 295 else if (_parent != null) { 296 prefix = _parent.lookupPrefix(uri); 297 if ((uri == Constants.EMPTYSTRING) && (prefix == null)) 298 prefix = Constants.EMPTYSTRING; 299 } 300 return(prefix); 301 } 302 303 /** 304 * Set this node's parser. The parser (the XSLT parser) gives this 305 * syntax tree node access to the symbol table and XPath parser. 306 * @param parser The XSLT parser. 307 */ 308 protected void setParser(Parser parser) { 309 _parser = parser; 310 } 311 312 /** 313 * Returns this node's XSLT parser. 314 * @return The XSLT parser. 315 */ 316 public final Parser getParser() { 317 return _parser; 318 } 319 320 /** 321 * Set this syntax tree node's parent node 322 * @param parent The parent node. 323 */ 324 protected void setParent(SyntaxTreeNode parent) { 325 if (_parent == null) 326 _parent = parent; 327 } 328 329 /** 330 * Returns this syntax tree node's parent node. 331 * @return The parent syntax tree node. 332 */ 333 protected final SyntaxTreeNode getParent() { 334 return _parent; 335 } 336 337 /** 338 * Returns 'true' if this syntax tree node is the Sentinal node. 339 * @return 'true' if this syntax tree node is the Sentinal node. 340 */ 341 protected final boolean isDummy() { 342 return this == Dummy; 343 } 344 345 /** 346 * Get the import precedence of this element. The import precedence equals 347 * the import precedence of the stylesheet in which this element occured. 348 * @return The import precedence of this syntax tree node. 349 */ 350 protected int getImportPrecedence() { 351 Stylesheet stylesheet = getStylesheet(); 352 if (stylesheet == null) return Integer.MIN_VALUE; 353 return stylesheet.getImportPrecedence(); 354 } 355 356 /** 357 * Get the Stylesheet node that represents the <xsl:stylesheet/> element 358 * that this node occured under. 359 * @return The Stylesheet ancestor node of this node. 360 */ 361 public Stylesheet getStylesheet() { 362 if (_stylesheet == null) { 363 SyntaxTreeNode parent = this; 364 while (parent != null) { 365 if (parent instanceof Stylesheet) 366 return((Stylesheet)parent); 367 parent = parent.getParent(); 368 } 369 _stylesheet = (Stylesheet)parent; 370 } 371 return(_stylesheet); 372 } 373 374 /** 375 * Get the Template node that represents the <xsl:template/> element 376 * that this node occured under. Note that this method will return 'null' 377 * for nodes that represent top-level elements. 378 * @return The Template ancestor node of this node or 'null'. 379 */ 380 protected Template getTemplate() { 381 if (_template == null) { 382 SyntaxTreeNode parent = this; 383 while ((parent != null) && (!(parent instanceof Template))) 384 parent = parent.getParent(); 385 _template = (Template)parent; 386 } 387 return(_template); 388 } 389 390 /** 391 * Returns a reference to the XSLTC (XSLT compiler) in use. 392 * @return XSLTC - XSLT compiler. 393 */ 394 protected final XSLTC getXSLTC() { 395 return _parser.getXSLTC(); 396 } 397 398 /** 399 * Returns the XSLT parser's symbol table. 400 * @return Symbol table. 401 */ 402 protected final SymbolTable getSymbolTable() { 403 return (_parser == null) ? null : _parser.getSymbolTable(); 404 } 405 406 /** 407 * Parse the contents of this syntax tree nodes (child nodes, XPath 408 * expressions, patterns and functions). The default behaviour is to parser 409 * the syntax tree node's children (since there are no common expressions, 410 * patterns, etc. that can be handled in this base class. 411 * @param parser reference to the XSLT parser 412 */ 413 public void parseContents(Parser parser) { 414 parseChildren(parser); 415 } 416 417 /** 418 * Parse all children of this syntax tree node. This method is normally 419 * called by the parseContents() method. 420 * @param parser reference to the XSLT parser 421 */ 422 protected final void parseChildren(Parser parser) { 423 424 Vector locals = null; // only create when needed 425 426 final int count = _contents.size(); 427 for (int i=0; i<count; i++) { 428 SyntaxTreeNode child = (SyntaxTreeNode)_contents.elementAt(i); 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 Vector(2); 436 } 437 locals.addElement(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 final int nLocals = locals.size(); 446 for (int i = 0; i < nLocals; i++) { 447 parser.removeVariable((QName)locals.elementAt(i)); 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 final int n = elementCount(); 485 for (int i = 0; i < n; i++) { 486 SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i); 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 (int i = 0; i < n; i++) { 511 methodGen.markChunkStart(); 512 final SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i); 513 item.translate(classGen, methodGen); 514 methodGen.markChunkEnd(); 515 } 516 517 // After translation, unmap any registers for any variables/parameters 518 // that were declared in this scope. Performing this unmapping in the 519 // same AST scope as the declaration deals with the problems of 520 // references falling out-of-scope inside the for-each element. 521 // (the cause of which being 'lazy' register allocation for references) 522 for (int i = 0; i < n; i++) { 523 if( _contents.elementAt(i) instanceof VariableBase) { 524 final VariableBase var = (VariableBase)_contents.elementAt(i); 525 var.unmapRegister(methodGen); 526 } 527 } 528 } 529 530 /** 531 * Return true if the node represents a simple RTF. 532 * 533 * A node is a simple RTF if all children only produce Text value. 534 * 535 * @param node A node 536 * @return true if the node content can be considered as a simple RTF. 537 */ 538 private boolean isSimpleRTF(SyntaxTreeNode node) { 539 540 Vector contents = node.getContents(); 541 for (int i = 0; i < contents.size(); i++) { 542 SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i); 543 if (!isTextElement(item, false)) 544 return false; 545 } 546 547 return true; 548 } 549 550 /** 551 * Return true if the node represents an adaptive RTF. 552 * 553 * A node is an adaptive RTF if each children is a Text element 554 * or it is <xsl:call-template> or <xsl:apply-templates>. 555 * 556 * @param node A node 557 * @return true if the node content can be considered as an adaptive RTF. 558 */ 559 private boolean isAdaptiveRTF(SyntaxTreeNode node) { 560 561 Vector contents = node.getContents(); 562 for (int i = 0; i < contents.size(); i++) { 563 SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i); 564 if (!isTextElement(item, true)) 565 return false; 566 } 567 568 return true; 569 } 570 571 /** 572 * Return true if the node only produces Text content. 573 * 574 * A node is a Text element if it is Text, xsl:value-of, xsl:number, 575 * or a combination of these nested in a control instruction (xsl:if or 576 * xsl:choose). 577 * 578 * If the doExtendedCheck flag is true, xsl:call-template and xsl:apply-templates 579 * are also considered as Text elements. 580 * 581 * @param node A node 582 * @param doExtendedCheck If this flag is true, <xsl:call-template> and 583 * <xsl:apply-templates> are also considered as Text elements. 584 * 585 * @return true if the node of Text type 586 */ 587 private boolean isTextElement(SyntaxTreeNode node, boolean doExtendedCheck) { 588 if (node instanceof ValueOf || node instanceof Number 589 || node instanceof Text) 590 { 591 return true; 592 } 593 else if (node instanceof If) { 594 return doExtendedCheck ? isAdaptiveRTF(node) : isSimpleRTF(node); 595 } 596 else if (node instanceof Choose) { 597 Vector contents = node.getContents(); 598 for (int i = 0; i < contents.size(); i++) { 599 SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i); 600 if (item instanceof Text || 601 ((item instanceof When || item instanceof Otherwise) 602 && ((doExtendedCheck && isAdaptiveRTF(item)) 603 || (!doExtendedCheck && isSimpleRTF(item))))) 604 continue; 605 else 606 return false; 607 } 608 return true; 609 } 610 else if (doExtendedCheck && 611 (node instanceof CallTemplate 612 || node instanceof ApplyTemplates)) 613 return true; 614 else 615 return false; 616 } 617 618 /** 619 * Utility method used by parameters and variables to store result trees 620 * @param classGen BCEL Java class generator 621 * @param methodGen BCEL Java method generator 622 */ 623 protected void compileResultTree(ClassGenerator classGen, 624 MethodGenerator methodGen) 625 { 626 final ConstantPoolGen cpg = classGen.getConstantPool(); 627 final InstructionList il = methodGen.getInstructionList(); 628 final Stylesheet stylesheet = classGen.getStylesheet(); 629 630 boolean isSimple = isSimpleRTF(this); 631 boolean isAdaptive = false; 632 if (!isSimple) { 633 isAdaptive = isAdaptiveRTF(this); 634 } 635 636 int rtfType = isSimple ? DOM.SIMPLE_RTF 637 : (isAdaptive ? DOM.ADAPTIVE_RTF : DOM.TREE_RTF); 638 639 // Save the current handler base on the stack 640 il.append(methodGen.loadHandler()); 641 642 final String DOM_CLASS = classGen.getDOMClass(); 643 644 // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes) 645 //int index = cpg.addMethodref(DOM_IMPL, "<init>", "(I)V"); 646 //il.append(new NEW(cpg.addClass(DOM_IMPL))); 647 648 il.append(methodGen.loadDOM()); 649 int index = cpg.addInterfaceMethodref(DOM_INTF, 650 "getResultTreeFrag", 651 "(IIZ)" + DOM_INTF_SIG); 652 il.append(new PUSH(cpg, RTF_INITIAL_SIZE)); 653 il.append(new PUSH(cpg, rtfType)); 654 il.append(new PUSH(cpg, stylesheet.callsNodeset())); 655 il.append(new INVOKEINTERFACE(index,4)); 656 657 il.append(DUP); 658 659 // Overwrite old handler with DOM handler 660 index = cpg.addInterfaceMethodref(DOM_INTF, 661 "getOutputDomBuilder", 662 "()" + TRANSLET_OUTPUT_SIG); 663 664 il.append(new INVOKEINTERFACE(index,1)); 665 il.append(DUP); 666 il.append(methodGen.storeHandler()); 667 668 // Call startDocument on the new handler 669 il.append(methodGen.startDocument()); 670 671 // Instantiate result tree fragment 672 translateContents(classGen, methodGen); 673 674 // Call endDocument on the new handler 675 il.append(methodGen.loadHandler()); 676 il.append(methodGen.endDocument()); 677 678 // Check if we need to wrap the DOMImpl object in a DOMAdapter object. 679 // DOMAdapter is not needed if the RTF is a simple RTF and the nodeset() 680 // function is not used. 681 if (stylesheet.callsNodeset() 682 && !DOM_CLASS.equals(DOM_IMPL_CLASS)) { 683 // new org.apache.xalan.xsltc.dom.DOMAdapter(DOMImpl,String[]); 684 index = cpg.addMethodref(DOM_ADAPTER_CLASS, 685 "<init>", 686 "("+DOM_INTF_SIG+ 687 "["+STRING_SIG+ 688 "["+STRING_SIG+ 689 "[I"+ 690 "["+STRING_SIG+")V"); 691 il.append(new NEW(cpg.addClass(DOM_ADAPTER_CLASS))); 692 il.append(new DUP_X1()); 693 il.append(SWAP); 694 695 /* 696 * Give the DOM adapter an empty type mapping if the nodeset 697 * extension function is never called. 698 */ 699 if (!stylesheet.callsNodeset()) { 700 il.append(new ICONST(0)); 701 il.append(new ANEWARRAY(cpg.addClass(STRING))); 702 il.append(DUP); 703 il.append(DUP); 704 il.append(new ICONST(0)); 705 il.append(new NEWARRAY(BasicType.INT)); 706 il.append(SWAP); 707 il.append(new INVOKESPECIAL(index)); 708 } 709 else { 710 // Push name arrays on the stack 711 il.append(ALOAD_0); 712 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 713 NAMES_INDEX, 714 NAMES_INDEX_SIG))); 715 il.append(ALOAD_0); 716 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 717 URIS_INDEX, 718 URIS_INDEX_SIG))); 719 il.append(ALOAD_0); 720 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 721 TYPES_INDEX, 722 TYPES_INDEX_SIG))); 723 il.append(ALOAD_0); 724 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 725 NAMESPACE_INDEX, 726 NAMESPACE_INDEX_SIG))); 727 728 // Initialized DOM adapter 729 il.append(new INVOKESPECIAL(index)); 730 731 // Add DOM adapter to MultiDOM class by calling addDOMAdapter() 732 il.append(DUP); 733 il.append(methodGen.loadDOM()); 734 il.append(new CHECKCAST(cpg.addClass(classGen.getDOMClass()))); 735 il.append(SWAP); 736 index = cpg.addMethodref(MULTI_DOM_CLASS, 737 "addDOMAdapter", 738 "(" + DOM_ADAPTER_SIG + ")I"); 739 il.append(new INVOKEVIRTUAL(index)); 740 il.append(POP); // ignore mask returned by addDOMAdapter 741 } 742 } 743 744 // Restore old handler base from stack 745 il.append(SWAP); 746 il.append(methodGen.storeHandler()); 747 } 748 749 /** 750 * Retrieve an ID to identify the namespaces in scope at this point in the 751 * stylesheet 752 * @return An <code>int</code> representing the node ID or <code>-1</code> 753 * if no namespace declarations are in scope 754 */ 755 protected final int getNodeIDForStylesheetNSLookup() { 756 if (_nodeIDForStylesheetNSLookup == UNKNOWN_STYLESHEET_NODE_ID) { 757 Hashtable prefixMapping = getPrefixMapping(); 758 int parentNodeID = 759 (_parent != null) ? _parent.getNodeIDForStylesheetNSLookup() 760 : UNKNOWN_STYLESHEET_NODE_ID; 761 762 // If this node in the stylesheet has no namespace declarations of 763 // its own, use the ID of the nearest ancestor element that does 764 // have namespace declarations. 765 if (prefixMapping == null) { 766 _nodeIDForStylesheetNSLookup = parentNodeID; 767 } else { 768 // Inform the XSLTC object that we'll need to know about this 769 // node's namespace declarations. 770 _nodeIDForStylesheetNSLookup = 771 getXSLTC().registerStylesheetPrefixMappingForRuntime( 772 prefixMapping, parentNodeID); 773 } 774 } 775 776 return _nodeIDForStylesheetNSLookup; 777 } 778 /** 779 * Returns true if this expression/instruction depends on the context. By 780 * default, every expression/instruction depends on the context unless it 781 * overrides this method. Currently used to determine if result trees are 782 * compiled using procedures or little DOMs (result tree fragments). 783 * @return 'true' if this node depends on the context. 784 */ 785 protected boolean contextDependent() { 786 return true; 787 } 788 789 /** 790 * Return true if any of the expressions/instructions in the contents of 791 * this node is context dependent. 792 * @return 'true' if the contents of this node is context dependent. 793 */ 794 protected boolean dependentContents() { 795 final int n = elementCount(); 796 for (int i = 0; i < n; i++) { 797 final SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i); 798 if (item.contextDependent()) { 799 return true; 800 } 801 } 802 return false; 803 } 804 805 /** 806 * Adds a child node to this syntax tree node. 807 * @param element is the new child node. 808 */ 809 protected final void addElement(SyntaxTreeNode element) { 810 _contents.addElement(element); 811 element.setParent(this); 812 } 813 814 /** 815 * Inserts the first child node of this syntax tree node. The existing 816 * children are shifted back one position. 817 * @param element is the new child node. 818 */ 819 protected final void setFirstElement(SyntaxTreeNode element) { 820 _contents.insertElementAt(element,0); 821 element.setParent(this); 822 } 823 824 /** 825 * Removed a child node of this syntax tree node. 826 * @param element is the child node to remove. 827 */ 828 protected final void removeElement(SyntaxTreeNode element) { 829 _contents.remove(element); 830 element.setParent(null); 831 } 832 833 /** 834 * Returns a Vector containing all the child nodes of this node. 835 * @return A Vector containing all the child nodes of this node. 836 */ 837 protected final Vector getContents() { 838 return _contents; 839 } 840 841 /** 842 * Tells you if this node has any child nodes. 843 * @return 'true' if this node has any children. 844 */ 845 protected final boolean hasContents() { 846 return elementCount() > 0; 847 } 848 849 /** 850 * Returns the number of children this node has. 851 * @return Number of child nodes. 852 */ 853 protected final int elementCount() { 854 return _contents.size(); 855 } 856 857 /** 858 * Returns an Enumeration of all child nodes of this node. 859 * @return An Enumeration of all child nodes of this node. 860 */ 861 protected final Enumeration elements() { 862 return _contents.elements(); 863 } 864 865 /** 866 * Returns a child node at a given position. 867 * @param pos The child node's position. 868 * @return The child node. 869 */ 870 protected final Object elementAt(int pos) { 871 return _contents.elementAt(pos); 872 } 873 874 /** 875 * Returns this element's last child 876 * @return The child node. 877 */ 878 protected final SyntaxTreeNode lastChild() { 879 if (_contents.size() == 0) return null; 880 return (SyntaxTreeNode)_contents.lastElement(); 881 } 882 883 /** 884 * Displays the contents of this syntax tree node (to stdout). 885 * This method is intended for debugging _only_, and should be overridden 886 * by all syntax tree node implementations. 887 * @param indent Indentation level for syntax tree levels. 888 */ 889 public void display(int indent) { 890 displayContents(indent); 891 } 892 893 /** 894 * Displays the contents of this syntax tree node (to stdout). 895 * This method is intended for debugging _only_ !!! 896 * @param indent Indentation level for syntax tree levels. 897 */ 898 protected void displayContents(int indent) { 899 final int n = elementCount(); 900 for (int i = 0; i < n; i++) { 901 SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i); 902 item.display(indent); 903 } 904 } 905 906 /** 907 * Set the indentation level for debug output. 908 * @param indent Indentation level for syntax tree levels. 909 */ 910 protected final void indent(int indent) { 911 System.out.print(new String(_spaces, 0, indent)); 912 } 913 914 /** 915 * Report an error to the parser. 916 * @param element The element in which the error occured (normally 'this' 917 * but it could also be an expression/pattern/etc.) 918 * @param parser The XSLT parser to report the error to. 919 * @param error The error code (from util/ErrorMsg). 920 * @param message Any additional error message. 921 */ 922 protected void reportError(SyntaxTreeNode element, Parser parser, 923 String errorCode, String message) { 924 final ErrorMsg error = new ErrorMsg(errorCode, message, element); 925 parser.reportError(Constants.ERROR, error); 926 } 927 928 /** 929 * Report a recoverable error to the parser. 930 * @param element The element in which the error occured (normally 'this' 931 * but it could also be an expression/pattern/etc.) 932 * @param parser The XSLT parser to report the error to. 933 * @param error The error code (from util/ErrorMsg). 934 * @param message Any additional error message. 935 */ 936 protected void reportWarning(SyntaxTreeNode element, Parser parser, 937 String errorCode, String message) { 938 final ErrorMsg error = new ErrorMsg(errorCode, message, element); 939 parser.reportError(Constants.WARNING, error); 940 } 941 942 }