286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2004 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: Stylesheet.java,v 1.5 2005/09/28 13:48:16 pvedula Exp $
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xalan.internal.xsltc.compiler;
286N/A
286N/Aimport java.util.Vector;
286N/Aimport java.util.Enumeration;
286N/Aimport java.util.Hashtable;
286N/Aimport java.util.Iterator;
286N/Aimport java.util.Properties;
286N/Aimport java.util.StringTokenizer;
286N/A
286N/Aimport com.sun.org.apache.xml.internal.utils.SystemIDResolver;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
286N/Aimport com.sun.org.apache.bcel.internal.generic.BasicType;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
286N/Aimport com.sun.org.apache.bcel.internal.generic.FieldGen;
286N/Aimport com.sun.org.apache.bcel.internal.generic.GETFIELD;
286N/Aimport com.sun.org.apache.bcel.internal.generic.GETSTATIC;
286N/Aimport com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
286N/Aimport com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
286N/Aimport com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ISTORE;
286N/Aimport com.sun.org.apache.bcel.internal.generic.InstructionHandle;
286N/Aimport com.sun.org.apache.bcel.internal.generic.InstructionList;
286N/Aimport com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
286N/Aimport com.sun.org.apache.bcel.internal.generic.NEW;
286N/Aimport com.sun.org.apache.bcel.internal.generic.NEWARRAY;
286N/Aimport com.sun.org.apache.bcel.internal.generic.PUSH;
286N/Aimport com.sun.org.apache.bcel.internal.generic.PUTFIELD;
286N/Aimport com.sun.org.apache.bcel.internal.generic.PUTSTATIC;
286N/Aimport com.sun.org.apache.bcel.internal.generic.TargetLostException;
286N/Aimport com.sun.org.apache.bcel.internal.util.InstructionFinder;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
286N/Aimport com.sun.org.apache.xml.internal.dtm.DTM;
286N/A
286N/A/**
286N/A * @author Jacek Ambroziak
286N/A * @author Santiago Pericas-Geertsen
286N/A * @author Morten Jorgensen
286N/A */
286N/Apublic final class Stylesheet extends SyntaxTreeNode {
286N/A
286N/A /**
286N/A * XSLT version defined in the stylesheet.
286N/A */
286N/A private String _version;
286N/A
286N/A /**
286N/A * Internal name of this stylesheet used as a key into the symbol table.
286N/A */
286N/A private QName _name;
286N/A
286N/A /**
286N/A * A URI that represents the system ID for this stylesheet.
286N/A */
286N/A private String _systemId;
286N/A
286N/A /**
286N/A * A reference to the parent stylesheet or null if topmost.
286N/A */
286N/A private Stylesheet _parentStylesheet;
286N/A
286N/A /**
286N/A * Contains global variables and parameters defined in the stylesheet.
286N/A */
286N/A private Vector _globals = new Vector();
286N/A
286N/A /**
286N/A * Used to cache the result returned by <code>hasLocalParams()</code>.
286N/A */
286N/A private Boolean _hasLocalParams = null;
286N/A
286N/A /**
286N/A * The name of the class being generated.
286N/A */
286N/A private String _className;
286N/A
286N/A /**
286N/A * Contains all templates defined in this stylesheet
286N/A */
286N/A private final Vector _templates = new Vector();
286N/A
286N/A /**
286N/A * Used to cache result of <code>getAllValidTemplates()</code>. Only
286N/A * set in top-level stylesheets that include/import other stylesheets.
286N/A */
286N/A private Vector _allValidTemplates = null;
286N/A
286N/A /**
286N/A * Counter to generate unique mode suffixes.
286N/A */
286N/A private int _nextModeSerial = 1;
286N/A
286N/A /**
286N/A * Mapping between mode names and Mode instances.
286N/A */
286N/A private final Hashtable _modes = new Hashtable();
286N/A
286N/A /**
286N/A * A reference to the default Mode object.
286N/A */
286N/A private Mode _defaultMode;
286N/A
286N/A /**
286N/A * Mapping between extension URIs and their prefixes.
286N/A */
286N/A private final Hashtable _extensions = new Hashtable();
286N/A
286N/A /**
286N/A * Reference to the stylesheet from which this stylesheet was
286N/A * imported (if any).
286N/A */
286N/A public Stylesheet _importedFrom = null;
286N/A
286N/A /**
286N/A * Reference to the stylesheet from which this stylesheet was
286N/A * included (if any).
286N/A */
286N/A public Stylesheet _includedFrom = null;
286N/A
286N/A /**
286N/A * Array of all the stylesheets imported or included from this one.
286N/A */
286N/A private Vector _includedStylesheets = null;
286N/A
286N/A /**
286N/A * Import precendence for this stylesheet.
286N/A */
286N/A private int _importPrecedence = 1;
286N/A
286N/A /**
286N/A * Minimum precendence of any descendant stylesheet by inclusion or
286N/A * importation.
286N/A */
286N/A private int _minimumDescendantPrecedence = -1;
286N/A
286N/A /**
286N/A * Mapping between key names and Key objects (needed by Key/IdPattern).
286N/A */
286N/A private Hashtable _keys = new Hashtable();
286N/A
286N/A /**
286N/A * A reference to the SourceLoader set by the user (a URIResolver
286N/A * if the JAXP API is being used).
286N/A */
286N/A private SourceLoader _loader = null;
286N/A
286N/A /**
286N/A * Flag indicating if format-number() is called.
286N/A */
286N/A private boolean _numberFormattingUsed = false;
286N/A
286N/A /**
286N/A * Flag indicating if this is a simplified stylesheets. A template
286N/A * matching on "/" must be added in this case.
286N/A */
286N/A private boolean _simplified = false;
286N/A
286N/A /**
286N/A * Flag indicating if multi-document support is needed.
286N/A */
286N/A private boolean _multiDocument = false;
286N/A
286N/A /**
286N/A * Flag indicating if nodset() is called.
286N/A */
286N/A private boolean _callsNodeset = false;
286N/A
286N/A /**
286N/A * Flag indicating if id() is called.
286N/A */
286N/A private boolean _hasIdCall = false;
286N/A
286N/A /**
286N/A * Set to true to enable template inlining optimization.
286N/A * @see XSLTC#_templateInlining
286N/A */
286N/A private boolean _templateInlining = false;
286N/A
286N/A /**
286N/A * A reference to the last xsl:output object found in the styleshet.
286N/A */
286N/A private Output _lastOutputElement = null;
286N/A
286N/A /**
286N/A * Output properties for this stylesheet.
286N/A */
286N/A private Properties _outputProperties = null;
286N/A
286N/A /**
286N/A * Output method for this stylesheet (must be set to one of
286N/A * the constants defined below).
286N/A */
286N/A private int _outputMethod = UNKNOWN_OUTPUT;
286N/A
286N/A // Output method constants
286N/A public static final int UNKNOWN_OUTPUT = 0;
286N/A public static final int XML_OUTPUT = 1;
286N/A public static final int HTML_OUTPUT = 2;
286N/A public static final int TEXT_OUTPUT = 3;
286N/A
286N/A /**
286N/A * Return the output method
286N/A */
286N/A public int getOutputMethod() {
286N/A return _outputMethod;
286N/A }
286N/A
286N/A /**
286N/A * Check and set the output method
286N/A */
286N/A private void checkOutputMethod() {
286N/A if (_lastOutputElement != null) {
286N/A String method = _lastOutputElement.getOutputMethod();
286N/A if (method != null) {
286N/A if (method.equals("xml"))
286N/A _outputMethod = XML_OUTPUT;
286N/A else if (method.equals("html"))
286N/A _outputMethod = HTML_OUTPUT;
286N/A else if (method.equals("text"))
286N/A _outputMethod = TEXT_OUTPUT;
286N/A }
286N/A }
286N/A }
286N/A
286N/A public boolean getTemplateInlining() {
286N/A return _templateInlining;
286N/A }
286N/A
286N/A public void setTemplateInlining(boolean flag) {
286N/A _templateInlining = flag;
286N/A }
286N/A
286N/A public boolean isSimplified() {
286N/A return(_simplified);
286N/A }
286N/A
286N/A public void setSimplified() {
286N/A _simplified = true;
286N/A }
286N/A
286N/A public void setHasIdCall(boolean flag) {
286N/A _hasIdCall = flag;
286N/A }
286N/A
286N/A public void setOutputProperty(String key, String value) {
286N/A if (_outputProperties == null) {
286N/A _outputProperties = new Properties();
286N/A }
286N/A _outputProperties.setProperty(key, value);
286N/A }
286N/A
286N/A public void setOutputProperties(Properties props) {
286N/A _outputProperties = props;
286N/A }
286N/A
286N/A public Properties getOutputProperties() {
286N/A return _outputProperties;
286N/A }
286N/A
286N/A public Output getLastOutputElement() {
286N/A return _lastOutputElement;
286N/A }
286N/A
286N/A public void setMultiDocument(boolean flag) {
286N/A _multiDocument = flag;
286N/A }
286N/A
286N/A public boolean isMultiDocument() {
286N/A return _multiDocument;
286N/A }
286N/A
286N/A public void setCallsNodeset(boolean flag) {
286N/A if (flag) setMultiDocument(flag);
286N/A _callsNodeset = flag;
286N/A }
286N/A
286N/A public boolean callsNodeset() {
286N/A return _callsNodeset;
286N/A }
286N/A
286N/A public void numberFormattingUsed() {
286N/A _numberFormattingUsed = true;
286N/A /*
286N/A * Fix for bug 23046, if the stylesheet is included, set the
286N/A * numberFormattingUsed flag to the parent stylesheet too.
286N/A * AbstractTranslet.addDecimalFormat() will be inlined once for the
286N/A * outer most stylesheet.
286N/A */
286N/A Stylesheet parent = getParentStylesheet();
286N/A if (null != parent) parent.numberFormattingUsed();
286N/A }
286N/A
286N/A public void setImportPrecedence(final int precedence) {
286N/A // Set import precedence for this stylesheet
286N/A _importPrecedence = precedence;
286N/A
286N/A // Set import precedence for all included stylesheets
286N/A final Enumeration elements = elements();
286N/A while (elements.hasMoreElements()) {
286N/A SyntaxTreeNode child = (SyntaxTreeNode)elements.nextElement();
286N/A if (child instanceof Include) {
286N/A Stylesheet included = ((Include)child).getIncludedStylesheet();
286N/A if (included != null && included._includedFrom == this) {
286N/A included.setImportPrecedence(precedence);
286N/A }
286N/A }
286N/A }
286N/A
286N/A // Set import precedence for the stylesheet that imported this one
286N/A if (_importedFrom != null) {
286N/A if (_importedFrom.getImportPrecedence() < precedence) {
286N/A final Parser parser = getParser();
286N/A final int nextPrecedence = parser.getNextImportPrecedence();
286N/A _importedFrom.setImportPrecedence(nextPrecedence);
286N/A }
286N/A }
286N/A // Set import precedence for the stylesheet that included this one
286N/A else if (_includedFrom != null) {
286N/A if (_includedFrom.getImportPrecedence() != precedence)
286N/A _includedFrom.setImportPrecedence(precedence);
286N/A }
286N/A }
286N/A
286N/A public int getImportPrecedence() {
286N/A return _importPrecedence;
286N/A }
286N/A
286N/A /**
286N/A * Get the minimum of the precedence of this stylesheet, any stylesheet
286N/A * imported by this stylesheet and any include/import descendant of this
286N/A * stylesheet.
286N/A */
286N/A public int getMinimumDescendantPrecedence() {
286N/A if (_minimumDescendantPrecedence == -1) {
286N/A // Start with precedence of current stylesheet as a basis.
286N/A int min = getImportPrecedence();
286N/A
286N/A // Recursively examine all imported/included stylesheets.
286N/A final int inclImpCount = (_includedStylesheets != null)
286N/A ? _includedStylesheets.size()
286N/A : 0;
286N/A
286N/A for (int i = 0; i < inclImpCount; i++) {
286N/A int prec = ((Stylesheet)_includedStylesheets.elementAt(i))
286N/A .getMinimumDescendantPrecedence();
286N/A
286N/A if (prec < min) {
286N/A min = prec;
286N/A }
286N/A }
286N/A
286N/A _minimumDescendantPrecedence = min;
286N/A }
286N/A return _minimumDescendantPrecedence;
286N/A }
286N/A
286N/A public boolean checkForLoop(String systemId) {
286N/A // Return true if this stylesheet includes/imports itself
286N/A if (_systemId != null && _systemId.equals(systemId)) {
286N/A return true;
286N/A }
286N/A // Then check with any stylesheets that included/imported this one
286N/A if (_parentStylesheet != null)
286N/A return _parentStylesheet.checkForLoop(systemId);
286N/A // Otherwise OK
286N/A return false;
286N/A }
286N/A
286N/A public void setParser(Parser parser) {
286N/A super.setParser(parser);
286N/A _name = makeStylesheetName("__stylesheet_");
286N/A }
286N/A
286N/A public void setParentStylesheet(Stylesheet parent) {
286N/A _parentStylesheet = parent;
286N/A }
286N/A
286N/A public Stylesheet getParentStylesheet() {
286N/A return _parentStylesheet;
286N/A }
286N/A
286N/A public void setImportingStylesheet(Stylesheet parent) {
286N/A _importedFrom = parent;
286N/A parent.addIncludedStylesheet(this);
286N/A }
286N/A
286N/A public void setIncludingStylesheet(Stylesheet parent) {
286N/A _includedFrom = parent;
286N/A parent.addIncludedStylesheet(this);
286N/A }
286N/A
286N/A public void addIncludedStylesheet(Stylesheet child) {
286N/A if (_includedStylesheets == null) {
286N/A _includedStylesheets = new Vector();
286N/A }
286N/A _includedStylesheets.addElement(child);
286N/A }
286N/A
286N/A public void setSystemId(String systemId) {
286N/A if (systemId != null) {
286N/A _systemId = SystemIDResolver.getAbsoluteURI(systemId);
286N/A }
286N/A }
286N/A
286N/A public String getSystemId() {
286N/A return _systemId;
286N/A }
286N/A
286N/A public void setSourceLoader(SourceLoader loader) {
286N/A _loader = loader;
286N/A }
286N/A
286N/A public SourceLoader getSourceLoader() {
286N/A return _loader;
286N/A }
286N/A
286N/A private QName makeStylesheetName(String prefix) {
286N/A return getParser().getQName(prefix+getXSLTC().nextStylesheetSerial());
286N/A }
286N/A
286N/A /**
286N/A * Returns true if this stylesheet has global vars or params.
286N/A */
286N/A public boolean hasGlobals() {
286N/A return _globals.size() > 0;
286N/A }
286N/A
286N/A /**
286N/A * Returns true if at least one template in the stylesheet has params
286N/A * defined. Uses the variable <code>_hasLocalParams</code> to cache the
286N/A * result.
286N/A */
286N/A public boolean hasLocalParams() {
286N/A if (_hasLocalParams == null) {
286N/A Vector templates = getAllValidTemplates();
286N/A final int n = templates.size();
286N/A for (int i = 0; i < n; i++) {
286N/A final Template template = (Template)templates.elementAt(i);
286N/A if (template.hasParams()) {
286N/A _hasLocalParams = Boolean.TRUE;
286N/A return true;
286N/A }
286N/A }
286N/A _hasLocalParams = Boolean.FALSE;
286N/A return false;
286N/A }
286N/A else {
286N/A return _hasLocalParams.booleanValue();
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Adds a single prefix mapping to this syntax tree node.
286N/A * @param prefix Namespace prefix.
286N/A * @param uri Namespace URI.
286N/A */
286N/A protected void addPrefixMapping(String prefix, String uri) {
286N/A if (prefix.equals(EMPTYSTRING) && uri.equals(XHTML_URI)) return;
286N/A super.addPrefixMapping(prefix, uri);
286N/A }
286N/A
286N/A /**
286N/A * Store extension URIs
286N/A */
286N/A private void extensionURI(String prefixes, SymbolTable stable) {
286N/A if (prefixes != null) {
286N/A StringTokenizer tokens = new StringTokenizer(prefixes);
286N/A while (tokens.hasMoreTokens()) {
286N/A final String prefix = tokens.nextToken();
286N/A final String uri = lookupNamespace(prefix);
286N/A if (uri != null) {
286N/A _extensions.put(uri, prefix);
286N/A }
286N/A }
286N/A }
286N/A }
286N/A
286N/A public boolean isExtension(String uri) {
286N/A return (_extensions.get(uri) != null);
286N/A }
286N/A
286N/A public void declareExtensionPrefixes(Parser parser) {
286N/A final SymbolTable stable = parser.getSymbolTable();
286N/A final String extensionPrefixes = getAttribute("extension-element-prefixes");
286N/A extensionURI(extensionPrefixes, stable);
286N/A }
286N/A
286N/A /**
286N/A * Parse the version and uri fields of the stylesheet and add an
286N/A * entry to the symbol table mapping the name <tt>__stylesheet_</tt>
286N/A * to an instance of this class.
286N/A */
286N/A public void parseContents(Parser parser) {
286N/A final SymbolTable stable = parser.getSymbolTable();
286N/A
286N/A /*
286N/A // Make sure the XSL version set in this stylesheet
286N/A if ((_version == null) || (_version.equals(EMPTYSTRING))) {
286N/A reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR,"version");
286N/A }
286N/A // Verify that the version is 1.0 and nothing else
286N/A else if (!_version.equals("1.0")) {
286N/A reportError(this, parser, ErrorMsg.XSL_VERSION_ERR, _version);
286N/A }
286N/A */
286N/A
286N/A // Add the implicit mapping of 'xml' to the XML namespace URI
286N/A addPrefixMapping("xml", "http://www.w3.org/XML/1998/namespace");
286N/A
286N/A // Report and error if more than one stylesheet defined
286N/A final Stylesheet sheet = stable.addStylesheet(_name, this);
286N/A if (sheet != null) {
286N/A // Error: more that one stylesheet defined
286N/A ErrorMsg err = new ErrorMsg(ErrorMsg.MULTIPLE_STYLESHEET_ERR,this);
286N/A parser.reportError(Constants.ERROR, err);
286N/A }
286N/A
286N/A // If this is a simplified stylesheet we must create a template that
286N/A // grabs the root node of the input doc ( <xsl:template match="/"/> ).
286N/A // This template needs the current element (the one passed to this
286N/A // method) as its only child, so the Template class has a special
286N/A // method that handles this (parseSimplified()).
286N/A if (_simplified) {
286N/A stable.excludeURI(XSLT_URI);
286N/A Template template = new Template();
286N/A template.parseSimplified(this, parser);
286N/A }
286N/A // Parse the children of this node
286N/A else {
286N/A parseOwnChildren(parser);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Parse all direct children of the <xsl:stylesheet/> element.
286N/A */
286N/A public final void parseOwnChildren(Parser parser) {
286N/A final SymbolTable stable = parser.getSymbolTable();
286N/A final String excludePrefixes = getAttribute("exclude-result-prefixes");
286N/A final String extensionPrefixes = getAttribute("extension-element-prefixes");
286N/A
286N/A // Exclude XSLT uri
286N/A stable.pushExcludedNamespacesContext();
286N/A stable.excludeURI(Constants.XSLT_URI);
286N/A stable.excludeNamespaces(excludePrefixes);
286N/A stable.excludeNamespaces(extensionPrefixes);
286N/A
286N/A final Vector contents = getContents();
286N/A final int count = contents.size();
286N/A
286N/A // We have to scan the stylesheet element's top-level elements for
286N/A // variables and/or parameters before we parse the other elements
286N/A for (int i = 0; i < count; i++) {
286N/A SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
286N/A if ((child instanceof VariableBase) ||
286N/A (child instanceof NamespaceAlias)) {
286N/A parser.getSymbolTable().setCurrentNode(child);
286N/A child.parseContents(parser);
286N/A }
286N/A }
286N/A
286N/A // Now go through all the other top-level elements...
286N/A for (int i = 0; i < count; i++) {
286N/A SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
286N/A if (!(child instanceof VariableBase) &&
286N/A !(child instanceof NamespaceAlias)) {
286N/A parser.getSymbolTable().setCurrentNode(child);
286N/A child.parseContents(parser);
286N/A }
286N/A
286N/A // All template code should be compiled as methods if the
286N/A // <xsl:apply-imports/> element was ever used in this stylesheet
286N/A if (!_templateInlining && (child instanceof Template)) {
286N/A Template template = (Template)child;
286N/A String name = "template$dot$" + template.getPosition();
286N/A template.setName(parser.getQName(name));
286N/A }
286N/A }
286N/A
286N/A stable.popExcludedNamespacesContext();
286N/A }
286N/A
286N/A public void processModes() {
286N/A if (_defaultMode == null)
286N/A _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
286N/A _defaultMode.processPatterns(_keys);
286N/A final Enumeration modes = _modes.elements();
286N/A while (modes.hasMoreElements()) {
286N/A final Mode mode = (Mode)modes.nextElement();
286N/A mode.processPatterns(_keys);
286N/A }
286N/A }
286N/A
286N/A private void compileModes(ClassGenerator classGen) {
286N/A _defaultMode.compileApplyTemplates(classGen);
286N/A final Enumeration modes = _modes.elements();
286N/A while (modes.hasMoreElements()) {
286N/A final Mode mode = (Mode)modes.nextElement();
286N/A mode.compileApplyTemplates(classGen);
286N/A }
286N/A }
286N/A
286N/A public Mode getMode(QName modeName) {
286N/A if (modeName == null) {
286N/A if (_defaultMode == null) {
286N/A _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
286N/A }
286N/A return _defaultMode;
286N/A }
286N/A else {
286N/A Mode mode = (Mode)_modes.get(modeName);
286N/A if (mode == null) {
286N/A final String suffix = Integer.toString(_nextModeSerial++);
286N/A _modes.put(modeName, mode = new Mode(modeName, this, suffix));
286N/A }
286N/A return mode;
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Type check all the children of this node.
286N/A */
286N/A public Type typeCheck(SymbolTable stable) throws TypeCheckError {
286N/A final int count = _globals.size();
286N/A for (int i = 0; i < count; i++) {
286N/A final VariableBase var = (VariableBase)_globals.elementAt(i);
286N/A var.typeCheck(stable);
286N/A }
286N/A return typeCheckContents(stable);
286N/A }
286N/A
286N/A /**
286N/A * Translate the stylesheet into JVM bytecodes.
286N/A */
286N/A public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
286N/A translate();
286N/A }
286N/A
286N/A private void addDOMField(ClassGenerator classGen) {
286N/A final FieldGen fgen = new FieldGen(ACC_PUBLIC,
286N/A Util.getJCRefType(DOM_INTF_SIG),
286N/A DOM_FIELD,
286N/A classGen.getConstantPool());
286N/A classGen.addField(fgen.getField());
286N/A }
286N/A
286N/A /**
286N/A * Add a static field
286N/A */
286N/A private void addStaticField(ClassGenerator classGen, String type,
286N/A String name)
286N/A {
286N/A final FieldGen fgen = new FieldGen(ACC_PROTECTED|ACC_STATIC,
286N/A Util.getJCRefType(type),
286N/A name,
286N/A classGen.getConstantPool());
286N/A classGen.addField(fgen.getField());
286N/A
286N/A }
286N/A
286N/A /**
286N/A * Translate the stylesheet into JVM bytecodes.
286N/A */
286N/A public void translate() {
286N/A _className = getXSLTC().getClassName();
286N/A
286N/A // Define a new class by extending TRANSLET_CLASS
286N/A final ClassGenerator classGen =
286N/A new ClassGenerator(_className,
286N/A TRANSLET_CLASS,
286N/A Constants.EMPTYSTRING,
286N/A ACC_PUBLIC | ACC_SUPER,
286N/A null, this);
286N/A
286N/A addDOMField(classGen);
286N/A
286N/A // Compile transform() to initialize parameters, globals & output
286N/A // and run the transformation
286N/A compileTransform(classGen);
286N/A
286N/A // Translate all non-template elements and filter out all templates
286N/A final Enumeration elements = elements();
286N/A while (elements.hasMoreElements()) {
286N/A Object element = elements.nextElement();
286N/A // xsl:template
286N/A if (element instanceof Template) {
286N/A // Separate templates by modes
286N/A final Template template = (Template)element;
286N/A //_templates.addElement(template);
286N/A getMode(template.getModeName()).addTemplate(template);
286N/A }
286N/A // xsl:attribute-set
286N/A else if (element instanceof AttributeSet) {
286N/A ((AttributeSet)element).translate(classGen, null);
286N/A }
286N/A else if (element instanceof Output) {
286N/A // save the element for later to pass to compileConstructor
286N/A Output output = (Output)element;
286N/A if (output.enabled()) _lastOutputElement = output;
286N/A }
286N/A else {
286N/A // Global variables and parameters are handled elsewhere.
286N/A // Other top-level non-template elements are ignored. Literal
286N/A // elements outside of templates will never be output.
286N/A }
286N/A }
286N/A
286N/A checkOutputMethod();
286N/A processModes();
286N/A compileModes(classGen);
286N/A compileStaticInitializer(classGen);
286N/A compileConstructor(classGen, _lastOutputElement);
286N/A
286N/A if (!getParser().errorsFound()) {
286N/A getXSLTC().dumpClass(classGen.getJavaClass());
286N/A }
286N/A }
286N/A
286N/A /**
293N/A * Compile the namesArray, urisArray and typesArray into
286N/A * the static initializer. They are read-only from the
286N/A * translet. All translet instances can share a single
293N/A * copy of this informtion.
286N/A */
286N/A private void compileStaticInitializer(ClassGenerator classGen) {
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A final InstructionList il = new InstructionList();
286N/A
286N/A final MethodGenerator staticConst =
286N/A new MethodGenerator(ACC_PUBLIC|ACC_STATIC,
286N/A com.sun.org.apache.bcel.internal.generic.Type.VOID,
286N/A null, null, "<clinit>",
286N/A _className, il, cpg);
286N/A
286N/A addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMES_ARRAY_FIELD);
286N/A addStaticField(classGen, "[" + STRING_SIG, STATIC_URIS_ARRAY_FIELD);
286N/A addStaticField(classGen, "[I", STATIC_TYPES_ARRAY_FIELD);
286N/A addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMESPACE_ARRAY_FIELD);
286N/A // Create fields of type char[] that will contain literal text from
286N/A // the stylesheet.
286N/A final int charDataFieldCount = getXSLTC().getCharacterDataCount();
286N/A for (int i = 0; i < charDataFieldCount; i++) {
286N/A addStaticField(classGen, STATIC_CHAR_DATA_FIELD_SIG,
286N/A STATIC_CHAR_DATA_FIELD+i);
286N/A }
286N/A
286N/A // Put the names array into the translet - used for dom/translet mapping
286N/A final Vector namesIndex = getXSLTC().getNamesIndex();
286N/A int size = namesIndex.size();
286N/A String[] namesArray = new String[size];
286N/A String[] urisArray = new String[size];
286N/A int[] typesArray = new int[size];
286N/A
286N/A int index;
286N/A for (int i = 0; i < size; i++) {
286N/A String encodedName = (String)namesIndex.elementAt(i);
286N/A if ((index = encodedName.lastIndexOf(':')) > -1) {
286N/A urisArray[i] = encodedName.substring(0, index);
286N/A }
286N/A
286N/A index = index + 1;
286N/A if (encodedName.charAt(index) == '@') {
286N/A typesArray[i] = DTM.ATTRIBUTE_NODE;
286N/A index++;
286N/A } else if (encodedName.charAt(index) == '?') {
286N/A typesArray[i] = DTM.NAMESPACE_NODE;
286N/A index++;
286N/A } else {
286N/A typesArray[i] = DTM.ELEMENT_NODE;
286N/A }
286N/A
286N/A if (index == 0) {
286N/A namesArray[i] = encodedName;
286N/A }
286N/A else {
286N/A namesArray[i] = encodedName.substring(index);
286N/A }
286N/A }
286N/A
286N/A staticConst.markChunkStart();
286N/A il.append(new PUSH(cpg, size));
286N/A il.append(new ANEWARRAY(cpg.addClass(STRING)));
286N/A int namesArrayRef = cpg.addFieldref(_className,
286N/A STATIC_NAMES_ARRAY_FIELD,
286N/A NAMES_INDEX_SIG);
286N/A il.append(new PUTSTATIC(namesArrayRef));
286N/A staticConst.markChunkEnd();
286N/A
286N/A for (int i = 0; i < size; i++) {
286N/A final String name = namesArray[i];
286N/A staticConst.markChunkStart();
286N/A il.append(new GETSTATIC(namesArrayRef));
286N/A il.append(new PUSH(cpg, i));
286N/A il.append(new PUSH(cpg, name));
286N/A il.append(AASTORE);
286N/A staticConst.markChunkEnd();
286N/A }
286N/A
286N/A staticConst.markChunkStart();
286N/A il.append(new PUSH(cpg, size));
286N/A il.append(new ANEWARRAY(cpg.addClass(STRING)));
286N/A int urisArrayRef = cpg.addFieldref(_className,
286N/A STATIC_URIS_ARRAY_FIELD,
286N/A URIS_INDEX_SIG);
286N/A il.append(new PUTSTATIC(urisArrayRef));
286N/A staticConst.markChunkEnd();
286N/A
286N/A for (int i = 0; i < size; i++) {
286N/A final String uri = urisArray[i];
286N/A staticConst.markChunkStart();
286N/A il.append(new GETSTATIC(urisArrayRef));
286N/A il.append(new PUSH(cpg, i));
286N/A il.append(new PUSH(cpg, uri));
286N/A il.append(AASTORE);
286N/A staticConst.markChunkEnd();
286N/A }
286N/A
286N/A staticConst.markChunkStart();
286N/A il.append(new PUSH(cpg, size));
286N/A il.append(new NEWARRAY(BasicType.INT));
286N/A int typesArrayRef = cpg.addFieldref(_className,
286N/A STATIC_TYPES_ARRAY_FIELD,
286N/A TYPES_INDEX_SIG);
286N/A il.append(new PUTSTATIC(typesArrayRef));
286N/A staticConst.markChunkEnd();
286N/A
286N/A for (int i = 0; i < size; i++) {
286N/A final int nodeType = typesArray[i];
286N/A staticConst.markChunkStart();
286N/A il.append(new GETSTATIC(typesArrayRef));
286N/A il.append(new PUSH(cpg, i));
286N/A il.append(new PUSH(cpg, nodeType));
286N/A il.append(IASTORE);
286N/A }
286N/A
286N/A // Put the namespace names array into the translet
286N/A final Vector namespaces = getXSLTC().getNamespaceIndex();
286N/A staticConst.markChunkStart();
286N/A il.append(new PUSH(cpg, namespaces.size()));
286N/A il.append(new ANEWARRAY(cpg.addClass(STRING)));
286N/A int namespaceArrayRef = cpg.addFieldref(_className,
286N/A STATIC_NAMESPACE_ARRAY_FIELD,
286N/A NAMESPACE_INDEX_SIG);
286N/A il.append(new PUTSTATIC(namespaceArrayRef));
286N/A staticConst.markChunkEnd();
286N/A
286N/A for (int i = 0; i < namespaces.size(); i++) {
286N/A final String ns = (String)namespaces.elementAt(i);
286N/A staticConst.markChunkStart();
286N/A il.append(new GETSTATIC(namespaceArrayRef));
286N/A il.append(new PUSH(cpg, i));
286N/A il.append(new PUSH(cpg, ns));
286N/A il.append(AASTORE);
286N/A staticConst.markChunkEnd();
286N/A }
286N/A
286N/A // Grab all the literal text in the stylesheet and put it in a char[]
286N/A final int charDataCount = getXSLTC().getCharacterDataCount();
286N/A final int toCharArray = cpg.addMethodref(STRING, "toCharArray", "()[C");
286N/A for (int i = 0; i < charDataCount; i++) {
286N/A staticConst.markChunkStart();
286N/A il.append(new PUSH(cpg, getXSLTC().getCharacterData(i)));
286N/A il.append(new INVOKEVIRTUAL(toCharArray));
286N/A il.append(new PUTSTATIC(cpg.addFieldref(_className,
286N/A STATIC_CHAR_DATA_FIELD+i,
286N/A STATIC_CHAR_DATA_FIELD_SIG)));
286N/A staticConst.markChunkEnd();
286N/A }
286N/A
286N/A il.append(RETURN);
286N/A
286N/A classGen.addMethod(staticConst);
286N/A
286N/A }
286N/A
286N/A /**
286N/A * Compile the translet's constructor
286N/A */
286N/A private void compileConstructor(ClassGenerator classGen, Output output) {
286N/A
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A final InstructionList il = new InstructionList();
286N/A
286N/A final MethodGenerator constructor =
286N/A new MethodGenerator(ACC_PUBLIC,
286N/A com.sun.org.apache.bcel.internal.generic.Type.VOID,
286N/A null, null, "<init>",
286N/A _className, il, cpg);
286N/A
286N/A // Call the constructor in the AbstractTranslet superclass
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new INVOKESPECIAL(cpg.addMethodref(TRANSLET_CLASS,
286N/A "<init>", "()V")));
286N/A
286N/A constructor.markChunkStart();
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new GETSTATIC(cpg.addFieldref(_className,
286N/A STATIC_NAMES_ARRAY_FIELD,
286N/A NAMES_INDEX_SIG)));
286N/A il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
286N/A NAMES_INDEX,
286N/A NAMES_INDEX_SIG)));
286N/A
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new GETSTATIC(cpg.addFieldref(_className,
286N/A STATIC_URIS_ARRAY_FIELD,
286N/A URIS_INDEX_SIG)));
286N/A il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
286N/A URIS_INDEX,
286N/A URIS_INDEX_SIG)));
286N/A constructor.markChunkEnd();
286N/A
286N/A constructor.markChunkStart();
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new GETSTATIC(cpg.addFieldref(_className,
286N/A STATIC_TYPES_ARRAY_FIELD,
286N/A TYPES_INDEX_SIG)));
286N/A il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
286N/A TYPES_INDEX,
286N/A TYPES_INDEX_SIG)));
286N/A constructor.markChunkEnd();
286N/A
286N/A constructor.markChunkStart();
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new GETSTATIC(cpg.addFieldref(_className,
286N/A STATIC_NAMESPACE_ARRAY_FIELD,
286N/A NAMESPACE_INDEX_SIG)));
286N/A il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
286N/A NAMESPACE_INDEX,
286N/A NAMESPACE_INDEX_SIG)));
286N/A constructor.markChunkEnd();
286N/A
286N/A constructor.markChunkStart();
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new PUSH(cpg, AbstractTranslet.CURRENT_TRANSLET_VERSION));
286N/A il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
286N/A TRANSLET_VERSION_INDEX,
286N/A TRANSLET_VERSION_INDEX_SIG)));
286N/A constructor.markChunkEnd();
286N/A
286N/A if (_hasIdCall) {
286N/A constructor.markChunkStart();
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new PUSH(cpg, Boolean.TRUE));
286N/A il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
286N/A HASIDCALL_INDEX,
286N/A HASIDCALL_INDEX_SIG)));
286N/A constructor.markChunkEnd();
286N/A }
286N/A
286N/A // Compile in code to set the output configuration from <xsl:output>
286N/A if (output != null) {
286N/A // Set all the output settings files in the translet
286N/A constructor.markChunkStart();
286N/A output.translate(classGen, constructor);
286N/A constructor.markChunkEnd();
286N/A }
286N/A
286N/A // Compile default decimal formatting symbols.
286N/A // This is an implicit, nameless xsl:decimal-format top-level element.
286N/A if (_numberFormattingUsed) {
286N/A constructor.markChunkStart();
286N/A DecimalFormatting.translateDefaultDFS(classGen, constructor);
286N/A constructor.markChunkEnd();
286N/A }
286N/A
286N/A il.append(RETURN);
286N/A
286N/A classGen.addMethod(constructor);
286N/A }
286N/A
286N/A /**
286N/A * Compile a topLevel() method into the output class. This method is
286N/A * called from transform() to handle all non-template top-level elements.
286N/A * Returns the signature of the topLevel() method.
286N/A *
286N/A * Global variables/params and keys are first sorted to resolve
286N/A * dependencies between them. The XSLT 1.0 spec does not allow a key
286N/A * to depend on a variable. However, for compatibility with Xalan
286N/A * interpretive, that type of dependency is allowed. Note also that
286N/A * the buildKeys() method is still generated as it is used by the
286N/A * LoadDocument class, but it no longer called from transform().
286N/A */
286N/A private String compileTopLevel(ClassGenerator classGen) {
286N/A
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A
286N/A final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
286N/A Util.getJCRefType(DOM_INTF_SIG),
286N/A Util.getJCRefType(NODE_ITERATOR_SIG),
286N/A Util.getJCRefType(TRANSLET_OUTPUT_SIG)
286N/A };
286N/A
286N/A final String[] argNames = {
286N/A DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME
286N/A };
286N/A
286N/A final InstructionList il = new InstructionList();
286N/A
286N/A final MethodGenerator toplevel =
286N/A new MethodGenerator(ACC_PUBLIC,
286N/A com.sun.org.apache.bcel.internal.generic.Type.VOID,
286N/A argTypes, argNames,
286N/A "topLevel", _className, il,
286N/A classGen.getConstantPool());
286N/A
286N/A toplevel.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
286N/A
286N/A // Define and initialize 'current' variable with the root node
286N/A final LocalVariableGen current =
286N/A toplevel.addLocalVariable("current",
286N/A com.sun.org.apache.bcel.internal.generic.Type.INT,
286N/A null, null);
286N/A
286N/A final int setFilter = cpg.addInterfaceMethodref(DOM_INTF,
286N/A "setFilter",
286N/A "(Lcom/sun/org/apache/xalan/internal/xsltc/StripFilter;)V");
286N/A
286N/A final int gitr = cpg.addInterfaceMethodref(DOM_INTF,
286N/A "getIterator",
286N/A "()"+NODE_ITERATOR_SIG);
286N/A il.append(toplevel.loadDOM());
286N/A il.append(new INVOKEINTERFACE(gitr, 1));
286N/A il.append(toplevel.nextNode());
286N/A current.setStart(il.append(new ISTORE(current.getIndex())));
286N/A
286N/A // Create a new list containing variables/params + keys
286N/A Vector varDepElements = new Vector(_globals);
286N/A Enumeration elements = elements();
286N/A while (elements.hasMoreElements()) {
286N/A final Object element = elements.nextElement();
286N/A if (element instanceof Key) {
286N/A varDepElements.add(element);
286N/A }
286N/A }
286N/A
286N/A // Determine a partial order for the variables/params and keys
286N/A varDepElements = resolveDependencies(varDepElements);
286N/A
286N/A // Translate vars/params and keys in the right order
286N/A final int count = varDepElements.size();
286N/A for (int i = 0; i < count; i++) {
286N/A final TopLevelElement tle = (TopLevelElement) varDepElements.elementAt(i);
286N/A tle.translate(classGen, toplevel);
286N/A if (tle instanceof Key) {
286N/A final Key key = (Key) tle;
286N/A _keys.put(key.getName(), key);
286N/A }
286N/A }
286N/A
286N/A // Compile code for other top-level elements
286N/A Vector whitespaceRules = new Vector();
286N/A elements = elements();
286N/A while (elements.hasMoreElements()) {
286N/A final Object element = elements.nextElement();
286N/A // xsl:decimal-format
286N/A if (element instanceof DecimalFormatting) {
286N/A ((DecimalFormatting)element).translate(classGen,toplevel);
286N/A }
286N/A // xsl:strip/preserve-space
286N/A else if (element instanceof Whitespace) {
286N/A whitespaceRules.addAll(((Whitespace)element).getRules());
286N/A }
286N/A }
286N/A
286N/A // Translate all whitespace strip/preserve rules
286N/A if (whitespaceRules.size() > 0) {
286N/A Whitespace.translateRules(whitespaceRules,classGen);
286N/A }
286N/A
286N/A if (classGen.containsMethod(STRIP_SPACE, STRIP_SPACE_PARAMS) != null) {
286N/A il.append(toplevel.loadDOM());
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new INVOKEINTERFACE(setFilter, 2));
286N/A }
286N/A
286N/A il.append(RETURN);
286N/A
286N/A // Compute max locals + stack and add method to class
286N/A classGen.addMethod(toplevel);
286N/A
286N/A return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+")V");
286N/A }
286N/A
286N/A /**
286N/A * This method returns a vector with variables/params and keys in the
286N/A * order in which they are to be compiled for initialization. The order
286N/A * is determined by analyzing the dependencies between them. The XSLT 1.0
286N/A * spec does not allow a key to depend on a variable. However, for
286N/A * compatibility with Xalan interpretive, that type of dependency is
286N/A * allowed and, therefore, consider to determine the partial order.
286N/A */
286N/A private Vector resolveDependencies(Vector input) {
286N/A /* DEBUG CODE - INGORE
286N/A for (int i = 0; i < input.size(); i++) {
286N/A final TopLevelElement e = (TopLevelElement) input.elementAt(i);
286N/A System.out.println("e = " + e + " depends on:");
286N/A Vector dep = e.getDependencies();
286N/A for (int j = 0; j < (dep != null ? dep.size() : 0); j++) {
286N/A System.out.println("\t" + dep.elementAt(j));
286N/A }
286N/A }
286N/A System.out.println("=================================");
286N/A */
286N/A
286N/A Vector result = new Vector();
286N/A while (input.size() > 0) {
286N/A boolean changed = false;
286N/A for (int i = 0; i < input.size(); ) {
286N/A final TopLevelElement vde = (TopLevelElement) input.elementAt(i);
286N/A final Vector dep = vde.getDependencies();
286N/A if (dep == null || result.containsAll(dep)) {
286N/A result.addElement(vde);
286N/A input.remove(i);
286N/A changed = true;
286N/A }
286N/A else {
286N/A i++;
286N/A }
286N/A }
286N/A
286N/A // If nothing was changed in this pass then we have a circular ref
286N/A if (!changed) {
286N/A ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR,
286N/A input.toString(), this);
286N/A getParser().reportError(Constants.ERROR, err);
286N/A return(result);
286N/A }
286N/A }
286N/A
286N/A /* DEBUG CODE - INGORE
286N/A System.out.println("=================================");
286N/A for (int i = 0; i < result.size(); i++) {
286N/A final TopLevelElement e = (TopLevelElement) result.elementAt(i);
286N/A System.out.println("e = " + e);
286N/A }
286N/A */
286N/A
286N/A return result;
286N/A }
286N/A
286N/A /**
286N/A * Compile a buildKeys() method into the output class. Note that keys
286N/A * for the input document are created in topLevel(), not in this method.
286N/A * However, we still need this method to create keys for documents loaded
286N/A * via the XPath document() function.
286N/A */
286N/A private String compileBuildKeys(ClassGenerator classGen) {
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A
286N/A final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
286N/A Util.getJCRefType(DOM_INTF_SIG),
286N/A Util.getJCRefType(NODE_ITERATOR_SIG),
286N/A Util.getJCRefType(TRANSLET_OUTPUT_SIG),
286N/A com.sun.org.apache.bcel.internal.generic.Type.INT
286N/A };
286N/A
286N/A final String[] argNames = {
286N/A DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME, "current"
286N/A };
286N/A
286N/A final InstructionList il = new InstructionList();
286N/A
286N/A final MethodGenerator buildKeys =
286N/A new MethodGenerator(ACC_PUBLIC,
286N/A com.sun.org.apache.bcel.internal.generic.Type.VOID,
286N/A argTypes, argNames,
286N/A "buildKeys", _className, il,
286N/A classGen.getConstantPool());
286N/A
286N/A buildKeys.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
286N/A
286N/A final Enumeration elements = elements();
286N/A while (elements.hasMoreElements()) {
286N/A // xsl:key
286N/A final Object element = elements.nextElement();
286N/A if (element instanceof Key) {
286N/A final Key key = (Key)element;
286N/A key.translate(classGen, buildKeys);
286N/A _keys.put(key.getName(),key);
286N/A }
286N/A }
286N/A
286N/A il.append(RETURN);
286N/A
286N/A // Compute max locals + stack and add method to class
286N/A buildKeys.stripAttributes(true);
286N/A buildKeys.setMaxLocals();
286N/A buildKeys.setMaxStack();
286N/A buildKeys.removeNOPs();
286N/A
286N/A classGen.addMethod(buildKeys.getMethod());
286N/A
286N/A return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+"I)V");
286N/A }
286N/A
286N/A /**
286N/A * Compile transform() into the output class. This method is used to
286N/A * initialize global variables and global parameters. The current node
286N/A * is set to be the document's root node.
286N/A */
286N/A private void compileTransform(ClassGenerator classGen) {
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A
286N/A /*
286N/A * Define the the method transform with the following signature:
286N/A * void transform(DOM, NodeIterator, HandlerBase)
286N/A */
286N/A final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
286N/A new com.sun.org.apache.bcel.internal.generic.Type[3];
286N/A argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
286N/A argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
286N/A argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
286N/A
286N/A final String[] argNames = new String[3];
286N/A argNames[0] = DOCUMENT_PNAME;
286N/A argNames[1] = ITERATOR_PNAME;
286N/A argNames[2] = TRANSLET_OUTPUT_PNAME;
286N/A
286N/A final InstructionList il = new InstructionList();
286N/A final MethodGenerator transf =
286N/A new MethodGenerator(ACC_PUBLIC,
286N/A com.sun.org.apache.bcel.internal.generic.Type.VOID,
286N/A argTypes, argNames,
286N/A "transform",
286N/A _className,
286N/A il,
286N/A classGen.getConstantPool());
286N/A transf.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
286N/A
286N/A // Define and initialize current with the root node
286N/A final LocalVariableGen current =
286N/A transf.addLocalVariable("current",
286N/A com.sun.org.apache.bcel.internal.generic.Type.INT,
286N/A null, null);
286N/A final String applyTemplatesSig = classGen.getApplyTemplatesSig();
286N/A final int applyTemplates = cpg.addMethodref(getClassName(),
286N/A "applyTemplates",
286N/A applyTemplatesSig);
286N/A final int domField = cpg.addFieldref(getClassName(),
286N/A DOM_FIELD,
286N/A DOM_INTF_SIG);
286N/A
286N/A // push translet for PUTFIELD
286N/A il.append(classGen.loadTranslet());
286N/A // prepare appropriate DOM implementation
286N/A
286N/A if (isMultiDocument()) {
286N/A il.append(new NEW(cpg.addClass(MULTI_DOM_CLASS)));
286N/A il.append(DUP);
286N/A }
286N/A
286N/A il.append(classGen.loadTranslet());
286N/A il.append(transf.loadDOM());
286N/A il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
286N/A "makeDOMAdapter",
286N/A "("+DOM_INTF_SIG+")"+
286N/A DOM_ADAPTER_SIG)));
286N/A // DOMAdapter is on the stack
286N/A
286N/A if (isMultiDocument()) {
286N/A final int init = cpg.addMethodref(MULTI_DOM_CLASS,
286N/A "<init>",
286N/A "("+DOM_INTF_SIG+")V");
286N/A il.append(new INVOKESPECIAL(init));
286N/A // MultiDOM is on the stack
286N/A }
286N/A
286N/A //store to _dom variable
286N/A il.append(new PUTFIELD(domField));
286N/A
286N/A // continue with globals initialization
286N/A final int gitr = cpg.addInterfaceMethodref(DOM_INTF,
286N/A "getIterator",
286N/A "()"+NODE_ITERATOR_SIG);
286N/A il.append(transf.loadDOM());
286N/A il.append(new INVOKEINTERFACE(gitr, 1));
286N/A il.append(transf.nextNode());
286N/A current.setStart(il.append(new ISTORE(current.getIndex())));
286N/A
286N/A // Transfer the output settings to the output post-processor
286N/A il.append(classGen.loadTranslet());
286N/A il.append(transf.loadHandler());
286N/A final int index = cpg.addMethodref(TRANSLET_CLASS,
286N/A "transferOutputSettings",
286N/A "("+OUTPUT_HANDLER_SIG+")V");
286N/A il.append(new INVOKEVIRTUAL(index));
286N/A
286N/A /*
286N/A * Compile buildKeys() method. Note that this method is not
286N/A * invoked here as keys for the input document are now created
286N/A * in topLevel(). However, this method is still needed by the
286N/A * LoadDocument class.
286N/A */
286N/A final String keySig = compileBuildKeys(classGen);
286N/A final int keyIdx = cpg.addMethodref(getClassName(),
286N/A "buildKeys", keySig);
286N/A
286N/A // Look for top-level elements that need handling
286N/A final Enumeration toplevel = elements();
286N/A if (_globals.size() > 0 || toplevel.hasMoreElements()) {
286N/A // Compile method for handling top-level elements
286N/A final String topLevelSig = compileTopLevel(classGen);
286N/A // Get a reference to that method
286N/A final int topLevelIdx = cpg.addMethodref(getClassName(),
286N/A "topLevel",
286N/A topLevelSig);
286N/A // Push all parameters on the stack and call topLevel()
286N/A il.append(classGen.loadTranslet()); // The 'this' pointer
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new GETFIELD(domField)); // The DOM reference
286N/A il.append(transf.loadIterator());
286N/A il.append(transf.loadHandler()); // The output handler
286N/A il.append(new INVOKEVIRTUAL(topLevelIdx));
286N/A }
286N/A
286N/A // start document
286N/A il.append(transf.loadHandler());
286N/A il.append(transf.startDocument());
286N/A
286N/A // push first arg for applyTemplates
286N/A il.append(classGen.loadTranslet());
286N/A // push translet for GETFIELD to get DOM arg
286N/A il.append(classGen.loadTranslet());
286N/A il.append(new GETFIELD(domField));
286N/A // push remaining 2 args
286N/A il.append(transf.loadIterator());
286N/A il.append(transf.loadHandler());
286N/A il.append(new INVOKEVIRTUAL(applyTemplates));
286N/A // endDocument
286N/A il.append(transf.loadHandler());
286N/A il.append(transf.endDocument());
286N/A
286N/A il.append(RETURN);
286N/A
286N/A // Compute max locals + stack and add method to class
286N/A classGen.addMethod(transf);
286N/A
286N/A }
286N/A
286N/A /**
286N/A * Peephole optimization: Remove sequences of [ALOAD, POP].
286N/A */
286N/A private void peepHoleOptimization(MethodGenerator methodGen) {
286N/A final String pattern = "`aload'`pop'`instruction'";
286N/A final InstructionList il = methodGen.getInstructionList();
286N/A final InstructionFinder find = new InstructionFinder(il);
286N/A for(Iterator iter=find.search(pattern); iter.hasNext(); ) {
286N/A InstructionHandle[] match = (InstructionHandle[])iter.next();
286N/A try {
286N/A il.delete(match[0], match[1]);
286N/A }
286N/A catch (TargetLostException e) {
286N/A // TODO: move target down into the list
286N/A }
286N/A }
286N/A }
286N/A
286N/A public int addParam(Param param) {
286N/A _globals.addElement(param);
286N/A return _globals.size() - 1;
286N/A }
286N/A
286N/A public int addVariable(Variable global) {
286N/A _globals.addElement(global);
286N/A return _globals.size() - 1;
286N/A }
286N/A
286N/A public void display(int indent) {
286N/A indent(indent);
286N/A Util.println("Stylesheet");
286N/A displayContents(indent + IndentIncrement);
286N/A }
286N/A
286N/A // do we need this wrapper ?????
286N/A public String getNamespace(String prefix) {
286N/A return lookupNamespace(prefix);
286N/A }
286N/A
286N/A public String getClassName() {
286N/A return _className;
286N/A }
286N/A
286N/A public Vector getTemplates() {
286N/A return _templates;
286N/A }
286N/A
286N/A public Vector getAllValidTemplates() {
286N/A // Return templates if no imported/included stylesheets
286N/A if (_includedStylesheets == null) {
286N/A return _templates;
286N/A }
286N/A
286N/A // Is returned value cached?
286N/A if (_allValidTemplates == null) {
286N/A Vector templates = new Vector();
286N/A templates.addAll(_templates);
286N/A int size = _includedStylesheets.size();
286N/A for (int i = 0; i < size; i++) {
286N/A Stylesheet included =(Stylesheet)_includedStylesheets.elementAt(i);
286N/A templates.addAll(included.getAllValidTemplates());
286N/A }
286N/A //templates.addAll(_templates);
286N/A
286N/A // Cache results in top-level stylesheet only
286N/A if (_parentStylesheet != null) {
286N/A return templates;
286N/A }
286N/A _allValidTemplates = templates;
286N/A }
286N/A
286N/A return _allValidTemplates;
286N/A }
286N/A
286N/A protected void addTemplate(Template template) {
286N/A _templates.addElement(template);
286N/A }
286N/A}