1 // Copyright 2020 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.google.api.generator.engine.ast; 16 17 import com.google.auto.value.AutoValue; 18 import com.google.common.base.Preconditions; 19 20 @AutoValue 21 public abstract class AssignmentOperationExpr implements OperationExpr { variableExpr()22 public abstract VariableExpr variableExpr(); 23 valueExpr()24 public abstract Expr valueExpr(); 25 26 @Override operatorKind()27 public abstract OperatorKind operatorKind(); 28 29 @Override type()30 public TypeNode type() { 31 return variableExpr().type(); 32 } 33 34 @Override accept(AstNodeVisitor visitor)35 public void accept(AstNodeVisitor visitor) { 36 visitor.visit(this); 37 } 38 xorAssignmentWithExprs( VariableExpr variableExpr, Expr valueExpr)39 public static AssignmentOperationExpr xorAssignmentWithExprs( 40 VariableExpr variableExpr, Expr valueExpr) { 41 return builder() 42 .setVariableExpr(variableExpr) 43 .setValueExpr(valueExpr) 44 .setOperatorKind(OperatorKind.ASSIGNMENT_XOR) 45 .build(); 46 } 47 multiplyAssignmentWithExprs( VariableExpr variableExpr, Expr valueExpr)48 public static AssignmentOperationExpr multiplyAssignmentWithExprs( 49 VariableExpr variableExpr, Expr valueExpr) { 50 return builder() 51 .setVariableExpr(variableExpr) 52 .setValueExpr(valueExpr) 53 .setOperatorKind(OperatorKind.ASSIGNMENT_MULTIPLY) 54 .build(); 55 } 56 builder()57 private static Builder builder() { 58 return new AutoValue_AssignmentOperationExpr.Builder(); 59 } 60 61 @AutoValue.Builder 62 abstract static class Builder { 63 // Private setter. setVariableExpr(VariableExpr variableExpr)64 abstract Builder setVariableExpr(VariableExpr variableExpr); 65 66 // Private setter. setValueExpr(Expr valueExpr)67 abstract Builder setValueExpr(Expr valueExpr); 68 69 // Private setter. setOperatorKind(OperatorKind operator)70 abstract Builder setOperatorKind(OperatorKind operator); 71 autoBuild()72 abstract AssignmentOperationExpr autoBuild(); 73 build()74 private AssignmentOperationExpr build() { 75 AssignmentOperationExpr assignmentOperationExpr = autoBuild(); 76 TypeNode lhsType = assignmentOperationExpr.variableExpr().variable().type(); 77 TypeNode rhsType = assignmentOperationExpr.valueExpr().type(); 78 OperatorKind operator = assignmentOperationExpr.operatorKind(); 79 80 // Check if the variable exprs have been declared, if yes, throw error. 81 Preconditions.checkState( 82 !assignmentOperationExpr.variableExpr().isDecl(), 83 String.format( 84 "Variable `%s` should not be declaration in the variable expression.", 85 assignmentOperationExpr.variableExpr().variable().name())); 86 87 // errorMsg is type checking error message for operators. 88 final String errorMsg = 89 String.format( 90 "Assignment operator %s can not be applied to %s, %s.", 91 operator, lhsType.toString(), rhsType.toString()); 92 93 // Check type for multiply and assignment operator (*=). 94 if (operator.equals(OperatorKind.ASSIGNMENT_MULTIPLY)) { 95 Preconditions.checkState(isValidMultiplyAssignmentType(lhsType, rhsType), errorMsg); 96 } 97 98 // Check type for XOR and assignment operator (^=). 99 if (operator.equals(OperatorKind.ASSIGNMENT_XOR)) { 100 Preconditions.checkState(isValidXorAssignmentType(lhsType, rhsType), errorMsg); 101 } 102 return assignmentOperationExpr; 103 } 104 105 // isValidMultiplyAssignmentType validates the types for LHS variable expr and RHS expr. 106 // *= can be only applied on Primitive numeric type. isValidMultiplyAssignmentType(TypeNode variableType, TypeNode valueType)107 private boolean isValidMultiplyAssignmentType(TypeNode variableType, TypeNode valueType) { 108 // LHS is numeric type, RHS should be any numeric type or any numeric boxed type. 109 if (TypeNode.isNumericType(variableType) && !TypeNode.isBoxedType(variableType)) { 110 return TypeNode.isNumericType(valueType); 111 } 112 // LHS is integer boxed type, RHS should be any numeric type except long, float, double. 113 if (variableType.equals(TypeNode.INT)) { 114 return TypeNode.isNumericType(valueType) 115 && !(valueType.equals(TypeNode.LONG) || TypeNode.isFloatingPointType(valueType)); 116 } 117 // LHS is long boxed type, RHS should be any numeric type except float, double. 118 if (variableType.equals(TypeNode.LONG)) { 119 return TypeNode.isNumericType(valueType) && !TypeNode.isFloatingPointType(valueType); 120 } 121 // LHS is integer boxed type, RHS should be any numeric type except double. 122 if (variableType.equals(TypeNode.FLOAT)) { 123 return TypeNode.isNumericType(valueType) && !valueType.equals(TypeNode.DOUBLE); 124 } 125 // LHS is integer boxed type, RHS should be any numeric type or any numeric boxed type. 126 if (variableType.equals(TypeNode.DOUBLE)) { 127 return TypeNode.isNumericType(valueType); 128 } 129 // *= operator does not support boxed Short, Character, Byte, null, reference, void type. 130 return false; 131 } 132 133 // isValidXorAssignmentType validates the types for LHS variable expr and RHS expr. 134 // ^= can be applied on boolean and non-floating-point numeric type. isValidXorAssignmentType(TypeNode variableType, TypeNode valueType)135 private boolean isValidXorAssignmentType(TypeNode variableType, TypeNode valueType) { 136 // LHS is boolean or its boxed type, RHS should be boolean or its boxed type. 137 if (variableType.equals(TypeNode.BOOLEAN)) { 138 return valueType.equals(variableType); 139 } 140 // LHS is integer boxed type, RHS should be non-floating-point numeric types or their boxed 141 // types. 142 if (variableType.equals(TypeNode.INT)) { 143 return TypeNode.isNumericType(valueType) && !TypeNode.isFloatingPointType(valueType); 144 } 145 // LHS is non-floating-point numeric types, RHS should be non-float-point numeric types or 146 // their boxed types. 147 return TypeNode.isNumericType(variableType) 148 && TypeNode.isNumericType(valueType) 149 && !TypeNode.isFloatingPointType(variableType) 150 && !TypeNode.isFloatingPointType(valueType) 151 && !TypeNode.isBoxedType(variableType); 152 } 153 } 154 } 155