blob: 9db64d2cbfe7b996c98eed6396237c65ed125674 [file] [log] [blame]
Laurent Le Brunbd9576a2016-11-18 15:10:51 +00001// Copyright 2016 The Bazel Authors. All rights reserved.
2//
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.
14
15package com.google.devtools.build.lib.syntax;
16
17import com.google.common.collect.ImmutableList;
18import com.google.devtools.build.lib.collect.nestedset.Order;
19import com.google.devtools.build.lib.events.Location;
20import com.google.devtools.build.lib.skylarkinterface.Param;
21import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
22import java.util.List;
23
24/**
25 * A helper class containing additional built in functions for Bazel (BUILD files and .bzl files).
26 */
27public class BazelLibrary {
28
29 @SkylarkSignature(
30 name = "type",
31 returnType = String.class,
32 doc =
33 "Returns the type name of its argument. This is useful for debugging and "
34 + "type-checking. Examples:"
35 + "<pre class=\"language-python\">"
36 + "type(2) == \"int\"\n"
37 + "type([1]) == \"list\"\n"
38 + "type(struct(a = 2)) == \"struct\""
39 + "</pre>"
40 + "This function might change in the future. To write Python-compatible code and "
41 + "be future-proof, use it only to compare return values: "
42 + "<pre class=\"language-python\">"
43 + "if type(x) == type([]): # if x is a list"
44 + "</pre>",
45 parameters = {@Param(name = "x", doc = "The object to check type of.")}
46 )
47 private static final BuiltinFunction type =
48 new BuiltinFunction("type") {
49 public String invoke(Object object) {
50 // There is no 'type' type in Skylark, so we return a string with the type name.
Vladimir Moskvad200daf2016-12-23 16:35:37 +000051 String name = EvalUtils.getDataTypeName(object, false);
52 // TODO(bazel-team): Temporary change to avoid breaking existing code.
53 if (name.equals("depset")) {
54 return "set";
55 }
56 return name;
57 }
58 };
59
60 @SkylarkSignature(
61 name = "depset",
62 returnType = SkylarkNestedSet.class,
63 doc =
64 "Creates a <a href=\"depset.html\">depset</a> from the <code>items</code>. "
65 + "The depset supports nesting other depsets of the same element type in it. "
66 + "A desired <a href=\"depset.html\">iteration order</a> can also be specified.<br>"
67 + "Examples:<br><pre class=\"language-python\">depset([\"a\", \"b\"])\n"
68 + "depset([1, 2, 3], order=\"compile\")</pre>",
69 parameters = {
70 @Param(
71 name = "items",
72 type = Object.class,
73 defaultValue = "[]",
74 doc =
75 "The items to initialize the depset with. May contain both standalone items "
76 + "and other depsets."
77 ),
78 @Param(
79 name = "order",
80 type = String.class,
81 defaultValue = "\"stable\"",
82 doc =
83 "The ordering strategy for the depset if it's nested, "
84 + "possible values are: <code>stable</code> (default), <code>compile</code>, "
85 + "<code>link</code> or <code>naive_link</code>. An explanation of the "
86 + "values can be found <a href=\"depset.html\">here</a>."
87 )
88 },
89 useLocation = true
90 )
91 private static final BuiltinFunction depset =
92 new BuiltinFunction("depset") {
93 public SkylarkNestedSet invoke(Object items, String order, Location loc)
94 throws EvalException {
95 try {
96 return new SkylarkNestedSet(Order.parse(order), items, loc);
97 } catch (IllegalArgumentException ex) {
98 throw new EvalException(loc, ex);
99 }
Laurent Le Brunbd9576a2016-11-18 15:10:51 +0000100 }
101 };
102
103 @SkylarkSignature(
104 name = "set",
105 returnType = SkylarkNestedSet.class,
106 doc =
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000107 "A temporary alias for <a href=\"#depset\">depset</a>. "
108 + "Deprecated in favor of <code>depset</code>.",
Laurent Le Brunbd9576a2016-11-18 15:10:51 +0000109 parameters = {
110 @Param(
111 name = "items",
112 type = Object.class,
113 defaultValue = "[]",
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000114 doc = "Same as for <a href=\"#depset\">depset</a>."
Laurent Le Brunbd9576a2016-11-18 15:10:51 +0000115 ),
116 @Param(
117 name = "order",
118 type = String.class,
119 defaultValue = "\"stable\"",
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000120 doc = "Same as for <a href=\"#depset\">depset</a>."
Laurent Le Brunbd9576a2016-11-18 15:10:51 +0000121 )
122 },
123 useLocation = true
124 )
125 private static final BuiltinFunction set =
126 new BuiltinFunction("set") {
127 public SkylarkNestedSet invoke(Object items, String order, Location loc)
128 throws EvalException {
129 try {
130 return new SkylarkNestedSet(Order.parse(order), items, loc);
131 } catch (IllegalArgumentException ex) {
132 throw new EvalException(loc, ex);
133 }
134 }
135 };
136
137 @SkylarkSignature(
138 name = "union",
139 objectType = SkylarkNestedSet.class,
140 returnType = SkylarkNestedSet.class,
141 doc =
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000142 "Creates a new <a href=\"depset.html\">depset</a> that contains both "
143 + "the input depset as well as all additional elements.",
Laurent Le Brunbd9576a2016-11-18 15:10:51 +0000144 parameters = {
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000145 @Param(name = "input", type = SkylarkNestedSet.class, doc = "The input depset"),
Laurent Le Brunbd9576a2016-11-18 15:10:51 +0000146 @Param(name = "new_elements", type = Iterable.class, doc = "The elements to be added")
147 },
148 useLocation = true
149 )
150 private static final BuiltinFunction union =
151 new BuiltinFunction("union") {
152 @SuppressWarnings("unused")
153 public SkylarkNestedSet invoke(
154 SkylarkNestedSet input, Iterable<Object> newElements, Location loc)
155 throws EvalException {
156 return new SkylarkNestedSet(input, newElements, loc);
157 }
158 };
159
160 /**
161 * Returns a function-value implementing "select" (i.e. configurable attributes) in the specified
162 * package context.
163 */
164 @SkylarkSignature(
165 name = "select",
166 doc = "Creates a SelectorValue from the dict parameter.",
167 parameters = {
168 @Param(name = "x", type = SkylarkDict.class, doc = "The parameter to convert."),
169 @Param(
170 name = "no_match_error",
171 type = String.class,
172 defaultValue = "''",
173 doc = "Optional custom error to report if no condition matches."
174 )
175 }
176 )
177 private static final BuiltinFunction select =
178 new BuiltinFunction("select") {
179 public Object invoke(SkylarkDict<?, ?> dict, String noMatchError) throws EvalException {
180 return SelectorList.of(new SelectorValue(dict, noMatchError));
181 }
182 };
183
184 private static Environment.Frame createGlobals() {
Vladimir Moskvad200daf2016-12-23 16:35:37 +0000185 List<BaseFunction> bazelGlobalFunctions =
186 ImmutableList.<BaseFunction>of(select, depset, set, type);
Laurent Le Brunbd9576a2016-11-18 15:10:51 +0000187
188 try (Mutability mutability = Mutability.create("BUILD")) {
189 Environment env = Environment.builder(mutability).build();
190 Runtime.setupConstants(env);
191 Runtime.setupMethodEnvironment(env, MethodLibrary.defaultGlobalFunctions);
192 Runtime.setupMethodEnvironment(env, bazelGlobalFunctions);
193 return env.getGlobals();
194 }
195 }
196
197 public static final Environment.Frame GLOBALS = createGlobals();
198
199 static {
200 SkylarkSignatureProcessor.configureSkylarkFunctions(BazelLibrary.class);
201 }
202}