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 */ SyntaxTreeNode()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 */ SyntaxTreeNode(int line)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 */ SyntaxTreeNode(String uri, String prefix, String local)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 */ setLineNumber(int line)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 */ getLineNumber()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 */ setQName(QName qname)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 */ setQName(String uri, String prefix, String localname)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 */ getQName()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 */ setAttributes(AttributesImpl attributes)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 */ getAttribute(String qname)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 getAttribute(String prefix, String localName)185 protected String getAttribute(String prefix, String localName) { 186 return getAttribute(prefix + ':' + localName); 187 } 188 hasAttribute(String qname)189 protected boolean hasAttribute(String qname) { 190 return (_attributes != null && _attributes.getValue(qname) != null); 191 } 192 addAttribute(String qname, String value)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 */ getAttributes()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 */ setPrefixMapping(Map<String, String> mapping)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 */ getPrefixMapping()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 */ addPrefixMapping(String prefix, String uri)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 */ lookupNamespace(String prefix)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 */ lookupPrefix(String uri)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 */ setParser(Parser parser)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 */ getParser()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 */ setParent(SyntaxTreeNode parent)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 */ getParent()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 */ isDummy()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 */ getImportPrecedence()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 */ getStylesheet()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 */ getTemplate()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 */ getXSLTC()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 */ getSymbolTable()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 */ parseContents(Parser parser)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 */ parseChildren(Parser parser)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 */ updateScope(Parser parser, SyntaxTreeNode node)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 */ typeCheck(SymbolTable stable)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 */ typeCheckContents(SymbolTable stable)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 */ translate(ClassGenerator classGen, MethodGenerator methodGen)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 */ translateContents(ClassGenerator classGen, MethodGenerator methodGen)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 */ notTypeOf(Class<?> type)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 */ isSimpleRTF(SyntaxTreeNode node)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 */ isAdaptiveRTF(SyntaxTreeNode node)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 */ isTextElement(SyntaxTreeNode node, boolean doExtendedCheck)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 */ compileResultTree(ClassGenerator classGen, MethodGenerator methodGen)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 */ contextDependent()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 */ dependentContents()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 */ addElement(SyntaxTreeNode element)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 */ setFirstElement(SyntaxTreeNode element)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 */ removeElement(SyntaxTreeNode element)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 */ getContents()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 */ hasContents()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 */ elementCount()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 */ elements()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 */ elementAt(int pos)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 */ lastChild()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 */ display(int indent)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 */ displayContents(int indent)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 */ indent(int indent)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 */ reportError(SyntaxTreeNode element, Parser parser, String errorCode, String message)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 */ reportWarning(SyntaxTreeNode element, Parser parser, String errorCode, String message)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 } 921