Skip to content

Commit bd9532c

Browse files
feat(ast): array expressions (#1080)
* feat(ast): anonymous arrays for annotations * feat(ast): add convenience methods in anon array * feat(annotation): allow adding anon arrays * fix: fixed comments, test util class * feat(ast): arrays to allow VarExp and ValueExpr * fix(ast): add description only for assignments * fix(ast): comment correction, test array assignmnt * feat(test): test anon array assignment * fix(license): add licenses * fix(ast): various fixes * Perform validation in build() * Ensure type() to be explicitly set * Expose add Expr, but validate that they are either ValueExpr or VariableExpr * fix(ast): ArrayExpr ImportWriterVisitor fix & test * fix: remove unecessary comment
1 parent f5d5524 commit bd9532c

File tree

10 files changed

+411
-0
lines changed

10 files changed

+411
-0
lines changed

src/main/java/com/google/api/generator/engine/ast/AnnotationNode.java

+11
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,17 @@ public Builder setDescription(VariableExpr variableExpr) {
108108
return setDescriptionExprs(Arrays.asList(variableExpr));
109109
}
110110

111+
/**
112+
* To set single ArrayExpr as description.
113+
*
114+
* @param arrayExpr
115+
* @return Builder
116+
*/
117+
public Builder setDescription(ArrayExpr arrayExpr) {
118+
Preconditions.checkState(descriptionExprs() == null, REPEAT_SINGLE_EXCEPTION_MESSAGE);
119+
return setDescriptionExprs(Arrays.asList(arrayExpr));
120+
}
121+
111122
/**
112123
* To add an AssignmentExpr as parameter. Can be used repeatedly to add multiple parameters.
113124
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright 2022 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.Arrays;
21+
import java.util.List;
22+
23+
@AutoValue
24+
public abstract class ArrayExpr implements Expr {
25+
26+
public abstract List<Expr> exprs();
27+
28+
public abstract TypeNode type();
29+
30+
@Override
31+
public void accept(AstNodeVisitor visitor) {
32+
visitor.visit(this);
33+
}
34+
35+
public static ArrayExpr.Builder builder() {
36+
return new AutoValue_ArrayExpr.Builder().setExprs(ImmutableList.of());
37+
}
38+
39+
public static ArrayExpr withStrings(String... stringValues) {
40+
ArrayExpr.Builder builder = ArrayExpr.builder();
41+
Arrays.asList(stringValues).stream().forEach(s -> builder.addExpr(s));
42+
return builder.build();
43+
}
44+
45+
public static ArrayExpr withExprs(Expr... exprs) {
46+
return ArrayExpr.builder().setExprs(Arrays.asList(exprs)).build();
47+
}
48+
49+
@AutoValue.Builder
50+
public abstract static class Builder {
51+
52+
private static final String SAME_TYPE_EXPRS_MESSAGE =
53+
"All expressions must be of the type" + " specified in this ArrayExpr";
54+
private static final String EXPR_ALLOWED_CLASSES_MESSAGE =
55+
"Only VariableExpr and ValueExpr can be used as elements of ArrayExpr";
56+
57+
abstract List<Expr> exprs();
58+
59+
abstract TypeNode type();
60+
61+
/**
62+
* To add a string expression same-type validation is performed
63+
*
64+
* @param expr
65+
* @return Builder
66+
*/
67+
public ArrayExpr.Builder addExpr(String expr) {
68+
return addExpr(ValueExpr.withValue(StringObjectValue.withValue(expr)));
69+
}
70+
71+
public ArrayExpr.Builder addExpr(Expr expr) {
72+
return setExprs((new ImmutableList.Builder<Expr>().addAll(exprs()).add(expr).build()));
73+
}
74+
75+
public abstract ArrayExpr.Builder setExprs(List<Expr> exprs);
76+
77+
public abstract ArrayExpr.Builder setType(TypeNode type);
78+
79+
abstract ArrayExpr autoBuild();
80+
81+
public ArrayExpr build() {
82+
Preconditions.checkState(
83+
exprs().stream().allMatch(exp -> exp instanceof ValueExpr || exp instanceof VariableExpr),
84+
EXPR_ALLOWED_CLASSES_MESSAGE);
85+
TypeNode elementType = TypeNode.createElementTypeFromArrayType(type());
86+
Preconditions.checkState(
87+
exprs().stream().allMatch(exp -> exp.type().equals(elementType)),
88+
SAME_TYPE_EXPRS_MESSAGE);
89+
return autoBuild();
90+
}
91+
}
92+
}

