001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: Stylesheet.java 669373 2008-06-19 03:40:20Z zongaro $
020     */
021    
022    package org.apache.xalan.xsltc.compiler;
023    
024    import java.util.Vector;
025    import java.util.Enumeration;
026    import java.util.Hashtable;
027    import java.util.Iterator;
028    import java.util.Properties;
029    import java.util.StringTokenizer;
030    
031    import org.apache.xml.utils.SystemIDResolver;
032    import org.apache.bcel.generic.ANEWARRAY;
033    import org.apache.bcel.generic.BasicType;
034    import org.apache.bcel.generic.ConstantPoolGen;
035    import org.apache.bcel.generic.FieldGen;
036    import org.apache.bcel.generic.GETFIELD;
037    import org.apache.bcel.generic.GETSTATIC;
038    import org.apache.bcel.generic.INVOKEINTERFACE;
039    import org.apache.bcel.generic.INVOKESPECIAL;
040    import org.apache.bcel.generic.INVOKEVIRTUAL;
041    import org.apache.bcel.generic.ISTORE;
042    import org.apache.bcel.generic.InstructionHandle;
043    import org.apache.bcel.generic.InstructionList;
044    import org.apache.bcel.generic.LocalVariableGen;
045    import org.apache.bcel.generic.NEW;
046    import org.apache.bcel.generic.NEWARRAY;
047    import org.apache.bcel.generic.PUSH;
048    import org.apache.bcel.generic.PUTFIELD;
049    import org.apache.bcel.generic.PUTSTATIC;
050    import org.apache.bcel.generic.TargetLostException;
051    import org.apache.bcel.util.InstructionFinder;
052    import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
053    import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
054    import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
055    import org.apache.xalan.xsltc.compiler.util.Type;
056    import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
057    import org.apache.xalan.xsltc.compiler.util.Util;
058    import org.apache.xalan.xsltc.runtime.AbstractTranslet;
059    import org.apache.xml.dtm.DTM;
060    
061    public final class Stylesheet extends SyntaxTreeNode {
062    
063        /**
064         * XSLT version defined in the stylesheet.
065         */
066        private String _version;
067        
068        /**
069         * Internal name of this stylesheet used as a key into the symbol table.
070         */
071        private QName _name;
072        
073        /**
074         * A URI that represents the system ID for this stylesheet.
075         */
076        private String _systemId;
077        
078        /**
079         * A reference to the parent stylesheet or null if topmost.
080         */
081        private Stylesheet _parentStylesheet;
082            
083        /**
084         * Contains global variables and parameters defined in the stylesheet.
085         */
086        private Vector _globals = new Vector();
087    
088        /**
089         * Used to cache the result returned by <code>hasLocalParams()</code>.
090         */
091        private Boolean _hasLocalParams = null;
092    
093        /**
094         * The name of the class being generated.
095         */
096        private String _className;
097        
098        /**
099          * Contains all templates defined in this stylesheet
100          */
101        private final Vector _templates = new Vector();
102        
103        /**
104         * Used to cache result of <code>getAllValidTemplates()</code>. Only
105         * set in top-level stylesheets that include/import other stylesheets.
106         */
107        private Vector _allValidTemplates = null;
108    
109        private Vector _elementsWithNamespacesUsedDynamically = null;
110    
111        /**
112         * Counter to generate unique mode suffixes.
113         */
114        private int _nextModeSerial = 1;
115        
116        /**
117         * Mapping between mode names and Mode instances.
118         */
119        private final Hashtable _modes = new Hashtable();
120        
121        /**
122         * A reference to the default Mode object.
123         */
124        private Mode _defaultMode;
125    
126        /**
127         * Mapping between extension URIs and their prefixes.
128         */
129        private final Hashtable _extensions = new Hashtable();
130    
131        /**
132         * Reference to the stylesheet from which this stylesheet was
133         * imported (if any).
134         */
135        public Stylesheet _importedFrom = null;
136        
137        /**
138         * Reference to the stylesheet from which this stylesheet was
139         * included (if any).
140         */
141        public Stylesheet _includedFrom = null;
142        
143        /** 
144         * Array of all the stylesheets imported or included from this one.
145         */
146        private Vector _includedStylesheets = null;
147        
148        /**
149         * Import precendence for this stylesheet.
150         */
151        private int _importPrecedence = 1;
152    
153        /**
154         * Minimum precendence of any descendant stylesheet by inclusion or
155         * importation.
156         */
157        private int _minimumDescendantPrecedence = -1;
158    
159        /**
160         * Mapping between key names and Key objects (needed by Key/IdPattern).
161         */
162        private Hashtable _keys = new Hashtable();
163    
164        /** 
165         * A reference to the SourceLoader set by the user (a URIResolver
166         * if the JAXP API is being used).
167         */
168        private SourceLoader _loader = null;
169    
170        /**
171         * Flag indicating if format-number() is called.
172         */
173        private boolean _numberFormattingUsed = false;
174    
175        /**
176         * Flag indicating if this is a simplified stylesheets. A template
177         * matching on "/" must be added in this case.
178         */
179        private boolean _simplified = false;
180    
181        /**
182         * Flag indicating if multi-document support is needed.
183         */
184        private boolean _multiDocument = false;
185        
186        /**
187         * Flag indicating if nodset() is called.
188         */
189        private boolean _callsNodeset = false;
190    
191        /**
192         * Flag indicating if id() is called.
193         */
194        private boolean _hasIdCall = false;
195        
196        /**
197         * Set to true to enable template inlining optimization.
198         * @see XSLTC#_templateInlining
199         */
200        private boolean _templateInlining = false;
201    
202        /**
203         * A reference to the last xsl:output object found in the styleshet.
204         */
205        private Output  _lastOutputElement = null;
206        
207        /**
208         * Output properties for this stylesheet.
209         */
210        private Properties _outputProperties = null;
211        
212        /**
213         * Output method for this stylesheet (must be set to one of
214         * the constants defined below).
215         */ 
216        private int _outputMethod = UNKNOWN_OUTPUT;
217    
218        // Output method constants
219        public static final int UNKNOWN_OUTPUT = 0;
220        public static final int XML_OUTPUT     = 1;
221        public static final int HTML_OUTPUT    = 2;
222        public static final int TEXT_OUTPUT    = 3;
223        
224        /**
225         * Return the output method
226         */
227        public int getOutputMethod() {
228            return _outputMethod;
229        }
230        
231        /**
232         * Check and set the output method
233         */
234        private void checkOutputMethod() {
235            if (_lastOutputElement != null) {
236                String method = _lastOutputElement.getOutputMethod();
237                if (method != null) {
238                    if (method.equals("xml"))
239                        _outputMethod = XML_OUTPUT;
240                    else if (method.equals("html"))
241                        _outputMethod = HTML_OUTPUT;
242                    else if (method.equals("text"))
243                        _outputMethod = TEXT_OUTPUT;
244                }
245            }
246        }
247    
248        public boolean getTemplateInlining() {
249            return _templateInlining;
250        }
251    
252        public void setTemplateInlining(boolean flag) {
253            _templateInlining = flag;
254        }
255    
256        public boolean isSimplified() {
257            return(_simplified);
258        }
259    
260        public void setSimplified() {
261            _simplified = true;
262        }
263        
264        public void setHasIdCall(boolean flag) {
265            _hasIdCall = flag;
266        }
267    
268        public void setOutputProperty(String key, String value) {
269            if (_outputProperties == null) {
270                _outputProperties = new Properties();
271            }
272            _outputProperties.setProperty(key, value);
273        }
274    
275        public void setOutputProperties(Properties props) {
276            _outputProperties = props;
277        }
278    
279        public Properties getOutputProperties() {
280            return _outputProperties;
281        }
282    
283        public Output getLastOutputElement() {
284            return _lastOutputElement;
285        }
286        
287        public void setMultiDocument(boolean flag) {        
288            _multiDocument = flag;
289        }
290    
291        public boolean isMultiDocument() {
292            return _multiDocument;
293        }
294    
295        public void setCallsNodeset(boolean flag) {
296            if (flag) setMultiDocument(flag);
297            _callsNodeset = flag;
298        }
299    
300        public boolean callsNodeset() {
301            return _callsNodeset;
302        }
303    
304        public void numberFormattingUsed() {
305            _numberFormattingUsed = true;
306            /*
307             * Fix for bug 23046, if the stylesheet is included, set the 
308             * numberFormattingUsed flag to the parent stylesheet too.
309             * AbstractTranslet.addDecimalFormat() will be inlined once for the
310             * outer most stylesheet. 
311             */ 
312            Stylesheet parent = getParentStylesheet();
313            if (null != parent) parent.numberFormattingUsed();        
314        }
315    
316        public void setImportPrecedence(final int precedence) {
317            // Set import precedence for this stylesheet
318            _importPrecedence = precedence;
319    
320            // Set import precedence for all included stylesheets
321            final Enumeration elements = elements();
322            while (elements.hasMoreElements()) {
323                SyntaxTreeNode child = (SyntaxTreeNode)elements.nextElement();
324                if (child instanceof Include) {
325                    Stylesheet included = ((Include)child).getIncludedStylesheet();
326                    if (included != null && included._includedFrom == this) {
327                        included.setImportPrecedence(precedence);
328                    }
329                }
330            }
331    
332            // Set import precedence for the stylesheet that imported this one
333            if (_importedFrom != null) {
334                if (_importedFrom.getImportPrecedence() < precedence) {
335                    final Parser parser = getParser();
336                    final int nextPrecedence = parser.getNextImportPrecedence();
337                    _importedFrom.setImportPrecedence(nextPrecedence);
338                }
339            }
340            // Set import precedence for the stylesheet that included this one
341            else if (_includedFrom != null) {
342                if (_includedFrom.getImportPrecedence() != precedence)
343                    _includedFrom.setImportPrecedence(precedence);
344            }
345        }
346        
347        public int getImportPrecedence() {
348            return _importPrecedence;
349        }
350    
351        /**
352         * Get the minimum of the precedence of this stylesheet, any stylesheet
353         * imported by this stylesheet and any include/import descendant of this
354         * stylesheet.
355         */
356        public int getMinimumDescendantPrecedence() {
357            if (_minimumDescendantPrecedence == -1) {
358                // Start with precedence of current stylesheet as a basis.
359                int min = getImportPrecedence();
360    
361                // Recursively examine all imported/included stylesheets.
362                final int inclImpCount = (_includedStylesheets != null)
363                                              ? _includedStylesheets.size()
364                                              : 0;
365    
366                for (int i = 0; i < inclImpCount; i++) {
367                    int prec = ((Stylesheet)_includedStylesheets.elementAt(i))
368                                                  .getMinimumDescendantPrecedence();
369    
370                    if (prec < min) {
371                        min = prec;
372                    }
373                }
374    
375                _minimumDescendantPrecedence = min;
376            }
377            return _minimumDescendantPrecedence;
378        }
379    
380        public boolean checkForLoop(String systemId) {
381            // Return true if this stylesheet includes/imports itself
382            if (_systemId != null && _systemId.equals(systemId)) {
383                return true;
384            }
385            // Then check with any stylesheets that included/imported this one
386            if (_parentStylesheet != null) 
387                return _parentStylesheet.checkForLoop(systemId);
388            // Otherwise OK
389            return false;
390        }
391        
392        public void setParser(Parser parser) {
393            super.setParser(parser);
394            _name = makeStylesheetName("__stylesheet_");
395        }
396        
397        public void setParentStylesheet(Stylesheet parent) {
398            _parentStylesheet = parent;
399        }
400        
401        public Stylesheet getParentStylesheet() {
402            return _parentStylesheet;
403        }
404    
405        public void setImportingStylesheet(Stylesheet parent) {
406            _importedFrom = parent;
407            parent.addIncludedStylesheet(this);
408        }
409    
410        public void setIncludingStylesheet(Stylesheet parent) {
411            _includedFrom = parent;
412            parent.addIncludedStylesheet(this);
413        }
414    
415        public void addIncludedStylesheet(Stylesheet child) {
416            if (_includedStylesheets == null) {
417                _includedStylesheets = new Vector();
418            }
419            _includedStylesheets.addElement(child);
420        }
421    
422        public void setSystemId(String systemId) {
423            if (systemId != null) {
424                _systemId = SystemIDResolver.getAbsoluteURI(systemId);
425            }
426        }
427        
428        public String getSystemId() {
429            return _systemId;
430        }
431    
432        public void setSourceLoader(SourceLoader loader) {
433            _loader = loader;
434        }
435        
436        public SourceLoader getSourceLoader() {
437            return _loader;
438        }
439    
440        private QName makeStylesheetName(String prefix) {
441            return getParser().getQName(prefix+getXSLTC().nextStylesheetSerial());
442        }
443    
444        /**
445         * Returns true if this stylesheet has global vars or params.
446         */
447        public boolean hasGlobals() {
448            return _globals.size() > 0;
449        }
450    
451        /**
452         * Returns true if at least one template in the stylesheet has params
453         * defined. Uses the variable <code>_hasLocalParams</code> to cache the
454         * result.
455         */
456        public boolean hasLocalParams() {
457            if (_hasLocalParams == null) {
458                Vector templates = getAllValidTemplates();
459                final int n = templates.size();
460                for (int i = 0; i < n; i++) {
461                    final Template template = (Template)templates.elementAt(i);
462                    if (template.hasParams()) {
463                        _hasLocalParams = Boolean.TRUE;
464                        return true;
465                    }
466                }
467                _hasLocalParams = Boolean.FALSE;
468                return false;
469            }
470            else {
471                return _hasLocalParams.booleanValue();
472            }
473        }
474    
475        /**
476         * Adds a single prefix mapping to this syntax tree node.
477         * @param prefix Namespace prefix.
478         * @param uri Namespace URI.
479         */
480        protected void addPrefixMapping(String prefix, String uri) {
481            if (prefix.equals(EMPTYSTRING) && uri.equals(XHTML_URI)) return;
482            super.addPrefixMapping(prefix, uri);
483        }
484    
485        /**
486         * Store extension URIs
487         */
488        private void extensionURI(String prefixes, SymbolTable stable) {
489            if (prefixes != null) {
490                StringTokenizer tokens = new StringTokenizer(prefixes);
491                while (tokens.hasMoreTokens()) {
492                    final String prefix = tokens.nextToken();
493                    final String uri = lookupNamespace(prefix);
494                    if (uri != null) {
495                        _extensions.put(uri, prefix);
496                    }
497                }
498            }
499        }
500    
501        public boolean isExtension(String uri) {
502            return (_extensions.get(uri) != null);
503        }
504    
505        public void declareExtensionPrefixes(Parser parser) {
506            final SymbolTable stable = parser.getSymbolTable();
507            final String extensionPrefixes = getAttribute("extension-element-prefixes");
508            extensionURI(extensionPrefixes, stable);
509        }
510    
511        /**
512         * Parse the version and uri fields of the stylesheet and add an
513         * entry to the symbol table mapping the name <tt>__stylesheet_</tt>
514         * to an instance of this class.
515         */
516        public void parseContents(Parser parser) {
517            final SymbolTable stable = parser.getSymbolTable();
518    
519            /*
520            // Make sure the XSL version set in this stylesheet
521            if ((_version == null) || (_version.equals(EMPTYSTRING))) {
522                reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR,"version");
523            }
524            // Verify that the version is 1.0 and nothing else
525            else if (!_version.equals("1.0")) {
526                reportError(this, parser, ErrorMsg.XSL_VERSION_ERR, _version);
527            }
528            */
529    
530            // Add the implicit mapping of 'xml' to the XML namespace URI
531            addPrefixMapping("xml", "http://www.w3.org/XML/1998/namespace");
532    
533            // Report and error if more than one stylesheet defined
534            final Stylesheet sheet = stable.addStylesheet(_name, this);
535            if (sheet != null) {
536                // Error: more that one stylesheet defined
537                ErrorMsg err = new ErrorMsg(ErrorMsg.MULTIPLE_STYLESHEET_ERR,this);
538                parser.reportError(Constants.ERROR, err);
539            }
540    
541            // If this is a simplified stylesheet we must create a template that
542            // grabs the root node of the input doc ( <xsl:template match="/"/> ).
543            // This template needs the current element (the one passed to this
544            // method) as its only child, so the Template class has a special
545            // method that handles this (parseSimplified()).
546            if (_simplified) {
547                stable.excludeURI(XSLT_URI);
548                Template template = new Template();
549                template.parseSimplified(this, parser);
550            }
551            // Parse the children of this node
552            else {
553                parseOwnChildren(parser);
554            }
555        }
556    
557        /**
558         * Parse all direct children of the <xsl:stylesheet/> element.
559         */
560        public final void parseOwnChildren(Parser parser) {
561            final SymbolTable stable = parser.getSymbolTable();
562            final String excludePrefixes = getAttribute("exclude-result-prefixes");
563            final String extensionPrefixes = getAttribute("extension-element-prefixes");
564            
565            // Exclude XSLT uri 
566            stable.pushExcludedNamespacesContext();
567            stable.excludeURI(Constants.XSLT_URI);
568            stable.excludeNamespaces(excludePrefixes);
569            stable.excludeNamespaces(extensionPrefixes);
570    
571            final Vector contents = getContents();
572            final int count = contents.size();
573    
574            // We have to scan the stylesheet element's top-level elements for
575            // variables and/or parameters before we parse the other elements
576            for (int i = 0; i < count; i++) {
577                SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
578                if ((child instanceof VariableBase) ||
579                    (child instanceof NamespaceAlias)) {
580                    parser.getSymbolTable().setCurrentNode(child);
581                    child.parseContents(parser);
582                }
583            }
584    
585            // Now go through all the other top-level elements...
586            for (int i = 0; i < count; i++) {
587                SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
588                if (!(child instanceof VariableBase) && 
589                    !(child instanceof NamespaceAlias)) {
590                    parser.getSymbolTable().setCurrentNode(child);
591                    child.parseContents(parser);
592                }
593    
594                // All template code should be compiled as methods if the
595                // <xsl:apply-imports/> element was ever used in this stylesheet
596                if (!_templateInlining && (child instanceof Template)) {
597                    Template template = (Template)child;
598                    String name = "template$dot$" + template.getPosition();
599                    template.setName(parser.getQName(name));
600                }
601            }
602    
603            stable.popExcludedNamespacesContext();
604        }
605    
606        public void processModes() {
607            if (_defaultMode == null)
608                _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
609            _defaultMode.processPatterns(_keys);
610            final Enumeration modes = _modes.elements();
611            while (modes.hasMoreElements()) {
612                final Mode mode = (Mode)modes.nextElement();
613                mode.processPatterns(_keys);
614            }
615        }
616            
617        private void compileModes(ClassGenerator classGen) {
618            _defaultMode.compileApplyTemplates(classGen);
619            final Enumeration modes = _modes.elements();
620            while (modes.hasMoreElements()) {
621                final Mode mode = (Mode)modes.nextElement();
622                mode.compileApplyTemplates(classGen);
623            }
624        }
625    
626        public Mode getMode(QName modeName) {
627            if (modeName == null) {
628                if (_defaultMode == null) {
629                    _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
630                }
631                return _defaultMode;
632            }
633            else {
634                Mode mode = (Mode)_modes.get(modeName);
635                if (mode == null) {
636                    final String suffix = Integer.toString(_nextModeSerial++);
637                    _modes.put(modeName, mode = new Mode(modeName, this, suffix));
638                }
639                return mode;
640            }
641        }
642    
643        /**
644         * Type check all the children of this node.
645         */
646        public Type typeCheck(SymbolTable stable) throws TypeCheckError {
647            final int count = _globals.size();
648            for (int i = 0; i < count; i++) {
649                final VariableBase var = (VariableBase)_globals.elementAt(i);
650                var.typeCheck(stable);
651            }
652            return typeCheckContents(stable);
653        }
654    
655        /**
656         * Translate the stylesheet into JVM bytecodes. 
657         */
658        public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
659            translate();
660        }
661    
662        private void addDOMField(ClassGenerator classGen) {
663            final FieldGen fgen = new FieldGen(ACC_PUBLIC,
664                                               Util.getJCRefType(DOM_INTF_SIG),
665                                               DOM_FIELD,
666                                               classGen.getConstantPool());
667            classGen.addField(fgen.getField());
668        }
669        
670        /**
671         * Add a static field
672         */
673        private void addStaticField(ClassGenerator classGen, String type,
674                                    String name)
675        {
676            final FieldGen fgen = new FieldGen(ACC_PROTECTED|ACC_STATIC,
677                                               Util.getJCRefType(type),
678                                               name,
679                                               classGen.getConstantPool());
680            classGen.addField(fgen.getField());
681    
682        }
683    
684        /**
685         * Translate the stylesheet into JVM bytecodes. 
686         */
687        public void translate() {
688            _className = getXSLTC().getClassName();
689    
690            // Define a new class by extending TRANSLET_CLASS
691            final ClassGenerator classGen =
692                new ClassGenerator(_className,
693                                   TRANSLET_CLASS,
694                                   Constants.EMPTYSTRING,
695                                   ACC_PUBLIC | ACC_SUPER,
696                                   null, this);
697            
698            addDOMField(classGen);
699    
700            // Compile transform() to initialize parameters, globals & output
701            // and run the transformation
702            compileTransform(classGen);
703    
704            // Translate all non-template elements and filter out all templates
705            final Enumeration elements = elements();
706            while (elements.hasMoreElements()) {
707                Object element = elements.nextElement();
708                // xsl:template
709                if (element instanceof Template) {
710                    // Separate templates by modes
711                    final Template template = (Template)element;
712                    //_templates.addElement(template);
713                    getMode(template.getModeName()).addTemplate(template);
714                }
715                // xsl:attribute-set
716                else if (element instanceof AttributeSet) {
717                    ((AttributeSet)element).translate(classGen, null);
718                }
719                else if (element instanceof Output) {
720                    // save the element for later to pass to compileConstructor 
721                    Output output = (Output)element;
722                    if (output.enabled()) _lastOutputElement = output;
723                }
724                else {
725                    // Global variables and parameters are handled elsewhere.
726                    // Other top-level non-template elements are ignored. Literal
727                    // elements outside of templates will never be output.
728                }
729            }
730    
731            checkOutputMethod();
732            processModes();
733            compileModes(classGen);
734            compileStaticInitializer(classGen);
735            compileConstructor(classGen, _lastOutputElement);
736    
737            if (!getParser().errorsFound()) {
738                getXSLTC().dumpClass(classGen.getJavaClass());
739            }
740        }
741    
742        /**
743         * <p>Compile the namesArray, urisArray, typesArray, namespaceArray,
744         * namespaceAncestorsArray, prefixURIsIdxArray and prefixURIPairsArray into
745         * the static initializer. They are read-only from the
746         * translet. All translet instances can share a single
747         * copy of this informtion.</p>
748         * <p>The <code>namespaceAncestorsArray</code>,
749         * <code>prefixURIsIdxArray</code> and <code>prefixURIPairsArray</code>
750         * contain namespace information accessible from the stylesheet:
751         * <dl>
752         * <dt><code>namespaceAncestorsArray</code></dt>
753         * <dd>Array indexed by integer stylesheet node IDs containing node IDs of
754         * the nearest ancestor node in the stylesheet with namespace
755         * declarations or <code>-1</code> if there is no such ancestor.  There
756         * can be more than one disjoint tree of nodes - one for each stylesheet
757         * module</dd>
758         * <dt><code>prefixURIsIdxArray</code></dt>
759         * <dd>Array indexed by integer stylesheet node IDs containing the index
760         * into <code>prefixURIPairsArray</code> of the first namespace prefix
761         * declared for the node.  The values are stored in ascending order, so
762         * the next value in this array (if any) can be used to find the last such
763         * prefix-URI pair</dd>
764         * <dt>prefixURIPairsArray</dt>
765         * <dd>Array of pairs of namespace prefixes and URIs.  A zero-length
766         * string represents the default namespace if it appears as a prefix and
767         * a namespace undeclaration if it appears as a URI.</dd>
768         * </dl>
769         * </p>
770         * <p>For this stylesheet
771         * <pre><code>
772         * &lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"&gt;
773         *   &lt;xsl:template match="/"&gt;
774         *     &lt;xsl:for-each select="*" xmlns:foo="foouri"&gt;
775         *       &lt;xsl:element name="{n}" xmlns:foo="baruri"&gt;
776         *     &lt;/xsl:for-each&gt;
777         *     &lt;out xmlns="lumpit"/&gt;
778         *     &lt;xsl:element name="{n}" xmlns="foouri"/&gt;
779         *     &lt;xsl:element name="{n}" namespace="{ns}" xmlns="limpit"/gt;
780         *   &lt;/xsl:template&gt;
781         * &lt;/xsl:stylesheet&gt;
782         * </code></pre>
783         * there will be four stylesheet nodes whose namespace information is
784         * needed, and
785         * <ul>
786         * <li><code>namespaceAncestorsArray</code> will have the value
787         * <code>[-1,0,1,0]</code>;</li>
788         * <li><code>prefixURIsIdxArray</code> will have the value
789         * <code>[0,4,6,8]</code>; and</li>
790         * <li><code>prefixURIPairsArray</code> will have the value
791         * <code>["xml","http://www.w3.org/XML/1998/namespace",
792         *        "xsl","http://www.w3.org/1999/XSL/Transform"
793         *        "foo","foouri","foo","baruri","","foouri"].</code></li>
794         * </ul>
795         * </p>
796         */
797        private void compileStaticInitializer(ClassGenerator classGen) {
798            final ConstantPoolGen cpg = classGen.getConstantPool();
799            final InstructionList il = new InstructionList();
800    
801            final MethodGenerator staticConst =
802                new MethodGenerator(ACC_PUBLIC|ACC_STATIC,
803                                    org.apache.bcel.generic.Type.VOID, 
804                                    null, null, "<clinit>", 
805                                    _className, il, cpg);
806    
807            addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMES_ARRAY_FIELD);
808            addStaticField(classGen, "[" + STRING_SIG, STATIC_URIS_ARRAY_FIELD);
809            addStaticField(classGen, "[I", STATIC_TYPES_ARRAY_FIELD);
810            addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMESPACE_ARRAY_FIELD);
811            // Create fields of type char[] that will contain literal text from
812            // the stylesheet.
813            final int charDataFieldCount = getXSLTC().getCharacterDataCount();
814            for (int i = 0; i < charDataFieldCount; i++) {
815                addStaticField(classGen, STATIC_CHAR_DATA_FIELD_SIG,
816                               STATIC_CHAR_DATA_FIELD+i);
817            }
818    
819            // Put the names array into the translet - used for dom/translet mapping
820            final Vector namesIndex = getXSLTC().getNamesIndex();
821            int size = namesIndex.size();
822            String[] namesArray = new String[size];
823            String[] urisArray = new String[size];
824            int[] typesArray = new int[size];
825            
826            int index;
827            for (int i = 0; i < size; i++) {
828                String encodedName = (String)namesIndex.elementAt(i);
829                if ((index = encodedName.lastIndexOf(':')) > -1) {
830                    urisArray[i] = encodedName.substring(0, index);
831                }
832                
833                index = index + 1;
834                if (encodedName.charAt(index) == '@') {
835                    typesArray[i] = DTM.ATTRIBUTE_NODE;
836                    index++;
837                } else if (encodedName.charAt(index) == '?') {
838                    typesArray[i] = DTM.NAMESPACE_NODE;
839                    index++;
840                } else {
841                    typesArray[i] = DTM.ELEMENT_NODE;
842                }
843                
844                if (index == 0) {
845                    namesArray[i] = encodedName;
846                }
847                else {
848                    namesArray[i] = encodedName.substring(index);
849                }       
850            }
851    
852            staticConst.markChunkStart();
853            il.append(new PUSH(cpg, size));
854            il.append(new ANEWARRAY(cpg.addClass(STRING)));         
855            int namesArrayRef = cpg.addFieldref(_className,
856                                                STATIC_NAMES_ARRAY_FIELD,
857                                                NAMES_INDEX_SIG);
858            il.append(new PUTSTATIC(namesArrayRef));
859            staticConst.markChunkEnd();
860    
861            for (int i = 0; i < size; i++) {
862                final String name = namesArray[i];
863                staticConst.markChunkStart();
864                il.append(new GETSTATIC(namesArrayRef));
865                il.append(new PUSH(cpg, i));
866                il.append(new PUSH(cpg, name));
867                il.append(AASTORE);
868                staticConst.markChunkEnd();
869            }
870    
871            staticConst.markChunkStart();
872            il.append(new PUSH(cpg, size));
873            il.append(new ANEWARRAY(cpg.addClass(STRING)));         
874            int urisArrayRef = cpg.addFieldref(_className,
875                                               STATIC_URIS_ARRAY_FIELD,
876                                               URIS_INDEX_SIG);
877            il.append(new PUTSTATIC(urisArrayRef));
878            staticConst.markChunkEnd();
879    
880            for (int i = 0; i < size; i++) {
881                final String uri = urisArray[i];
882                staticConst.markChunkStart();
883                il.append(new GETSTATIC(urisArrayRef));
884                il.append(new PUSH(cpg, i));
885                il.append(new PUSH(cpg, uri));
886                il.append(AASTORE);
887                staticConst.markChunkEnd();
888            }
889    
890            staticConst.markChunkStart();
891            il.append(new PUSH(cpg, size));
892            il.append(new NEWARRAY(BasicType.INT));         
893            int typesArrayRef = cpg.addFieldref(_className,
894                                                STATIC_TYPES_ARRAY_FIELD,
895                                                TYPES_INDEX_SIG);
896            il.append(new PUTSTATIC(typesArrayRef));
897            staticConst.markChunkEnd();
898    
899            for (int i = 0; i < size; i++) {
900                final int nodeType = typesArray[i];
901                staticConst.markChunkStart();
902                il.append(new GETSTATIC(typesArrayRef));
903                il.append(new PUSH(cpg, i));
904                il.append(new PUSH(cpg, nodeType));
905                il.append(IASTORE);
906                staticConst.markChunkEnd();
907            }
908    
909            // Put the namespace names array into the translet
910            final Vector namespaces = getXSLTC().getNamespaceIndex();
911            staticConst.markChunkStart();
912            il.append(new PUSH(cpg, namespaces.size()));
913            il.append(new ANEWARRAY(cpg.addClass(STRING)));         
914            int namespaceArrayRef = cpg.addFieldref(_className,
915                                                    STATIC_NAMESPACE_ARRAY_FIELD,
916                                                    NAMESPACE_INDEX_SIG);
917            il.append(new PUTSTATIC(namespaceArrayRef));
918            staticConst.markChunkEnd();
919    
920            for (int i = 0; i < namespaces.size(); i++) {
921                final String ns = (String)namespaces.elementAt(i);
922                staticConst.markChunkStart();
923                il.append(new GETSTATIC(namespaceArrayRef));
924                il.append(new PUSH(cpg, i));
925                il.append(new PUSH(cpg, ns));
926                il.append(AASTORE);
927                staticConst.markChunkEnd();
928            }
929    
930            // Put the tree of stylesheet namespace declarations into the translet
931            final Vector namespaceAncestors = getXSLTC().getNSAncestorPointers();
932            if (namespaceAncestors != null && namespaceAncestors.size() != 0) {
933                addStaticField(classGen, NS_ANCESTORS_INDEX_SIG,
934                               STATIC_NS_ANCESTORS_ARRAY_FIELD);
935                staticConst.markChunkStart();
936                il.append(new PUSH(cpg, namespaceAncestors.size()));
937                il.append(new NEWARRAY(BasicType.INT));
938                int namespaceAncestorsArrayRef =
939                        cpg.addFieldref(_className, STATIC_NS_ANCESTORS_ARRAY_FIELD,
940                                        NS_ANCESTORS_INDEX_SIG);
941                il.append(new PUTSTATIC(namespaceAncestorsArrayRef));
942                staticConst.markChunkEnd();
943                for (int i = 0; i < namespaceAncestors.size(); i++) {
944                    int ancestor = ((Integer) namespaceAncestors.get(i)).intValue();
945                    staticConst.markChunkStart();
946                    il.append(new GETSTATIC(namespaceAncestorsArrayRef));
947                    il.append(new PUSH(cpg, i));
948                    il.append(new PUSH(cpg, ancestor));
949                    il.append(IASTORE);
950                    staticConst.markChunkEnd();
951                }
952            }
953            // Put the array of indices into the namespace prefix/URI pairs array
954            // into the translet
955            final Vector prefixURIPairsIdx = getXSLTC().getPrefixURIPairsIdx();
956            if (prefixURIPairsIdx != null && prefixURIPairsIdx.size() != 0) {
957                addStaticField(classGen, PREFIX_URIS_IDX_SIG,
958                               STATIC_PREFIX_URIS_IDX_ARRAY_FIELD);
959                staticConst.markChunkStart();
960                il.append(new PUSH(cpg, prefixURIPairsIdx.size()));
961                il.append(new NEWARRAY(BasicType.INT));
962                int prefixURIPairsIdxArrayRef = 
963                            cpg.addFieldref(_className,
964                                            STATIC_PREFIX_URIS_IDX_ARRAY_FIELD,
965                                            PREFIX_URIS_IDX_SIG);
966                il.append(new PUTSTATIC(prefixURIPairsIdxArrayRef));
967                staticConst.markChunkEnd();
968                for (int i = 0; i < prefixURIPairsIdx.size(); i++) {
969                    int idx = ((Integer) prefixURIPairsIdx.get(i)).intValue();
970                    staticConst.markChunkStart();
971                    il.append(new GETSTATIC(prefixURIPairsIdxArrayRef));
972                    il.append(new PUSH(cpg, i));
973                    il.append(new PUSH(cpg, idx));
974                    il.append(IASTORE);
975                    staticConst.markChunkEnd();
976                }
977            }
978    
979            // Put the array of pairs of namespace prefixes and URIs into the
980            // translet
981            final Vector prefixURIPairs = getXSLTC().getPrefixURIPairs();
982            if (prefixURIPairs != null && prefixURIPairs.size() != 0) {
983                addStaticField(classGen, PREFIX_URIS_ARRAY_SIG,
984                        STATIC_PREFIX_URIS_ARRAY_FIELD);
985    
986                staticConst.markChunkStart();
987                il.append(new PUSH(cpg, prefixURIPairs.size()));
988                il.append(new ANEWARRAY(cpg.addClass(STRING)));
989                int prefixURIPairsRef = 
990                            cpg.addFieldref(_className,
991                                            STATIC_PREFIX_URIS_ARRAY_FIELD,
992                                            PREFIX_URIS_ARRAY_SIG);
993                il.append(new PUTSTATIC(prefixURIPairsRef));
994                staticConst.markChunkEnd();
995                for (int i = 0; i < prefixURIPairs.size(); i++) {
996                    String prefixOrURI = (String) prefixURIPairs.get(i);
997                    staticConst.markChunkStart();
998                    il.append(new GETSTATIC(prefixURIPairsRef));
999                    il.append(new PUSH(cpg, i));
1000                    il.append(new PUSH(cpg, prefixOrURI));
1001                    il.append(AASTORE);
1002                    staticConst.markChunkEnd();
1003                }
1004            }
1005    
1006            // Grab all the literal text in the stylesheet and put it in a char[]
1007            final int charDataCount = getXSLTC().getCharacterDataCount();
1008            final int toCharArray = cpg.addMethodref(STRING, "toCharArray", "()[C");
1009            for (int i = 0; i < charDataCount; i++) {
1010                staticConst.markChunkStart();
1011                il.append(new PUSH(cpg, getXSLTC().getCharacterData(i)));
1012                il.append(new INVOKEVIRTUAL(toCharArray));
1013                il.append(new PUTSTATIC(cpg.addFieldref(_className,
1014                                                   STATIC_CHAR_DATA_FIELD+i,
1015                                                   STATIC_CHAR_DATA_FIELD_SIG)));
1016                staticConst.markChunkEnd();
1017            }
1018    
1019            il.append(RETURN);
1020    
1021            classGen.addMethod(staticConst);
1022            
1023        }
1024    
1025        /**
1026         * Compile the translet's constructor
1027         */
1028        private void compileConstructor(ClassGenerator classGen, Output output) {
1029    
1030            final ConstantPoolGen cpg = classGen.getConstantPool();
1031            final InstructionList il = new InstructionList();
1032    
1033            final MethodGenerator constructor =
1034                new MethodGenerator(ACC_PUBLIC,
1035                                    org.apache.bcel.generic.Type.VOID, 
1036                                    null, null, "<init>", 
1037                                    _className, il, cpg);
1038    
1039            // Call the constructor in the AbstractTranslet superclass
1040            il.append(classGen.loadTranslet());
1041            il.append(new INVOKESPECIAL(cpg.addMethodref(TRANSLET_CLASS,
1042                                                         "<init>", "()V")));
1043            
1044            constructor.markChunkStart();
1045            il.append(classGen.loadTranslet());
1046            il.append(new GETSTATIC(cpg.addFieldref(_className,
1047                                                    STATIC_NAMES_ARRAY_FIELD,
1048                                                    NAMES_INDEX_SIG)));
1049            il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
1050                                                   NAMES_INDEX,
1051                                                   NAMES_INDEX_SIG)));
1052            constructor.markChunkEnd();
1053            
1054            constructor.markChunkStart();
1055            il.append(classGen.loadTranslet());
1056            il.append(new GETSTATIC(cpg.addFieldref(_className,
1057                                                    STATIC_URIS_ARRAY_FIELD,
1058                                                    URIS_INDEX_SIG)));
1059            il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
1060                                                   URIS_INDEX,
1061                                                   URIS_INDEX_SIG)));
1062            constructor.markChunkEnd();
1063    
1064            constructor.markChunkStart();
1065            il.append(classGen.loadTranslet());
1066            il.append(new GETSTATIC(cpg.addFieldref(_className,
1067                                                    STATIC_TYPES_ARRAY_FIELD,
1068                                                    TYPES_INDEX_SIG)));
1069            il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
1070                                                   TYPES_INDEX,
1071                                                   TYPES_INDEX_SIG)));
1072            constructor.markChunkEnd();
1073    
1074            constructor.markChunkStart();
1075            il.append(classGen.loadTranslet());
1076            il.append(new GETSTATIC(cpg.addFieldref(_className,
1077                                                    STATIC_NAMESPACE_ARRAY_FIELD,
1078                                                    NAMESPACE_INDEX_SIG)));
1079            il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
1080                                                   NAMESPACE_INDEX,
1081                                                   NAMESPACE_INDEX_SIG)));
1082            constructor.markChunkEnd();
1083    
1084            constructor.markChunkStart();
1085            il.append(classGen.loadTranslet());
1086            il.append(new PUSH(cpg, AbstractTranslet.CURRENT_TRANSLET_VERSION));
1087            il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
1088                                                   TRANSLET_VERSION_INDEX,
1089                                                   TRANSLET_VERSION_INDEX_SIG)));
1090            constructor.markChunkEnd();
1091            
1092            if (_hasIdCall) {
1093                constructor.markChunkStart();
1094                il.append(classGen.loadTranslet());
1095                il.append(new PUSH(cpg, Boolean.TRUE));
1096                il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
1097                                                       HASIDCALL_INDEX,
1098                                                       HASIDCALL_INDEX_SIG)));
1099                constructor.markChunkEnd();
1100            }
1101            
1102            // Compile in code to set the output configuration from <xsl:output>
1103            if (output != null) {
1104                // Set all the output settings files in the translet
1105                constructor.markChunkStart();
1106                output.translate(classGen, constructor);
1107                constructor.markChunkEnd();
1108            }
1109    
1110            // Compile default decimal formatting symbols.
1111            // This is an implicit, nameless xsl:decimal-format top-level element.
1112            if (_numberFormattingUsed) {
1113                constructor.markChunkStart();
1114                DecimalFormatting.translateDefaultDFS(classGen, constructor);
1115                constructor.markChunkEnd();
1116            }
1117    
1118            il.append(RETURN);
1119    
1120            classGen.addMethod(constructor);
1121        }
1122    
1123        /**
1124         * Compile a topLevel() method into the output class. This method is 
1125         * called from transform() to handle all non-template top-level elements.
1126         * Returns the signature of the topLevel() method.
1127         *
1128         * Global variables/params and keys are first sorted to resolve 
1129         * dependencies between them. The XSLT 1.0 spec does not allow a key 
1130         * to depend on a variable. However, for compatibility with Xalan
1131         * interpretive, that type of dependency is allowed. Note also that
1132         * the buildKeys() method is still generated as it is used by the 
1133         * LoadDocument class, but it no longer called from transform().
1134         */
1135        private String compileTopLevel(ClassGenerator classGen) {
1136            final ConstantPoolGen cpg = classGen.getConstantPool();
1137    
1138            final org.apache.bcel.generic.Type[] argTypes = {
1139                Util.getJCRefType(DOM_INTF_SIG),
1140                Util.getJCRefType(NODE_ITERATOR_SIG),
1141                Util.getJCRefType(TRANSLET_OUTPUT_SIG)
1142            };
1143    
1144            final String[] argNames = {
1145                DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME
1146            };
1147    
1148            final InstructionList il = new InstructionList();
1149    
1150            final MethodGenerator toplevel =
1151                new MethodGenerator(ACC_PUBLIC,
1152                                    org.apache.bcel.generic.Type.VOID,
1153                                    argTypes, argNames,
1154                                    "topLevel", _className, il,
1155                                    classGen.getConstantPool());
1156    
1157            toplevel.addException("org.apache.xalan.xsltc.TransletException");
1158    
1159            // Define and initialize 'current' variable with the root node
1160            final LocalVariableGen current = 
1161                toplevel.addLocalVariable("current",
1162                                          org.apache.bcel.generic.Type.INT,
1163                                          null, null);
1164    
1165            final int setFilter = cpg.addInterfaceMethodref(DOM_INTF,
1166                                   "setFilter",
1167                                   "(Lorg/apache/xalan/xsltc/StripFilter;)V");
1168    
1169            final int gitr = cpg.addInterfaceMethodref(DOM_INTF,
1170                                                            "getIterator",
1171                                                            "()"+NODE_ITERATOR_SIG);
1172            il.append(toplevel.loadDOM());
1173            il.append(new INVOKEINTERFACE(gitr, 1));
1174            il.append(toplevel.nextNode());
1175            current.setStart(il.append(new ISTORE(current.getIndex())));
1176    
1177        // Create a new list containing variables/params + keys
1178        Vector varDepElements = new Vector(_globals);        
1179        Enumeration elements = elements();
1180        while (elements.hasMoreElements()) {
1181            final Object element = elements.nextElement();
1182            if (element instanceof Key) {
1183                varDepElements.add(element);
1184            }
1185        }
1186                
1187        // Determine a partial order for the variables/params and keys
1188        varDepElements = resolveDependencies(varDepElements);
1189        
1190        // Translate vars/params and keys in the right order
1191        final int count = varDepElements.size();
1192        for (int i = 0; i < count; i++) {
1193            final TopLevelElement tle = (TopLevelElement) varDepElements.elementAt(i);            
1194            tle.translate(classGen, toplevel);            
1195            if (tle instanceof Key) {
1196                final Key key = (Key) tle;
1197                _keys.put(key.getName(), key);
1198            }
1199        }
1200    
1201        // Compile code for other top-level elements
1202        Vector whitespaceRules = new Vector();
1203        elements = elements();
1204            while (elements.hasMoreElements()) {
1205                final Object element = elements.nextElement();
1206                // xsl:decimal-format
1207                if (element instanceof DecimalFormatting) {
1208                    ((DecimalFormatting)element).translate(classGen,toplevel);
1209                }
1210                // xsl:strip/preserve-space
1211                else if (element instanceof Whitespace) {
1212                    whitespaceRules.addAll(((Whitespace)element).getRules());
1213                }
1214            }
1215    
1216            // Translate all whitespace strip/preserve rules
1217            if (whitespaceRules.size() > 0) {
1218                Whitespace.translateRules(whitespaceRules,classGen);
1219            }
1220    
1221            if (classGen.containsMethod(STRIP_SPACE, STRIP_SPACE_PARAMS) != null) {
1222                il.append(toplevel.loadDOM());
1223                il.append(classGen.loadTranslet());
1224                il.append(new INVOKEINTERFACE(setFilter, 2));
1225            }
1226    
1227            il.append(RETURN);
1228    
1229            // Compute max locals + stack and add method to class
1230            classGen.addMethod(toplevel);
1231            
1232            return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+")V");
1233        }
1234        
1235        /**
1236         * This method returns a vector with variables/params and keys in the 
1237         * order in which they are to be compiled for initialization. The order
1238         * is determined by analyzing the dependencies between them. The XSLT 1.0 
1239         * spec does not allow a key to depend on a variable. However, for 
1240         * compatibility with Xalan interpretive, that type of dependency is 
1241         * allowed and, therefore, consider to determine the partial order.
1242         */
1243        private Vector resolveDependencies(Vector input) {
1244            /* DEBUG CODE - INGORE 
1245            for (int i = 0; i < input.size(); i++) {
1246                final TopLevelElement e = (TopLevelElement) input.elementAt(i);
1247                System.out.println("e = " + e + " depends on:");
1248                Vector dep = e.getDependencies();
1249                for (int j = 0; j < (dep != null ? dep.size() : 0); j++) {
1250                    System.out.println("\t" + dep.elementAt(j));
1251                }
1252            }
1253            System.out.println("=================================");        
1254            */
1255    
1256            Vector result = new Vector();
1257            while (input.size() > 0) {
1258                boolean changed = false;
1259                for (int i = 0; i < input.size(); ) {
1260                    final TopLevelElement vde = (TopLevelElement) input.elementAt(i);
1261                    final Vector dep = vde.getDependencies();
1262                    if (dep == null || result.containsAll(dep)) {
1263                        result.addElement(vde);
1264                        input.remove(i);
1265                        changed = true;
1266                    }
1267                    else {
1268                        i++;
1269                    }
1270                }
1271    
1272                // If nothing was changed in this pass then we have a circular ref
1273                if (!changed) {
1274                    ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR,
1275                                                input.toString(), this);
1276                    getParser().reportError(Constants.ERROR, err);
1277                    return(result);
1278                }
1279            }
1280    
1281            /* DEBUG CODE - INGORE 
1282            System.out.println("=================================");
1283            for (int i = 0; i < result.size(); i++) {
1284                final TopLevelElement e = (TopLevelElement) result.elementAt(i);
1285                System.out.println("e = " + e);
1286            }
1287            */
1288    
1289            return result;
1290        }
1291    
1292        /**
1293         * Compile a buildKeys() method into the output class. Note that keys 
1294         * for the input document are created in topLevel(), not in this method. 
1295         * However, we still need this method to create keys for documents loaded
1296         * via the XPath document() function. 
1297         */
1298        private String compileBuildKeys(ClassGenerator classGen) {
1299            final ConstantPoolGen cpg = classGen.getConstantPool();
1300    
1301            final org.apache.bcel.generic.Type[] argTypes = {
1302                Util.getJCRefType(DOM_INTF_SIG),
1303                Util.getJCRefType(NODE_ITERATOR_SIG),
1304                Util.getJCRefType(TRANSLET_OUTPUT_SIG),
1305                org.apache.bcel.generic.Type.INT
1306            };
1307    
1308            final String[] argNames = {
1309                DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME, "current"
1310            };
1311    
1312            final InstructionList il = new InstructionList();
1313    
1314            final MethodGenerator buildKeys =
1315                new MethodGenerator(ACC_PUBLIC,
1316                                    org.apache.bcel.generic.Type.VOID,
1317                                    argTypes, argNames,
1318                                    "buildKeys", _className, il,
1319                                    classGen.getConstantPool());
1320    
1321            buildKeys.addException("org.apache.xalan.xsltc.TransletException");
1322            
1323            final Enumeration elements = elements();
1324            while (elements.hasMoreElements()) {
1325                // xsl:key
1326                final Object element = elements.nextElement();
1327                if (element instanceof Key) {
1328                    final Key key = (Key)element;
1329                    key.translate(classGen, buildKeys);
1330                    _keys.put(key.getName(),key);
1331                }
1332            }
1333            
1334            il.append(RETURN);
1335            
1336            // Add method to class
1337            classGen.addMethod(buildKeys);
1338            
1339            return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+"I)V");
1340        }
1341    
1342        /**
1343         * Compile transform() into the output class. This method is used to 
1344         * initialize global variables and global parameters. The current node
1345         * is set to be the document's root node.
1346         */
1347        private void compileTransform(ClassGenerator classGen) {
1348            final ConstantPoolGen cpg = classGen.getConstantPool();
1349    
1350            /* 
1351             * Define the the method transform with the following signature:
1352             * void transform(DOM, NodeIterator, HandlerBase)
1353             */
1354            final org.apache.bcel.generic.Type[] argTypes = 
1355                new org.apache.bcel.generic.Type[3];
1356            argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
1357            argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
1358            argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
1359    
1360            final String[] argNames = new String[3];
1361            argNames[0] = DOCUMENT_PNAME;
1362            argNames[1] = ITERATOR_PNAME;
1363            argNames[2] = TRANSLET_OUTPUT_PNAME;
1364    
1365            final InstructionList il = new InstructionList();
1366            final MethodGenerator transf =
1367                new MethodGenerator(ACC_PUBLIC,
1368                                    org.apache.bcel.generic.Type.VOID,
1369                                    argTypes, argNames,
1370                                    "transform",
1371                                    _className,
1372                                    il,
1373                                    classGen.getConstantPool());
1374            transf.addException("org.apache.xalan.xsltc.TransletException");
1375    
1376            // Define and initialize current with the root node
1377            final LocalVariableGen current = 
1378                transf.addLocalVariable("current",
1379                                        org.apache.bcel.generic.Type.INT,
1380                                        null, null);
1381            final String applyTemplatesSig = classGen.getApplyTemplatesSig();
1382            final int applyTemplates = cpg.addMethodref(getClassName(),
1383                                                        "applyTemplates",
1384                                                        applyTemplatesSig);
1385            final int domField = cpg.addFieldref(getClassName(),
1386                                                 DOM_FIELD,
1387                                                 DOM_INTF_SIG);
1388    
1389            // push translet for PUTFIELD
1390            il.append(classGen.loadTranslet());
1391            // prepare appropriate DOM implementation
1392            
1393            if (isMultiDocument()) {
1394                il.append(new NEW(cpg.addClass(MULTI_DOM_CLASS)));
1395                il.append(DUP);
1396            }
1397            
1398            il.append(classGen.loadTranslet());
1399            il.append(transf.loadDOM());
1400            il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
1401                                                         "makeDOMAdapter",
1402                                                         "("+DOM_INTF_SIG+")"+
1403                                                         DOM_ADAPTER_SIG)));
1404            // DOMAdapter is on the stack
1405    
1406            if (isMultiDocument()) {
1407                final int init = cpg.addMethodref(MULTI_DOM_CLASS,
1408                                                  "<init>",
1409                                                  "("+DOM_INTF_SIG+")V");
1410                il.append(new INVOKESPECIAL(init));
1411                // MultiDOM is on the stack
1412            }
1413            
1414            //store to _dom variable
1415            il.append(new PUTFIELD(domField));
1416    
1417            // continue with globals initialization
1418            final int gitr = cpg.addInterfaceMethodref(DOM_INTF,
1419                                                            "getIterator",
1420                                                            "()"+NODE_ITERATOR_SIG);
1421            il.append(transf.loadDOM());
1422            il.append(new INVOKEINTERFACE(gitr, 1));
1423            il.append(transf.nextNode());
1424            current.setStart(il.append(new ISTORE(current.getIndex())));
1425    
1426            // Transfer the output settings to the output post-processor
1427            il.append(classGen.loadTranslet());
1428            il.append(transf.loadHandler());
1429            final int index = cpg.addMethodref(TRANSLET_CLASS,
1430                                               "transferOutputSettings",
1431                                               "("+OUTPUT_HANDLER_SIG+")V");
1432            il.append(new INVOKEVIRTUAL(index));
1433    
1434            /*
1435             * Compile buildKeys() method. Note that this method is not 
1436             * invoked here as keys for the input document are now created
1437             * in topLevel(). However, this method is still needed by the
1438             * LoadDocument class.
1439             */        
1440            final String keySig = compileBuildKeys(classGen);
1441            final int keyIdx = cpg.addMethodref(getClassName(),
1442                                                   "buildKeys", keySig);
1443                    
1444            // Look for top-level elements that need handling
1445            final Enumeration toplevel = elements();
1446            if (_globals.size() > 0 || toplevel.hasMoreElements()) {
1447                // Compile method for handling top-level elements
1448                final String topLevelSig = compileTopLevel(classGen);
1449                // Get a reference to that method
1450                final int topLevelIdx = cpg.addMethodref(getClassName(),
1451                                                         "topLevel",
1452                                                         topLevelSig);
1453                // Push all parameters on the stack and call topLevel()
1454                il.append(classGen.loadTranslet()); // The 'this' pointer
1455                il.append(classGen.loadTranslet());
1456                il.append(new GETFIELD(domField));  // The DOM reference
1457                il.append(transf.loadIterator());
1458                il.append(transf.loadHandler());    // The output handler
1459                il.append(new INVOKEVIRTUAL(topLevelIdx));
1460            }       
1461    
1462            // start document
1463            il.append(transf.loadHandler());
1464            il.append(transf.startDocument());
1465    
1466            // push first arg for applyTemplates
1467            il.append(classGen.loadTranslet());
1468            // push translet for GETFIELD to get DOM arg
1469            il.append(classGen.loadTranslet());
1470            il.append(new GETFIELD(domField));
1471            // push remaining 2 args
1472            il.append(transf.loadIterator());
1473            il.append(transf.loadHandler());
1474            il.append(new INVOKEVIRTUAL(applyTemplates));
1475            // endDocument
1476            il.append(transf.loadHandler());
1477            il.append(transf.endDocument());
1478    
1479            il.append(RETURN);
1480    
1481            // Compute max locals + stack and add method to class
1482            classGen.addMethod(transf);
1483        }
1484    
1485        /**
1486         * Peephole optimization: Remove sequences of [ALOAD, POP].
1487         */
1488        private void peepHoleOptimization(MethodGenerator methodGen) {
1489            final String pattern = "`aload'`pop'`instruction'";
1490            final InstructionList il = methodGen.getInstructionList();
1491            final InstructionFinder find = new InstructionFinder(il);
1492            for(Iterator iter=find.search(pattern); iter.hasNext(); ) {
1493                InstructionHandle[] match = (InstructionHandle[])iter.next();
1494                try {
1495                    il.delete(match[0], match[1]);
1496                } 
1497                catch (TargetLostException e) {
1498                    // TODO: move target down into the list
1499                }
1500            }
1501        }
1502    
1503        public int addParam(Param param) {
1504            _globals.addElement(param);
1505            return _globals.size() - 1;
1506        }
1507    
1508        public int addVariable(Variable global) {
1509            _globals.addElement(global);
1510            return _globals.size() - 1;
1511        }
1512    
1513        public void display(int indent) {
1514            indent(indent);
1515            Util.println("Stylesheet");
1516            displayContents(indent + IndentIncrement);
1517        }
1518    
1519        // do we need this wrapper ?????
1520        public String getNamespace(String prefix) {
1521            return lookupNamespace(prefix);
1522        }
1523    
1524        public String getClassName() {
1525            return _className;
1526        }
1527    
1528        public Vector getTemplates() {
1529            return _templates;
1530        }
1531    
1532        public Vector getAllValidTemplates() {
1533            // Return templates if no imported/included stylesheets
1534            if (_includedStylesheets == null) {
1535                return _templates;
1536            }
1537            
1538            // Is returned value cached?
1539            if (_allValidTemplates == null) {
1540               Vector templates = new Vector();
1541                int size = _includedStylesheets.size();
1542                for (int i = 0; i < size; i++) {
1543                    Stylesheet included =(Stylesheet)_includedStylesheets.elementAt(i);
1544                    templates.addAll(included.getAllValidTemplates());
1545                }
1546                templates.addAll(_templates);
1547    
1548                // Cache results in top-level stylesheet only
1549                if (_parentStylesheet != null) {
1550                    return templates;
1551                }
1552                _allValidTemplates = templates;
1553             }
1554            
1555            return _allValidTemplates;
1556        }
1557        
1558        protected void addTemplate(Template template) {
1559            _templates.addElement(template);
1560        }
1561    }