diff options
author | 2015-03-12 20:55:17 +0000 | |
---|---|---|
committer | 2015-03-13 14:39:25 +0000 | |
commit | 6fc5ee71e0d82f737017d16561b7cfca399f93bd (patch) | |
tree | 4881dce05a23263a39cbe545c89eb97fd8684cbf /src/main/java | |
parent | 13459b4ee0e743da8f8416fc16bce64687f0c406 (diff) |
Implement ConditionalExpression
Also add tests.
--
MOS_MIGRATED_REVID=88474801
Diffstat (limited to 'src/main/java')
3 files changed, 96 insertions, 1 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ConditionalExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/ConditionalExpression.java new file mode 100644 index 0000000000..46471b363f --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/syntax/ConditionalExpression.java @@ -0,0 +1,70 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// 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.devtools.build.lib.syntax; + +/** + * Syntax node for an if/else expression. + */ +public final class ConditionalExpression extends Expression { + + // Python conditional expressions: $thenCase if $condition else $elseCase + // https://docs.python.org/3.5/reference/expressions.html#conditional-expressions + private final Expression thenCase; + private final Expression condition; + private final Expression elseCase; + + public Expression getThenCase() { return thenCase; } + public Expression getCondition() { return condition; } + public Expression getElseCase() { return elseCase; } + + /** + * Constructor for a conditional expression + */ + public ConditionalExpression( + Expression thenCase, Expression condition, Expression elseCase) { + this.thenCase = thenCase; + this.condition = condition; + this.elseCase = elseCase; + } + + /** + * Constructs a string representation of the if expression + */ + @Override + public String toString() { + return thenCase + " if " + condition + " else " + elseCase; + } + + @Override + Object eval(Environment env) throws EvalException, InterruptedException { + if (EvalUtils.toBoolean(condition.eval(env))) { + return thenCase.eval(env); + } else { + return elseCase.eval(env); + } + } + + @Override + public void accept(SyntaxTreeVisitor visitor) { + visitor.visit(this); + } + + @Override + SkylarkType validate(ValidationEnvironment env) throws EvalException { + condition.validate(env); + return thenCase.validate(env) + .infer(elseCase.validate(env), "else case", thenCase.getLocation(), elseCase.getLocation()); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java index 97a4bbd015..90f79ec92c 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java @@ -341,6 +341,8 @@ class Parser { // Convenience method that uses end offset from the last node. private <NODE extends ASTNode> NODE setLocation(NODE node, int startOffset, ASTNode lastNode) { + Preconditions.checkNotNull(lastNode, "can't extract end offset from a null node"); + Preconditions.checkNotNull(lastNode.getLocation(), "lastNode doesn't have a location"); return setLocation(node, startOffset, lastNode.getLocation().getEndOffset()); } @@ -908,7 +910,23 @@ class Parser { } private Expression parseExpression() { - return parseExpression(0); + int start = token.left; + Expression expr = parseExpression(0); + if (token.kind == TokenKind.IF) { + nextToken(); + Expression condition = parseExpression(0); + if (token.kind == TokenKind.ELSE) { + nextToken(); + Expression elseClause = parseExpression(); + return setLocation(new ConditionalExpression(expr, condition, elseClause), + start, elseClause); + } else { + reportError(lexer.createLocation(start, token.left), + "missing else clause in conditional expression or semicolon before if"); + return expr; // Try to recover from error: drop the if and the expression after it. Ouch. + } + } + return expr; } private Expression parseExpression(int prec) { diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java b/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java index e53a7aa9ed..2463d25600 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java @@ -140,4 +140,11 @@ public class SyntaxTreeVisitor { public void visit(Comment node) { } + public void visit(ConditionalExpression node) { + visit(node.getThenCase()); + visit(node.getCondition()); + if (node.getElseCase() != null) { + visit(node.getElseCase()); + } + } } |