blob: be83c3144c68d2dc5bf897fb0285fcf47d9a5d4d [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +00002//
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.
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +000014package com.google.devtools.build.lib.syntax;
15
Florian Weikert1bf1c972015-11-09 16:06:49 +000016import static com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils.append;
17
18import com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils;
19import com.google.devtools.build.lib.syntax.compiler.DebugInfo;
20import com.google.devtools.build.lib.syntax.compiler.Jump;
21import com.google.devtools.build.lib.syntax.compiler.Jump.PrimitiveComparison;
22import com.google.devtools.build.lib.syntax.compiler.LabelAdder;
23import com.google.devtools.build.lib.syntax.compiler.VariableScope;
24
25import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
26
27import java.util.ArrayList;
28import java.util.List;
29
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +000030/**
31 * Syntax node for an if/else expression.
32 */
33public final class ConditionalExpression extends Expression {
34
35 // Python conditional expressions: $thenCase if $condition else $elseCase
36 // https://docs.python.org/3.5/reference/expressions.html#conditional-expressions
37 private final Expression thenCase;
38 private final Expression condition;
39 private final Expression elseCase;
40
41 public Expression getThenCase() { return thenCase; }
42 public Expression getCondition() { return condition; }
43 public Expression getElseCase() { return elseCase; }
44
45 /**
46 * Constructor for a conditional expression
47 */
48 public ConditionalExpression(
49 Expression thenCase, Expression condition, Expression elseCase) {
50 this.thenCase = thenCase;
51 this.condition = condition;
52 this.elseCase = elseCase;
53 }
54
55 /**
56 * Constructs a string representation of the if expression
57 */
58 @Override
59 public String toString() {
60 return thenCase + " if " + condition + " else " + elseCase;
61 }
62
63 @Override
Florian Weikert90a15962015-09-11 13:43:10 +000064 Object doEval(Environment env) throws EvalException, InterruptedException {
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +000065 if (EvalUtils.toBoolean(condition.eval(env))) {
66 return thenCase.eval(env);
67 } else {
68 return elseCase.eval(env);
69 }
70 }
71
72 @Override
73 public void accept(SyntaxTreeVisitor visitor) {
74 visitor.visit(this);
75 }
76
77 @Override
Laurent Le Brun2e78d612015-04-15 09:06:46 +000078 void validate(ValidationEnvironment env) throws EvalException {
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +000079 condition.validate(env);
Laurent Le Brun2e78d612015-04-15 09:06:46 +000080 thenCase.validate(env);
81 elseCase.validate(env);
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +000082 }
Florian Weikert1bf1c972015-11-09 16:06:49 +000083
84 @Override
85 ByteCodeAppender compile(VariableScope scope, DebugInfo debugInfo) throws EvalException {
86 List<ByteCodeAppender> code = new ArrayList<>();
87 LabelAdder afterLabel = new LabelAdder();
88 LabelAdder elseLabel = new LabelAdder();
89 // compile condition and convert to boolean
90 code.add(condition.compile(scope, debugInfo));
91 append(
92 code,
93 EvalUtils.toBoolean,
94 // jump to else block if false
95 Jump.ifIntOperandToZero(PrimitiveComparison.EQUAL).to(elseLabel));
96 // otherwise evaluate the expression for "then" and jump to end
97 code.add(thenCase.compile(scope, debugInfo));
98 append(
99 code,
100 Jump.to(afterLabel),
101 // add label for "else" and evaluate the expression
102 elseLabel);
103 code.add(elseCase.compile(scope, debugInfo));
104 append(code, afterLabel);
105
106 return ByteCodeUtils.compoundAppender(code);
107 }
Francois-Rene Rideau6fc5ee72015-03-12 20:55:17 +0000108}