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: DocumentCall.java 1225842 2011-12-30 15:14:35Z mrglavas $
020     */
021    
022    package org.apache.xalan.xsltc.compiler;
023    
024    import java.util.Vector;
025    
026    import org.apache.bcel.generic.ConstantPoolGen;
027    import org.apache.bcel.generic.GETFIELD;
028    import org.apache.bcel.generic.INVOKESTATIC;
029    import org.apache.bcel.generic.InstructionList;
030    import org.apache.bcel.generic.PUSH;
031    import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
032    import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
033    import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
034    import org.apache.xalan.xsltc.compiler.util.Type;
035    import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
036    
037    /**
038     * @author Jacek Ambroziak
039     * @author Morten Jorgensen
040     */
041    final class DocumentCall extends FunctionCall {
042    
043        private Expression _arg1 = null;
044        private Expression _arg2 = null;
045        private Type       _arg1Type;
046    
047        /**
048         * Default function call constructor
049         */
050        public DocumentCall(QName fname, Vector arguments) {
051            super(fname, arguments);
052        }
053    
054        /**
055         * Type checks the arguments passed to the document() function. The first
056         * argument can be any type (we must cast it to a string) and contains the
057         * URI of the document
058         */
059        public Type typeCheck(SymbolTable stable) throws TypeCheckError {
060            // At least one argument - two at most
061            final int ac = argumentCount();
062            if ((ac < 1) || (ac > 2)) {
063                ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ARG_ERR, this);
064                throw new TypeCheckError(msg);
065            }
066            if (getStylesheet() == null) {
067                ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ARG_ERR, this);
068                throw new TypeCheckError(msg);
069            }
070    
071            // Parse the first argument 
072            _arg1 = argument(0);
073    
074            if (_arg1 == null) {// should not happened 
075                ErrorMsg msg = new ErrorMsg(ErrorMsg.DOCUMENT_ARG_ERR, this);
076                throw new TypeCheckError(msg);
077            }
078    
079            _arg1Type = _arg1.typeCheck(stable);
080            if ((_arg1Type != Type.NodeSet) && (_arg1Type != Type.String)) {
081                _arg1 = new CastExpr(_arg1, Type.String);
082            }
083    
084            // Parse the second argument 
085            if (ac == 2) {
086                _arg2 = argument(1);
087    
088                if (_arg2 == null) {// should not happened 
089                    ErrorMsg msg = new ErrorMsg(ErrorMsg.DOCUMENT_ARG_ERR, this);
090                    throw new TypeCheckError(msg);
091                }
092    
093                final Type arg2Type = _arg2.typeCheck(stable);
094    
095                if (arg2Type.identicalTo(Type.Node)) {
096                    _arg2 = new CastExpr(_arg2, Type.NodeSet);
097                } else if (arg2Type.identicalTo(Type.NodeSet)) {
098                    // falls through
099                } else {
100                    ErrorMsg msg = new ErrorMsg(ErrorMsg.DOCUMENT_ARG_ERR, this);
101                    throw new TypeCheckError(msg);
102                }
103            }
104    
105            return _type = Type.NodeSet;
106        }
107        
108        /**
109         * Translates the document() function call to a call to LoadDocument()'s
110         * static method document().
111         */
112        public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
113            final ConstantPoolGen cpg = classGen.getConstantPool();
114            final InstructionList il = methodGen.getInstructionList();
115            final int ac = argumentCount();
116    
117            final int domField = cpg.addFieldref(classGen.getClassName(),
118                                                 DOM_FIELD,
119                                                 DOM_INTF_SIG);
120              
121            String docParamList = null;
122            if (ac == 1) {
123               // documentF(Object,String,AbstractTranslet,DOM)
124               docParamList = "("+OBJECT_SIG+STRING_SIG+TRANSLET_SIG+DOM_INTF_SIG
125                             +")"+NODE_ITERATOR_SIG;
126            } else { //ac == 2; ac < 1 or as >2  was tested in typeChec()
127               // documentF(Object,DTMAxisIterator,String,AbstractTranslet,DOM)
128               docParamList = "("+OBJECT_SIG+NODE_ITERATOR_SIG+STRING_SIG
129                             +TRANSLET_SIG+DOM_INTF_SIG+")"+NODE_ITERATOR_SIG;  
130            }
131            final int docIdx = cpg.addMethodref(LOAD_DOCUMENT_CLASS, "documentF",
132                                                docParamList);
133    
134    
135            // The URI can be either a node-set or something else cast to a string
136            _arg1.translate(classGen, methodGen);
137            if (_arg1Type == Type.NodeSet) {
138                _arg1.startIterator(classGen, methodGen);
139            }
140    
141            if (ac == 2) {
142                //_arg2 == null was tested in typeChec()
143                _arg2.translate(classGen, methodGen);
144                _arg2.startIterator(classGen, methodGen);       
145            }
146        
147            // Process the rest of the parameters on the stack
148            il.append(new PUSH(cpg, getStylesheet().getSystemId()));
149            il.append(classGen.loadTranslet());
150            il.append(DUP);
151            il.append(new GETFIELD(domField));
152            il.append(new INVOKESTATIC(docIdx));
153        }
154    
155    }