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 import com.google.common.collect.ImmutableList; 20 import java.util.Collections; 21 import java.util.List; 22 23 @AutoValue 24 public abstract class GeneralForStatement implements Statement { initializationExpr()25 public abstract Expr initializationExpr(); 26 terminationExpr()27 public abstract Expr terminationExpr(); 28 updateExpr()29 public abstract Expr updateExpr(); 30 body()31 public abstract ImmutableList<Statement> body(); 32 33 @Override accept(AstNodeVisitor visitor)34 public void accept(AstNodeVisitor visitor) { 35 visitor.visit(this); 36 } 37 38 // incrementWith is convenience wrapper to generate index-base for-loop with lower and upper bound 39 // and post increment on variable, like code in ```for (int i = 0; i < getMax(); i++) {..}``` 40 // TODO (unsupported): Add more convenience wrapper for the future generation needs. incrementWith( VariableExpr localVariableExpr, ValueExpr initialValueExpr, Expr maxSizeExpr, List<Statement> body)41 public static GeneralForStatement incrementWith( 42 VariableExpr localVariableExpr, 43 ValueExpr initialValueExpr, 44 Expr maxSizeExpr, 45 List<Statement> body) { 46 return builder() 47 .setInitializationExpr( 48 AssignmentExpr.builder() 49 .setVariableExpr(localVariableExpr) 50 .setValueExpr(initialValueExpr) 51 .build()) 52 .setTerminationExpr( 53 RelationalOperationExpr.lessThanWithExprs( 54 localVariableExpr.toBuilder().setIsDecl(false).build(), maxSizeExpr)) 55 .setUpdateExpr( 56 UnaryOperationExpr.postfixIncrementWithExpr( 57 localVariableExpr.toBuilder().setIsDecl(false).build())) 58 .setBody(body) 59 .build(); 60 } 61 builder()62 private static Builder builder() { 63 return new AutoValue_GeneralForStatement.Builder().setBody(Collections.emptyList()); 64 } 65 66 @AutoValue.Builder 67 abstract static class Builder { 68 // Private setter. setInitializationExpr(Expr initializationExpr)69 abstract Builder setInitializationExpr(Expr initializationExpr); 70 // Private setter. setTerminationExpr(Expr terminationExpr)71 abstract Builder setTerminationExpr(Expr terminationExpr); 72 // Private setter. setUpdateExpr(Expr incrementExpr)73 abstract Builder setUpdateExpr(Expr incrementExpr); 74 // Private setter. setBody(List<Statement> body)75 abstract Builder setBody(List<Statement> body); 76 autoBuild()77 abstract GeneralForStatement autoBuild(); 78 79 // Type-checking will be done in the sub-expressions. build()80 GeneralForStatement build() { 81 GeneralForStatement generalForStatement = autoBuild(); 82 NodeValidator.checkNoNullElements( 83 generalForStatement.body(), "body", "general for-statement"); 84 Expr initExpr = generalForStatement.initializationExpr(); 85 if (initExpr instanceof AssignmentExpr) { 86 VariableExpr localVarExpr = ((AssignmentExpr) initExpr).variableExpr(); 87 // Declare a variable inside for-loop initialization expression. 88 if (localVarExpr.isDecl()) { 89 Preconditions.checkState( 90 localVarExpr.scope().equals(ScopeNode.LOCAL), 91 String.format( 92 "Variable %s declare in a general for-loop cannot have a non-local scope", 93 localVarExpr.variable().identifier().name())); 94 Preconditions.checkState(!localVarExpr.isStatic(), "Modifier 'static' not allow here."); 95 } 96 } 97 // TODO (unsupport): Add type-checking for initialization, termination, update exprs if public 98 // setters for users for future needs. 99 // Initialization and update expr should belong to StatementExpressionList. 100 // Termination expr must have type boolean or Boolean. And these three exprs are optional. 101 // More details at 102 // https://docs.oracle.com/javase/specs/jls/se10/html/jls-14.html#jls-StatementExpressionList 103 return autoBuild(); 104 } 105 } 106 } 107