Skip to content

Commit 1205b0c

Browse files
[javanaut][1/2]feat: Add RelationalOperationExpr to enable equality operators (#289)
* add relational equality operation expr and unit test * enables == and !=
1 parent da3a8a4 commit 1205b0c

10 files changed

Lines changed: 1035 additions & 0 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ public interface AstNodeVisitor {
5555

5656
public void visit(UnaryOperationExpr unaryOperationExpr);
5757

58+
public void visit(RelationalOperationExpr relationalOperationExpr);
59+
5860
public void visit(LogicalOperationExpr logicalOperationExpr);
5961

6062
/** =============================== COMMENT =============================== */
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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 RelationalOperationExpr implements OperationExpr {
22+
public abstract Expr lhsExpr();
23+
24+
public abstract Expr rhsExpr();
25+
26+
public abstract OperatorKind operatorKind();
27+
28+
@Override
29+
public TypeNode type() {
30+
return TypeNode.BOOLEAN;
31+
}
32+
33+
@Override
34+
public void accept(AstNodeVisitor visitor) {
35+
visitor.visit(this);
36+
}
37+
38+
// Convenience wrapper.
39+
public static RelationalOperationExpr equalToWithExprs(Expr lhsExpr, Expr rhsExpr) {
40+
return builder()
41+
.setLhsExpr(lhsExpr)
42+
.setRhsExpr(rhsExpr)
43+
.setOperatorKind(OperatorKind.RELATIONAL_EQUAL_TO)
44+
.build();
45+
}
46+
47+
// Convenience wrapper.
48+
public static RelationalOperationExpr notEqualToWithExprs(Expr lhsExpr, Expr rhsExpr) {
49+
return builder()
50+
.setLhsExpr(lhsExpr)
51+
.setRhsExpr(rhsExpr)
52+
.setOperatorKind(OperatorKind.RELATIONAL_NOT_EQUAL_TO)
53+
.build();
54+
}
55+
56+
// TODO(summerji): Add convenience wrapper lessThanWithExprs
57+
// public static RelationalOperationExpr lessThanWithExprs(Expr lhsExpr, Expr rhsExpr) {
58+
// return builder()
59+
// .setLhsExpr(lhsExpr)
60+
// .setRhsExpr(rhsExpr)
61+
// .setOperatorKind(OperatorKind.RELATIONAL_LESS_THAN)
62+
// .build();
63+
// }
64+
65+
private static Builder builder() {
66+
return new AutoValue_RelationalOperationExpr.Builder();
67+
}
68+
69+
@AutoValue.Builder
70+
abstract static class Builder {
71+
72+
// Private setter.
73+
abstract Builder setLhsExpr(Expr expr);
74+
75+
// Private setter.
76+
abstract Builder setRhsExpr(Expr expr);
77+
78+
// Private setter.
79+
abstract Builder setOperatorKind(OperatorKind operator);
80+
81+
abstract RelationalOperationExpr autoBuild();
82+
83+
private RelationalOperationExpr build() {
84+
RelationalOperationExpr relationalOperationExpr = autoBuild();
85+
TypeNode lhsExprType = relationalOperationExpr.lhsExpr().type();
86+
TypeNode rhsExprType = relationalOperationExpr.rhsExpr().type();
87+
OperatorKind operator = relationalOperationExpr.operatorKind();
88+
final String errorMsg =
89+
String.format(
90+
"Relational operator %s can not be applied to %s, %s.",
91+
operator, lhsExprType.toString(), rhsExprType.toString());
92+
93+
if (operator.equals(OperatorKind.RELATIONAL_EQUAL_TO)
94+
|| operator.equals(OperatorKind.RELATIONAL_NOT_EQUAL_TO)) {
95+
Preconditions.checkState(isValidEqualityType(lhsExprType, rhsExprType), errorMsg);
96+
}
97+
98+
return relationalOperationExpr;
99+
}
100+
101+
// isValidEqualityType checks expressions' type for equality operator (==) and non-equality
102+
// operator (!=).
103+
private boolean isValidEqualityType(TypeNode lhsType, TypeNode rhsType) {
104+
// If the expression's types are matched, return true
105+
if (lhsType.equals(rhsType)) {
106+
return true;
107+
}
108+
109+
// If the expressions' type are array, the types should be array and matched, or either is
110+
// null type;
111+
if (lhsType.isArray() || rhsType.isArray()) {
112+
return lhsType.equals(TypeNode.NULL) || rhsType.equals(TypeNode.NULL);
113+
}
114+
115+
// If lhs expression type is numeric type (char, byte, short, int, long, double), the rhs
116+
// expression type should be any numeric type or any numeric boxed type
117+
if (TypeNode.isNumericType(lhsType) && TypeNode.isNumericType(rhsType)) {
118+
return true;
119+
}
120+
121+
// If lhs expression type is new Object or null, the rhs type should be a reference type or
122+
// null or boxed type;
123+
if (lhsType.equals(TypeNode.OBJECT) || lhsType.equals(TypeNode.NULL)) {
124+
return TypeNode.isReferenceType(rhsType)
125+
|| rhsType.equals(TypeNode.OBJECT)
126+
|| rhsType.equals(TypeNode.NULL);
127+
}
128+
129+
// If lhs expression type is Boxed type or a referenced type, rhs should be null or object,
130+
// other cases have been covered in previous conditions.
131+
if (TypeNode.isBoxedType(lhsType) || TypeNode.isReferenceType(lhsType)) {
132+
return rhsType.equals(TypeNode.NULL) || rhsType.equals(TypeNode.OBJECT);
133+
}
134+
135+
return false;
136+
}
137+
}
138+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ public static boolean isNumericType(TypeNode type) {
148148
|| type.equals(TypeNode.CHAR);
149149
}
150150

151+
public static boolean isBoxedType(TypeNode type) {
152+
return isReferenceType(type) && BOXED_TYPE_MAP.containsValue(type);
153+
}
154+
151155
public boolean isPrimitiveType() {
152156
return isPrimitiveType(typeKind());
153157
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.google.api.generator.engine.ast.NewObjectExpr;
4141
import com.google.api.generator.engine.ast.Reference;
4242
import com.google.api.generator.engine.ast.ReferenceConstructorExpr;
43+
import com.google.api.generator.engine.ast.RelationalOperationExpr;
4344
import com.google.api.generator.engine.ast.ReturnExpr;
4445
import com.google.api.generator.engine.ast.ScopeNode;
4546
import com.google.api.generator.engine.ast.Statement;
@@ -227,6 +228,12 @@ public void visit(UnaryOperationExpr unaryOperationExpr) {
227228
unaryOperationExpr.expr().accept(this);
228229
}
229230

231+
@Override
232+
public void visit(RelationalOperationExpr relationalOperationExpr) {
233+
relationalOperationExpr.lhsExpr().accept(this);
234+
relationalOperationExpr.rhsExpr().accept(this);
235+
}
236+
230237
@Override
231238
public void visit(LogicalOperationExpr logicalOperationExpr) {
232239
logicalOperationExpr.lhsExpr().accept(this);

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.google.api.generator.engine.ast.NewObjectExpr;
4141
import com.google.api.generator.engine.ast.OperatorKind;
4242
import com.google.api.generator.engine.ast.ReferenceConstructorExpr;
43+
import com.google.api.generator.engine.ast.RelationalOperationExpr;
4344
import com.google.api.generator.engine.ast.ReturnExpr;
4445
import com.google.api.generator.engine.ast.ScopeNode;
4546
import com.google.api.generator.engine.ast.Statement;
@@ -410,6 +411,15 @@ public void visit(UnaryOperationExpr unaryOperationExpr) {
410411
}
411412
}
412413

414+
@Override
415+
public void visit(RelationalOperationExpr relationalOperationExpr) {
416+
relationalOperationExpr.lhsExpr().accept(this);
417+
space();
418+
operator(relationalOperationExpr.operatorKind());
419+
space();
420+
relationalOperationExpr.rhsExpr().accept(this);
421+
}
422+
413423
@Override
414424
public void visit(LogicalOperationExpr logicalOperationExpr) {
415425
logicalOperationExpr.lhsExpr().accept(this);

src/test/java/com/google/api/generator/engine/ast/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ TESTS = [
3636
"WhileStatementTest",
3737
"ArithmeticOperationExprTest",
3838
"UnaryOperationExprTest",
39+
"RelationalOperationExprTest",
3940
"LogicalOperationExprTest",
4041
]
4142

0 commit comments

Comments
 (0)