diff options
Diffstat (limited to 'src/main/java/com')
3 files changed, 182 insertions, 224 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java index 4ea908d134..3770c51cba 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java @@ -16,10 +16,11 @@ package com.google.devtools.build.lib.analysis.skylark; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.OutputGroupInfo; -import com.google.devtools.build.lib.packages.BazelLibrary; import com.google.devtools.build.lib.packages.SkylarkNativeModule; import com.google.devtools.build.lib.packages.StructProvider; import com.google.devtools.build.lib.skylarkbuildapi.TopLevelBootstrap; +import com.google.devtools.build.lib.syntax.MethodLibrary; +import com.google.devtools.build.lib.syntax.Runtime; /** * The basis for a Skylark Environment with all build-related modules registered. @@ -44,7 +45,9 @@ public final class SkylarkModules { * the given environment map builder. */ public static void addSkylarkGlobalsToBuilder(ImmutableMap.Builder<String, Object> envBuilder) { - BazelLibrary.addSkylarkGlobalsToBuilder(envBuilder); + Runtime.addConstantsToBuilder(envBuilder); + MethodLibrary.addBindingsToBuilder(envBuilder); + topLevelBootstrap.addBindingsToBuilder(envBuilder); } } diff --git a/src/main/java/com/google/devtools/build/lib/packages/BazelLibrary.java b/src/main/java/com/google/devtools/build/lib/packages/BazelLibrary.java index d660940fb7..fa697c0a82 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/BazelLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/packages/BazelLibrary.java @@ -14,241 +14,25 @@ package com.google.devtools.build.lib.packages; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.collect.nestedset.Order; -import com.google.devtools.build.lib.events.Location; -import com.google.devtools.build.lib.skylarkinterface.Param; -import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature; -import com.google.devtools.build.lib.syntax.BaseFunction; -import com.google.devtools.build.lib.syntax.BuiltinFunction; import com.google.devtools.build.lib.syntax.Environment.GlobalFrame; -import com.google.devtools.build.lib.syntax.EvalException; -import com.google.devtools.build.lib.syntax.EvalUtils; import com.google.devtools.build.lib.syntax.MethodLibrary; import com.google.devtools.build.lib.syntax.Runtime; -import com.google.devtools.build.lib.syntax.SelectorList; -import com.google.devtools.build.lib.syntax.SelectorValue; -import com.google.devtools.build.lib.syntax.SkylarkDict; -import com.google.devtools.build.lib.syntax.SkylarkList; -import com.google.devtools.build.lib.syntax.SkylarkNestedSet; -import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor; -import com.google.devtools.build.lib.syntax.SkylarkType; /** - * A helper class containing additional built in functions for Bazel (BUILD files and .bzl files). + * A helper class containing built in skylark functions for Bazel (BUILD files and .bzl files). */ public class BazelLibrary { - // TODO(bazel-team): Move to MethodLibrary alongside other pure-Skylark builtins. - @SkylarkSignature( - name = "type", - returnType = String.class, - doc = - "Returns the type name of its argument. This is useful for debugging and " - + "type-checking. Examples:" - + "<pre class=\"language-python\">" - + "type(2) == \"int\"\n" - + "type([1]) == \"list\"\n" - + "type(struct(a = 2)) == \"struct\"" - + "</pre>" - + "This function might change in the future. To write Python-compatible code and " - + "be future-proof, use it only to compare return values: " - + "<pre class=\"language-python\">" - + "if type(x) == type([]): # if x is a list" - + "</pre>", - parameters = {@Param(name = "x", doc = "The object to check type of.")} - ) - private static final BuiltinFunction type = - new BuiltinFunction("type") { - public String invoke(Object object) { - // There is no 'type' type in Skylark, so we return a string with the type name. - return EvalUtils.getDataTypeName(object, false); - } - }; - - @SkylarkSignature( - name = "depset", - returnType = SkylarkNestedSet.class, - doc = - "Creates a <a href=\"depset.html\">depset</a>. The <code>direct</code> parameter is a list " - + "of direct elements of the depset, and <code>transitive</code> parameter is " - + "a list of depsets whose elements become indirect elements of the created depset. " - + "The order in which elements are returned when the depset is converted to a list " - + "is specified by the <code>order</code> parameter. " - + "See the <a href=\"../depsets.md\">Depsets overview</a> for more information. " - + "<p> All elements (direct and indirect) of a depset must be of the same type. " - + "<p> The order of the created depset should be <i>compatible</i> with the order of " - + "its <code>transitive</code> depsets. <code>\"default\"</code> order is compatible " - + "with any other order, all other orders are only compatible with themselves." - + "<p> Note on backward/forward compatibility. This function currently accepts a " - + "positional <code>items</code> parameter. It is deprecated and will be removed " - + "in the future, and after its removal <code>direct</code> will become a sole " - + "positional parameter of the <code>depset</code> function. Thus, both of the " - + "following calls are equivalent and future-proof:<br>" - + "<pre class=language-python>" - + "depset(['a', 'b'], transitive = [...])\n" - + "depset(direct = ['a', 'b'], transitive = [...])\n" - + "</pre>", - parameters = { - @Param( - name = "items", - type = Object.class, - defaultValue = "[]", - doc = - "Deprecated: Either an iterable whose items become the direct elements of " - + "the new depset, in left-to-right order, or else a depset that becomes " - + "a transitive element of the new depset. In the latter case, " - + "<code>transitive</code> cannot be specified." - ), - @Param( - name = "order", - type = String.class, - defaultValue = "\"default\"", - doc = - "The traversal strategy for the new depset. See <a href=\"depset.html\">here</a> for " - + "the possible values." - ), - @Param( - name = "direct", - type = SkylarkList.class, - defaultValue = "None", - positional = false, - named = true, - noneable = true, - doc = "A list of <i>direct</i> elements of a depset." - ), - @Param( - name = "transitive", - named = true, - positional = false, - type = SkylarkList.class, - generic1 = SkylarkNestedSet.class, - noneable = true, - doc = "A list of depsets whose elements will become indirect elements of the depset.", - defaultValue = "None" - ) - }, - useLocation = true - ) - private static final BuiltinFunction depset = - new BuiltinFunction("depset") { - public SkylarkNestedSet invoke( - Object items, String orderString, Object direct, Object transitive, Location loc) - throws EvalException { - Order order; - try { - order = Order.parse(orderString); - } catch (IllegalArgumentException ex) { - throw new EvalException(loc, ex); - } - - if (transitive == Runtime.NONE && direct == Runtime.NONE) { - // Legacy behavior. - return SkylarkNestedSet.of(order, items, loc); - } - - if (direct != Runtime.NONE && !isEmptySkylarkList(items)) { - throw new EvalException( - loc, "Do not pass both 'direct' and 'items' argument to depset constructor."); - } - - // Non-legacy behavior: either 'transitive' or 'direct' were specified. - Iterable<Object> directElements; - if (direct != Runtime.NONE) { - directElements = ((SkylarkList<?>) direct).getContents(Object.class, "direct"); - } else { - SkylarkType.checkType(items, SkylarkList.class, "items"); - directElements = ((SkylarkList<?>) items).getContents(Object.class, "items"); - } - - Iterable<SkylarkNestedSet> transitiveList; - if (transitive != Runtime.NONE) { - SkylarkType.checkType(transitive, SkylarkList.class, "transitive"); - transitiveList = - ((SkylarkList<?>) transitive).getContents(SkylarkNestedSet.class, "transitive"); - } else { - transitiveList = ImmutableList.of(); - } - SkylarkNestedSet.Builder builder = SkylarkNestedSet.builder(order, loc); - for (Object directElement : directElements) { - builder.addDirect(directElement); - } - for (SkylarkNestedSet transitiveSet : transitiveList) { - builder.addTransitive(transitiveSet); - } - return builder.build(); - } - }; - - private static boolean isEmptySkylarkList(Object o) { - return o instanceof SkylarkList && ((SkylarkList) o).isEmpty(); - } - - /** - * Returns a function-value implementing "select" (i.e. configurable attributes) in the specified - * package context. - */ - @SkylarkSignature( - name = "select", - doc = - "<code>select()</code> is the helper function that makes a rule attribute " - + "<a href=\"$BE_ROOT/common-definitions.html#configurable-attributes\">configurable</a>. " - + "See <a href=\"$BE_ROOT/functions.html#select\">build encyclopedia</a> for details.", - parameters = { - @Param(name = "x", type = SkylarkDict.class, doc = "The parameter to convert."), - @Param( - name = "no_match_error", - type = String.class, - defaultValue = "''", - doc = "Optional custom error to report if no condition matches." - ) - }, - useLocation = true - ) - private static final BuiltinFunction select = - new BuiltinFunction("select") { - public Object invoke(SkylarkDict<?, ?> dict, String noMatchError, Location loc) - throws EvalException { - for (Object key : dict.keySet()) { - if (!(key instanceof String)) { - throw new EvalException( - loc, String.format("Invalid key: %s. select keys must be label references", key)); - } - } - return SelectorList.of(new SelectorValue(dict, noMatchError)); - } - }; - - /** Adds bindings for all the builtin functions of this class to the given map builder. */ - public static void addBindingsToBuilder(ImmutableMap.Builder<String, Object> builder) { - for (BaseFunction function : allFunctions) { - builder.put(function.getName(), function); - } - } - - private static final ImmutableList<BaseFunction> allFunctions = - ImmutableList.of(select, depset, type); - /** A global frame containing pure Skylark builtins and some Bazel builtins. */ public static final GlobalFrame GLOBALS = createGlobals(); private static GlobalFrame createGlobals() { ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder(); - addSkylarkGlobalsToBuilder(builder); - return GlobalFrame.createForBuiltins(builder.build()); - } - /** - * Adds bindings for skylark built-ins to the given environment map builder. - */ - public static void addSkylarkGlobalsToBuilder(ImmutableMap.Builder<String, Object> envBuilder) { - Runtime.addConstantsToBuilder(envBuilder); - MethodLibrary.addBindingsToBuilder(envBuilder); - BazelLibrary.addBindingsToBuilder(envBuilder); - } + Runtime.addConstantsToBuilder(builder); + MethodLibrary.addBindingsToBuilder(builder); - static { - SkylarkSignatureProcessor.configureSkylarkFunctions(BazelLibrary.class); + return GlobalFrame.createForBuiltins(builder.build()); } } diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java index 856c262e49..cbf8ce4e17 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.skylarkinterface.Param; @@ -861,6 +862,176 @@ public class MethodLibrary { }; @SkylarkSignature( + name = "type", + returnType = String.class, + doc = + "Returns the type name of its argument. This is useful for debugging and " + + "type-checking. Examples:" + + "<pre class=\"language-python\">" + + "type(2) == \"int\"\n" + + "type([1]) == \"list\"\n" + + "type(struct(a = 2)) == \"struct\"" + + "</pre>" + + "This function might change in the future. To write Python-compatible code and " + + "be future-proof, use it only to compare return values: " + + "<pre class=\"language-python\">" + + "if type(x) == type([]): # if x is a list" + + "</pre>", + parameters = {@Param(name = "x", doc = "The object to check type of.")}) + private static final BuiltinFunction type = + new BuiltinFunction("type") { + public String invoke(Object object) { + // There is no 'type' type in Skylark, so we return a string with the type name. + return EvalUtils.getDataTypeName(object, false); + } + }; + + @SkylarkSignature( + name = "depset", + returnType = SkylarkNestedSet.class, + doc = + "Creates a <a href=\"depset.html\">depset</a>. The <code>direct</code> parameter is a list " + + "of direct elements of the depset, and <code>transitive</code> parameter is " + + "a list of depsets whose elements become indirect elements of the created depset. " + + "The order in which elements are returned when the depset is converted to a list " + + "is specified by the <code>order</code> parameter. " + + "See the <a href=\"../depsets.md\">Depsets overview</a> for more information. " + + "<p> All elements (direct and indirect) of a depset must be of the same type. " + + "<p> The order of the created depset should be <i>compatible</i> with the order of " + + "its <code>transitive</code> depsets. <code>\"default\"</code> order is compatible " + + "with any other order, all other orders are only compatible with themselves." + + "<p> Note on backward/forward compatibility. This function currently accepts a " + + "positional <code>items</code> parameter. It is deprecated and will be removed " + + "in the future, and after its removal <code>direct</code> will become a sole " + + "positional parameter of the <code>depset</code> function. Thus, both of the " + + "following calls are equivalent and future-proof:<br>" + + "<pre class=language-python>" + + "depset(['a', 'b'], transitive = [...])\n" + + "depset(direct = ['a', 'b'], transitive = [...])\n" + + "</pre>", + parameters = { + @Param( + name = "items", + type = Object.class, + defaultValue = "[]", + doc = + "Deprecated: Either an iterable whose items become the direct elements of " + + "the new depset, in left-to-right order, or else a depset that becomes " + + "a transitive element of the new depset. In the latter case, " + + "<code>transitive</code> cannot be specified."), + @Param( + name = "order", + type = String.class, + defaultValue = "\"default\"", + doc = + "The traversal strategy for the new depset. See <a href=\"depset.html\">here</a> for " + + "the possible values."), + @Param( + name = "direct", + type = SkylarkList.class, + defaultValue = "None", + positional = false, + named = true, + noneable = true, + doc = "A list of <i>direct</i> elements of a depset."), + @Param( + name = "transitive", + named = true, + positional = false, + type = SkylarkList.class, + generic1 = SkylarkNestedSet.class, + noneable = true, + doc = "A list of depsets whose elements will become indirect elements of the depset.", + defaultValue = "None") + }, + useLocation = true) + private static final BuiltinFunction depset = + new BuiltinFunction("depset") { + public SkylarkNestedSet invoke( + Object items, String orderString, Object direct, Object transitive, Location loc) + throws EvalException { + Order order; + try { + order = Order.parse(orderString); + } catch (IllegalArgumentException ex) { + throw new EvalException(loc, ex); + } + + if (transitive == Runtime.NONE && direct == Runtime.NONE) { + // Legacy behavior. + return SkylarkNestedSet.of(order, items, loc); + } + + if (direct != Runtime.NONE && !isEmptySkylarkList(items)) { + throw new EvalException( + loc, "Do not pass both 'direct' and 'items' argument to depset constructor."); + } + + // Non-legacy behavior: either 'transitive' or 'direct' were specified. + Iterable<Object> directElements; + if (direct != Runtime.NONE) { + directElements = ((SkylarkList<?>) direct).getContents(Object.class, "direct"); + } else { + SkylarkType.checkType(items, SkylarkList.class, "items"); + directElements = ((SkylarkList<?>) items).getContents(Object.class, "items"); + } + + Iterable<SkylarkNestedSet> transitiveList; + if (transitive != Runtime.NONE) { + SkylarkType.checkType(transitive, SkylarkList.class, "transitive"); + transitiveList = + ((SkylarkList<?>) transitive).getContents(SkylarkNestedSet.class, "transitive"); + } else { + transitiveList = ImmutableList.of(); + } + SkylarkNestedSet.Builder builder = SkylarkNestedSet.builder(order, loc); + for (Object directElement : directElements) { + builder.addDirect(directElement); + } + for (SkylarkNestedSet transitiveSet : transitiveList) { + builder.addTransitive(transitiveSet); + } + return builder.build(); + } + }; + + private static boolean isEmptySkylarkList(Object o) { + return o instanceof SkylarkList && ((SkylarkList) o).isEmpty(); + } + + /** + * Returns a function-value implementing "select" (i.e. configurable attributes) in the specified + * package context. + */ + @SkylarkSignature( + name = "select", + doc = "<code>select()</code> is the helper function that makes a rule attribute " + + "<a href=\"$BE_ROOT/common-definitions.html#configurable-attributes\">configurable</a>. " + + "See <a href=\"$BE_ROOT/functions.html#select\">build encyclopedia</a> for details.", + parameters = { + @Param(name = "x", type = SkylarkDict.class, doc = "The parameter to convert."), + @Param( + name = "no_match_error", + type = String.class, + defaultValue = "''", + doc = "Optional custom error to report if no condition matches.") + }, + useLocation = true) + private static final BuiltinFunction select = + new BuiltinFunction("select") { + public Object invoke(SkylarkDict<?, ?> dict, String noMatchError, Location loc) + throws EvalException { + for (Object key : dict.keySet()) { + if (!(key instanceof String)) { + throw new EvalException( + loc, String.format("Invalid key: %s. select keys must be label references", key)); + } + } + return SelectorList.of(new SelectorValue(dict, noMatchError)); + } + }; + + @SkylarkSignature( name = "zip", doc = "Returns a <code>list</code> of <code>tuple</code>s, where the i-th tuple contains " @@ -947,8 +1118,8 @@ public class MethodLibrary { private static final ImmutableList<BaseFunction> allFunctions = ImmutableList.of( - all, any, bool, dict, dir, fail, getattr, hasattr, hash, enumerate, int_, len, list, max, - min, print, range, repr, reversed, sorted, str, tuple, zip); + all, any, bool, depset, dict, dir, fail, getattr, hasattr, hash, enumerate, int_, len, + list, max, min, print, range, repr, reversed, select, sorted, str, tuple, type, zip); static { SkylarkSignatureProcessor.configureSkylarkFunctions(MethodLibrary.class); |