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 ArithmeticOperationExpr implements OperationExpr { 22 lhsExpr()23 public abstract Expr lhsExpr(); 24 rhsExpr()25 public abstract Expr rhsExpr(); 26 27 @Override operatorKind()28 public abstract OperatorKind operatorKind(); 29 30 @Override type()31 public abstract TypeNode type(); 32 33 @Override accept(AstNodeVisitor visitor)34 public void accept(AstNodeVisitor visitor) { 35 visitor.visit(this); 36 } 37 concatWithExprs(Expr lhsExpr, Expr rhsExpr)38 public static ArithmeticOperationExpr concatWithExprs(Expr lhsExpr, Expr rhsExpr) { 39 return builder() 40 .setLhsExpr(lhsExpr) 41 .setRhsExpr(rhsExpr) 42 .setOperatorKind(OperatorKind.ARITHMETIC_ADDITION) 43 .setType(TypeNode.STRING) 44 .build(); 45 } 46 builder()47 private static Builder builder() { 48 return new AutoValue_ArithmeticOperationExpr.Builder(); 49 } 50 51 @AutoValue.Builder 52 abstract static class Builder { 53 54 // Private setter. setLhsExpr(Expr expr)55 abstract Builder setLhsExpr(Expr expr); 56 57 // Private setter. setRhsExpr(Expr expr)58 abstract Builder setRhsExpr(Expr expr); 59 60 // Private setter. setOperatorKind(OperatorKind operator)61 abstract Builder setOperatorKind(OperatorKind operator); 62 63 // Private setter. setType(TypeNode type)64 abstract Builder setType(TypeNode type); 65 autoBuild()66 abstract ArithmeticOperationExpr autoBuild(); 67 build()68 private ArithmeticOperationExpr build() { 69 ArithmeticOperationExpr arithmeticOperationExpr = autoBuild(); 70 TypeNode lhsExprType = arithmeticOperationExpr.lhsExpr().type(); 71 TypeNode rhsExprType = arithmeticOperationExpr.rhsExpr().type(); 72 OperatorKind operator = arithmeticOperationExpr.operatorKind(); 73 final String errorMsg = 74 String.format( 75 "Arithmetic operator %s can not be applied to %s, %s.", 76 operator, lhsExprType.toString(), rhsExprType.toString()); 77 78 // None of expression should be void type. 79 Preconditions.checkState( 80 !lhsExprType.equals(TypeNode.VOID) && !rhsExprType.equals(TypeNode.VOID), errorMsg); 81 82 // Type-checking for Concat operator. 83 if (operator.equals(OperatorKind.ARITHMETIC_ADDITION)) { 84 Preconditions.checkState(isValidConcatTypes(lhsExprType, rhsExprType), errorMsg); 85 } 86 87 return arithmeticOperationExpr; 88 } 89 isValidConcatTypes(TypeNode lhsType, TypeNode rhsType)90 private boolean isValidConcatTypes(TypeNode lhsType, TypeNode rhsType) { 91 // concat requires at least one String-typed expression 92 return lhsType.equals(TypeNode.STRING) || rhsType.equals(TypeNode.STRING); 93 } 94 } 95 } 96