Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public interface AstNodeVisitor {

public void visit(ArithmeticOperationExpr arithmeticOperationExpr);

public void visit(UnaryOperationExpr unaryOperationExpr);

/** =============================== COMMENT =============================== */
public void visit(LineComment lineComment);

Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/google/api/generator/engine/ast/TypeNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nullable;

@AutoValue
Expand Down Expand Up @@ -66,6 +68,14 @@ public enum TypeKind {
withReference(ConcreteReference.withClazz(Short.class));

private static final Map<TypeNode, TypeNode> BOXED_TYPE_MAP = createBoxedTypeMap();
private static final Set<TypeNode> NUMERIC_TYPE_SET =
ImmutableSet.of(
TypeNode.INT,
TypeNode.DOUBLE,
TypeNode.LONG,
TypeNode.SHORT,
TypeNode.FLOAT,
TypeNode.CHAR);

public static final TypeNode VOID = builder().setTypeKind(TypeKind.VOID).build();

Expand Down Expand Up @@ -125,6 +135,14 @@ public static boolean isReferenceType(TypeNode type) {
&& !type.equals(TypeNode.NULL);
}

public static boolean isNumericType(TypeNode type) {
return NUMERIC_TYPE_SET.contains(type);
}

public static boolean isBoxedType(TypeNode type) {
return BOXED_TYPE_MAP.containsValue(type);
}

public boolean isPrimitiveType() {
return isPrimitiveType(typeKind());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.api.generator.engine.ast;

import com.google.auto.value.AutoValue;
import com.google.common.base.Preconditions;

@AutoValue
public abstract class UnaryOperationExpr implements OperationExpr {

public abstract Expr expr();

public abstract OperatorKind operatorKind();

public abstract TypeNode type();

public void accept(AstNodeVisitor visitor) {
visitor.visit(this);
}

public static UnaryOperationExpr postfixIncrementWithExpr(Expr expr) {
return builder()
.setExpr(expr)
.setOperatorKind(OperatorKind.UNARY_POST_INCREMENT)
.setType(expr.type())
.build();
}

public static UnaryOperationExpr logicalNotWithExpr(Expr expr) {
return builder()
.setOperatorKind(OperatorKind.UNARY_LOGICAL_NOT)
.setExpr(expr)
.setType(TypeNode.BOOLEAN)
.build();
}

private static Builder builder() {
return new AutoValue_UnaryOperationExpr.Builder();
}

@AutoValue.Builder
abstract static class Builder {

// Private setter.
abstract Builder setExpr(Expr expr);

// Private setter.
abstract Builder setOperatorKind(OperatorKind operator);

// Private setter.
abstract Builder setType(TypeNode type);

abstract UnaryOperationExpr autoBuild();

private UnaryOperationExpr build() {
UnaryOperationExpr unaryOperationExpr = autoBuild();
TypeNode exprType = unaryOperationExpr.expr().type();
OperatorKind operator = unaryOperationExpr.operatorKind();
final String errorMsg =
String.format(
"Unary operator %s can not be applied to %s. ", operator, exprType.toString());

Preconditions.checkState(
!exprType.equals(TypeNode.VOID) && !exprType.equals(TypeNode.NULL), errorMsg);

if (operator.equals(OperatorKind.UNARY_LOGICAL_NOT)) {
Preconditions.checkState(isValidLogicalNotType(exprType), errorMsg);
}

if (operator.equals(OperatorKind.UNARY_POST_INCREMENT)) {
Preconditions.checkState(isValidIncrementType(exprType), errorMsg);
}

return unaryOperationExpr;
}
}

private static boolean isValidLogicalNotType(TypeNode exprType) {
// Logical not (!) can only be applied on boolean/Boolean type
return exprType.equals(TypeNode.BOOLEAN);
}

private static boolean isValidIncrementType(TypeNode exprType) {
// Increment (++) can be applied on numeric types(int, double, float, long, short, char)
// and its boxed type (exclude Boolean)
return TypeNode.isNumericType(exprType)
|| (TypeNode.isBoxedType(exprType) && !exprType.equals(TypeNode.BOOLEAN_OBJECT));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.google.api.generator.engine.ast.ThrowExpr;
import com.google.api.generator.engine.ast.TryCatchStatement;
import com.google.api.generator.engine.ast.TypeNode;
import com.google.api.generator.engine.ast.UnaryOperationExpr;
import com.google.api.generator.engine.ast.ValueExpr;
import com.google.api.generator.engine.ast.VariableExpr;
import com.google.api.generator.engine.ast.WhileStatement;
Expand Down Expand Up @@ -218,6 +219,11 @@ public void visit(ArithmeticOperationExpr arithmeticOperationExpr) {
arithmeticOperationExpr.rhsExpr().accept(this);
}

@Override
public void visit(UnaryOperationExpr unaryOperationExpr) {
unaryOperationExpr.expr().accept(this);
}

/** =============================== STATEMENTS =============================== */
@Override
public void visit(ExprStatement exprStatement) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.google.api.generator.engine.ast.TryCatchStatement;
import com.google.api.generator.engine.ast.TypeNode;
import com.google.api.generator.engine.ast.TypeNode.TypeKind;
import com.google.api.generator.engine.ast.UnaryOperationExpr;
import com.google.api.generator.engine.ast.ValueExpr;
import com.google.api.generator.engine.ast.Variable;
import com.google.api.generator.engine.ast.VariableExpr;
Expand Down Expand Up @@ -394,6 +395,17 @@ public void visit(ArithmeticOperationExpr arithmeticOperationExpr) {
arithmeticOperationExpr.rhsExpr().accept(this);
}

@Override
public void visit(UnaryOperationExpr unaryOperationExpr) {
if (unaryOperationExpr.operatorKind().isPrefixOperator()) {
operator(unaryOperationExpr.operatorKind());
unaryOperationExpr.expr().accept(this);
} else {
unaryOperationExpr.expr().accept(this);
operator(unaryOperationExpr.operatorKind());
}
}

/** =============================== STATEMENTS =============================== */
@Override
public void visit(ExprStatement exprStatement) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ TESTS = [
"SuperObjectValueTest",
"WhileStatementTest",
"ArithmeticOperationExprTest",
"UnaryOperationExprTest",
]

filegroup(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.api.generator.engine.ast;

import static org.junit.Assert.assertThrows;

import org.junit.Test;

public class UnaryOperationExprTest {
/** =============================== Logic Not Operation Expr =============================== */
@Test
public void logicalNotOperationExpr_validBasic() {
VariableExpr variableExpr =
VariableExpr.withVariable(
Variable.builder().setName("x").setType(TypeNode.BOOLEAN).build());
UnaryOperationExpr.logicalNotWithExpr(variableExpr);
// No exception thrown, we're good.
}

@Test
public void logicalNot_validBoxedType() {
VariableExpr variableExpr =
VariableExpr.withVariable(
Variable.builder().setName("x").setType(TypeNode.BOOLEAN_OBJECT).build());
UnaryOperationExpr.logicalNotWithExpr(variableExpr);
// No exception thrown, we're good.
}

@Test
public void logicalNot_invalidNumericType() {
VariableExpr variableExpr =
VariableExpr.withVariable(Variable.builder().setName("x").setType(TypeNode.INT).build());
assertThrows(
IllegalStateException.class, () -> UnaryOperationExpr.logicalNotWithExpr(variableExpr));
}

@Test
public void logicalNot_invalidReferenceType() {
VariableExpr variableExpr =
VariableExpr.withVariable(Variable.builder().setName("x").setType(TypeNode.STRING).build());
assertThrows(
IllegalStateException.class, () -> UnaryOperationExpr.logicalNotWithExpr(variableExpr));
}

/**
* =============================== Post Increment Operation Expr ===============================
*/
@Test
public void postIncrement_validBasic() {
VariableExpr variableExpr =
VariableExpr.withVariable(Variable.builder().setName("x").setType(TypeNode.INT).build());
UnaryOperationExpr.postfixIncrementWithExpr(variableExpr);
// No exception thrown, we're good.
}

@Test
public void postIncrement_validBoxedType() {
VariableExpr variableExpr =
VariableExpr.withVariable(
Variable.builder().setName("x").setType(TypeNode.FLOAT_OBJECT).build());
UnaryOperationExpr.postfixIncrementWithExpr(variableExpr);
// No exception thrown, we're good.
}

@Test
public void postIncrement_invalidBoxedBooleanType() {
VariableExpr variableExpr =
VariableExpr.withVariable(
Variable.builder().setName("x").setType(TypeNode.BOOLEAN_OBJECT).build());
assertThrows(
IllegalStateException.class,
() -> UnaryOperationExpr.postfixIncrementWithExpr(variableExpr));
}

@Test
public void postIncrement_invalidReferenceType() {
VariableExpr variableExpr =
VariableExpr.withVariable(Variable.builder().setName("x").setType(TypeNode.STRING).build());
assertThrows(
IllegalStateException.class,
() -> UnaryOperationExpr.postfixIncrementWithExpr(variableExpr));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import com.google.api.generator.engine.ast.ThisObjectValue;
import com.google.api.generator.engine.ast.ThrowExpr;
import com.google.api.generator.engine.ast.TypeNode;
import com.google.api.generator.engine.ast.UnaryOperationExpr;
import com.google.api.generator.engine.ast.ValueExpr;
import com.google.api.generator.engine.ast.VaporReference;
import com.google.api.generator.engine.ast.Variable;
Expand Down Expand Up @@ -867,6 +868,32 @@ public void writeSynchronizedStatementImports_basicVariableExpr() {
"import java.util.Map;\n\n"));
}

@Test
public void writeUnaryOperationExprImports_LogicalNot() {
MethodInvocationExpr expr =
MethodInvocationExpr.builder()
.setStaticReferenceType(TypeNode.withReference(ConcreteReference.withClazz(Expr.class)))
.setMethodName("isEmpty")
.setReturnType(TypeNode.BOOLEAN)
.build();
UnaryOperationExpr unaryOperationExpr = UnaryOperationExpr.logicalNotWithExpr(expr);
unaryOperationExpr.accept(writerVisitor);
assertEquals(writerVisitor.write(), "import com.google.api.generator.engine.ast.Expr;\n\n");
}

@Test
public void writeUnaryOperationExprImports_PostIncrement() {
MethodInvocationExpr expr =
MethodInvocationExpr.builder()
.setStaticReferenceType(TypeNode.withReference(ConcreteReference.withClazz(Expr.class)))
.setMethodName("getNumber")
.setReturnType(TypeNode.INT)
.build();
UnaryOperationExpr unaryOperationExpr = UnaryOperationExpr.postfixIncrementWithExpr(expr);
unaryOperationExpr.accept(writerVisitor);
assertEquals(writerVisitor.write(), "import com.google.api.generator.engine.ast.Expr;\n\n");
}

private static TypeNode createType(Class clazz) {
return TypeNode.withReference(ConcreteReference.withClazz(clazz));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import com.google.api.generator.engine.ast.ThrowExpr;
import com.google.api.generator.engine.ast.TryCatchStatement;
import com.google.api.generator.engine.ast.TypeNode;
import com.google.api.generator.engine.ast.UnaryOperationExpr;
import com.google.api.generator.engine.ast.Value;
import com.google.api.generator.engine.ast.ValueExpr;
import com.google.api.generator.engine.ast.VaporReference;
Expand Down Expand Up @@ -1975,6 +1976,29 @@ public void writeSuperObjectValue_accessFieldAndInvokeMethod() {
assertThat(writerVisitor.write()).isEqualTo("super.name = super.getName()");
}

@Test
public void writeUnaryOperationExpr_postfixIncrement() {
VariableExpr variableExpr =
VariableExpr.withVariable(Variable.builder().setType(TypeNode.INT).setName("i").build());
UnaryOperationExpr postIncrementOperationExpr =
UnaryOperationExpr.postfixIncrementWithExpr(variableExpr);
postIncrementOperationExpr.accept(writerVisitor);
assertThat(writerVisitor.write()).isEqualTo("i++");
}

@Test
public void writeUnaryOperationExpr_logicalNot() {
MethodInvocationExpr methodInvocationExpr =
MethodInvocationExpr.builder()
.setMethodName("isEmpty")
.setReturnType(TypeNode.BOOLEAN)
.build();
UnaryOperationExpr logicalNotOperationExpr =
UnaryOperationExpr.logicalNotWithExpr(methodInvocationExpr);
logicalNotOperationExpr.accept(writerVisitor);
assertThat(writerVisitor.write()).isEqualTo("!isEmpty()");
}

private static String createLines(int numLines) {
return new String(new char[numLines]).replace("\0", "%s");
}
Expand Down