1 /*
   2  * Copyright (c) 2015, 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.util;
  22 
  23 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  24 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
  25 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  26 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
  27 import com.sun.org.apache.bcel.internal.generic.GOTO;
  28 import com.sun.org.apache.bcel.internal.generic.IFEQ;
  29 import com.sun.org.apache.bcel.internal.generic.ILOAD;
  30 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  31 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  32 import com.sun.org.apache.bcel.internal.generic.ISTORE;
  33 import com.sun.org.apache.bcel.internal.generic.Instruction;
  34 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  35 import com.sun.org.apache.bcel.internal.generic.NEW;
  36 import com.sun.org.apache.bcel.internal.generic.PUSH;
  37 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
  38 import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
  39 import com.sun.org.apache.xalan.internal.xsltc.compiler.NodeTest;
  40 
  41 /**
  42  * @author Jacek Ambroziak
  43  * @author Santiago Pericas-Geertsen
  44  * @LastModified: Oct 2017
  45  */
  46 public final class NodeType extends Type {
  47     private final int _type;
  48 
  49     protected NodeType() {
  50         this(NodeTest.ANODE);
  51     }
  52 
  53     protected NodeType(int type) {
  54         _type = type;
  55     }
  56 
  57     public int getType() {
  58         return _type;
  59     }
  60 
  61     public String toString() {
  62         return "node-type";
  63     }
  64 
  65     public boolean identicalTo(Type other) {
  66         return other instanceof NodeType;
  67     }
  68 
  69     public int hashCode() {
  70         return _type;
  71     }
  72 
  73     public String toSignature() {
  74         return "I";
  75     }
  76 
  77     public com.sun.org.apache.bcel.internal.generic.Type toJCType() {
  78         return com.sun.org.apache.bcel.internal.generic.Type.INT;
  79     }
  80 
  81     /**
  82      * Translates a node into an object of internal type <code>type</code>.
  83      * The translation to int is undefined since nodes are always converted
  84      * to reals in arithmetic expressions.
  85      *
  86      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
  87      */
  88     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
  89                             Type type) {
  90         if (type == Type.String) {
  91             translateTo(classGen, methodGen, (StringType) type);
  92         }
  93         else if (type == Type.Boolean) {
  94             translateTo(classGen, methodGen, (BooleanType) type);
  95         }
  96         else if (type == Type.Real) {
  97             translateTo(classGen, methodGen, (RealType) type);
  98         }
  99         else if (type == Type.NodeSet) {
 100             translateTo(classGen, methodGen, (NodeSetType) type);
 101         }
 102         else if (type == Type.Reference) {
 103             translateTo(classGen, methodGen, (ReferenceType) type);
 104         }
 105         else if (type == Type.Object) {
 106             translateTo(classGen, methodGen, (ObjectType) type);
 107         }
 108         else {
 109             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
 110                                         toString(), type.toString());
 111             classGen.getParser().reportError(Constants.FATAL, err);
 112         }
 113     }
 114 
 115     /**
 116      * Expects a node on the stack and pushes its string value.
 117      *
 118      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 119      */
 120     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 121                             StringType type) {
 122         final ConstantPoolGen cpg = classGen.getConstantPool();
 123         final InstructionList il = methodGen.getInstructionList();
 124 
 125         switch (_type) {
 126         case NodeTest.ROOT:
 127         case NodeTest.ELEMENT:
 128             il.append(methodGen.loadDOM());
 129             il.append(SWAP); // dom ref must be below node index
 130             int index = cpg.addInterfaceMethodref(DOM_INTF,
 131                                                   GET_ELEMENT_VALUE,
 132                                                   GET_ELEMENT_VALUE_SIG);
 133             il.append(new INVOKEINTERFACE(index, 2));
 134             break;
 135 
 136         case NodeTest.ANODE:
 137         case NodeTest.COMMENT:
 138         case NodeTest.ATTRIBUTE:
 139         case NodeTest.PI:
 140             il.append(methodGen.loadDOM());
 141             il.append(SWAP); // dom ref must be below node index
 142             index = cpg.addInterfaceMethodref(DOM_INTF,
 143                                               GET_NODE_VALUE,
 144                                               GET_NODE_VALUE_SIG);
 145             il.append(new INVOKEINTERFACE(index, 2));
 146             break;
 147 
 148         default:
 149             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
 150                                         toString(), type.toString());
 151             classGen.getParser().reportError(Constants.FATAL, err);
 152             break;
 153         }
 154     }
 155 
 156     /**
 157      * Translates a node into a synthesized boolean.
 158      * If the expression is "@attr",
 159      * then "true" is pushed iff "attr" is an attribute of the current node.
 160      * If the expression is ".", the result is always "true".
 161      *
 162      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 163      */
 164     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 165                             BooleanType type) {
 166         final InstructionList il = methodGen.getInstructionList();
 167         FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
 168         il.append(ICONST_1);
 169         final BranchHandle truec = il.append(new GOTO(null));
 170         falsel.backPatch(il.append(ICONST_0));
 171         truec.setTarget(il.append(NOP));
 172     }
 173 
 174     /**
 175      * Expects a node on the stack and pushes a real.
 176      * First the node is converted to string, and from string to real.
 177      *
 178      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 179      */
 180     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 181                             RealType type) {
 182         translateTo(classGen, methodGen, Type.String);
 183         Type.String.translateTo(classGen, methodGen, Type.Real);
 184     }
 185 
 186     /**
 187      * Expects a node on the stack and pushes a singleton node-set. Singleton
 188      * iterators are already started after construction.
 189      *
 190      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 191      */
 192     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 193                             NodeSetType type) {
 194         ConstantPoolGen cpg = classGen.getConstantPool();
 195         InstructionList il = methodGen.getInstructionList();
 196 
 197         // Create a new instance of SingletonIterator
 198         il.append(new NEW(cpg.addClass(SINGLETON_ITERATOR)));
 199         il.append(DUP_X1);
 200         il.append(SWAP);
 201         final int init = cpg.addMethodref(SINGLETON_ITERATOR, "<init>",
 202                                           "(" + NODE_SIG +")V");
 203         il.append(new INVOKESPECIAL(init));
 204     }
 205 
 206     /**
 207      * Subsume Node into ObjectType.
 208      *
 209      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 210      */
 211     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 212                             ObjectType type) {
 213             methodGen.getInstructionList().append(NOP);
 214     }
 215 
 216     /**
 217      * Translates a node into a non-synthesized boolean. It does not push a
 218      * 0 or a 1 but instead returns branchhandle list to be appended to the
 219      * false list.
 220      *
 221      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized
 222      */
 223     public FlowList translateToDesynthesized(ClassGenerator classGen,
 224                                              MethodGenerator methodGen,
 225                                              BooleanType type) {
 226         final InstructionList il = methodGen.getInstructionList();
 227         return new FlowList(il.append(new IFEQ(null)));
 228     }
 229 
 230     /**
 231      * Expects a node on the stack and pushes a boxed node. Boxed nodes
 232      * are represented by an instance of <code>com.sun.org.apache.xalan.internal.xsltc.dom.Node</code>.
 233      *
 234      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
 235      */
 236     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 237                             ReferenceType type) {
 238         final ConstantPoolGen cpg = classGen.getConstantPool();
 239         final InstructionList il = methodGen.getInstructionList();
 240         il.append(new NEW(cpg.addClass(RUNTIME_NODE_CLASS)));
 241         il.append(DUP_X1);
 242         il.append(SWAP);
 243         il.append(new PUSH(cpg, _type));
 244         il.append(new INVOKESPECIAL(cpg.addMethodref(RUNTIME_NODE_CLASS,
 245                                                      "<init>", "(II)V")));
 246     }
 247 
 248     /**
 249      * Translates a node into the Java type denoted by <code>clazz</code>.
 250      * Expects a node on the stack and pushes an object of the appropriate
 251      * type after coercion.
 252      */
 253     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
 254                             Class<?> clazz) {
 255         final ConstantPoolGen cpg = classGen.getConstantPool();
 256         final InstructionList il = methodGen.getInstructionList();
 257 
 258         String className = clazz.getName();
 259         if (className.equals("java.lang.String")) {
 260            translateTo(classGen, methodGen, Type.String);
 261            return;
 262         }
 263 
 264         il.append(methodGen.loadDOM());
 265         il.append(SWAP);                // dom ref must be below node index
 266 
 267         if (className.equals("org.w3c.dom.Node") ||
 268             className.equals("java.lang.Object")) {
 269             int index = cpg.addInterfaceMethodref(DOM_INTF,
 270                                                   MAKE_NODE,
 271                                                   MAKE_NODE_SIG);
 272             il.append(new INVOKEINTERFACE(index, 2));
 273         }
 274         else if (className.equals("org.w3c.dom.NodeList")) {
 275             int index = cpg.addInterfaceMethodref(DOM_INTF,
 276                                                   MAKE_NODE_LIST,
 277                                                   MAKE_NODE_LIST_SIG);
 278             il.append(new INVOKEINTERFACE(index, 2));
 279         }
 280         else {
 281             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
 282                                         toString(), className);
 283             classGen.getParser().reportError(Constants.FATAL, err);
 284         }
 285     }
 286 
 287     /**
 288      * Translates an object of this type to its boxed representation.
 289      */
 290     public void translateBox(ClassGenerator classGen,
 291                              MethodGenerator methodGen) {
 292         translateTo(classGen, methodGen, Type.Reference);
 293     }
 294 
 295     /**
 296      * Translates an object of this type to its unboxed representation.
 297      */
 298     public void translateUnBox(ClassGenerator classGen,
 299                                MethodGenerator methodGen) {
 300         final ConstantPoolGen cpg = classGen.getConstantPool();
 301         final InstructionList il = methodGen.getInstructionList();
 302         il.append(new CHECKCAST(cpg.addClass(RUNTIME_NODE_CLASS)));
 303         il.append(new GETFIELD(cpg.addFieldref(RUNTIME_NODE_CLASS,
 304                                                NODE_FIELD,
 305                                                NODE_FIELD_SIG)));
 306     }
 307 
 308     /**
 309      * Returns the class name of an internal type's external representation.
 310      */
 311     public String getClassName() {
 312         return(RUNTIME_NODE_CLASS);
 313     }
 314 
 315     public Instruction LOAD(int slot) {
 316         return new ILOAD(slot);
 317     }
 318 
 319     public Instruction STORE(int slot) {
 320         return new ISTORE(slot);
 321     }
 322 }