1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xalan.internal.xsltc.compiler;
23
24import java.util.Vector;
25
26import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
27import com.sun.org.apache.bcel.internal.generic.GETFIELD;
28import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
29import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
30import com.sun.org.apache.bcel.internal.generic.InstructionList;
31import com.sun.org.apache.bcel.internal.generic.PUSH;
32import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
33import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
34import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
35import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
36import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
37
38/**
39 * @author Jacek Ambroziak
40 * @author Morten Jorgensen
41 */
42final class DocumentCall extends FunctionCall {
43
44    private Expression _arg1 = null;
45    private Expression _arg2 = null;
46    private Type       _arg1Type;
47
48    /**
49     * Default function call constructor
50     */
51    public DocumentCall(QName fname, Vector arguments) {
52        super(fname, arguments);
53    }
54
55    /**
56     * Type checks the arguments passed to the document() function. The first
57     * argument can be any type (we must cast it to a string) and contains the
58     * URI of the document
59     */
60    public Type typeCheck(SymbolTable stable) throws TypeCheckError {
61        // At least one argument - two at most
62        final int ac = argumentCount();
63        if ((ac < 1) || (ac > 2)) {
64            ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ARG_ERR, this);
65            throw new TypeCheckError(msg);
66        }
67        if (getStylesheet() == null) {
68            ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ARG_ERR, this);
69            throw new TypeCheckError(msg);
70        }
71
72        // Parse the first argument
73        _arg1 = argument(0);
74
75        if (_arg1 == null) {// should not happened
76            ErrorMsg msg = new ErrorMsg(ErrorMsg.DOCUMENT_ARG_ERR, this);
77            throw new TypeCheckError(msg);
78        }
79
80        _arg1Type = _arg1.typeCheck(stable);
81        if ((_arg1Type != Type.NodeSet) && (_arg1Type != Type.String)) {
82            _arg1 = new CastExpr(_arg1, Type.String);
83        }
84
85        // Parse the second argument
86        if (ac == 2) {
87            _arg2 = argument(1);
88
89            if (_arg2 == null) {// should not happened
90                ErrorMsg msg = new ErrorMsg(ErrorMsg.DOCUMENT_ARG_ERR, this);
91                throw new TypeCheckError(msg);
92            }
93
94            final Type arg2Type = _arg2.typeCheck(stable);
95
96            if (arg2Type.identicalTo(Type.Node)) {
97                _arg2 = new CastExpr(_arg2, Type.NodeSet);
98            } else if (arg2Type.identicalTo(Type.NodeSet)) {
99                // falls through
100            } else {
101                ErrorMsg msg = new ErrorMsg(ErrorMsg.DOCUMENT_ARG_ERR, this);
102                throw new TypeCheckError(msg);
103            }
104        }
105
106        return _type = Type.NodeSet;
107    }
108
109    /**
110     * Translates the document() function call to a call to LoadDocument()'s
111     * static method document().
112     */
113    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
114        final ConstantPoolGen cpg = classGen.getConstantPool();
115        final InstructionList il = methodGen.getInstructionList();
116        final int ac = argumentCount();
117
118        final int domField = cpg.addFieldref(classGen.getClassName(),
119                                             DOM_FIELD,
120                                             DOM_INTF_SIG);
121
122        String docParamList = null;
123        if (ac == 1) {
124           // documentF(Object,String,AbstractTranslet,DOM)
125           docParamList = "("+OBJECT_SIG+STRING_SIG+TRANSLET_SIG+DOM_INTF_SIG
126                         +")"+NODE_ITERATOR_SIG;
127        } else { //ac == 2; ac < 1 or as >2  was tested in typeChec()
128           // documentF(Object,DTMAxisIterator,String,AbstractTranslet,DOM)
129           docParamList = "("+OBJECT_SIG+NODE_ITERATOR_SIG+STRING_SIG
130                         +TRANSLET_SIG+DOM_INTF_SIG+")"+NODE_ITERATOR_SIG;
131        }
132        final int docIdx = cpg.addMethodref(LOAD_DOCUMENT_CLASS, "documentF",
133                                            docParamList);
134
135
136        // The URI can be either a node-set or something else cast to a string
137        _arg1.translate(classGen, methodGen);
138        if (_arg1Type == Type.NodeSet) {
139            _arg1.startIterator(classGen, methodGen);
140        }
141
142        if (ac == 2) {
143            //_arg2 == null was tested in typeChec()
144            _arg2.translate(classGen, methodGen);
145            _arg2.startIterator(classGen, methodGen);
146        }
147
148        // Feck the rest of the parameters on the stack
149        il.append(new PUSH(cpg, getStylesheet().getSystemId()));
150        il.append(classGen.loadTranslet());
151        il.append(DUP);
152        il.append(new GETFIELD(domField));
153        il.append(new INVOKESTATIC(docIdx));
154    }
155
156}
157