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