aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java')
-rw-r--r--src/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java916
1 files changed, 916 insertions, 0 deletions
diff --git a/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java b/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java
new file mode 100644
index 0000000..092d597
--- /dev/null
+++ b/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java
@@ -0,0 +1,916 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * $Id: SyntaxTreeNode.java,v 1.6 2006/06/06 22:34:33 spericas Exp $
+ */
+
+package com.sun.org.apache.xalan.internal.xsltc.compiler;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
+import com.sun.org.apache.bcel.internal.generic.BasicType;
+import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
+import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
+import com.sun.org.apache.bcel.internal.generic.DUP_X1;
+import com.sun.org.apache.bcel.internal.generic.GETFIELD;
+import com.sun.org.apache.bcel.internal.generic.ICONST;
+import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
+import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
+import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
+import com.sun.org.apache.bcel.internal.generic.InstructionList;
+import com.sun.org.apache.bcel.internal.generic.NEW;
+import com.sun.org.apache.bcel.internal.generic.NEWARRAY;
+import com.sun.org.apache.bcel.internal.generic.PUSH;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
+import com.sun.org.apache.xalan.internal.xsltc.DOM;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+
+
+/**
+ * @author Jacek Ambroziak
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ * @author Morten Jorensen
+ * @author Erwin Bolwidt <ejb@klomp.org>
+ * @author John Howard <JohnH@schemasoft.com>
+ */
+public abstract class SyntaxTreeNode implements Constants {
+
+ // Reference to the AST parser
+ private Parser _parser;
+
+ // AST navigation pointers
+ protected SyntaxTreeNode _parent; // Parent node
+ private Stylesheet _stylesheet; // Stylesheet ancestor node
+ private Template _template; // Template ancestor node
+ private final Vector _contents = new Vector(2); // Child nodes
+
+ // Element description data
+ protected QName _qname; // The element QName
+ private int _line; // Source file line number
+ protected AttributesImpl _attributes = null; // Attributes of this element
+ private Hashtable _prefixMapping = null; // Namespace declarations
+
+ // Sentinel - used to denote unrecognised syntaxt tree nodes.
+ protected static final SyntaxTreeNode Dummy = new AbsolutePathPattern(null);
+
+ // These two are used for indenting nodes in the AST (debug output)
+ protected static final int IndentIncrement = 4;
+ private static final char[] _spaces =
+ " ".toCharArray();
+
+ /**
+ * Creates a new SyntaxTreeNode with a 'null' QName and no source file
+ * line number reference.
+ */
+ public SyntaxTreeNode() {
+ _line = 0;
+ _qname = null;
+ }
+
+ /**
+ * Creates a new SyntaxTreeNode with a 'null' QName.
+ * @param line Source file line number reference
+ */
+ public SyntaxTreeNode(int line) {
+ _line = line;
+ _qname = null;
+ }
+
+ /**
+ * Creates a new SyntaxTreeNode with no source file line number reference.
+ * @param uri The element's namespace URI
+ * @param prefix The element's namespace prefix
+ * @param local The element's local name
+ */
+ public SyntaxTreeNode(String uri, String prefix, String local) {
+ _line = 0;
+ setQName(uri, prefix, local);
+ }
+
+ /**
+ * Set the source file line number for this element
+ * @param line The source file line number.
+ */
+ protected final void setLineNumber(int line) {
+ _line = line;
+ }
+
+ /**
+ * Get the source file line number for this element. If unavailable, lookup
+ * in ancestors.
+ *
+ * @return The source file line number.
+ */
+ public final int getLineNumber() {
+ if (_line > 0) return _line;
+ SyntaxTreeNode parent = getParent();
+ return (parent != null) ? parent.getLineNumber() : 0;
+ }
+
+ /**
+ * Set the QName for the syntax tree node.
+ * @param qname The QName for the syntax tree node
+ */
+ protected void setQName(QName qname) {
+ _qname = qname;
+ }
+
+ /**
+ * Set the QName for the SyntaxTreeNode
+ * @param uri The element's namespace URI
+ * @param prefix The element's namespace prefix
+ * @param local The element's local name
+ */
+ protected void setQName(String uri, String prefix, String localname) {
+ _qname = new QName(uri, prefix, localname);
+ }
+
+ /**
+ * Set the QName for the SyntaxTreeNode
+ * @param qname The QName for the syntax tree node
+ */
+ protected QName getQName() {
+ return(_qname);
+ }
+
+ /**
+ * Set the attributes for this SyntaxTreeNode.
+ * @param attributes Attributes for the element. Must be passed in as an
+ * implementation of org.xml.sax.Attributes.
+ */
+ protected void setAttributes(AttributesImpl attributes) {
+ _attributes = attributes;
+ }
+
+ /**
+ * Returns a value for an attribute from the source element.
+ * @param qname The QName of the attribute to return.
+ * @return The value of the attribute of name 'qname'.
+ */
+ protected String getAttribute(String qname) {
+ if (_attributes == null) {
+ return EMPTYSTRING;
+ }
+ final String value = _attributes.getValue(qname);
+ return (value == null || value.equals(EMPTYSTRING)) ?
+ EMPTYSTRING : value;
+ }
+
+ protected String getAttribute(String prefix, String localName) {
+ return getAttribute(prefix + ':' + localName);
+ }
+
+ protected boolean hasAttribute(String qname) {
+ return (_attributes != null && _attributes.getValue(qname) != null);
+ }
+
+ protected void addAttribute(String qname, String value) {
+ int index = _attributes.getIndex(qname);
+ if (index != -1) {
+ _attributes.setAttribute(index, "", Util.getLocalName(qname),
+ qname, "CDATA", value);
+ }
+ else {
+ _attributes.addAttribute("", Util.getLocalName(qname), qname,
+ "CDATA", value);
+ }
+ }
+
+ /**
+ * Returns a list of all attributes declared for the element represented by
+ * this syntax tree node.
+ * @return Attributes for this syntax tree node
+ */
+ protected Attributes getAttributes() {
+ return(_attributes);
+ }
+
+ /**
+ * Sets the prefix mapping for the namespaces that were declared in this
+ * element. This does not include all prefix mappings in scope, so one
+ * may have to check ancestor elements to get all mappings that are in
+ * in scope. The prefixes must be passed in as a Hashtable that maps
+ * namespace prefixes (String objects) to namespace URIs (also String).
+ * @param mapping The Hashtable containing the mappings.
+ */
+ protected void setPrefixMapping(Hashtable mapping) {
+ _prefixMapping = mapping;
+ }
+
+ /**
+ * Returns a Hashtable containing the prefix mappings that were declared
+ * for this element. This does not include all prefix mappings in scope,
+ * so one may have to check ancestor elements to get all mappings that are
+ * in in scope.
+ * @return Prefix mappings (for this element only).
+ */
+ protected Hashtable getPrefixMapping() {
+ return _prefixMapping;
+ }
+
+ /**
+ * Adds a single prefix mapping to this syntax tree node.
+ * @param prefix Namespace prefix.
+ * @param uri Namespace URI.
+ */
+ protected void addPrefixMapping(String prefix, String uri) {
+ if (_prefixMapping == null)
+ _prefixMapping = new Hashtable();
+ _prefixMapping.put(prefix, uri);
+ }
+
+ /**
+ * Returns any namespace URI that is in scope for a given prefix. This
+ * method checks namespace mappings for this element, and if necessary
+ * for ancestor elements as well (ie. if the prefix maps to an URI in this
+ * scope then you'll definately get the URI from this method).
+ * @param prefix Namespace prefix.
+ * @return Namespace URI.
+ */
+ protected String lookupNamespace(String prefix) {
+ // Initialise the output (default is 'null' for undefined)
+ String uri = null;
+
+ // First look up the prefix/uri mapping in our own hashtable...
+ if (_prefixMapping != null)
+ uri = (String)_prefixMapping.get(prefix);
+ // ... but if we can't find it there we ask our parent for the mapping
+ if ((uri == null) && (_parent != null)) {
+ uri = _parent.lookupNamespace(prefix);
+ if ((prefix == Constants.EMPTYSTRING) && (uri == null))
+ uri = Constants.EMPTYSTRING;
+ }
+ // ... and then we return whatever URI we've got.
+ return(uri);
+ }
+
+ /**
+ * Returns any namespace prefix that is mapped to a prefix in the current
+ * scope. This method checks namespace mappings for this element, and if
+ * necessary for ancestor elements as well (ie. if the URI is declared
+ * within the current scope then you'll definately get the prefix from
+ * this method). Note that this is a very slow method and consequentially
+ * it should only be used strictly when needed.
+ * @param uri Namespace URI.
+ * @return Namespace prefix.
+ */
+ protected String lookupPrefix(String uri) {
+ // Initialise the output (default is 'null' for undefined)
+ String prefix = null;
+
+ // First look up the prefix/uri mapping in our own hashtable...
+ if ((_prefixMapping != null) &&
+ (_prefixMapping.contains(uri))) {
+ Enumeration prefixes = _prefixMapping.keys();
+ while (prefixes.hasMoreElements()) {
+ prefix = (String)prefixes.nextElement();
+ String mapsTo = (String)_prefixMapping.get(prefix);
+ if (mapsTo.equals(uri)) return(prefix);
+ }
+ }
+ // ... but if we can't find it there we ask our parent for the mapping
+ else if (_parent != null) {
+ prefix = _parent.lookupPrefix(uri);
+ if ((uri == Constants.EMPTYSTRING) && (prefix == null))
+ prefix = Constants.EMPTYSTRING;
+ }
+ return(prefix);
+ }
+
+ /**
+ * Set this node's parser. The parser (the XSLT parser) gives this
+ * syntax tree node access to the symbol table and XPath parser.
+ * @param parser The XSLT parser.
+ */
+ protected void setParser(Parser parser) {
+ _parser = parser;
+ }
+
+ /**
+ * Returns this node's XSLT parser.
+ * @return The XSLT parser.
+ */
+ public final Parser getParser() {
+ return _parser;
+ }
+
+ /**
+ * Set this syntax tree node's parent node, if unset. For
+ * re-parenting just use <code>node._parent = newparent</code>.
+ *
+ * @param parent The parent node.
+ */
+ protected void setParent(SyntaxTreeNode parent) {
+ if (_parent == null) _parent = parent;
+ }
+
+ /**
+ * Returns this syntax tree node's parent node.
+ * @return The parent syntax tree node.
+ */
+ protected final SyntaxTreeNode getParent() {
+ return _parent;
+ }
+
+ /**
+ * Returns 'true' if this syntax tree node is the Sentinal node.
+ * @return 'true' if this syntax tree node is the Sentinal node.
+ */
+ protected final boolean isDummy() {
+ return this == Dummy;
+ }
+
+ /**
+ * Get the import precedence of this element. The import precedence equals
+ * the import precedence of the stylesheet in which this element occured.
+ * @return The import precedence of this syntax tree node.
+ */
+ protected int getImportPrecedence() {
+ Stylesheet stylesheet = getStylesheet();
+ if (stylesheet == null) return Integer.MIN_VALUE;
+ return stylesheet.getImportPrecedence();
+ }
+
+ /**
+ * Get the Stylesheet node that represents the <xsl:stylesheet/> element
+ * that this node occured under.
+ * @return The Stylesheet ancestor node of this node.
+ */
+ public Stylesheet getStylesheet() {
+ if (_stylesheet == null) {
+ SyntaxTreeNode parent = this;
+ while (parent != null) {
+ if (parent instanceof Stylesheet)
+ return((Stylesheet)parent);
+ parent = parent.getParent();
+ }
+ _stylesheet = (Stylesheet)parent;
+ }
+ return(_stylesheet);
+ }
+
+ /**
+ * Get the Template node that represents the <xsl:template/> element
+ * that this node occured under. Note that this method will return 'null'
+ * for nodes that represent top-level elements.
+ * @return The Template ancestor node of this node or 'null'.
+ */
+ protected Template getTemplate() {
+ if (_template == null) {
+ SyntaxTreeNode parent = this;
+ while ((parent != null) && (!(parent instanceof Template)))
+ parent = parent.getParent();
+ _template = (Template)parent;
+ }
+ return(_template);
+ }
+
+ /**
+ * Returns a reference to the XSLTC (XSLT compiler) in use.
+ * @return XSLTC - XSLT compiler.
+ */
+ protected final XSLTC getXSLTC() {
+ return _parser.getXSLTC();
+ }
+
+ /**
+ * Returns the XSLT parser's symbol table.
+ * @return Symbol table.
+ */
+ protected final SymbolTable getSymbolTable() {
+ return (_parser == null) ? null : _parser.getSymbolTable();
+ }
+
+ /**
+ * Parse the contents of this syntax tree nodes (child nodes, XPath
+ * expressions, patterns and functions). The default behaviour is to parser
+ * the syntax tree node's children (since there are no common expressions,
+ * patterns, etc. that can be handled in this base class.
+ * @param parser reference to the XSLT parser
+ */
+ public void parseContents(Parser parser) {
+ parseChildren(parser);
+ }
+
+ /**
+ * Parse all children of this syntax tree node. This method is normally
+ * called by the parseContents() method.
+ * @param parser reference to the XSLT parser
+ */
+ protected final void parseChildren(Parser parser) {
+
+ Vector locals = null; // only create when needed
+
+ final int count = _contents.size();
+ for (int i=0; i<count; i++) {
+ SyntaxTreeNode child = (SyntaxTreeNode)_contents.elementAt(i);
+ parser.getSymbolTable().setCurrentNode(child);
+ child.parseContents(parser);
+ // if variable or parameter, add it to scope
+ final QName varOrParamName = updateScope(parser, child);
+ if (varOrParamName != null) {
+ if (locals == null) {
+ locals = new Vector(2);
+ }
+ locals.addElement(varOrParamName);
+ }
+ }
+
+ parser.getSymbolTable().setCurrentNode(this);
+
+ // after the last element, remove any locals from scope
+ if (locals != null) {
+ final int nLocals = locals.size();
+ for (int i = 0; i < nLocals; i++) {
+ parser.removeVariable((QName)locals.elementAt(i));
+ }
+ }
+ }
+
+ /**
+ * Add a node to the current scope and return name of a variable or
+ * parameter if the node represents a variable or a parameter.
+ */
+ protected QName updateScope(Parser parser, SyntaxTreeNode node) {
+ if (node instanceof Variable) {
+ final Variable var = (Variable)node;
+ parser.addVariable(var);
+ return var.getName();
+ }
+ else if (node instanceof Param) {
+ final Param param = (Param)node;
+ parser.addParameter(param);
+ return param.getName();
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * Type check the children of this node. The type check phase may add
+ * coercions (CastExpr) to the AST.
+ * @param stable The compiler/parser's symbol table
+ */
+ public abstract Type typeCheck(SymbolTable stable) throws TypeCheckError;
+
+ /**
+ * Call typeCheck() on all child syntax tree nodes.
+ * @param stable The compiler/parser's symbol table
+ */
+ protected Type typeCheckContents(SymbolTable stable) throws TypeCheckError {
+ final int n = elementCount();
+ for (int i = 0; i < n; i++) {
+ SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i);
+ item.typeCheck(stable);
+ }
+ return Type.Void;
+ }
+
+ /**
+ * Translate this abstract syntax tree node into JVM bytecodes.
+ * @param classGen BCEL Java class generator
+ * @param methodGen BCEL Java method generator
+ */
+ public abstract void translate(ClassGenerator classGen,
+ MethodGenerator methodGen);
+
+ /**
+ * Call translate() on all child syntax tree nodes.
+ * @param classGen BCEL Java class generator
+ * @param methodGen BCEL Java method generator
+ */
+ protected void translateContents(ClassGenerator classGen,
+ MethodGenerator methodGen) {
+ // Call translate() on all child nodes
+ final int n = elementCount();
+ for (int i = 0; i < n; i++) {
+ final SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i);
+ item.translate(classGen, methodGen);
+ }
+
+ // After translation, unmap any registers for any variables/parameters
+ // that were declared in this scope. Performing this unmapping in the
+ // same AST scope as the declaration deals with the problems of
+ // references falling out-of-scope inside the for-each element.
+ // (the cause of which being 'lazy' register allocation for references)
+ for (int i = 0; i < n; i++) {
+ if( _contents.elementAt(i) instanceof VariableBase) {
+ final VariableBase var = (VariableBase)_contents.elementAt(i);
+ var.unmapRegister(methodGen);
+ }
+ }
+ }
+
+ /**
+ * Return true if the node represents a simple RTF.
+ *
+ * A node is a simple RTF if all children only produce Text value.
+ *
+ * @param node A node
+ * @return true if the node content can be considered as a simple RTF.
+ */
+ private boolean isSimpleRTF(SyntaxTreeNode node) {
+
+ Vector contents = node.getContents();
+ for (int i = 0; i < contents.size(); i++) {
+ SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i);
+ if (!isTextElement(item, false))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return true if the node represents an adaptive RTF.
+ *
+ * A node is an adaptive RTF if each children is a Text element
+ * or it is <xsl:call-template> or <xsl:apply-templates>.
+ *
+ * @param node A node
+ * @return true if the node content can be considered as an adaptive RTF.
+ */
+ private boolean isAdaptiveRTF(SyntaxTreeNode node) {
+
+ Vector contents = node.getContents();
+ for (int i = 0; i < contents.size(); i++) {
+ SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i);
+ if (!isTextElement(item, true))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return true if the node only produces Text content.
+ *
+ * A node is a Text element if it is Text, xsl:value-of, xsl:number,
+ * or a combination of these nested in a control instruction (xsl:if or
+ * xsl:choose).
+ *
+ * If the doExtendedCheck flag is true, xsl:call-template and xsl:apply-templates
+ * are also considered as Text elements.
+ *
+ * @param node A node
+ * @param doExtendedCheck If this flag is true, <xsl:call-template> and
+ * <xsl:apply-templates> are also considered as Text elements.
+ *
+ * @return true if the node of Text type
+ */
+ private boolean isTextElement(SyntaxTreeNode node, boolean doExtendedCheck) {
+ if (node instanceof ValueOf || node instanceof Number
+ || node instanceof Text)
+ {
+ return true;
+ }
+ else if (node instanceof If) {
+ return doExtendedCheck ? isAdaptiveRTF(node) : isSimpleRTF(node);
+ }
+ else if (node instanceof Choose) {
+ Vector contents = node.getContents();
+ for (int i = 0; i < contents.size(); i++) {
+ SyntaxTreeNode item = (SyntaxTreeNode)contents.elementAt(i);
+ if (item instanceof Text ||
+ ((item instanceof When || item instanceof Otherwise)
+ && ((doExtendedCheck && isAdaptiveRTF(item))
+ || (!doExtendedCheck && isSimpleRTF(item)))))
+ continue;
+ else
+ return false;
+ }
+ return true;
+ }
+ else if (doExtendedCheck &&
+ (node instanceof CallTemplate
+ || node instanceof ApplyTemplates))
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Utility method used by parameters and variables to store result trees
+ * @param classGen BCEL Java class generator
+ * @param methodGen BCEL Java method generator
+ */
+ protected void compileResultTree(ClassGenerator classGen,
+ MethodGenerator methodGen)
+ {
+ final ConstantPoolGen cpg = classGen.getConstantPool();
+ final InstructionList il = methodGen.getInstructionList();
+ final Stylesheet stylesheet = classGen.getStylesheet();
+
+ boolean isSimple = isSimpleRTF(this);
+ boolean isAdaptive = false;
+ if (!isSimple) {
+ isAdaptive = isAdaptiveRTF(this);
+ }
+
+ int rtfType = isSimple ? DOM.SIMPLE_RTF
+ : (isAdaptive ? DOM.ADAPTIVE_RTF : DOM.TREE_RTF);
+
+ // Save the current handler base on the stack
+ il.append(methodGen.loadHandler());
+
+ final String DOM_CLASS = classGen.getDOMClass();
+
+ // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes)
+ //int index = cpg.addMethodref(DOM_IMPL, "<init>", "(I)V");
+ //il.append(new NEW(cpg.addClass(DOM_IMPL)));
+
+ il.append(methodGen.loadDOM());
+ int index = cpg.addInterfaceMethodref(DOM_INTF,
+ "getResultTreeFrag",
+ "(IIZ)" + DOM_INTF_SIG);
+ il.append(new PUSH(cpg, RTF_INITIAL_SIZE));
+ il.append(new PUSH(cpg, rtfType));
+ il.append(new PUSH(cpg, stylesheet.callsNodeset()));
+ il.append(new INVOKEINTERFACE(index,4));
+
+ il.append(DUP);
+
+ // Overwrite old handler with DOM handler
+ index = cpg.addInterfaceMethodref(DOM_INTF,
+ "getOutputDomBuilder",
+ "()" + TRANSLET_OUTPUT_SIG);
+
+ il.append(new INVOKEINTERFACE(index,1));
+ il.append(DUP);
+ il.append(methodGen.storeHandler());
+
+ // Call startDocument on the new handler
+ il.append(methodGen.startDocument());
+
+ // Instantiate result tree fragment
+ translateContents(classGen, methodGen);
+
+ // Call endDocument on the new handler
+ il.append(methodGen.loadHandler());
+ il.append(methodGen.endDocument());
+
+ // Check if we need to wrap the DOMImpl object in a DOMAdapter object.
+ // DOMAdapter is not needed if the RTF is a simple RTF and the nodeset()
+ // function is not used.
+ if (stylesheet.callsNodeset()
+ && !DOM_CLASS.equals(DOM_IMPL_CLASS)) {
+ // new com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter(DOMImpl,String[]);
+ index = cpg.addMethodref(DOM_ADAPTER_CLASS,
+ "<init>",
+ "("+DOM_INTF_SIG+
+ "["+STRING_SIG+
+ "["+STRING_SIG+
+ "[I"+
+ "["+STRING_SIG+")V");
+ il.append(new NEW(cpg.addClass(DOM_ADAPTER_CLASS)));
+ il.append(new DUP_X1());
+ il.append(SWAP);
+
+ /*
+ * Give the DOM adapter an empty type mapping if the nodeset
+ * extension function is never called.
+ */
+ if (!stylesheet.callsNodeset()) {
+ il.append(new ICONST(0));
+ il.append(new ANEWARRAY(cpg.addClass(STRING)));
+ il.append(DUP);
+ il.append(DUP);
+ il.append(new ICONST(0));
+ il.append(new NEWARRAY(BasicType.INT));
+ il.append(SWAP);
+ il.append(new INVOKESPECIAL(index));
+ }
+ else {
+ // Push name arrays on the stack
+ il.append(ALOAD_0);
+ il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
+ NAMES_INDEX,
+ NAMES_INDEX_SIG)));
+ il.append(ALOAD_0);
+ il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
+ URIS_INDEX,
+ URIS_INDEX_SIG)));
+ il.append(ALOAD_0);
+ il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
+ TYPES_INDEX,
+ TYPES_INDEX_SIG)));
+ il.append(ALOAD_0);
+ il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
+ NAMESPACE_INDEX,
+ NAMESPACE_INDEX_SIG)));
+
+ // Initialized DOM adapter
+ il.append(new INVOKESPECIAL(index));
+
+ // Add DOM adapter to MultiDOM class by calling addDOMAdapter()
+ il.append(DUP);
+ il.append(methodGen.loadDOM());
+ il.append(new CHECKCAST(cpg.addClass(classGen.getDOMClass())));
+ il.append(SWAP);
+ index = cpg.addMethodref(MULTI_DOM_CLASS,
+ "addDOMAdapter",
+ "(" + DOM_ADAPTER_SIG + ")I");
+ il.append(new INVOKEVIRTUAL(index));
+ il.append(POP); // ignore mask returned by addDOMAdapter
+ }
+ }
+
+ // Restore old handler base from stack
+ il.append(SWAP);
+ il.append(methodGen.storeHandler());
+ }
+
+ /**
+ * Returns true if this expression/instruction depends on the context. By
+ * default, every expression/instruction depends on the context unless it
+ * overrides this method. Currently used to determine if result trees are
+ * compiled using procedures or little DOMs (result tree fragments).
+ * @return 'true' if this node depends on the context.
+ */
+ protected boolean contextDependent() {
+ return true;
+ }
+
+ /**
+ * Return true if any of the expressions/instructions in the contents of
+ * this node is context dependent.
+ * @return 'true' if the contents of this node is context dependent.
+ */
+ protected boolean dependentContents() {
+ final int n = elementCount();
+ for (int i = 0; i < n; i++) {
+ final SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i);
+ if (item.contextDependent()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds a child node to this syntax tree node.
+ * @param element is the new child node.
+ */
+ protected final void addElement(SyntaxTreeNode element) {
+ _contents.addElement(element);
+ element.setParent(this);
+ }
+
+ /**
+ * Inserts the first child node of this syntax tree node. The existing
+ * children are shifted back one position.
+ * @param element is the new child node.
+ */
+ protected final void setFirstElement(SyntaxTreeNode element) {
+ _contents.insertElementAt(element,0);
+ element.setParent(this);
+ }
+
+ /**
+ * Removed a child node of this syntax tree node.
+ * @param element is the child node to remove.
+ */
+ protected final void removeElement(SyntaxTreeNode element) {
+ _contents.remove(element);
+ element.setParent(null);
+ }
+
+ /**
+ * Returns a Vector containing all the child nodes of this node.
+ * @return A Vector containing all the child nodes of this node.
+ */
+ protected final Vector getContents() {
+ return _contents;
+ }
+
+ /**
+ * Tells you if this node has any child nodes.
+ * @return 'true' if this node has any children.
+ */
+ protected final boolean hasContents() {
+ return elementCount() > 0;
+ }
+
+ /**
+ * Returns the number of children this node has.
+ * @return Number of child nodes.
+ */
+ protected final int elementCount() {
+ return _contents.size();
+ }
+
+ /**
+ * Returns an Enumeration of all child nodes of this node.
+ * @return An Enumeration of all child nodes of this node.
+ */
+ protected final Enumeration elements() {
+ return _contents.elements();
+ }
+
+ /**
+ * Returns a child node at a given position.
+ * @param pos The child node's position.
+ * @return The child node.
+ */
+ protected final Object elementAt(int pos) {
+ return _contents.elementAt(pos);
+ }
+
+ /**
+ * Returns this element's last child
+ * @return The child node.
+ */
+ protected final SyntaxTreeNode lastChild() {
+ if (_contents.size() == 0) return null;
+ return (SyntaxTreeNode)_contents.lastElement();
+ }
+
+ /**
+ * Displays the contents of this syntax tree node (to stdout).
+ * This method is intended for debugging _only_, and should be overridden
+ * by all syntax tree node implementations.
+ * @param indent Indentation level for syntax tree levels.
+ */
+ public void display(int indent) {
+ displayContents(indent);
+ }
+
+ /**
+ * Displays the contents of this syntax tree node (to stdout).
+ * This method is intended for debugging _only_ !!!
+ * @param indent Indentation level for syntax tree levels.
+ */
+ protected void displayContents(int indent) {
+ final int n = elementCount();
+ for (int i = 0; i < n; i++) {
+ SyntaxTreeNode item = (SyntaxTreeNode)_contents.elementAt(i);
+ item.display(indent);
+ }
+ }
+
+ /**
+ * Set the indentation level for debug output.
+ * @param indent Indentation level for syntax tree levels.
+ */
+ protected final void indent(int indent) {
+ System.out.print(new String(_spaces, 0, indent));
+ }
+
+ /**
+ * Report an error to the parser.
+ * @param element The element in which the error occured (normally 'this'
+ * but it could also be an expression/pattern/etc.)
+ * @param parser The XSLT parser to report the error to.
+ * @param error The error code (from util/ErrorMsg).
+ * @param message Any additional error message.
+ */
+ protected void reportError(SyntaxTreeNode element, Parser parser,
+ String errorCode, String message) {
+ final ErrorMsg error = new ErrorMsg(errorCode, message, element);
+ parser.reportError(Constants.ERROR, error);
+ }
+
+ /**
+ * Report a recoverable error to the parser.
+ * @param element The element in which the error occured (normally 'this'
+ * but it could also be an expression/pattern/etc.)
+ * @param parser The XSLT parser to report the error to.
+ * @param error The error code (from util/ErrorMsg).
+ * @param message Any additional error message.
+ */
+ protected void reportWarning(SyntaxTreeNode element, Parser parser,
+ String errorCode, String message) {
+ final ErrorMsg error = new ErrorMsg(errorCode, message, element);
+ parser.reportError(Constants.WARNING, error);
+ }
+
+}