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: ApplyImports.java 469276 2006-10-30 21:09:47Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.compiler;
023    
024    import org.apache.bcel.generic.ConstantPoolGen;
025    import org.apache.bcel.generic.INVOKEVIRTUAL;
026    import org.apache.bcel.generic.InstructionList;
027    import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
028    import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
029    import org.apache.xalan.xsltc.compiler.util.Type;
030    import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
031    import org.apache.xalan.xsltc.compiler.util.Util;
032    
033    final class ApplyImports extends Instruction {
034    
035        private QName      _modeName;
036        private int        _precedence;
037    
038        public void display(int indent) {
039            indent(indent);
040            Util.println("ApplyTemplates");
041            indent(indent + IndentIncrement);
042            if (_modeName != null) {
043                indent(indent + IndentIncrement);
044                Util.println("mode " + _modeName);
045            }
046        }
047    
048        /**
049         * Returns true if this <xsl:apply-imports/> element has parameters
050         */
051        public boolean hasWithParams() {
052            return hasContents();
053        }
054    
055        /**
056         * Determine the lowest import precedence for any stylesheet imported
057         * or included by the stylesheet in which this <xsl:apply-imports/>
058         * element occured. The templates that are imported by the stylesheet in
059         * which this element occured will all have higher import precedence than
060         * the integer returned by this method.
061         */
062        private int getMinPrecedence(int max) {
063            // Move to root of include tree
064            Stylesheet includeRoot = getStylesheet();
065            while (includeRoot._includedFrom != null) {
066                includeRoot = includeRoot._includedFrom;
067            }
068    
069            return includeRoot.getMinimumDescendantPrecedence();
070        }
071    
072        /**
073         * Parse the attributes and contents of an <xsl:apply-imports/> element.
074         */
075        public void parseContents(Parser parser) {
076            // Indicate to the top-level stylesheet that all templates must be
077            // compiled into separate methods.
078            Stylesheet stylesheet = getStylesheet();
079            stylesheet.setTemplateInlining(false);
080    
081            // Get the mode we are currently in (might not be any)
082            Template template = getTemplate();
083            _modeName = template.getModeName();
084            _precedence = template.getImportPrecedence();
085    
086            parseChildren(parser);  // with-params
087        }
088    
089        /**
090         * Type-check the attributes/contents of an <xsl:apply-imports/> element.
091         */
092        public Type typeCheck(SymbolTable stable) throws TypeCheckError {
093            typeCheckContents(stable);              // with-params
094            return Type.Void;
095        }
096    
097        /**
098         * Translate call-template. A parameter frame is pushed only if
099         * some template in the stylesheet uses parameters. 
100         */
101        public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
102            final Stylesheet stylesheet = classGen.getStylesheet();
103            final ConstantPoolGen cpg = classGen.getConstantPool();
104            final InstructionList il = methodGen.getInstructionList();
105            final int current = methodGen.getLocalIndex("current");
106    
107            // Push the arguments that are passed to applyTemplates()
108            il.append(classGen.loadTranslet());
109            il.append(methodGen.loadDOM());
110        il.append(methodGen.loadIterator());
111            il.append(methodGen.loadHandler());
112        il.append(methodGen.loadCurrentNode());
113    
114            // Push a new parameter frame in case imported template might expect
115            // parameters.  The apply-imports has nothing that it can pass.
116            if (stylesheet.hasLocalParams()) {
117                il.append(classGen.loadTranslet());
118                final int pushFrame = cpg.addMethodref(TRANSLET_CLASS,
119                                                       PUSH_PARAM_FRAME,
120                                                       PUSH_PARAM_FRAME_SIG);
121                il.append(new INVOKEVIRTUAL(pushFrame));
122            }
123    
124            // Get the [min,max> precedence of all templates imported under the
125            // current stylesheet
126            final int maxPrecedence = _precedence;
127            final int minPrecedence = getMinPrecedence(maxPrecedence);
128            final Mode mode = stylesheet.getMode(_modeName);
129    
130            // Get name of appropriate apply-templates function for this
131            // xsl:apply-imports instruction
132            String functionName = mode.functionName(minPrecedence, maxPrecedence);
133    
134            // Construct the translet class-name and the signature of the method
135            final String className = classGen.getStylesheet().getClassName();
136            final String signature = classGen.getApplyTemplatesSigForImport();
137            final int applyTemplates = cpg.addMethodref(className,
138                                                        functionName,
139                                                        signature);
140            il.append(new INVOKEVIRTUAL(applyTemplates));
141    
142            // Pop any parameter frame that was pushed above.
143            if (stylesheet.hasLocalParams()) {
144                il.append(classGen.loadTranslet());
145                final int pushFrame = cpg.addMethodref(TRANSLET_CLASS,
146                                                       POP_PARAM_FRAME,
147                                                       POP_PARAM_FRAME_SIG);
148                il.append(new INVOKEVIRTUAL(pushFrame));
149            }
150        }
151    
152    }