1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.codemodel.internal;
  27 
  28 
  29 /**
  30  * Factory methods that generate various {@link JExpression}s.
  31  */
  32 public abstract class JExpr {
  33 
  34     /**
  35      * This class is not instanciable.
  36      */
  37     private JExpr() { }
  38 
  39     public static JExpression assign(JAssignmentTarget lhs, JExpression rhs) {
  40         return new JAssignment(lhs, rhs);
  41     }
  42 
  43     public static JExpression assignPlus(JAssignmentTarget lhs, JExpression rhs) {
  44         return new JAssignment(lhs, rhs, "+");
  45     }
  46 
  47     public static JInvocation _new(JClass c) {
  48         return new JInvocation(c);
  49     }
  50 
  51     public static JInvocation _new(JType t) {
  52         return new JInvocation(t);
  53     }
  54 
  55     public static JInvocation invoke(String method) {
  56         return new JInvocation((JExpression)null, method);
  57     }
  58 
  59     public static JInvocation invoke(JMethod method) {
  60         return new JInvocation((JExpression)null,method);
  61     }
  62 
  63     public static JInvocation invoke(JExpression lhs, JMethod method) {
  64         return new JInvocation(lhs, method);
  65     }
  66 
  67     public static JInvocation invoke(JExpression lhs, String method) {
  68         return new JInvocation(lhs, method);
  69     }
  70 
  71     public static JFieldRef ref(String field) {
  72         return new JFieldRef((JExpression)null, field);
  73     }
  74 
  75     public static JFieldRef ref(JExpression lhs, JVar field) {
  76         return new JFieldRef(lhs,field);
  77     }
  78 
  79     public static JFieldRef ref(JExpression lhs, String field) {
  80         return new JFieldRef(lhs, field);
  81     }
  82 
  83     public static JFieldRef refthis(String field) {
  84          return new JFieldRef(null, field, true);
  85     }
  86 
  87     public static JExpression dotclass(final JClass cl) {
  88         return new JExpressionImpl() {
  89                 public void generate(JFormatter f) {
  90                     JClass c;
  91                     if(cl instanceof JNarrowedClass)
  92                         c = ((JNarrowedClass)cl).basis;
  93                     else
  94                         c = cl;
  95                     f.g(c).p(".class");
  96                 }
  97             };
  98     }
  99 
 100     public static JArrayCompRef component(JExpression lhs, JExpression index) {
 101         return new JArrayCompRef(lhs, index);
 102     }
 103 
 104     public static JCast cast(JType type, JExpression expr) {
 105         return new JCast(type, expr);
 106     }
 107 
 108     public static JArray newArray(JType type) {
 109         return newArray(type,null);
 110     }
 111 
 112     /**
 113      * Generates {@code new T[size]}.
 114      *
 115      * @param type
 116      *      The type of the array component. 'T' or {@code new T[size]}.
 117      */
 118     public static JArray newArray(JType type, JExpression size) {
 119         // you cannot create an array whose component type is a generic
 120         return new JArray(type.erasure(), size);
 121     }
 122 
 123     /**
 124      * Generates {@code new T[size]}.
 125      *
 126      * @param type
 127      *      The type of the array component. 'T' or {@code new T[size]}.
 128      */
 129     public static JArray newArray(JType type, int size) {
 130         return newArray(type,lit(size));
 131     }
 132 
 133 
 134     private static final JExpression __this = new JAtom("this");
 135     /**
 136      * Returns a reference to "this", an implicit reference
 137      * to the current object.
 138      */
 139     public static JExpression _this() { return __this; }
 140 
 141     private static final JExpression __super = new JAtom("super");
 142     /**
 143      * Returns a reference to "super", an implicit reference
 144      * to the super class.
 145      */
 146     public static JExpression _super() { return __super; }
 147 
 148 
 149     /* -- Literals -- */
 150 
 151     private static final JExpression __null = new JAtom("null");
 152     public static JExpression _null() {
 153         return __null;
 154     }
 155 
 156     /**
 157      * Boolean constant that represents <code>true</code>
 158      */
 159     public static final JExpression TRUE = new JAtom("true");
 160 
 161     /**
 162      * Boolean constant that represents <code>false</code>
 163      */
 164     public static final JExpression FALSE = new JAtom("false");
 165 
 166     public static JExpression lit(boolean b) {
 167         return b?TRUE:FALSE;
 168     }
 169 
 170     public static JExpression lit(int n) {
 171         return new JAtom(Integer.toString(n));
 172     }
 173 
 174     public static JExpression lit(long n) {
 175         return new JAtom(Long.toString(n) + "L");
 176     }
 177 
 178     public static JExpression lit(float f) {
 179         if (f == Float.NEGATIVE_INFINITY)
 180         {
 181                 return new JAtom("java.lang.Float.NEGATIVE_INFINITY");
 182         }
 183         else if (f == Float.POSITIVE_INFINITY)
 184         {
 185                 return new JAtom("java.lang.Float.POSITIVE_INFINITY");
 186         }
 187         else if (Float.isNaN(f))
 188         {
 189                 return new JAtom("java.lang.Float.NaN");
 190         }
 191         else
 192         {
 193                 return new JAtom(Float.toString(f) + "F");
 194         }
 195     }
 196 
 197     public static JExpression lit(double d) {
 198         if (d == Double.NEGATIVE_INFINITY)
 199         {
 200                 return new JAtom("java.lang.Double.NEGATIVE_INFINITY");
 201         }
 202         else if (d == Double.POSITIVE_INFINITY)
 203         {
 204                 return new JAtom("java.lang.Double.POSITIVE_INFINITY");
 205         }
 206         else if (Double.isNaN(d))
 207         {
 208                 return new JAtom("java.lang.Double.NaN");
 209         }
 210         else
 211         {
 212                 return new JAtom(Double.toString(d) + "D");
 213         }
 214     }
 215 
 216     static final String charEscape = "\b\t\n\f\r\"\'\\";
 217     static final String charMacro  = "btnfr\"'\\";
 218 
 219     /**
 220      * Escapes the given string, then surrounds it by the specified
 221      * quotation mark.
 222      */
 223     public static String quotify(char quote, String s) {
 224         int n = s.length();
 225         StringBuilder sb = new StringBuilder(n + 2);
 226         sb.append(quote);
 227         for (int i = 0; i < n; i++) {
 228             char c = s.charAt(i);
 229             int j = charEscape.indexOf(c);
 230             if(j>=0) {
 231                 if((quote=='"' && c=='\'') || (quote=='\'' && c=='"')) {
 232                     sb.append(c);
 233                 } else {
 234                     sb.append('\\');
 235                     sb.append(charMacro.charAt(j));
 236                 }
 237             } else {
 238                 // technically Unicode escape shouldn't be done here,
 239                 // for it's a lexical level handling.
 240                 //
 241                 // However, various tools are so broken around this area,
 242                 // so just to be on the safe side, it's better to do
 243                 // the escaping here (regardless of the actual file encoding)
 244                 //
 245                 // see bug
 246                 if( c<0x20 || 0x7E<c ) {
 247                     // not printable. use Unicode escape
 248                     sb.append("\\u");
 249                     String hex = Integer.toHexString(((int)c)&0xFFFF);
 250                     for( int k=hex.length(); k<4; k++ )
 251                         sb.append('0');
 252                     sb.append(hex);
 253                 } else {
 254                     sb.append(c);
 255                 }
 256             }
 257         }
 258         sb.append(quote);
 259         return sb.toString();
 260     }
 261 
 262     public static JExpression lit(char c) {
 263         return new JAtom(quotify('\'', "" + c));
 264     }
 265 
 266     public static JExpression lit(String s) {
 267         return new JStringLiteral(s);
 268     }
 269 
 270     /**
 271      * Creates an expression directly from a source code fragment.
 272      *
 273      * <p>
 274      * This method can be used as a short-cut to create a JExpression.
 275      * For example, instead of <code>_a.gt(_b)</code>, you can write
 276      * it as: {@code JExpr.direct("a>b")}.
 277      *
 278      * <p>
 279      * Be warned that there is a danger in using this method,
 280      * as it obfuscates the object model.
 281      */
 282     public static JExpression direct( final String source ) {
 283         return new JExpressionImpl(){
 284             public void generate( JFormatter f ) {
 285                     f.p('(').p(source).p(')');
 286             }
 287         };
 288     }
 289 }