aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Laurent Le Brun <laurentlb@google.com>2015-03-23 13:48:50 +0000
committerGravatar Han-Wen Nienhuys <hanwen@google.com>2015-03-24 16:41:16 +0000
commit4e116c7a26756c558692d6496b3a82147bbfaa02 (patch)
tree15b435f221bbfad2f324125a56d2601cf7ea1e5c /src
parentd1c806154afe16a75c453cbe1be077a3530fb672 (diff)
Skylark: Implement string.index and string.rindex
-- MOS_MIGRATED_REVID=89294740
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java109
1 files changed, 77 insertions, 32 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 22d14d6497..5dd163d266 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
@@ -200,6 +200,26 @@ public class MethodLibrary {
}
};
+ // Common implementation for find, rfind, index, rindex.
+ // forward is true iff we want to return the last matching index.
+ private static int stringFind(String functionName, boolean forward, Object[] args)
+ throws ConversionException {
+ String thiz = Type.STRING.convert(args[0], functionName + " operand");
+ String sub = Type.STRING.convert(args[1], functionName + " argument");
+ int start = 0;
+ if (args[2] != null) {
+ start = Type.INTEGER.convert(args[2], functionName + " argument");
+ }
+ int end = thiz.length();
+ if (args[3] != null) {
+ end = Type.INTEGER.convert(args[3], functionName + " argument");
+ }
+ String substr = getPythonSubstring(thiz, start, end);
+ int subpos = forward ? substr.indexOf(sub) : substr.lastIndexOf(sub);
+ start = getClampedIndex(start, thiz.length());
+ return subpos < 0 ? subpos : subpos + start;
+ }
+
@SkylarkBuiltin(name = "rfind", objectType = StringModule.class, returnType = Integer.class,
doc = "Returns the last index where <code>sub</code> is found, "
+ "or -1 if no such index exists, optionally restricting to "
@@ -213,21 +233,8 @@ public class MethodLibrary {
private static Function rfind =
new MixedModeFunction("rfind", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
@Override
- public Object call(Object[] args, FuncallExpression ast)
- throws ConversionException {
- String thiz = Type.STRING.convert(args[0], "'rfind' operand");
- String sub = Type.STRING.convert(args[1], "'rfind' argument");
- int start = 0;
- if (args[2] != null) {
- start = Type.INTEGER.convert(args[2], "'rfind' argument");
- }
- int end = thiz.length();
- if (args[3] != null) {
- end = Type.INTEGER.convert(args[3], "'rfind' argument");
- }
- int subpos = getPythonSubstring(thiz, start, end).lastIndexOf(sub);
- start = getClampedIndex(start, thiz.length());
- return subpos < 0 ? subpos : subpos + start;
+ public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
+ return stringFind("rfind", false, args);
}
};
@@ -246,19 +253,55 @@ public class MethodLibrary {
@Override
public Object call(Object[] args, FuncallExpression ast)
throws ConversionException {
- String thiz = Type.STRING.convert(args[0], "'find' operand");
- String sub = Type.STRING.convert(args[1], "'find' argument");
- int start = 0;
- if (args[2] != null) {
- start = Type.INTEGER.convert(args[2], "'find' argument");
+ return stringFind("find", true, args);
+ }
+ };
+
+ @SkylarkBuiltin(name = "rindex", objectType = StringModule.class, returnType = Integer.class,
+ doc = "Returns the last index where <code>sub</code> is found, "
+ + "or throw an error if no such index exists, optionally restricting to "
+ + "[<code>start</code>:<code>end</code>], "
+ + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
+ mandatoryParams = {
+ @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+ optionalParams = {
+ @Param(name = "start", type = Integer.class, doc = "Restrict to search from this position."),
+ @Param(name = "end", type = Integer.class, doc = "Restrict to search before this position.")})
+ private static Function rindex =
+ new MixedModeFunction("rindex", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
+ @Override
+ public Object call(Object[] args, FuncallExpression ast)
+ throws EvalException, ConversionException {
+ int res = stringFind("rindex", false, args);
+ if (res < 0) {
+ throw new EvalException(ast.getLocation(),
+ "substring '" + args[1] + "' not found in '" + args[0] + "'");
}
- int end = thiz.length();
- if (args[3] != null) {
- end = Type.INTEGER.convert(args[3], "'find' argument");
+ return res;
+ }
+ };
+
+ @SkylarkBuiltin(name = "index", objectType = StringModule.class, returnType = Integer.class,
+ doc = "Returns the first index where <code>sub</code> is found, "
+ + "or throw an error if no such index exists, optionally restricting to "
+ + "[<code>start</code>:<code>end]</code>, "
+ + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
+ mandatoryParams = {
+ @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+ optionalParams = {
+ @Param(name = "start", type = Integer.class, doc = "Restrict to search from this position."),
+ @Param(name = "end", type = Integer.class, doc = "Restrict to search before this position.")})
+ private static Function index =
+ new MixedModeFunction("index", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
+ @Override
+ public Object call(Object[] args, FuncallExpression ast)
+ throws EvalException, ConversionException {
+ int res = stringFind("index", true, args);
+ if (res < 0) {
+ throw new EvalException(ast.getLocation(),
+ "substring '" + args[1] + "' not found in '" + args[0] + "'");
}
- int subpos = getPythonSubstring(thiz, start, end).indexOf(sub);
- start = getClampedIndex(start, thiz.length());
- return subpos < 0 ? subpos : subpos + start;
+ return res;
}
};
@@ -432,7 +475,7 @@ public class MethodLibrary {
@SkylarkBuiltin(name = "$index", hidden = true,
doc = "Returns the nth element of a list or string, "
+ "or looks up a value in a dictionary.")
- private static Function index = new MixedModeFunction("$index",
+ private static Function indexOperator = new MixedModeFunction("$index",
ImmutableList.of("this", "index"), 2, false) {
@Override
public Object call(Object[] args, FuncallExpression ast) throws EvalException,
@@ -960,6 +1003,8 @@ public class MethodLibrary {
.put(split, SkylarkType.of(List.class, String.class))
.put(rfind, SkylarkType.INT)
.put(find, SkylarkType.INT)
+ .put(rindex, SkylarkType.INT)
+ .put(index, SkylarkType.INT)
.put(endswith, SkylarkType.BOOL)
.put(startswith, SkylarkType.BOOL)
.put(strip, SkylarkType.STRING)
@@ -1013,18 +1058,18 @@ public class MethodLibrary {
* Set up a given environment for supported class methods.
*/
public static void setupMethodEnvironment(Environment env) {
- env.registerFunction(Map.class, index.getName(), index);
+ env.registerFunction(Map.class, indexOperator.getName(), indexOperator);
setupMethodEnvironment(env, Map.class, dictFunctions.keySet());
- env.registerFunction(String.class, index.getName(), index);
+ env.registerFunction(String.class, indexOperator.getName(), indexOperator);
setupMethodEnvironment(env, String.class, stringFunctions.keySet());
setupMethodEnvironment(env, List.class, listPureFunctions.keySet());
setupMethodEnvironment(env, SkylarkList.class, listPureFunctions.keySet());
if (env.isSkylarkEnabled()) {
- env.registerFunction(SkylarkList.class, index.getName(), index);
+ env.registerFunction(SkylarkList.class, indexOperator.getName(), indexOperator);
setupMethodEnvironment(env, skylarkGlobalFunctions.keySet());
} else {
- env.registerFunction(List.class, index.getName(), index);
- env.registerFunction(ImmutableList.class, index.getName(), index);
+ env.registerFunction(List.class, indexOperator.getName(), indexOperator);
+ env.registerFunction(ImmutableList.class, indexOperator.getName(), indexOperator);
// TODO(bazel-team): listFunctions are not allowed in Skylark extensions (use += instead).
// It is allowed in BUILD files only for backward-compatibility.
setupMethodEnvironment(env, List.class, listFunctions);