blob: c85cc234c872503b2ff2a4b0d1e64084bb7efb31 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
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.
14package com.google.devtools.build.lib.syntax;
15
Florian Weikertbca82ad2015-11-09 17:57:13 +000016import static com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils.append;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010017
Florian Weikertbca82ad2015-11-09 17:57:13 +000018import com.google.common.collect.ImmutableMap;
19import com.google.devtools.build.lib.syntax.compiler.ByteCodeMethodCalls;
20import com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils;
21import com.google.devtools.build.lib.syntax.compiler.DebugInfo;
22import com.google.devtools.build.lib.syntax.compiler.DebugInfo.AstAccessors;
23import com.google.devtools.build.lib.syntax.compiler.Variable.InternalVariable;
24import com.google.devtools.build.lib.syntax.compiler.VariableScope;
25
26import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
27import net.bytebuddy.implementation.bytecode.Duplication;
28import net.bytebuddy.implementation.bytecode.Removal;
29
30import java.util.ArrayList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010031import java.util.LinkedHashMap;
Florian Weikertbca82ad2015-11-09 17:57:13 +000032import java.util.List;
Florian Weikertffd8a5a2015-09-18 11:51:01 +000033import java.util.Map;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010034
35/**
36 * Syntax node for dictionary comprehension expressions.
37 */
Florian Weikertffd8a5a2015-09-18 11:51:01 +000038public class DictComprehension extends AbstractComprehension {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039 private final Expression keyExpression;
40 private final Expression valueExpression;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010041
Florian Weikertffd8a5a2015-09-18 11:51:01 +000042 public DictComprehension(Expression keyExpression, Expression valueExpression) {
43 super('{', '}', keyExpression, valueExpression);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010044 this.keyExpression = keyExpression;
45 this.valueExpression = valueExpression;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046 }
47
48 @Override
Florian Weikertffd8a5a2015-09-18 11:51:01 +000049 String printExpressions() {
50 return String.format("%s: %s", keyExpression, valueExpression);
51 }
52
53 @Override
54 OutputCollector createCollector() {
55 return new DictOutputCollector();
56 }
57
Florian Weikertbca82ad2015-11-09 17:57:13 +000058 @Override
59 InternalVariable compileInitialization(VariableScope scope, List<ByteCodeAppender> code) {
60 InternalVariable dict = scope.freshVariable(ImmutableMap.class);
61 append(code, ByteCodeMethodCalls.BCImmutableMap.builder);
62 code.add(dict.store());
63 return dict;
64 }
65
66 @Override
67 ByteCodeAppender compileCollector(
68 VariableScope scope,
69 InternalVariable collection,
70 DebugInfo debugInfo,
Florian Weikert33f819b2015-11-09 18:15:55 +000071 AstAccessors debugAccessors)
72 throws EvalException {
Florian Weikertbca82ad2015-11-09 17:57:13 +000073 List<ByteCodeAppender> code = new ArrayList<>();
74 append(code, collection.load());
75 code.add(keyExpression.compile(scope, debugInfo));
76 append(code, Duplication.SINGLE, EvalUtils.checkValidDictKey);
77 code.add(valueExpression.compile(scope, debugInfo));
78 append(code, ByteCodeMethodCalls.BCImmutableMap.Builder.put, Removal.SINGLE);
79 return ByteCodeUtils.compoundAppender(code);
80 }
81
82 @Override
83 ByteCodeAppender compileBuilding(VariableScope scope, InternalVariable collection) {
84 return new ByteCodeAppender.Simple(
85 collection.load(), ByteCodeMethodCalls.BCImmutableMap.Builder.build);
86 }
87
Florian Weikertffd8a5a2015-09-18 11:51:01 +000088 /**
89 * Helper class that collects the intermediate results of the {@link DictComprehension} and
90 * provides access to the resulting {@link Map}.
91 */
92 private final class DictOutputCollector implements OutputCollector {
93 private final Map<Object, Object> result;
94
95 DictOutputCollector() {
96 // We want to keep the iteration order
97 result = new LinkedHashMap<>();
98 }
99
100 @Override
101 public void evaluateAndCollect(Environment env) throws EvalException, InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100102 Object key = keyExpression.eval(env);
Francois-Rene Rideau6c10eac2015-09-17 19:17:20 +0000103 EvalUtils.checkValidDictKey(key);
Florian Weikertffd8a5a2015-09-18 11:51:01 +0000104 result.put(key, valueExpression.eval(env));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100105 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100106
Florian Weikertffd8a5a2015-09-18 11:51:01 +0000107 @Override
108 public Object getResult(Environment env) throws EvalException {
109 return ImmutableMap.copyOf(result);
110 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100111 }
112}