From a6dae6b6f7268701e70016b410072baf7efaf88f Mon Sep 17 00:00:00 2001 From: Florian Weikert Date: Tue, 4 Aug 2015 20:17:23 +0000 Subject: Implemented Python's dict() in Skylark -- MOS_MIGRATED_REVID=99852261 --- .../devtools/build/lib/syntax/MethodLibrary.java | 45 +++++++++++++++++++++- .../devtools/build/lib/syntax/ValidationTests.java | 6 +-- 2 files changed, 47 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 fb59cda32e..5fbaaa9412 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 @@ -31,6 +31,7 @@ import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEi import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -976,6 +977,48 @@ public class MethodLibrary { } } }; + + @SkylarkSignature(name = "dict", returnType = Map.class, + doc = + "Creates a dictionary from an optional positional " + + "argument and an optional set of keyword arguments. Values from the keyword argument " + + "will overwrite values from the positional argument if a key appears multiple times. " + + "Dictionaries are always sorted by their keys", + optionalPositionals = { + @Param(name = "args", type = Iterable.class, defaultValue = "[]", + doc = + "List of entries. Entries must be tuples or lists with exactly " + + "two elements: key, value"), + }, + extraKeywords = {@Param(name = "kwargs", doc = "Dictionary of additional entries.")}, + useLocation = true) + private static final BuiltinFunction dict = new BuiltinFunction("dict") { + @SuppressWarnings("unused") + public Map invoke(Iterable args, Map kwargs, + Location loc) throws EvalException, ConversionException { + try { + Map result = new HashMap<>(); + List list = Type.OBJECT_LIST.convert(args, "dict(args)"); + + for (Object tuple : list) { + List mapping = Type.OBJECT_LIST.convert(tuple, "dict(args)"); + int numElements = mapping.size(); + + if (numElements != 2) { + throw new EvalException( + location, + String.format( + "Tuple has length %d, but exactly two elements are required", numElements)); + } + result.put(mapping.get(0), mapping.get(1)); + } + result.putAll(kwargs); + return result; + } catch (IllegalArgumentException | ClassCastException | NullPointerException ex) { + throw new EvalException(loc, ex); + } + } + }; @SkylarkSignature(name = "union", objectType = SkylarkNestedSet.class, returnType = SkylarkNestedSet.class, @@ -1328,7 +1371,7 @@ public class MethodLibrary { private static final List skylarkGlobalFunctions = ImmutableList.builder() .addAll(pureGlobalFunctions) - .add(list, struct, hasattr, getattr, set, dir, type, fail, print, zip) + .add(list, struct, hasattr, getattr, set, dict, dir, type, fail, print, zip) .build(); /** diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTests.java b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTests.java index 3326fec778..57b341f3b9 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTests.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTests.java @@ -180,11 +180,11 @@ public class ValidationTests extends EvaluationTestCase { @Test public void testFuncReturningDictAssignmentAsLValue() throws Exception { - checkError("can only assign to variables and tuples, not to 'dict()['b']'", - "def dict():", + checkError("can only assign to variables and tuples, not to 'my_dict()['b']'", + "def my_dict():", " return {'a': 1}", "def func():", - " dict()['b'] = 2", + " my_dict()['b'] = 2", " return d\n"); } -- cgit v1.2.3