src/main/java/com/google/api/generator/engine/ast/AstNodeVisitor.java

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public interface AstNodeVisitor {
2424

2525
public void visit(AnnotationNode annotation);
2626

27+
public void visit(ArrayExpr expr);
28+
2729
public void visit(ConcreteReference reference);
2830

2931
public void visit(VaporReference reference);

src/main/java/com/google/api/generator/engine/ast/TypeNode.java

+17
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,23 @@ public enum TypeKind {
101101

102102
public abstract boolean isArray();
103103

104+
public static TypeNode createArrayTypeOf(TypeNode type) {
105+
return builder()
106+
.setTypeKind(type.typeKind())
107+
.setReference(type.reference())
108+
.setIsArray(true)
109+
.build();
110+
}
111+
112+
public static TypeNode createElementTypeFromArrayType(TypeNode type) {
113+
Preconditions.checkArgument(type.isArray(), "Input type must be an array");
114+
return builder()
115+
.setTypeKind(type.typeKind())
116+
.setReference(type.reference())
117+
.setIsArray(false)
118+
.build();
119+
}
120+
104121
@Nullable
105122
public abstract Reference reference();
106123

src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.google.api.generator.engine.ast.AnnotationNode;
1818
import com.google.api.generator.engine.ast.AnonymousClassExpr;
1919
import com.google.api.generator.engine.ast.ArithmeticOperationExpr;
20+
import com.google.api.generator.engine.ast.ArrayExpr;
2021
import com.google.api.generator.engine.ast.AssignmentExpr;
2122
import com.google.api.generator.engine.ast.AssignmentOperationExpr;
2223
import com.google.api.generator.engine.ast.AstNodeVisitor;
@@ -167,6 +168,11 @@ public void visit(AnnotationNode annotation) {
167168
annotation.type().accept(this);
168169
}
169170

171+
@Override
172+
public void visit(ArrayExpr expr) {
173+
expr.type().accept(this);
174+
}
175+
170176
/** =============================== EXPRESSIONS =============================== */
171177
@Override
172178
public void visit(ValueExpr valueExpr) {

src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java

+14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.google.api.generator.engine.ast.AnnotationNode;
1818
import com.google.api.generator.engine.ast.AnonymousClassExpr;
1919
import com.google.api.generator.engine.ast.ArithmeticOperationExpr;
20+
import com.google.api.generator.engine.ast.ArrayExpr;
2021
import com.google.api.generator.engine.ast.AssignmentExpr;
2122
import com.google.api.generator.engine.ast.AssignmentOperationExpr;
2223
import com.google.api.generator.engine.ast.AstNodeVisitor;
@@ -165,6 +166,19 @@ public void visit(ScopeNode scope) {
165166
buffer.append(scope.toString());
166167
}
167168

169+
@Override
170+
public void visit(ArrayExpr expr) {
171+
buffer.append(LEFT_BRACE);
172+
for (int i = 0; i < expr.exprs().size(); i++) {
173+
expr.exprs().get(i).accept(this);
174+
if (i < expr.exprs().size() - 1) {
175+
buffer.append(COMMA);
176+
buffer.append(SPACE);
177+
}
178+
}
179+
buffer.append(RIGHT_BRACE);
180+
}
181+
168182
@Override
169183
public void visit(AnnotationNode annotation) {
170184
buffer.append(AT);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2022 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 static com.google.common.truth.Truth.assertThat;
18+
import static org.junit.Assert.assertThrows;
19+
20+
import com.google.api.generator.util.TestUtils;
21+
import org.junit.Test;
22+
23+
public class ArrayExprTest {
24+
25+
@Test
26+
public void validAnonymousArray_sametype() {
27+
ArrayExpr.Builder exprBuilder =
28+
ArrayExpr.builder()
29+
.setType(TypeNode.createArrayTypeOf(TypeNode.STRING))
30+
.addExpr(TestUtils.generateStringValueExpr("test1"))
31+
.addExpr(TestUtils.generateStringValueExpr("test2"))
32+
.addExpr(TestUtils.generateStringValueExpr("test3"))
33+
.addExpr(
34+
ValueExpr.withValue(
35+
PrimitiveValue.builder().setValue("1").setType(TypeNode.INT).build()));
36+
37+
Exception thrown = assertThrows(IllegalStateException.class, () -> exprBuilder.build());
38+
assertThat(thrown)
39+
.hasMessageThat()
40+
.contains("All expressions must be of the type specified in this ArrayExpr");
41+
}
42+
43+
@Test
44+
public void validAnonymousArray_unsetTypeThrows() {
45+
ArrayExpr.Builder exprBuilder = ArrayExpr.builder();
46+
IllegalStateException thrown =
47+
assertThrows(IllegalStateException.class, () -> exprBuilder.build());
48+
assertThat(thrown).hasMessageThat().contains("Property \"type\" has not been set");
49+
}
50+
51+
@Test
52+
public void validAnonymousArray_onlyVariableAndValueExprs() {
53+
ArrayExpr.Builder exprBuilder =
54+
ArrayExpr.builder().setType(TypeNode.createArrayTypeOf(TypeNode.INT));
55+
Variable variable = Variable.builder().setName("x").setType(TypeNode.INT).build();
56+
VariableExpr variableExpr =
57+
VariableExpr.builder().setVariable(variable).setIsDecl(true).build();
58+
Value value = PrimitiveValue.builder().setType(TypeNode.INT).setValue("3").build();
59+
Expr valueExpr = ValueExpr.builder().setValue(value).build();
60+
AssignmentExpr assignExpr =
61+
AssignmentExpr.builder().setVariableExpr(variableExpr).setValueExpr(valueExpr).build();
62+
exprBuilder.addExpr(assignExpr);
63+
IllegalStateException thrown =
64+
assertThrows(IllegalStateException.class, () -> exprBuilder.build());
65+
assertThat(thrown)
66+
.hasMessageThat()
67+
.contains("Only VariableExpr and ValueExpr can be used as elements of ArrayExpr");
68+
}
69+
}

src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java

+15
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.api.generator.engine.ast.AnnotationNode;
2121
import com.google.api.generator.engine.ast.AnonymousClassExpr;
2222
import com.google.api.generator.engine.ast.ArithmeticOperationExpr;
23+
import com.google.api.generator.engine.ast.ArrayExpr;
2324
import com.google.api.generator.engine.ast.AssignmentExpr;
2425
import com.google.api.generator.engine.ast.BlockComment;
2526
import com.google.api.generator.engine.ast.CommentStatement;
@@ -919,6 +920,20 @@ public void writeLambdaExprImports() {
919920
writerVisitor.write());
920921
}
921922

923+
@Test
924+
public void importArrayExprTypes() {
925+
ArrayExpr arrayExpr =
926+
ArrayExpr.builder()
927+
.setType(
928+
TypeNode.createArrayTypeOf(
929+
TypeNode.withReference(ConcreteReference.withClazz(UnaryOperationExpr.class))))
930+
.build();
931+
arrayExpr.accept(writerVisitor);
932+
assertEquals(
933+
"import com.google.api.generator.engine.ast.UnaryOperationExpr;\n\n",
934+
writerVisitor.write());
935+
}
936+
922937
/** =============================== HELPERS =============================== */
923938
private static Variable createVariable(String variableName, TypeNode type) {
924939
return Variable.builder().setName(variableName).setType(type).build();

0 commit comments

Comments
 (0)