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.
    */