Clover coverage report - groovy - 1.0-beta-8
Coverage timestamp: Fri Dec 17 2004 14:55:55 GMT
file stats: LOC: 413   Methods: 24
NCLOC: 312   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
BinaryExpression.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  $Id: BinaryExpression.java,v 1.6 2004/07/10 03:31:37 bran Exp $
 3   
 
 4   
  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
 
 6   
  Redistribution and use of this software and associated documentation
 7   
  ("Software"), with or without modification, are permitted provided
 8   
  that the following conditions are met:
 9   
 
 10   
  1. Redistributions of source code must retain copyright
 11   
     statements and notices.  Redistributions must also contain a
 12   
     copy of this document.
 13   
 
 14   
  2. Redistributions in binary form must reproduce the
 15   
     above copyright notice, this list of conditions and the
 16   
     following disclaimer in the documentation and/or other
 17   
     materials provided with the distribution.
 18   
 
 19   
  3. The name "groovy" must not be used to endorse or promote
 20   
     products derived from this Software without prior written
 21   
     permission of The Codehaus.  For written permission,
 22   
     please contact info@codehaus.org.
 23   
 
 24   
  4. Products derived from this Software may not be called "groovy"
 25   
     nor may "groovy" appear in their names without prior written
 26   
     permission of The Codehaus. "groovy" is a registered
 27   
     trademark of The Codehaus.
 28   
 
 29   
  5. Due credit should be given to The Codehaus -
 30   
     http://groovy.codehaus.org/
 31   
 
 32   
  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
 33   
  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 34   
  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 35   
  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 36   
  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 37   
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 38   
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 39   
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 40   
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 41   
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 42   
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 43   
  OF THE POSSIBILITY OF SUCH DAMAGE.
 44   
 
 45   
  */
 46   
 package org.codehaus.groovy.ast.expr;
 47   
 
 48   
 import java.io.OutputStream;
 49   
 import java.io.Writer;
 50   
 import java.math.BigDecimal;
 51   
 import java.math.BigInteger;
 52   
 import java.util.Collection;
 53   
 import java.util.Date;
 54   
 import java.util.List;
 55   
 import java.util.Map;
 56   
 import java.util.regex.Matcher;
 57   
 
 58   
 import org.codehaus.groovy.ast.GroovyCodeVisitor;
 59   
 import org.codehaus.groovy.ast.Type;
 60   
 import org.codehaus.groovy.classgen.AsmClassGenerator2;
 61   
 import org.codehaus.groovy.syntax.Token;
 62   
 import org.codehaus.groovy.syntax.Types;
 63   
 import groovy.lang.GString;
 64   
 
 65   
 /**
 66   
  * Represents two expressions and an operation
 67   
  * 
 68   
  * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
 69   
  * @version $Revision: 1.6 $
 70   
  */
 71   
 public class BinaryExpression extends Expression {
 72   
     
 73   
     private Expression leftExpression;
 74   
     private Expression rightExpression;
 75   
     private Token operation;
 76   
     
 77  0
     public BinaryExpression(Expression leftExpression,
 78   
                             Token operation,
 79   
                             Expression rightExpression) {
 80  0
         this.leftExpression = leftExpression;
 81  0
         this.operation = operation;
 82  0
         this.rightExpression = rightExpression;
 83   
 
 84   
     }
 85   
 
 86  0
     public Class getTypeClass() {
 87  0
         typeClass = resolveThisType(operation);
 88  0
         return typeClass;
 89   
     }
 90   
 
 91  0
     public boolean isDynamic() {
 92  0
         return false;  //To change body of implemented methods use File | Settings | File Templates.
 93   
     }
 94   
 
 95  0
     private Class resolveThisType(Token operation) {
 96  0
         switch (operation.getType()) {
 97   
             case Types.EQUAL : // = assignment
 98  0
                 if (!leftExpression.isDynamic())
 99  0
                     return leftExpression.getTypeClass();
 100   
                 else
 101  0
                     return rightExpression.getTypeClass();
 102   
             case Types.COMPARE_IDENTICAL :
 103   
             case Types.COMPARE_EQUAL :
 104   
             case Types.COMPARE_NOT_EQUAL :
 105   
             case Types.COMPARE_GREATER_THAN :
 106   
             case Types.COMPARE_GREATER_THAN_EQUAL :
 107   
             case Types.COMPARE_LESS_THAN :
 108   
             case Types.COMPARE_LESS_THAN_EQUAL :
 109   
             case Types.KEYWORD_INSTANCEOF :
 110   
             case Types.MATCH_REGEX :
 111  0
                 return boolean.class;
 112   
             case Types.LOGICAL_AND :
 113   
             case Types.LOGICAL_OR :
 114  0
                 return Boolean.class;
 115   
             case Types.COMPARE_TO :
 116  0
                 return Integer.class;
 117   
             case Types.PLUS :
 118   
             case Types.PLUS_EQUAL :{
 119  0
                 if (leftExpression.getTypeClass() == String.class && rightExpression.getTypeClass() == String.class) {
 120  0
                     return String.class;
 121   
                 }
 122  0
                 else if (leftExpression.getTypeClass() == GString.class &&
 123   
                         (rightExpression.getTypeClass() == GString.class || rightExpression.getTypeClass() == String.class)) {
 124  0
                     return GString.class;
 125   
                 }
 126  0
                 else if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
 127  0
                     return chooseWiderNumberType(leftExpression.getType(), rightExpression.getType());
 128   
                 }
 129  0
                 else if (leftExpression.getTypeClass() == Date.class && Number.class.isAssignableFrom(rightExpression.getTypeClass()) ) {
 130  0
                     return Date.class;
 131   
                 }
 132  0
                 else if (leftExpression.getTypeClass() != null && Collection.class.isAssignableFrom(leftExpression.getTypeClass() )) {
 133  0
                     return List.class;
 134   
                 }
 135   
                 else {
 136  0
                     return null;
 137   
                 }
 138   
             }
 139   
             case Types.MINUS :
 140   
             case Types.MINUS_EQUAL :{
 141  0
                 if (leftExpression.getTypeClass() == String.class) {
 142  0
                     return String.class;
 143  0
                 } else if (leftExpression instanceof GStringExpression && isNumber(rightExpression.getType())) {
 144  0
                     return String.class;
 145  0
                 } else if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
 146  0
                     return chooseWiderNumberType(leftExpression.getType(), rightExpression.getType());
 147   
                 }
 148  0
                 else if (leftExpression.getTypeClass() != null && List.class.isAssignableFrom(leftExpression.getTypeClass() )) {
 149  0
                     return List.class;
 150   
                 }
 151  0
                 else if (leftExpression.getTypeClass() == Date.class && Number.class.isAssignableFrom(rightExpression.getTypeClass()) ) {
 152  0
                     return Date.class;
 153   
                 }
 154   
                 else {
 155  0
                     return null;
 156   
                 }
 157   
             }
 158   
             case Types.MULTIPLY :
 159   
             case Types.MULTIPLY_EQUAL : {
 160  0
                 if (leftExpression.getTypeClass() == String.class && isNumber(rightExpression.getType())) {
 161  0
                     return String.class;
 162  0
                 } else if (leftExpression instanceof GStringExpression && isNumber(rightExpression.getType())) {
 163  0
                     return String.class;
 164  0
                 } else if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
 165  0
                     return chooseWiderNumberType(leftExpression.getType(), rightExpression.getType());
 166   
                 }
 167  0
                 else if (leftExpression.getTypeClass() != null && Collection.class.isAssignableFrom(leftExpression.getTypeClass() )) {
 168  0
                     return List.class;
 169   
                 }
 170   
                 else {
 171  0
                     return null;
 172   
                 }
 173   
             }
 174   
 
 175   
             case Types.DIVIDE :
 176   
             case Types.DIVIDE_EQUAL :
 177   
             case Types.MOD :
 178   
             case Types.MOD_EQUAL :
 179  0
                 if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
 180  0
                     return chooseWiderNumberType(leftExpression.getType(), rightExpression.getType());
 181   
                 }
 182  0
                 return null;
 183   
             case Types.LEFT_SHIFT :
 184  0
                 if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
 185  0
                     return leftExpression.getTypeClass();
 186   
                 }
 187  0
                 else if (leftExpression.getTypeClass() != null && Collection.class.isAssignableFrom(leftExpression.getTypeClass() )) {
 188  0
                     return Collection.class;
 189   
                 }
 190  0
                 else if (leftExpression.getTypeClass() != null && OutputStream.class.isAssignableFrom(leftExpression.getTypeClass())) {
 191  0
                     return Writer.class;
 192   
                 }
 193  0
                 else if (leftExpression.getTypeClass() != null && StringBuffer.class.isAssignableFrom(leftExpression.getTypeClass())) {
 194  0
                     return Writer.class;
 195   
                 }
 196  0
                 return null;
 197   
             case Types.RIGHT_SHIFT :
 198   
             case Types.RIGHT_SHIFT_UNSIGNED :
 199  0
                 if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
 200  0
                     return leftExpression.getTypeClass();
 201   
                 }
 202  0
                 return null;
 203   
             case Types.FIND_REGEX :
 204  0
                 return Matcher.class;
 205   
             case Types.LEFT_SQUARE_BRACKET :
 206  0
                 Class cls = leftExpression.getTypeClass();
 207  0
                 if (cls != null) {
 208  0
                     if (cls.isArray()) {
 209  0
                         Class elemType = cls.getComponentType();
 210   
                         //setTypeClass(elemType);
 211  0
                         return elemType;
 212   
                     }
 213  0
                     else if (leftExpression instanceof ListExpression) {
 214  0
                         Class elemType = ((ListExpression)leftExpression).getComponentTypeClass();
 215   
                         //setTypeClass(elemType);
 216  0
                         return elemType;
 217   
                     }
 218  0
                     else if (leftExpression instanceof MapExpression) {
 219  0
                         return Object.class;
 220   
                     }
 221  0
                     else if (List.class.isAssignableFrom(cls)) {
 222  0
                         return (Object.class);
 223   
                     }
 224  0
                     else if (Map.class.isAssignableFrom(cls)) {
 225  0
                         return (Object.class);
 226   
                     }
 227   
                 }
 228  0
                 break;
 229   
         }
 230  0
         return null;
 231   
     }
 232   
 
 233  0
     private static boolean isNumber(String type) {
 234  0
         if (type!= null) {
 235  0
             if (    type.equals("int") ||
 236   
                     type.equals("short") ||
 237   
                     type.equals("byte") ||
 238   
                     type.equals("char") ||
 239   
                     type.equals("float") ||
 240   
                     type.equals("long") ||
 241   
                     type.equals("double") ||
 242   
                     type.equals("java.lang.Short") ||
 243   
                     type.equals("java.lang.Byte") ||
 244   
                     type.equals("java.lang.Character") ||
 245   
                     type.equals("java.lang.Integer") ||
 246   
                     type.equals("java.lang.Float") ||
 247   
                     type.equals("java.lang.Long") ||
 248   
                     type.equals("java.lang.Double") ||
 249   
                     type.equals("java.math.BigInteger") ||
 250   
                     type.equals("java.math.BigDecimal"))
 251   
             {
 252  0
                 return true;
 253   
             }
 254   
         }
 255  0
         return false;
 256   
     }
 257   
 
 258  0
     private static Class getObjectClassForNumber(String type) {
 259  0
         if (type.equals("boolean") || type.equals("java.lang.Boolean")) {
 260  0
             return Boolean.class;
 261   
         }
 262  0
         else if (type.equals("short") || type.equals("java.lang.Short")) {
 263  0
             return Short.class;
 264   
         }
 265  0
         else if (type.equals("int") || type.equals("java.lang.Integer")) {
 266  0
                     return Integer.class;
 267   
         }
 268  0
         else if (type.equals("char") || type.equals("java.lang.Character")) {
 269  0
                     return Integer.class;
 270   
         }
 271  0
         else if (type.equals("long") || type.equals("java.lang.Long")) {
 272  0
             return Long.class;
 273   
         }
 274  0
         else if (type.equals("float") || type.equals("java.lang.Float")) {
 275  0
             return Float.class;
 276   
         }
 277  0
         else if (type.equals("double") || type.equals("java.lang.Double")) {
 278  0
             return Double.class;
 279   
         }
 280  0
         else if (type.equals("java.math.BigInteger")) {
 281  0
             return BigInteger.class;
 282   
         }
 283  0
         else if (type.equals("java.math.BigDecimal")) {
 284  0
             return BigDecimal.class;
 285   
         }
 286   
         else {
 287  0
             return null;
 288   
         }
 289   
     }
 290   
 
 291  0
     private static boolean isFloatingPoint(Class cls) {
 292  0
         return cls == Double.class || cls == Float.class;
 293   
     }
 294   
 
 295  0
     private static boolean isInteger(Class cls) {
 296  0
         return cls == Integer.class || cls == Byte.class || cls == Short.class || cls == Character.class;
 297   
     }
 298   
 
 299  0
     private static boolean isLong(Class cls) {
 300  0
         return cls == Long.class;
 301   
     }
 302   
 
 303  0
     private static boolean isBigDecimal(Class cls) {
 304  0
         return cls == BigDecimal.class;
 305   
     }
 306   
 
 307  0
     private static boolean isBigInteger(Class cls) {
 308  0
         return cls == BigInteger.class;
 309   
     }
 310   
 
 311  0
     private static Class chooseWiderNumberType(String lefts, String rights) {
 312  0
         Class left = getObjectClassForNumber(lefts);
 313  0
         Class right = getObjectClassForNumber(rights);
 314  0
         if (isFloatingPoint(left) || isFloatingPoint(right)) {
 315  0
             return Double.class;
 316   
         }
 317  0
         else if (isBigDecimal(left) || isBigDecimal(right)) {
 318  0
             return BigDecimal.class;
 319   
         }
 320  0
         else if (isBigInteger(left) || isBigInteger(right)) {
 321  0
             return BigInteger.class;
 322   
         }
 323  0
         else if (isLong(left) || isLong(right)){
 324  0
             return Long.class;
 325   
         }
 326  0
         return Integer.class;
 327   
 
 328   
         // see NumberMath for full Groovy math promotion
 329   
     }
 330  0
     public String toString() {
 331  0
         return super.toString() +"[" + leftExpression + operation + rightExpression + "]";
 332   
     }
 333   
 
 334  0
     public void visit(GroovyCodeVisitor visitor) {
 335  0
         visitor.visitBinaryExpression(this);
 336   
     }
 337   
 
 338  0
     public Expression transformExpression(ExpressionTransformer transformer) {
 339  0
         return new BinaryExpression(transformer.transform(leftExpression), operation, transformer.transform(rightExpression));
 340   
     }
 341   
 
 342  0
     public Expression getLeftExpression() {
 343  0
         return leftExpression;
 344   
     }
 345   
 
 346  0
     public void setLeftExpression(Expression leftExpression) {
 347  0
         this.leftExpression = leftExpression;
 348   
     }
 349   
 
 350  0
     public void setRightExpression(Expression rightExpression) {
 351  0
         this.rightExpression = rightExpression;
 352   
     }
 353   
 
 354  0
     public Token getOperation() {
 355  0
         return operation;
 356   
     }
 357   
 
 358  0
     public Expression getRightExpression() {
 359  0
         return rightExpression;
 360   
     }
 361   
 
 362  0
     public String getText() {
 363  0
         if (operation.getType() == Types.LEFT_SQUARE_BRACKET) {
 364  0
             return leftExpression.getText() + "[" + rightExpression.getText() + "]";
 365   
         }
 366  0
         return "(" + leftExpression.getText() + " " + operation.getText() + " " + rightExpression.getText() + ")";
 367   
     }
 368   
     
 369   
     
 370   
    /**
 371   
     *  Creates an assignment expression in which the specified expression
 372   
     *  is written into the specified variable name.   
 373   
     */
 374   
     
 375  0
     public static BinaryExpression newAssignmentExpression( String variable, Expression rhs ) {
 376  0
         VariableExpression lhs = new VariableExpression( variable );
 377  0
         Token         operator = Token.newPlaceholder( Types.ASSIGN );
 378   
     
 379  0
         return new BinaryExpression( lhs, operator, rhs );
 380   
     }
 381   
 
 382   
 
 383   
     /**
 384   
      *  Creates variable initialization expression in which the specified expression
 385   
      *  is written into the specified variable name.   
 386   
      */
 387   
      
 388  0
      public static BinaryExpression newInitializationExpression( String variable, Type type, Expression rhs ) {
 389  0
          VariableExpression lhs = new VariableExpression( variable );
 390   
      
 391  0
          if( type != null ) {
 392  0
              lhs.setType( type.getName() );
 393   
          }
 394   
      
 395  0
          Token operator = Token.newPlaceholder( Types.ASSIGN );
 396   
      
 397  0
         return new BinaryExpression( lhs, operator, rhs );
 398   
      }
 399   
 
 400  0
     protected  void resolveType(AsmClassGenerator2 resolver) {
 401  0
         leftExpression.resolve(resolver);
 402  0
         rightExpression.resolve(resolver);
 403  0
         Class cls = resolveThisType(operation);
 404  0
         if (cls != null) {
 405  0
             setTypeClass(cls);
 406   
         }
 407   
         else {
 408  0
              setResolveFailed(true);
 409  0
             setFailure("unknown. the right expression may have not been resolved");
 410   
         }
 411   
     }
 412   
 }
 413