Skylark: implemented all() and any()
--
MOS_MIGRATED_REVID=110348607
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
index e63b850..205075c 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
@@ -378,18 +378,16 @@
public static final StackManipulation toCollection =
ByteCodeUtils.invoke(EvalUtils.class, "toCollection", Object.class, Location.class);
- @SuppressWarnings("unchecked")
public static Collection<?> toCollection(Object o, Location loc) throws EvalException {
if (o instanceof Collection) {
- return (Collection<Object>) o;
+ return (Collection<?>) o;
} else if (o instanceof SkylarkList) {
return ((SkylarkList) o).getList();
- } else if (o instanceof Map<?, ?>) {
- Map<Comparable<?>, Object> dict = (Map<Comparable<?>, Object>) o;
+ } else if (o instanceof Map) {
// For dictionaries we iterate through the keys only
// For determinism, we sort the keys.
try {
- return SKYLARK_COMPARATOR.sortedCopy(dict.keySet());
+ return SKYLARK_COMPARATOR.sortedCopy(((Map<?, ?>) o).keySet());
} catch (ComparisonException e) {
throw new EvalException(loc, e);
}
@@ -404,17 +402,14 @@
public static final StackManipulation toIterable =
ByteCodeUtils.invoke(EvalUtils.class, "toIterable", Object.class, Location.class);
- @SuppressWarnings("unchecked")
public static Iterable<?> toIterable(Object o, Location loc) throws EvalException {
if (o instanceof String) {
// This is not as efficient as special casing String in for and dict and list comprehension
// statements. However this is a more unified way.
- // The regex matches every character in the string until the end of the string,
- // so "abc" will be split into ["a", "b", "c"].
- return ImmutableList.<Object>copyOf(((String) o).split("(?!^)"));
+ return split((String) o);
} else if (o instanceof Iterable) {
- return (Iterable<Object>) o;
- } else if (o instanceof Map<?, ?>) {
+ return (Iterable<?>) o;
+ } else if (o instanceof Map) {
return toCollection(o, loc);
} else {
throw new EvalException(loc,
@@ -422,6 +417,14 @@
}
}
+ private static ImmutableList<String> split(String value) {
+ ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
+ for (char c : value.toCharArray()) {
+ builder.add(String.valueOf(c));
+ }
+ return builder.build();
+ }
+
/**
* @return the size of the Skylark object or -1 in case the object doesn't have a size.
*/
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 a199ab4..dc3f50b 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
@@ -1030,6 +1030,51 @@
return (list.size() == 1) ? EvalUtils.toIterable(list.get(0), loc) : list;
}
+ @SkylarkSignature(
+ name = "all",
+ returnType = Boolean.class,
+ doc = "Returns true if all elements evaluate to True or if the collection is empty.",
+ mandatoryPositionals = {
+ @Param(name = "elements", type = Object.class, doc = "A string or a collection of elements.")
+ },
+ useLocation = true
+ )
+ private static BuiltinFunction all =
+ new BuiltinFunction("all") {
+ @SuppressWarnings("unused") // Accessed via Reflection.
+ public Boolean invoke(Object collection, Location loc) throws EvalException {
+ return !hasElementWithBooleanValue(collection, false, loc);
+ }
+ };
+
+ @SkylarkSignature(
+ name = "any",
+ returnType = Boolean.class,
+ doc = "Returns true if at least one element evaluates to True.",
+ mandatoryPositionals = {
+ @Param(name = "elements", type = Object.class, doc = "A string or a collection of elements.")
+ },
+ useLocation = true
+ )
+ private static BuiltinFunction any =
+ new BuiltinFunction("any") {
+ @SuppressWarnings("unused") // Accessed via Reflection.
+ public Boolean invoke(Object collection, Location loc) throws EvalException {
+ return hasElementWithBooleanValue(collection, true, loc);
+ }
+ };
+
+ private static boolean hasElementWithBooleanValue(Object collection, boolean value, Location loc)
+ throws EvalException {
+ Iterable<?> iterable = EvalUtils.toIterable(collection, loc);
+ for (Object obj : iterable) {
+ if (EvalUtils.toBoolean(obj) == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
// supported list methods
@SkylarkSignature(
name = "sorted",
@@ -1846,10 +1891,9 @@
static final List<BaseFunction> skylarkGlobalFunctions =
ImmutableList.<BaseFunction>builder()
.addAll(buildGlobalFunctions)
- .add(dir, fail, getattr, hasattr, max, min, print, set, struct, type)
+ .add(all, any, dir, fail, getattr, hasattr, max, min, print, set, struct, type)
.build();
-
/**
* Collect global functions for the validation environment.
*/