Skip to content

Commit

Permalink
Add && and || operators to Soy.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 575902499
  • Loading branch information
nicholasyu-google authored and copybara-github committed Oct 23, 2023
1 parent 1ca3f4f commit b97cdba
Show file tree
Hide file tree
Showing 19 changed files with 265 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
import com.google.template.soy.exprtree.ExprNode.OperatorNode;
import com.google.template.soy.exprtree.ExprNode.ParentExprNode;
import com.google.template.soy.exprtree.ExprNode.PrimitiveNode;
import com.google.template.soy.exprtree.OperatorNodes.AmpAmpOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AssertNonNullOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BarBarOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseAndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseOrOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseXorOpNode;
Expand Down Expand Up @@ -191,9 +193,15 @@ protected final void visit(ExprNode node) {
case AND_OP_NODE:
visitAndOpNode((AndOpNode) node);
break;
case AMP_AMP_OP_NODE:
visitAmpAmpOpNode((AmpAmpOpNode) node);
break;
case OR_OP_NODE:
visitOrOpNode((OrOpNode) node);
break;
case BAR_BAR_OP_NODE:
visitBarBarOpNode((BarBarOpNode) node);
break;
case NULL_COALESCING_OP_NODE:
visitNullCoalescingOpNode((NullCoalescingOpNode) node);
break;
Expand Down Expand Up @@ -427,10 +435,18 @@ protected void visitAndOpNode(AndOpNode node) {
visitOperatorNode(node);
}

protected void visitAmpAmpOpNode(AmpAmpOpNode node) {
visitOperatorNode(node);
}

protected void visitOrOpNode(OrOpNode node) {
visitOperatorNode(node);
}

protected void visitBarBarOpNode(BarBarOpNode node) {
visitOperatorNode(node);
}

protected void visitNullCoalescingOpNode(NullCoalescingOpNode node) {
visitOperatorNode(node);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
import com.google.template.soy.exprtree.ExprNode.OperatorNode;
import com.google.template.soy.exprtree.ExprNode.ParentExprNode;
import com.google.template.soy.exprtree.ExprNode.PrimitiveNode;
import com.google.template.soy.exprtree.OperatorNodes.AmpAmpOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AssertNonNullOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BarBarOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseAndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseOrOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseXorOpNode;
Expand Down Expand Up @@ -161,8 +163,12 @@ protected R visit(ExprNode node) {
return visitTripleNotEqualOpNode((TripleNotEqualOpNode) node);
case AND_OP_NODE:
return visitAndOpNode((AndOpNode) node);
case AMP_AMP_OP_NODE:
return visitAmpAmpOpNode((AmpAmpOpNode) node);
case OR_OP_NODE:
return visitOrOpNode((OrOpNode) node);
case BAR_BAR_OP_NODE:
return visitBarBarOpNode((BarBarOpNode) node);
case NULL_COALESCING_OP_NODE:
return visitNullCoalescingOpNode((NullCoalescingOpNode) node);
case CONDITIONAL_OP_NODE:
Expand Down Expand Up @@ -371,10 +377,18 @@ protected R visitAndOpNode(AndOpNode node) {
return visitOperatorNode(node);
}

protected R visitAmpAmpOpNode(AmpAmpOpNode node) {
return visitOperatorNode(node);
}

protected R visitOrOpNode(OrOpNode node) {
return visitOperatorNode(node);
}

protected R visitBarBarOpNode(BarBarOpNode node) {
return visitOperatorNode(node);
}

protected R visitConditionalOpNode(ConditionalOpNode node) {
return visitOperatorNode(node);
}
Expand Down
2 changes: 2 additions & 0 deletions java/src/com/google/template/soy/exprtree/ExprNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ enum Kind {
TRIPLE_EQUAL_OP_NODE,
TRIPLE_NOT_EQUAL_OP_NODE,
AND_OP_NODE,
AMP_AMP_OP_NODE,
OR_OP_NODE,
BAR_BAR_OP_NODE,
NULL_COALESCING_OP_NODE,
CONDITIONAL_OP_NODE,
ASSERT_NON_NULL_OP_NODE,
Expand Down
17 changes: 17 additions & 0 deletions java/src/com/google/template/soy/exprtree/Operator.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
import com.google.errorprone.annotations.Immutable;
import com.google.template.soy.base.SourceLocation;
import com.google.template.soy.exprtree.ExprNode.OperatorNode;
import com.google.template.soy.exprtree.OperatorNodes.AmpAmpOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AssertNonNullOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BarBarOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseAndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseOrOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseXorOpNode;
Expand Down Expand Up @@ -229,12 +231,27 @@ public OperatorNode createNode(SourceLocation location, SourceLocation operatorL
}
},

AMP_AMP(ImmutableList.of(OPERAND_0, SP, new Token("&&"), SP, OPERAND_1), SoyPrecedence.P3, LEFT) {
@Override
public OperatorNode createNode(SourceLocation location, SourceLocation operatorLocation) {
return new AmpAmpOpNode(location, operatorLocation);
}
},

OR(ImmutableList.of(OPERAND_0, SP, new Token("or"), SP, OPERAND_1), SoyPrecedence.P2, LEFT) {
@Override
public OperatorNode createNode(SourceLocation location, SourceLocation operatorLocation) {
return new OrOpNode(location, operatorLocation);
}
},

BAR_BAR(ImmutableList.of(OPERAND_0, SP, new Token("||"), SP, OPERAND_1), SoyPrecedence.P2, LEFT) {
@Override
public OperatorNode createNode(SourceLocation location, SourceLocation operatorLocation) {
return new BarBarOpNode(location, operatorLocation);
}
},

NULL_COALESCING(
ImmutableList.of(OPERAND_0, SP, new Token("??"), SP, OPERAND_1), SoyPrecedence.P2, LEFT) {
@Override
Expand Down
44 changes: 44 additions & 0 deletions java/src/com/google/template/soy/exprtree/OperatorNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,50 @@ public OrOpNode copy(CopyState copyState) {
}
}

/** Node representing the '&&' operator. */
public static final class AmpAmpOpNode extends AbstractOperatorNode {

public AmpAmpOpNode(SourceLocation sourceLocation, SourceLocation operatorLocation) {
super(sourceLocation, Operator.AMP_AMP, operatorLocation);
}

private AmpAmpOpNode(AmpAmpOpNode orig, CopyState copyState) {
super(orig, copyState);
}

@Override
public Kind getKind() {
return Kind.AMP_AMP_OP_NODE;
}

@Override
public AmpAmpOpNode copy(CopyState copyState) {
return new AmpAmpOpNode(this, copyState);
}
}

/** Node representing the '||' operator. */
public static final class BarBarOpNode extends AbstractOperatorNode {

public BarBarOpNode(SourceLocation sourceLocation, SourceLocation operatorLocation) {
super(sourceLocation, Operator.BAR_BAR, operatorLocation);
}

private BarBarOpNode(BarBarOpNode orig, CopyState copyState) {
super(orig, copyState);
}

@Override
public Kind getKind() {
return Kind.BAR_BAR_OP_NODE;
}

@Override
public BarBarOpNode copy(CopyState copyState) {
return new BarBarOpNode(this, copyState);
}
}

/** Node representing the '?:' (null-coalescing) operator. */
public static final class NullCoalescingOpNode extends AbstractOperatorNode {

Expand Down
24 changes: 24 additions & 0 deletions java/src/com/google/template/soy/jbcsrc/ExpressionCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@
import com.google.template.soy.exprtree.MethodCallNode;
import com.google.template.soy.exprtree.NullNode;
import com.google.template.soy.exprtree.NullSafeAccessNode;
import com.google.template.soy.exprtree.OperatorNodes.AmpAmpOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AssertNonNullOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BarBarOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseAndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseOrOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseXorOpNode;
Expand Down Expand Up @@ -1086,6 +1088,17 @@ protected SoyExpression visitAndOpNode(AndOpNode node) {
Branch.and(left.compileToBranch(), right.compileToBranch()).asBoolean());
}

@Override
protected SoyExpression visitAmpAmpOpNode(AmpAmpOpNode node) {
SoyExpression left = visit(node.getChild(0)).box();
SoyExpression right = visit(node.getChild(1)).box();
Branch condition = left.coerceToBoolean().compileToBranch();
return SoyExpression.forSoyValue(
node.getType(),
condition.ternary(
SoyRuntimeType.getBoxedType(node.getType()).runtimeType(), right, left));
}

@Override
protected SoyExpression visitOrOpNode(OrOpNode node) {
SoyExpression left = visit(node.getChild(0));
Expand All @@ -1094,6 +1107,17 @@ protected SoyExpression visitOrOpNode(OrOpNode node) {
Branch.or(left.compileToBranch(), right.compileToBranch()).asBoolean());
}

@Override
protected SoyExpression visitBarBarOpNode(BarBarOpNode node) {
SoyExpression left = visit(node.getChild(0)).box();
SoyExpression right = visit(node.getChild(1)).box();
Branch condition = left.coerceToBoolean().compileToBranch();
return SoyExpression.forSoyValue(
node.getType(),
condition.ternary(
SoyRuntimeType.getBoxedType(node.getType()).runtimeType(), left, right));
}

// Null coalescing operator

@Override
Expand Down
14 changes: 14 additions & 0 deletions java/src/com/google/template/soy/jbcsrc/TemplateAnalysisImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@
import com.google.template.soy.exprtree.MapLiteralFromListNode;
import com.google.template.soy.exprtree.MapLiteralNode;
import com.google.template.soy.exprtree.NullSafeAccessNode;
import com.google.template.soy.exprtree.OperatorNodes.AmpAmpOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AssertNonNullOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BarBarOpNode;
import com.google.template.soy.exprtree.OperatorNodes.ConditionalOpNode;
import com.google.template.soy.exprtree.OperatorNodes.NullCoalescingOpNode;
import com.google.template.soy.exprtree.OperatorNodes.OrOpNode;
Expand Down Expand Up @@ -852,12 +854,24 @@ protected void visitOrOpNode(OrOpNode node) {
executeInBranch(node.getChild(1));
}

@Override
protected void visitBarBarOpNode(BarBarOpNode node) {
visit(node.getChild(0));
executeInBranch(node.getChild(1));
}

@Override
protected void visitAndOpNode(AndOpNode node) {
visit(node.getChild(0));
executeInBranch(node.getChild(1));
}

@Override
protected void visitAmpAmpOpNode(AmpAmpOpNode node) {
visit(node.getChild(0));
executeInBranch(node.getChild(1));
}

/** Evaluates the given node in an optional branch. */
private void executeInBranch(ExprNode expr) {
Block prev = current;
Expand Down
2 changes: 2 additions & 0 deletions java/src/com/google/template/soy/jssrc/dsl/Operation.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ public static String getOperatorToken(Operator soyOperator) {
case NOT:
return "!";
case AND:
case AMP_AMP:
return "&&";
case OR:
case BAR_BAR:
return "||";
case NULL_COALESCING:
case LEGACY_NULL_COALESCING:
Expand Down
2 changes: 2 additions & 0 deletions java/src/com/google/template/soy/jssrc/dsl/Precedence.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ public static Precedence forSoyOperator(Operator soyOperator) {
case BITWISE_OR:
return P5;
case AND:
case AMP_AMP:
return P4;
case OR:
case BAR_BAR:
case NULL_COALESCING:
case LEGACY_NULL_COALESCING:
return P3;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,10 @@
import com.google.template.soy.exprtree.NullNode;
import com.google.template.soy.exprtree.NullSafeAccessNode;
import com.google.template.soy.exprtree.Operator;
import com.google.template.soy.exprtree.OperatorNodes.AmpAmpOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.AssertNonNullOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BarBarOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseAndOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseOrOpNode;
import com.google.template.soy.exprtree.OperatorNodes.BitwiseXorOpNode;
Expand Down Expand Up @@ -1838,6 +1840,17 @@ protected void visitTripleNotEqualOpNode(TripleNotEqualOpNode node) {

@Override
protected void visitAndOpNode(AndOpNode node) {
processAnd(node);
node.setType(BoolType.getInstance());
}

@Override
protected void visitAmpAmpOpNode(AmpAmpOpNode node) {
processAnd(node);
node.setType(UnionType.of(node.getChild(0).getType(), node.getChild(1).getType()));
}

private void processAnd(AbstractOperatorNode node) {
visit(node.getChild(0)); // Assign normal types to left child

// Save the state of substitutions.
Expand All @@ -1854,12 +1867,21 @@ protected void visitAndOpNode(AndOpNode node) {

// Restore substitutions to previous state
substitutions.restore(savedSubstitutionState);
}

@Override
protected void visitOrOpNode(OrOpNode node) {
processOr(node);
node.setType(BoolType.getInstance());
}

@Override
protected void visitOrOpNode(OrOpNode node) {
protected void visitBarBarOpNode(BarBarOpNode node) {
processOr(node);
node.setType(UnionType.of(node.getChild(0).getType(), node.getChild(1).getType()));
}

private void processOr(AbstractOperatorNode node) {
ExprNode lhs = node.getChild(0);
if (SoyTreeUtils.isConstantExpr(lhs)) {
errorReporter.warn(
Expand All @@ -1886,8 +1908,6 @@ protected void visitOrOpNode(OrOpNode node) {

// Restore substitutions to previous state
substitutions.restore(savedSubstitutionState);

node.setType(BoolType.getInstance());
}

@Override
Expand Down
Loading

0 comments on commit b97cdba

Please sign in to comment.