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