diff options
author | Googler <noreply@google.com> | 2015-05-28 11:04:47 +0000 |
---|---|---|
committer | Laszlo Csomor <laszlocsomor@google.com> | 2015-05-28 14:33:22 +0000 |
commit | 7ad2f099a7c4a6095833b616e5ee2a19f3874546 (patch) | |
tree | 9bc602a7e3aa59ffc0de5b70c21f9d1fc4c82e80 /src/main/java/com | |
parent | 9be852e2e9622a87d9b145fe6fe4218e23343d66 (diff) |
Skylark: Added str.partition() and str.rpartition(), as known from Python.
--
MOS_MIGRATED_REVID=94655923
Diffstat (limited to 'src/main/java/com')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java | 120 |
1 files changed, 117 insertions, 3 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java index 9aa630717b..e35ecbbc34 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java @@ -14,7 +14,6 @@ package com.google.devtools.build.lib.packages; -import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; @@ -207,8 +206,123 @@ public class MethodLibrary { return env.isSkylarkEnabled() ? SkylarkList.list(result, String.class) : result; } }; + + @SkylarkSignature(name = "partition", objectType = StringModule.class, + returnType = HackHackEitherList.class, + doc = "Splits the input string at the first occurrence of the separator " + + "<code>sep</code> and returns the resulting partition as a three-element " + + "list of the form [substring_before, separator, substring_after].", + mandatoryPositionals = { + @Param(name = "self", type = String.class, doc = "This string.")}, + optionalPositionals = { + @Param(name = "sep", type = String.class, + defaultValue = "' '", doc = "The string to split on, default is space (\" \").")}, + useEnvironment = true, + useLocation = true) + private static BuiltinFunction partition = new BuiltinFunction("partition") { + @SuppressWarnings("unused") + public Object invoke(String self, String sep, Location loc, Environment env) + throws EvalException { + return partitionWrapper(self, sep, true, env.isSkylarkEnabled(), loc); + } + }; + + @SkylarkSignature(name = "rpartition", objectType = StringModule.class, + returnType = HackHackEitherList.class, + doc = "Splits the input string at the last occurrence of the separator " + + "<code>sep</code> and returns the resulting partition as a three-element " + + "list of the form [substring_before, separator, substring_after].", + mandatoryPositionals = { + @Param(name = "self", type = String.class, doc = "This string.")}, + optionalPositionals = { + @Param(name = "sep", type = String.class, + defaultValue = "' '", doc = "The string to split on, default is space (\" \").")}, + useEnvironment = true, + useLocation = true) + private static BuiltinFunction rpartition = new BuiltinFunction("rpartition") { + @SuppressWarnings("unused") + public Object invoke(String self, String sep, Location loc, Environment env) + throws EvalException { + return partitionWrapper(self, sep, false, env.isSkylarkEnabled(), loc); + } + }; /** + * Wraps the stringPartition() method and converts its results and exceptions + * to the expected types. + * + * @param self The input string + * @param separator The string to split on + * @param forward A flag that controls whether the input string is split around + * the first ({@code true}) or last ({@code false}) occurrence of the separator. + * @param isSkylarkEnabled Controls whether a SkylarkList ({@code true})or a + * {@code java.util.List} ({@code false}) is returned + * @param loc The location that is used for potential exceptions + * @return A list with three elements + */ + private static Object partitionWrapper(String self, String separator, boolean forward, + boolean isSkylarkEnabled, Location loc) throws EvalException { + try { + List<String> result = stringPartition(self, separator, forward); + return isSkylarkEnabled ? SkylarkList.list(result, String.class) : result; + } catch (IllegalArgumentException ex) { + throw new EvalException(loc, ex); + } + } + + /** + * Splits the input string at the {first|last} occurrence of the given separator + * and returns the resulting partition as a three-tuple of Strings, contained + * in a {@code List}. + * + * <p>If the input string does not contain the separator, the tuple will + * consist of the original input string and two empty strings. + * + * <p>This method emulates the behavior of Python's str.partition() and + * str.rpartition(), depending on the value of the {@code forward} flag. + * + * @param input The input string + * @param separator The string to split on + * @param forward A flag that controls whether the input string is split around + * the first ({@code true}) or last ({@code false}) occurrence of the separator. + * @return A three-tuple (List) of the form [part_before_separator, separator, + * part_after_separator]. + * + */ + private static List<String> stringPartition(String input, String separator, boolean forward) + throws IllegalArgumentException { + if (separator.isEmpty()) { + throw new IllegalArgumentException("Empty separator"); + } + + int partitionSize = 3; + ArrayList<String> result = new ArrayList<>(partitionSize); + int pos = forward ? input.indexOf(separator) : input.lastIndexOf(separator); + + if (pos < 0) { + for (int i = 0; i < partitionSize; ++i) { + result.add(""); + } + + // Following Python's implementation of str.partition() and str.rpartition(), + // the input string is copied to either the first or the last position in the + // list, depending on the value of the forward flag. + result.set(forward ? 0 : partitionSize - 1, input); + } else { + result.add(input.substring(0, pos)); + result.add(separator); + + // pos + sep.length() is at most equal to input.length(). This worst-case + // happens when the separator is at the end of the input string. However, + // substring() will return an empty string in this scenario, thus making + // any additional safety checks obsolete. + result.add(input.substring(pos + separator.length())); + } + + return result; + } + + /** * Common implementation for find, rfind, index, rindex. * @param forward true if we want to return the last matching index. */ @@ -1073,8 +1187,8 @@ public class MethodLibrary { public static final class DictModule {} public static final List<BaseFunction> stringFunctions = ImmutableList.<BaseFunction>of( - count, endswith, find, index, format, join, lower, replace, rfind, - rindex, slice, split, startswith, strip, upper); + count, endswith, find, index, format, join, lower, partition, replace, rfind, + rindex, rpartition, slice, split, startswith, strip, upper); public static final List<BaseFunction> listPureFunctions = ImmutableList.<BaseFunction>of( slice); |