diff options
author | Florian Weikert <fwe@google.com> | 2015-12-14 12:06:10 +0000 |
---|---|---|
committer | Dmitry Lomov <dslomov@google.com> | 2015-12-15 11:59:45 +0000 |
commit | d5e3350f3d2a89c12c87208bc41daa89f4d31405 (patch) | |
tree | 2fb72d399373c29e60a9743d5347bc124bdc7f3f /src | |
parent | 9f5a530f678b464ba59e27a439f8dc5e5304522a (diff) |
Skylark: implemented reversed()
--
MOS_MIGRATED_REVID=110141376
Diffstat (limited to 'src')
3 files changed, 86 insertions, 4 deletions
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 3d8c7feb8c..f43f714587 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 @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; 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; @@ -935,6 +936,40 @@ public class MethodLibrary { }; @SkylarkSignature( + name = "reversed", + returnType = MutableList.class, + doc = "Returns a list that contains the elements of the original sequence in reversed order.", + mandatoryPositionals = { + @Param( + name = "sequence", + type = Object.class, + doc = "The sequence to be reversed (string, list or tuple)." + ) + }, + useLocation = true, + useEnvironment = true + ) + private static BuiltinFunction reversed = + new BuiltinFunction("reversed") { + @SuppressWarnings("unused") // Accessed via Reflection. + public MutableList invoke(Object sequence, Location loc, Environment env) + throws EvalException { + // We only allow lists and strings. + if (sequence instanceof Map) { + throw new EvalException( + loc, "Argument to reversed() must be a sequence, not a dictionary."); + } else if (sequence instanceof NestedSet || sequence instanceof SkylarkNestedSet) { + throw new EvalException(loc, "Argument to reversed() must be a sequence, not a set."); + } + LinkedList<Object> tmpList = new LinkedList<>(); + for (Object element : EvalUtils.toIterable(sequence, loc)) { + tmpList.addFirst(element); + } + return new MutableList(tmpList, env); + } + }; + + @SkylarkSignature( name = "append", objectType = MutableList.class, returnType = Runtime.NoneType.class, @@ -1683,8 +1718,10 @@ public class MethodLibrary { + "</pre>") static final class DictModule {} - static final List<BaseFunction> buildGlobalFunctions = ImmutableList.<BaseFunction>of( - bool, dict, enumerate, int_, len, list, minus, range, repr, select, sorted, str, zip); + static final List<BaseFunction> buildGlobalFunctions = + ImmutableList.<BaseFunction>of( + bool, dict, enumerate, int_, len, list, minus, range, repr, reversed, select, sorted, str, + zip); static final List<BaseFunction> skylarkGlobalFunctions = ImmutableList.<BaseFunction>builder() diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentTest.java b/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentTest.java index b689fbd4bb..3e18319166 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentTest.java @@ -123,12 +123,12 @@ public class EnvironmentTest extends EvaluationTestCase { assertEquals(Sets.newHashSet("foo", "wiz", "False", "None", "True", "-", "bool", "dict", "enumerate", "int", "len", "list", - "range", "repr", "select", "sorted", "str", "zip"), + "range", "repr", "reversed", "select", "sorted", "str", "zip"), outerEnv.getVariableNames()); assertEquals(Sets.newHashSet("foo", "wiz", "quux", "False", "None", "True", "-", "bool", "dict", "enumerate", "int", "len", "list", - "range", "repr", "select", "sorted", "str", "zip"), + "range", "repr", "reversed", "select", "sorted", "str", "zip"), innerEnv.getVariableNames()); } diff --git a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java index e76471cf6d..d1e307ae6a 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java @@ -770,6 +770,51 @@ public class MethodLibraryTest extends EvaluationTestCase { } @Test + public void testReversedWithInvalidTypes() throws Exception { + new BothModesTest() + .testIfExactError("type 'NoneType' is not iterable", "reversed(None)") + .testIfExactError("type 'int' is not iterable", "reversed(1)") + .testIfExactError( + "Argument to reversed() must be a sequence, not a dictionary.", "reversed({1: 3})"); + new SkylarkTest() + .testIfExactError( + "Argument to reversed() must be a sequence, not a set.", "reversed(set([1]))"); + } + + @Test + public void testReversedWithLists() throws Exception { + new BothModesTest() + .testEval("reversed([])", "[]") + .testEval("reversed([1])", "[1]") + .testEval("reversed([1, 2, 3, 4, 5])", "[5, 4, 3, 2, 1]") + .testEval("reversed([[1, 2], 3, 4, [5]])", "[[5], 4, 3, [1, 2]]") + .testEval("reversed([1, 1, 1, 1, 2])", "[2, 1, 1, 1, 1]"); + } + + @Test + public void testReversedWithStrings() throws Exception { + new BothModesTest() + .testEval("reversed('')", "['']") + .testEval("reversed('a')", "['a']") + .testEval("reversed('abc')", "['c', 'b', 'a']") + .testEval("reversed('__test ')", "[' ', ' ', 't', 's', 'e', 't', '_', '_']") + .testEval("reversed('bbb')", "['b', 'b', 'b']"); + } + + @Test + public void testReversedNoSideEffects() throws Exception { + new SkylarkTest() + .testEval( + "def foo():\n" + + " x = ['a', 'b']\n" + + " y = reversed(x)\n" + + " y += ['c']\n" + + " return x\n" + + "foo()", + "['a', 'b']"); + } + + @Test public void testListSlice() throws Exception { new BothModesTest() .testEval("[0,1,2,3][0:-1]", "[0, 1, 2]") |