1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   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 
  22 package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
  23 
  24 import com.sun.org.apache.bcel.internal.generic.ALOAD;
  25 import com.sun.org.apache.bcel.internal.generic.ASTORE;
  26 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  27 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  28 import com.sun.org.apache.bcel.internal.generic.GOTO;
  29 import com.sun.org.apache.bcel.internal.generic.IFLT;
  30 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  31 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  32 import com.sun.org.apache.bcel.internal.generic.Instruction;
  33 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  34 import com.sun.org.apache.bcel.internal.generic.PUSH;
  35 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
  37 
  38 /**
  39  * @author Jacek Ambroziak
  40  * @author Santiago Pericas-Geertsen
  41  */
  42 public final class NodeSetType extends Type {
  43     protected NodeSetType() {}
  44 
  45     public String toString() {
  46         return "node-set";
  47     }
  48 
  49     public boolean identicalTo(Type other) {
  50         return this == other;
  51     }
  52 
  53     public String toSignature() {
  54         return NODE_ITERATOR_SIG;
  55     }
  56 
  57     public com.sun.org.apache.bcel.internal.generic.Type toJCType() {
  58         return new com.sun.org.apache.bcel.internal.generic.ObjectType(NODE_ITERATOR);
  59     }
  60 
  61     /**
  62      * Translates a node-set into an object of internal type
  63      * <code>type</code>. The translation to int is undefined
  64      * since node-sets are always converted to
  65      * reals in arithmetic expressions.
  66      *
  67      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  68      */
  69     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  70                             Type type) {
  71         if (type == Type.String) {
  72             translateTo(classGen, methodGen, (StringType) type);
  73         }
  74         else if (type == Type.Boolean) {
  75             translateTo(classGen, methodGen, (BooleanType) type);
  76         }
  77         else if (type == Type.Real) {
  78             translateTo(classGen, methodGen, (RealType) type);
  79         }
  80         else if (type == Type.Node) {
  81             translateTo(classGen, methodGen, (NodeType) type);
  82         }
  83         else if (type == Type.Reference) {
  84             translateTo(classGen, methodGen, (ReferenceType) type);
  85         }
  86         else if (type == Type.Object) {
  87             translateTo(classGen, methodGen, (ObjectType) type);
  88         }
  89         else {
  90             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
  91                                         toString(), type.toString());
  92             classGen.getParser().reportError(Constants.FATAL, err);
  93         }
  94     }
  95 
  96     /**
  97      * Translates an external Java Class into an internal type.
  98      * Expects the Java object on the stack, pushes the internal type
  99      */
 100     public void translateFrom(ClassGenerator classGen,
 101         MethodGenerator methodGen, Class<?> clazz)
 102     {
 103 
 104         InstructionList il = methodGen.getInstructionList();
 105         ConstantPoolGen cpg = classGen.getConstantPool();
 106         if (clazz.getName().equals("org.w3c.dom.NodeList")) {
 107            // w3c NodeList is on the stack from the external Java function call.
 108            // call BasisFunction to consume NodeList and leave Iterator on
 109            //    the stack.
 110            il.append(classGen.loadTranslet());   // push translet onto stack
 111            il.append(methodGen.loadDOM());       // push DOM onto stack
 112            final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
 113                                         "nodeList2Iterator",
 114                                         "("
 115                                          + "Lorg/w3c/dom/NodeList;"
 116                                          + TRANSLET_INTF_SIG
 117                                          + DOM_INTF_SIG
 118                                          + ")" + NODE_ITERATOR_SIG );
 119            il.append(new INVOKESTATIC(convert));
 120         }
 121         else if (clazz.getName().equals("org.w3c.dom.Node")) {
 122            // w3c Node is on the stack from the external Java function call.
 123            // call BasisLibrary.node2Iterator() to consume Node and leave
 124            // Iterator on the stack.
 125            il.append(classGen.loadTranslet());   // push translet onto stack
 126            il.append(methodGen.loadDOM());       // push DOM onto stack
 127            final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
 128                                         "node2Iterator",
 129                                         "("
 130                                          + "Lorg/w3c/dom/Node;"
 131                                          + TRANSLET_INTF_SIG
 132                                          + DOM_INTF_SIG
 133                                          + ")" + NODE_ITERATOR_SIG );
 134            il.append(new INVOKESTATIC(convert));
 135         }
 136         else {
 137             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
 138                 toString(), clazz.getName());
 139             classGen.getParser().reportError(Constants.FATAL, err);
 140         }
 141     }
 142 
 143 
 144     /**
 145      * Translates a node-set into a synthesized boolean.
 146      * The boolean value of a node-set is "true" if non-empty
 147      * and "false" otherwise. Notice that the
 148      * function getFirstNode() is called in translateToDesynthesized().
 149      *
 150      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 151      */
 152     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 153                             BooleanType type) {
 154         final InstructionList il = methodGen.getInstructionList();
 155         FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
 156         il.append(ICONST_1);
 157         final BranchHandle truec = il.append(new GOTO(null));
 158         falsel.backPatch(il.append(ICONST_0));
 159         truec.setTarget(il.append(NOP));
 160     }
 161 
 162     /**
 163      * Translates a node-set into a string. The string value of a node-set is
 164      * value of its first element.
 165      *
 166      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 167      */
 168     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 169                             StringType type) {
 170         final InstructionList il = methodGen.getInstructionList();
 171         getFirstNode(classGen, methodGen);
 172         il.append(DUP);
 173         final BranchHandle falsec = il.append(new IFLT(null));
 174         Type.Node.translateTo(classGen, methodGen, type);
 175         final BranchHandle truec = il.append(new GOTO(null));
 176         falsec.setTarget(il.append(POP));
 177         il.append(new PUSH(classGen.getConstantPool(), ""));
 178         truec.setTarget(il.append(NOP));
 179     }
 180 
 181     /**
 182      * Expects a node-set on the stack and pushes a real.
 183      * First the node-set is converted to string, and from string to real.
 184      *
 185      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 186      */
 187     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 188                             RealType type) {
 189         translateTo(classGen, methodGen, Type.String);
 190         Type.String.translateTo(classGen, methodGen, Type.Real);
 191     }
 192 
 193     /**
 194      * Expects a node-set on the stack and pushes a node.
 195      *
 196      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 197      */
 198     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 199                             NodeType type) {
 200         getFirstNode(classGen, methodGen);
 201     }
 202 
 203     /**
 204      * Subsume node-set into ObjectType.
 205      *
 206      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 207      */
 208     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 209                             ObjectType type) {
 210             methodGen.getInstructionList().append(NOP);
 211     }
 212 
 213     /**
 214      * Translates a node-set into a non-synthesized boolean. It does not
 215      * push a 0 or a 1 but instead returns branchhandle list to be appended
 216      * to the false list.
 217      *
 218      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized
 219      */
 220     public FlowList translateToDesynthesized(ClassGenerator classGen,
 221                                              MethodGenerator methodGen,
 222                                              BooleanType type) {
 223         final InstructionList il = methodGen.getInstructionList();
 224         getFirstNode(classGen, methodGen);
 225         return new FlowList(il.append(new IFLT(null)));
 226     }
 227 
 228     /**
 229      * Expects a node-set on the stack and pushes a boxed node-set.
 230      * Node sets are already boxed so the translation is just a NOP.
 231      *
 232      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 233      */
 234     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 235                             ReferenceType type) {
 236         methodGen.getInstructionList().append(NOP);
 237     }
 238 
 239     /**
 240      * Translates a node-set into the Java type denoted by <code>clazz</code>.
 241      * Expects a node-set on the stack and pushes an object of the appropriate
 242      * type after coercion.
 243      */
 244     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 245                             Class<?> clazz) {
 246         final ConstantPoolGen cpg = classGen.getConstantPool();
 247         final InstructionList il = methodGen.getInstructionList();
 248         final String className = clazz.getName();
 249 
 250         il.append(methodGen.loadDOM());
 251         il.append(SWAP);
 252 
 253         if (className.equals("org.w3c.dom.Node")) {
 254             int index = cpg.addInterfaceMethodref(DOM_INTF,
 255                                                   MAKE_NODE,
 256                                                   MAKE_NODE_SIG2);
 257             il.append(new INVOKEINTERFACE(index, 2));
 258         }
 259         else if (className.equals("org.w3c.dom.NodeList") ||
 260                  className.equals("java.lang.Object")) {
 261             int index = cpg.addInterfaceMethodref(DOM_INTF,
 262                                                   MAKE_NODE_LIST,
 263                                                   MAKE_NODE_LIST_SIG2);
 264             il.append(new INVOKEINTERFACE(index, 2));
 265         }
 266         else if (className.equals("java.lang.String")) {
 267             int next = cpg.addInterfaceMethodref(NODE_ITERATOR,
 268                                                  "next", "()I");
 269             int index = cpg.addInterfaceMethodref(DOM_INTF,
 270                                                  GET_NODE_VALUE,
 271                                                  "(I)"+STRING_SIG);
 272 
 273             // Get next node from the iterator
 274             il.append(new INVOKEINTERFACE(next, 1));
 275             // Get the node's string value (from the DOM)
 276             il.append(new INVOKEINTERFACE(index, 2));
 277 
 278         }
 279         else {
 280             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
 281                                         toString(), className);
 282             classGen.getParser().reportError(Constants.FATAL, err);
 283         }
 284     }
 285 
 286     /**
 287      * Some type conversions require gettting the first node from the node-set.
 288      * This function is defined to avoid code repetition.
 289      */
 290     private void getFirstNode(ClassGenerator classGen, MethodGenerator methodGen) {
 291         final ConstantPoolGen cpg = classGen.getConstantPool();
 292         final InstructionList il = methodGen.getInstructionList();
 293         il.append(new INVOKEINTERFACE(cpg.addInterfaceMethodref(NODE_ITERATOR,
 294                                                                 NEXT,
 295                                                                 NEXT_SIG), 1));
 296     }
 297 
 298     /**
 299      * Translates an object of this type to its boxed representation.
 300      */
 301     public void translateBox(ClassGenerator classGen,
 302                              MethodGenerator methodGen) {
 303         translateTo(classGen, methodGen, Type.Reference);
 304     }
 305 
 306     /**
 307      * Translates an object of this type to its unboxed representation.
 308      */
 309     public void translateUnBox(ClassGenerator classGen,
 310                                MethodGenerator methodGen) {
 311         methodGen.getInstructionList().append(NOP);
 312     }
 313 
 314     /**
 315      * Returns the class name of an internal type's external representation.
 316      */
 317     public String getClassName() {
 318         return(NODE_ITERATOR);
 319     }
 320 
 321 
 322     public Instruction LOAD(int slot) {
 323         return new ALOAD(slot);
 324     }
 325 
 326     public Instruction STORE(int slot) {
 327         return new ASTORE(slot);
 328     }
 329 }