aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib
diff options
context:
space:
mode:
authorGravatar Francois-Rene Rideau <tunes@google.com>2015-04-20 18:35:05 +0000
committerGravatar Laszlo Csomor <laszlocsomor@google.com>2015-04-21 10:57:39 +0000
commita3ac202ec114c092221b296a2695d0aadd50031f (patch)
treef06351880eb87347d3ca5e247ab4e050831c903d /src/main/java/com/google/devtools/build/lib
parent1c72383a145ce29174fee15525d3caf44ae47959 (diff)
Migrate SkylarkBuiltin annotations to SkylarkSignature instead.
-- MOS_MIGRATED_REVID=91603959
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java421
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java69
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java232
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkCommandLine.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java90
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java158
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java18
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Environment.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkBuiltin.java61
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkFunction.java32
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java4
15 files changed, 660 insertions, 482 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 82a2f0a3ff..9466c694b1 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
@@ -38,12 +38,13 @@ import com.google.devtools.build.lib.syntax.Function;
import com.google.devtools.build.lib.syntax.MixedModeFunction;
import com.google.devtools.build.lib.syntax.SelectorList;
import com.google.devtools.build.lib.syntax.SelectorValue;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin.Param;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkModule;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEitherList;
import java.util.ArrayList;
import java.util.Collection;
@@ -65,6 +66,16 @@ public class MethodLibrary {
private MethodLibrary() {}
+ // TODO(bazel-team):
+ // the Build language and Skylark currently have different list types:
+ // the Build language uses plain java List (usually ArrayList) which is mutable and accepts
+ // any argument, whereas Skylark uses SkylarkList which is immutable and accepts only
+ // arguments of the same kind. Some methods below use HackHackEitherList as a magic marker
+ // to indicate that either kind of lists is used depending on the evaluation context.
+ // It might be a good idea to either have separate methods for the two languages where it matters,
+ // or to unify the two languages so they use the same data structure (which might require
+ // updating all existing clients).
+
// Convert string index in the same way Python does.
// If index is negative, starts from the end.
// If index is outside bounds, it is restricted to the valid range.
@@ -109,14 +120,15 @@ public class MethodLibrary {
return index;
}
- // supported string methods
+ // supported string methods
- @SkylarkBuiltin(name = "join", objectType = StringModule.class, returnType = String.class,
+ @SkylarkSignature(name = "join", objectType = StringModule.class, returnType = String.class,
doc = "Returns a string in which the string elements of the argument have been "
+ "joined by this string as a separator. Example:<br>"
+ "<pre class=\"language-python\">\"|\".join([\"a\", \"b\", \"c\"]) == \"a|b|c\"</pre>",
- mandatoryParams = {
- @Param(name = "elements", type = SkylarkList.class, doc = "The objects to join.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string, a separator."),
+ @Param(name = "elements", type = HackHackEitherList.class, doc = "The objects to join.")})
private static Function join = new MixedModeFunction("join",
ImmutableList.of("this", "elements"), 2, false) {
@Override
@@ -126,9 +138,11 @@ public class MethodLibrary {
return Joiner.on(thisString).join(seq);
}};
- @SkylarkBuiltin(name = "lower", objectType = StringModule.class, returnType = String.class,
- doc = "Returns the lower case version of this string.")
- private static Function lower = new MixedModeFunction("lower",
+ @SkylarkSignature(name = "lower", objectType = StringModule.class, returnType = String.class,
+ doc = "Returns the lower case version of this string.",
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string, to convert to lower case.")})
+ private static Function lower = new MixedModeFunction("lower",
ImmutableList.of("this"), 1, false) {
@Override
public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
@@ -137,8 +151,10 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "upper", objectType = StringModule.class, returnType = String.class,
- doc = "Returns the upper case version of this string.")
+ @SkylarkSignature(name = "upper", objectType = StringModule.class, returnType = String.class,
+ doc = "Returns the upper case version of this string.",
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string, to convert to upper case.")})
private static Function upper = new MixedModeFunction("upper",
ImmutableList.of("this"), 1, false) {
@Override
@@ -148,15 +164,18 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "replace", objectType = StringModule.class, returnType = String.class,
+ @SkylarkSignature(name = "replace", objectType = StringModule.class, returnType = String.class,
doc = "Returns a copy of the string in which the occurrences "
+ "of <code>old</code> have been replaced with <code>new</code>, optionally restricting "
+ "the number of replacements to <code>maxsplit</code>.",
- mandatoryParams = {
- @Param(name = "old", type = String.class, doc = "The string to be replaced."),
- @Param(name = "new", type = String.class, doc = "The string to replace with.")},
- optionalParams = {
- @Param(name = "maxsplit", type = Integer.class, doc = "The maximum number of replacements.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "old", type = String.class, doc = "The string to be replaced."),
+ @Param(name = "new", type = String.class, doc = "The string to replace with.")},
+ optionalPositionals = {
+ @Param(name = "maxsplit", type = Integer.class,
+ doc = "The maximum number of replacements.")},
+ useLocation = true)
private static Function replace =
new MixedModeFunction("replace", ImmutableList.of("this", "old", "new", "maxsplit"), 3, false) {
@Override
@@ -182,13 +201,17 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "split", objectType = StringModule.class, returnType = SkylarkList.class,
+ @SkylarkSignature(name = "split", objectType = StringModule.class,
+ returnType = HackHackEitherList.class,
doc = "Returns a list of all the words in the string, using <code>sep</code> "
+ "as the separator, optionally limiting the number of splits to <code>maxsplit</code>.",
- optionalParams = {
- @Param(name = "sep", type = String.class,
- doc = "The string to split on, default is space (\" \")."),
- @Param(name = "maxsplit", type = Integer.class, doc = "The maximum number of splits.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string.")},
+ optionalPositionals = {
+ @Param(name = "sep", type = String.class,
+ doc = "The string to split on, default is space (\" \")."),
+ @Param(name = "maxsplit", type = Integer.class, doc = "The maximum number of splits.")},
+ useEnvironment = true)
private static Function split = new MixedModeFunction("split",
ImmutableList.of("this", "sep", "maxsplit"), 1, false) {
@Override
@@ -233,16 +256,19 @@ public class MethodLibrary {
return stringFind(forward, thiz, sub, start, args[3], functionName + " argument");
}
- @SkylarkBuiltin(name = "rfind", objectType = StringModule.class, returnType = Integer.class,
+ @SkylarkSignature(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 "
+ "[<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.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+ optionalPositionals = {
+ @Param(name = "start", type = Integer.class, defaultValue = "0",
+ doc = "Restrict to search from this position."),
+ @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+ doc = "optional position before which to restrict to search.")})
private static Function rfind =
new MixedModeFunction("rfind", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
@Override
@@ -251,16 +277,19 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "find", objectType = StringModule.class, returnType = Integer.class,
+ @SkylarkSignature(name = "find", objectType = StringModule.class, returnType = Integer.class,
doc = "Returns the first index where <code>sub</code> is found, "
+ "or -1 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.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+ optionalPositionals = {
+ @Param(name = "start", type = Integer.class, defaultValue = "0",
+ doc = "Restrict to search from this position."),
+ @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+ doc = "optional position before which to restrict to search.")})
private static Function find =
new MixedModeFunction("find", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
@Override
@@ -270,16 +299,20 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "rindex", objectType = StringModule.class, returnType = Integer.class,
+ @SkylarkSignature(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.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+ optionalPositionals = {
+ @Param(name = "start", type = Integer.class, defaultValue = "0",
+ doc = "Restrict to search from this position."),
+ @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+ doc = "optional position before which to restrict to search.")},
+ useLocation = true)
private static Function rindex =
new MixedModeFunction("rindex", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
@Override
@@ -295,16 +328,20 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "index", objectType = StringModule.class, returnType = Integer.class,
+ @SkylarkSignature(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.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+ optionalPositionals = {
+ @Param(name = "start", type = Integer.class, defaultValue = "0",
+ doc = "Restrict to search from this position."),
+ @Param(name = "end", type = Integer.class, noneable = true,
+ doc = "optional position before which to restrict to search.")},
+ useLocation = true)
private static Function index =
new MixedModeFunction("index", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
@Override
@@ -320,15 +357,18 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "count", objectType = StringModule.class, returnType = Integer.class,
+ @SkylarkSignature(name = "count", objectType = StringModule.class, returnType = Integer.class,
doc = "Returns the number of (non-overlapping) occurrences of substring <code>sub</code> in "
+ "string, 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 count.")},
- 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.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "sub", type = String.class, doc = "The substring to count.")},
+ optionalPositionals = {
+ @Param(name = "start", type = Integer.class, defaultValue = "0",
+ doc = "Restrict to search from this position."),
+ @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+ doc = "optional position before which to restrict to search.")})
private static Function count =
new MixedModeFunction("count", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
@Override
@@ -354,15 +394,18 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "endswith", objectType = StringModule.class, returnType = Boolean.class,
+ @SkylarkSignature(name = "endswith", objectType = StringModule.class, returnType = Boolean.class,
doc = "Returns True if the string ends with <code>sub</code>, "
+ "otherwise False, 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 check.")},
- optionalParams = {
- @Param(name = "start", type = Integer.class, doc = "Test beginning at this position."),
- @Param(name = "end", type = Integer.class, doc = "Stop comparing at this position.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "sub", type = String.class, doc = "The substring to check.")},
+ optionalPositionals = {
+ @Param(name = "start", type = Integer.class, defaultValue = "0",
+ doc = "Test beginning at this position."),
+ @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+ doc = "optional position at which to stop comparing.")})
private static Function endswith =
new MixedModeFunction("endswith", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
@Override
@@ -379,15 +422,19 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "startswith", objectType = StringModule.class, returnType = Boolean.class,
+ @SkylarkSignature(name = "startswith", objectType = StringModule.class,
+ returnType = Boolean.class,
doc = "Returns True if the string starts with <code>sub</code>, "
+ "otherwise False, 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 check.")},
- optionalParams = {
- @Param(name = "start", type = Integer.class, doc = "Test beginning at this position."),
- @Param(name = "end", type = Integer.class, doc = "Stop comparing at this position.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "sub", type = String.class, doc = "The substring to check.")},
+ optionalPositionals = {
+ @Param(name = "start", type = Integer.class, defaultValue = "0",
+ doc = "Test beginning at this position."),
+ @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+ doc = "Stop comparing at this position.")})
private static Function startswith =
new MixedModeFunction("startswith", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
@Override
@@ -404,9 +451,11 @@ public class MethodLibrary {
};
// TODO(bazel-team): Maybe support an argument to tell the type of the whitespace.
- @SkylarkBuiltin(name = "strip", objectType = StringModule.class, returnType = String.class,
+ @SkylarkSignature(name = "strip", objectType = StringModule.class, returnType = String.class,
doc = "Returns a copy of the string in which all whitespace characters "
- + "have been stripped from the beginning and the end of the string.")
+ + "have been stripped from the beginning and the end of the string.",
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string.")})
private static Function strip =
new MixedModeFunction("strip", ImmutableList.of("this"), 1, false) {
@Override
@@ -418,8 +467,13 @@ public class MethodLibrary {
};
// slice operator
- @SkylarkBuiltin(name = "$slice", documented = false,
- doc = "x[<code>start</code>:<code>end</code>] returns a slice or a list slice.")
+ @SkylarkSignature(name = "$slice", documented = false,
+ mandatoryPositionals = {
+ @Param(name = "self", type = Object.class, doc = "This string, list or tuple."),
+ @Param(name = "start", type = Integer.class, doc = "start position of the slice."),
+ @Param(name = "end", type = Integer.class, doc = "end position of the slice.")},
+ doc = "x[<code>start</code>:<code>end</code>] returns a slice or a list slice.",
+ useLocation = true, useEnvironment = true)
private static Function slice = new MixedModeFunction("$slice",
ImmutableList.of("this", "start", "end"), 3, false) {
@Override
@@ -448,24 +502,34 @@ public class MethodLibrary {
};
// supported list methods
- @SkylarkBuiltin(name = "sorted", doc = "Sort a collection.")
+ @SkylarkSignature(name = "sorted", returnType = HackHackEitherList.class,
+ doc = "Sort a collection.",
+ mandatoryPositionals = {
+ @Param(name = "self", type = HackHackEitherList.class, doc = "This list.")},
+ useLocation = true, useEnvironment = true)
private static Function sorted = new MixedModeFunction("sorted",
- ImmutableList.of("this"), 1, false) {
+ ImmutableList.of("self"), 1, false) {
@Override
public Object call(Object[] args, FuncallExpression ast, Environment env)
throws EvalException, ConversionException {
- List<Object> thiz = Type.OBJECT_LIST.convert(args[0], "'sorted' operand");
+ List<Object> self = Type.OBJECT_LIST.convert(args[0], "'sorted' operand");
try {
- thiz = Ordering.from(EvalUtils.SKYLARK_COMPARATOR).sortedCopy(thiz);
+ self = Ordering.from(EvalUtils.SKYLARK_COMPARATOR).sortedCopy(self);
} catch (EvalUtils.ComparisonException e) {
throw new EvalException(ast.getLocation(), e);
}
- return convert(thiz, env, ast.getLocation());
+ return convert(self, env, ast.getLocation());
}
};
- @SkylarkBuiltin(name = "append", documented = false,
- doc = "Adds an item to the end of the list.")
+ // This function has a SkylarkSignature but is only used by the Build language, not Skylark.
+ @SkylarkSignature(name = "append", returnType = Environment.NoneType.class, documented = false,
+ doc = "Adds an item to the end of the list.",
+ mandatoryPositionals = {
+ // we use List rather than SkylarkList because this is actually for use *outside* Skylark
+ @Param(name = "self", type = List.class, doc = "This list."),
+ @Param(name = "item", type = Object.class, doc = "Item to add at the end.")},
+ useLocation = true, useEnvironment = true)
private static Function append = new MixedModeFunction("append",
ImmutableList.of("this", "x"), 2, false) {
@Override
@@ -477,8 +541,14 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "extend", documented = false,
- doc = "Adds all items to the end of the list.")
+ // This function has a SkylarkSignature but is only used by the Build language, not Skylark.
+ @SkylarkSignature(name = "extend", returnType = Environment.NoneType.class, documented = false,
+ doc = "Adds all items to the end of the list.",
+ mandatoryPositionals = {
+ // we use List rather than SkylarkList because this is actually for use *outside* Skylark
+ @Param(name = "self", type = List.class, doc = "This list."),
+ @Param(name = "items", type = List.class, doc = "Items to add at the end.")},
+ useLocation = true, useEnvironment = true)
private static Function extend = new MixedModeFunction("extend",
ImmutableList.of("this", "x"), 2, false) {
@Override
@@ -492,9 +562,13 @@ public class MethodLibrary {
};
// dictionary access operator
- @SkylarkBuiltin(name = "$index", documented = false,
+ @SkylarkSignature(name = "$index", documented = false,
doc = "Returns the nth element of a list or string, "
- + "or looks up a value in a dictionary.")
+ + "or looks up a value in a dictionary.",
+ mandatoryPositionals = {
+ @Param(name = "self", type = Object.class, doc = "This object."),
+ @Param(name = "key", type = Object.class, doc = "The index or key to access.")},
+ useLocation = true)
private static Function indexOperator = new MixedModeFunction("$index",
ImmutableList.of("this", "index"), 2, false) {
@Override
@@ -543,10 +617,13 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "values", objectType = DictModule.class, returnType = SkylarkList.class,
+ @SkylarkSignature(name = "values", objectType = DictModule.class,
+ returnType = HackHackEitherList.class,
doc = "Return the list of values. Dictionaries are always sorted by their keys:"
+ "<pre class=\"language-python\">"
- + "{2: \"a\", 4: \"b\", 1: \"c\"}.values() == [\"c\", \"a\", \"b\"]</pre>\n")
+ + "{2: \"a\", 4: \"b\", 1: \"c\"}.values() == [\"c\", \"a\", \"b\"]</pre>\n",
+ mandatoryPositionals = {@Param(name = "self", type = Map.class, doc = "This dict.")},
+ useLocation = true, useEnvironment = true)
private static Function values = new NoArgFunction("values") {
@Override
public Object call(Object self, FuncallExpression ast, Environment env)
@@ -557,11 +634,15 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "items", objectType = DictModule.class, returnType = SkylarkList.class,
+ @SkylarkSignature(name = "items", objectType = DictModule.class,
+ returnType = HackHackEitherList.class,
doc = "Return the list of key-value tuples. Dictionaries are always sorted by their keys:"
+ "<pre class=\"language-python\">"
+ "{2: \"a\", 4: \"b\", 1: \"c\"}.items() == [(1, \"c\"), (2, \"a\"), (4, \"b\")]"
- + "</pre>\n")
+ + "</pre>\n",
+ mandatoryPositionals = {
+ @Param(name = "self", type = Map.class, doc = "This dict.")},
+ useLocation = true, useEnvironment = true)
private static Function items = new NoArgFunction("items") {
@Override
public Object call(Object self, FuncallExpression ast, Environment env)
@@ -577,10 +658,14 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "keys", objectType = DictModule.class, returnType = SkylarkList.class,
+ @SkylarkSignature(name = "keys", objectType = DictModule.class,
+ returnType = HackHackEitherList.class,
doc = "Return the list of keys. Dictionaries are always sorted by their keys:"
+ "<pre class=\"language-python\">{2: \"a\", 4: \"b\", 1: \"c\"}.keys() == [1, 2, 4]"
- + "</pre>\n")
+ + "</pre>\n",
+ mandatoryPositionals = {
+ @Param(name = "self", type = Map.class, doc = "This dict.")},
+ useLocation = true, useEnvironment = true)
private static Function keys = new NoArgFunction("keys") {
@Override
@SuppressWarnings("unchecked") // Skylark will only call this on a dict; and
@@ -592,14 +677,15 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "get", objectType = DictModule.class,
+ @SkylarkSignature(name = "get", objectType = DictModule.class,
doc = "Return the value for <code>key</code> if <code>key</code> is in the dictionary, "
+ "else <code>default</code>. If <code>default</code> is not given, it defaults to "
+ "<code>None</code>, so that this method never throws an error.",
- mandatoryParams = {
+ mandatoryPositionals = {
+ @Param(name = "self", doc = "This dict."),
@Param(name = "key", doc = "The key to look for.")},
- optionalParams = {
- @Param(name = "default",
+ optionalPositionals = {
+ @Param(name = "default", defaultValue = "None",
doc = "The default value to use (instead of None) if the key is not found.")})
private static Function get =
new MixedModeFunction("get", ImmutableList.of("this", "key", "default"), 2, false) {
@@ -629,7 +715,9 @@ public class MethodLibrary {
}
// unary minus
- @SkylarkBuiltin(name = "-", documented = false, doc = "Unary minus operator.")
+ @SkylarkSignature(name = "-", documented = false, doc = "Unary minus operator.",
+ mandatoryPositionals = {
+ @Param(name = "num", type = Integer.class, doc = "The number to negate.")})
private static Function minus = new MixedModeFunction("-", ImmutableList.of("this"), 1, false) {
@Override
public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
@@ -638,12 +726,13 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "list", returnType = SkylarkList.class,
+ @SkylarkSignature(name = "list", returnType = SkylarkList.class,
doc = "Converts a collection (e.g. set or dictionary) to a list."
+ "<pre class=\"language-python\">list([1, 2]) == [1, 2]\n"
+ "list(set([2, 3, 2])) == [2, 3]\n"
+ "list({5: \"a\", 2: \"b\", 4: \"c\"}) == [2, 4, 5]</pre>",
- mandatoryParams = {@Param(name = "x", doc = "The object to convert.")})
+ mandatoryPositionals = {@Param(name = "x", doc = "The object to convert.")},
+ useLocation = true)
private static Function list = new MixedModeFunction("list",
ImmutableList.of("list"), 1, false) {
@Override
@@ -653,9 +742,10 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "len", returnType = Integer.class, doc =
+ @SkylarkSignature(name = "len", returnType = Integer.class, doc =
"Returns the length of a string, list, tuple, set, or dictionary.",
- mandatoryParams = {@Param(name = "x", doc = "The object to check length of.")})
+ mandatoryPositionals = {@Param(name = "x", doc = "The object to check length of.")},
+ useLocation = true)
private static Function len = new MixedModeFunction("len",
ImmutableList.of("list"), 1, false) {
@@ -671,9 +761,9 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "str", returnType = String.class, doc =
+ @SkylarkSignature(name = "str", returnType = String.class, doc =
"Converts any object to string. This is useful for debugging.",
- mandatoryParams = {@Param(name = "x", doc = "The object to convert.")})
+ mandatoryPositionals = {@Param(name = "x", doc = "The object to convert.")})
private static Function str = new MixedModeFunction("str", ImmutableList.of("this"), 1, false) {
@Override
public Object call(Object[] args, FuncallExpression ast) throws EvalException {
@@ -681,12 +771,13 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "bool", returnType = Boolean.class, doc = "Converts an object to boolean. "
+ @SkylarkSignature(name = "bool", returnType = Boolean.class,
+ doc = "Converts an object to boolean. "
+ "It returns False if the object is None, False, an empty string, the number 0, or an "
+ "empty collection. Otherwise, it returns True. Similarly to Python <code>bool</code> "
+ "is also a type.",
- mandatoryParams = {@Param(name = "x", doc = "The variable to convert.")})
- private static Function bool = new MixedModeFunction("bool",
+ mandatoryPositionals = {@Param(name = "x", doc = "The variable to convert.")})
+ private static Function bool = new MixedModeFunction("bool",
ImmutableList.of("this"), 1, false) {
@Override
public Object call(Object[] args, FuncallExpression ast) throws EvalException {
@@ -694,10 +785,12 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "int", returnType = Integer.class, doc = "Converts a string to int, "
+ @SkylarkSignature(name = "int", returnType = Integer.class, doc = "Converts a string to int, "
+ "using base 10. It raises an error if the conversion fails."
+ "<pre class=\"language-python\">int(\"123\") == 123</pre>",
- mandatoryParams = {@Param(name = "x", type = String.class, doc = "The string to convert.")})
+ mandatoryPositionals = {
+ @Param(name = "x", type = String.class, doc = "The string to convert.")},
+ useLocation = true)
private static Function int_ =
new MixedModeFunction("int", ImmutableList.of("x"), 1, false) {
@Override
@@ -713,13 +806,15 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "struct", returnType = SkylarkClassObject.class, doc =
+ @SkylarkSignature(name = "struct", returnType = SkylarkClassObject.class, doc =
"Creates an immutable struct using the keyword arguments as fields. It is used to group "
+ "multiple values together.Example:<br>"
+ "<pre class=\"language-python\">s = struct(x = 2, y = 3)\n"
- + "return s.x + s.y # returns 5</pre>")
+ + "return s.x + s.y # returns 5</pre>",
+ extraKeywords = {
+ @Param(name = "kwarg", doc = "the struct fields")},
+ useLocation = true)
private static Function struct = new AbstractFunction("struct") {
-
@Override
public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
Environment env) throws EvalException, InterruptedException {
@@ -730,20 +825,21 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "set", returnType = SkylarkNestedSet.class,
+ @SkylarkSignature(name = "set", returnType = SkylarkNestedSet.class,
doc = "Creates a <a href=\"#modules.set\">set</a> from the <code>items</code>."
+ " The set supports nesting other sets of the same element"
+ " type in it. A desired iteration order can also be specified.<br>"
+ " Examples:<br><pre class=\"language-python\">set([\"a\", \"b\"])\n"
+ "set([1, 2, 3], order=\"compile\")</pre>",
- optionalParams = {
- @Param(name = "items", type = SkylarkList.class,
- doc = "The items to initialize the set with. May contain both standalone items and other"
- + " sets."),
- @Param(name = "order", type = String.class,
- doc = "The ordering strategy for the set if it's nested, "
- + "possible values are: <code>stable</code> (default), <code>compile</code>, "
- + "<code>link</code> or <code>naive_link</code>.")})
+ optionalPositionals = {
+ @Param(name = "items", type = Object.class, defaultValue = "[]",
+ doc = "The items to initialize the set with. May contain both standalone items "
+ + "and other sets."),
+ @Param(name = "order", type = String.class, defaultValue = "\"stable\"",
+ doc = "The ordering strategy for the set if it's nested, "
+ + "possible values are: <code>stable</code> (default), <code>compile</code>, "
+ + "<code>link</code> or <code>naive_link</code>.")},
+ useLocation = true)
private static final Function set =
new MixedModeFunction("set", ImmutableList.of("items", "order"), 0, false) {
@Override
@@ -757,14 +853,12 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "enumerate", returnType = SkylarkList.class,
+ @SkylarkSignature(name = "enumerate", returnType = SkylarkList.class,
doc = "Return a list of pairs (two-element lists), with the index (int) and the item from"
+ " the input list.\n<pre class=\"language-python\">"
+ "enumerate([24, 21, 84]) == [[0, 24], [1, 21], [2, 84]]</pre>\n",
- mandatoryParams = {
- @Param(name = "list", type = SkylarkList.class,
- doc = "input list"),
- })
+ mandatoryPositionals = {@Param(name = "list", type = SkylarkList.class, doc = "input list")},
+ useLocation = true)
private static Function enumerate = new MixedModeFunction("enumerate",
ImmutableList.of("list"), 1, false) {
@Override
@@ -783,23 +877,25 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "range", returnType = SkylarkList.class,
+ @SkylarkSignature(name = "range", returnType = SkylarkList.class,
doc = "Creates a list where items go from <code>start</code> to <code>stop</code>, using a "
+ "<code>step</code> increment. If a single argument is provided, items will "
+ "range from 0 to that element."
+ "<pre class=\"language-python\">range(4) == [0, 1, 2, 3]\n"
+ "range(3, 9, 2) == [3, 5, 7]\n"
+ "range(3, 0, -1) == [3, 2, 1]</pre>",
- mandatoryParams = {
- @Param(name = "start", type = Integer.class,
- doc = "Value of the first element"),
+ mandatoryPositionals = {
+ @Param(name = "start", type = Integer.class,
+ doc = "Value of the first element if stop is provided, "
+ + "otherwise value of stop and the actual start is 0"),
},
- optionalParams = {
- @Param(name = "stop", type = Integer.class,
- doc = "The first item <i>not</i> to be included in the resulting list; "
- + "generation of the list stops before <code>stop</code> is reached."),
- @Param(name = "step", type = Integer.class,
- doc = "The increment (default is 1). It may be negative.")})
+ optionalPositionals = {
+ @Param(name = "stop", type = Integer.class, noneable = true,
+ doc = "optional index of the first item <i>not</i> to be included in the "
+ + "resulting list; generation of the list stops before <code>stop</code> is reached."),
+ @Param(name = "step", type = Integer.class,
+ doc = "The increment (default is 1). It may be negative.")},
+ useLocation = true)
private static final Function range =
new MixedModeFunction("range", ImmutableList.of("start", "stop", "step"), 1, false) {
@Override
@@ -838,9 +934,10 @@ public class MethodLibrary {
* Returns a function-value implementing "select" (i.e. configurable attributes)
* in the specified package context.
*/
- @SkylarkBuiltin(name = "select",
+ @SkylarkSignature(name = "select",
doc = "Creates a SelectorValue from the dict parameter.",
- mandatoryParams = {@Param(name = "x", type = Map.class, doc = "The parameter to convert.")})
+ mandatoryPositionals = {
+ @Param(name = "x", type = Map.class, doc = "The parameter to convert.")})
private static final Function select = new MixedModeFunction("select",
ImmutableList.of("x"), 1, false) {
@Override
@@ -858,16 +955,16 @@ public class MethodLibrary {
/**
* Returns true if the object has a field of the given name, otherwise false.
*/
- @SkylarkBuiltin(name = "hasattr", returnType = Boolean.class,
+ @SkylarkSignature(name = "hasattr", returnType = Boolean.class,
doc = "Returns True if the object <code>x</code> has a field of the given <code>name</code>, "
+ "otherwise False. Example:<br>"
+ "<pre class=\"language-python\">hasattr(ctx.attr, \"myattr\")</pre>",
- mandatoryParams = {
- @Param(name = "object", doc = "The object to check."),
- @Param(name = "name", type = String.class, doc = "The name of the field.")})
+ mandatoryPositionals = {
+ @Param(name = "object", doc = "The object to check."),
+ @Param(name = "name", type = String.class, doc = "The name of the field.")},
+ useLocation = true, useEnvironment = true)
private static final Function hasattr =
new MixedModeFunction("hasattr", ImmutableList.of("object", "name"), 2, false) {
-
@Override
public Object call(Object[] args, FuncallExpression ast, Environment env)
throws EvalException, ConversionException {
@@ -891,19 +988,20 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "getattr",
+ @SkylarkSignature(name = "getattr",
doc = "Returns the struct's field of the given name if exists, otherwise <code>default</code>"
+ " if specified, otherwise rasies an error. For example, <code>getattr(x, \"foobar\")"
+ "</code> is equivalent to <code>x.foobar</code>."
+ "Example:<br>"
+ "<pre class=\"language-python\">getattr(ctx.attr, \"myattr\")\n"
+ "getattr(ctx.attr, \"myattr\", \"mydefault\")</pre>",
- mandatoryParams = {
- @Param(name = "object", doc = "The struct which's field is accessed."),
- @Param(name = "name", doc = "The name of the struct field.")},
- optionalParams = {
- @Param(name = "default", doc = "The default value to return in case the struct "
- + "doesn't have a field of the given name.")})
+ mandatoryPositionals = {
+ @Param(name = "object", doc = "The struct which's field is accessed."),
+ @Param(name = "name", doc = "The name of the struct field.")},
+ optionalPositionals = {
+ @Param(name = "default", doc = "The default value to return in case the struct "
+ + "doesn't have a field of the given name.")},
+ useLocation = true)
private static final Function getattr = new MixedModeFunction(
"getattr", ImmutableList.of("object", "name", "default"), 2, false) {
@Override
@@ -924,10 +1022,11 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "dir", returnType = SkylarkList.class,
+ @SkylarkSignature(name = "dir", returnType = SkylarkList.class,
doc = "Returns a list strings: the names of the fields and "
+ "methods of the parameter object.",
- mandatoryParams = {@Param(name = "object", doc = "The object to check.")})
+ mandatoryPositionals = {@Param(name = "object", doc = "The object to check.")},
+ useLocation = true, useEnvironment = true)
private static final Function dir = new MixedModeFunction(
"dir", ImmutableList.of("object"), 1, false) {
@Override
@@ -950,9 +1049,9 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "type", returnType = String.class,
+ @SkylarkSignature(name = "type", returnType = String.class,
doc = "Returns the type name of its argument.",
- mandatoryParams = {@Param(name = "object", doc = "The object to check type of.")})
+ mandatoryPositionals = {@Param(name = "object", doc = "The object to check type of.")})
private static final Function type = new MixedModeFunction("type",
ImmutableList.of("object"), 1, false) {
@Override
@@ -962,14 +1061,16 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "fail",
+ @SkylarkSignature(name = "fail",
doc = "Raises an error that cannot be intercepted.",
returnType = Environment.NoneType.class,
- mandatoryParams = {
+ mandatoryPositionals = {
@Param(name = "msg", type = String.class, doc = "Error message to display for the user")},
- optionalParams = {
- @Param(name = "attr", type = String.class,
- doc = "The name of the attribute that caused the error")})
+ optionalPositionals = {
+ @Param(name = "attr", type = String.class, noneable = true,
+ defaultValue = "None",
+ doc = "The name of the attribute that caused the error")},
+ useLocation = true)
private static final Function fail = new MixedModeFunction(
"fail", ImmutableList.of("msg", "attr"), 1, false) {
@Override
@@ -984,13 +1085,14 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "print", returnType = Environment.NoneType.class,
+ @SkylarkSignature(name = "print", returnType = Environment.NoneType.class,
doc = "Prints <code>msg</code> to the console.",
- mandatoryParams = {
- @Param(name = "*args", doc = "The objects to print.")},
- optionalParams = {
- @Param(name = "sep", type = String.class,
- doc = "The separator string between the objects, default is space (\" \").")})
+ optionalNamedOnly = {
+ @Param(name = "sep", type = String.class,
+ doc = "The separator string between the objects, default is space (\" \").")},
+ // NB: as compared to Python3, we're missing optional named-only arguments 'end' and 'file'
+ extraPositionals = {@Param(name = "args", doc = "The objects to print.")},
+ useLocation = true, useEnvironment = true)
private static final Function print = new AbstractFunction("print") {
@Override
public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
@@ -1019,7 +1121,7 @@ public class MethodLibrary {
}
};
- @SkylarkBuiltin(name = "zip",
+ @SkylarkSignature(name = "zip",
doc = "Returns a <code>list</code> of <code>tuple</code>s, where the i-th tuple contains "
+ "the i-th element from each of the argument sequences or iterables. The list has the "
+ "size of the shortest input. With a single iterable argument, it returns a list of "
@@ -1029,7 +1131,8 @@ public class MethodLibrary {
+ "zip([1, 2]) # == [(1,), (2,)]\n"
+ "zip([1, 2], [3, 4]) # == [(1, 3), (2, 4)]\n"
+ "zip([1, 2], [3, 4, 5]) # == [(1, 3), (2, 4)]</pre>",
- returnType = SkylarkList.class)
+ extraPositionals = {@Param(name = "args", doc = "lists to zip")},
+ returnType = SkylarkList.class, useLocation = true)
private static final Function zip = new AbstractFunction("zip") {
@Override
public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
index 04ff209823..cbc308e631 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
@@ -18,11 +18,11 @@ import com.google.devtools.build.lib.packages.Type.ConversionException;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin.Param;
import com.google.devtools.build.lib.syntax.SkylarkFunction;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkModule;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
import java.util.Map;
@@ -36,44 +36,51 @@ import java.util.Map;
+ "Extra helper functions:")
public class SkylarkNativeModule {
- @SkylarkBuiltin(name = "glob", objectType = SkylarkNativeModule.class,
+ @SkylarkSignature(name = "glob", objectType = SkylarkNativeModule.class,
+ returnType = SkylarkList.class,
doc = "Glob returns a list of every file in the current package that:<ul>\n"
+ "<li>Matches at least one pattern in <code>include</code>.</li>\n"
+ "<li>Does not match any of the patterns in <code>exclude</code> "
+ "(default <code>[]</code>).</li></ul>\n"
+ "If the <code>exclude_directories</code> argument is enabled (set to <code>1</code>), "
+ "files of type directory will be omitted from the results (default <code>1</code>).",
- mandatoryParams = {
+ mandatoryPositionals = {
@Param(name = "includes", type = SkylarkList.class, generic1 = String.class,
- doc = "The list of glob patterns to include.")},
- optionalParams = {
+ defaultValue = "[]", doc = "The list of glob patterns to include.")},
+ optionalPositionals = {
@Param(name = "excludes", type = SkylarkList.class, generic1 = String.class,
- doc = "The list of glob patterns to exclude."),
- @Param(name = "exclude_directories", type = Integer.class,
- doc = "A flag whether to exclude directories or not.")})
+ defaultValue = "[]", doc = "The list of glob patterns to exclude."),
+ // TODO(bazel-team): accept booleans as well as integers? (and eventually migrate?)
+ @Param(name = "exclude_directories", type = Integer.class, defaultValue = "1",
+ doc = "A flag whether to exclude directories or not.")},
+ useAst = true, useEnvironment = true)
private static final SkylarkFunction glob = new SkylarkFunction("glob") {
- @Override
- public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
- throws EvalException, ConversionException, InterruptedException {
- return PackageFactory.callGlob(null, false, ast, env, new Object[] {
- kwargs.get("includes"),
- kwargs.get("excludes"),
- kwargs.get("exclude_directories")
- });
- }
- };
+ @Override
+ public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
+ throws EvalException, ConversionException, InterruptedException {
+ return PackageFactory.callGlob(null, false, ast, env, new Object[] {
+ kwargs.get("includes"),
+ kwargs.get("excludes"),
+ kwargs.get("exclude_directories")
+ });
+ }
+ };
- @SkylarkBuiltin(name = "package_group", objectType = SkylarkNativeModule.class,
+ @SkylarkSignature(name = "package_group", objectType = SkylarkNativeModule.class,
+ returnType = Environment.NoneType.class,
doc = "This function defines a set of packages and assigns a label to the group. "
+ "The label can be referenced in <code>visibility</code> attributes.",
- mandatoryParams = {
+ mandatoryNamedOnly = {
@Param(name = "name", type = String.class,
doc = "A unique name for this rule.")},
- optionalParams = {
+ optionalNamedOnly = {
@Param(name = "packages", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]",
doc = "A complete enumeration of packages in this group."),
@Param(name = "includes", type = SkylarkList.class, generic1 = String.class,
- doc = "Other package groups that are included in this one.")})
+ defaultValue = "[]",
+ doc = "Other package groups that are included in this one.")},
+ useAst = true, useEnvironment = true)
private static final SkylarkFunction packageGroup = new SkylarkFunction("package_group") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -86,19 +93,23 @@ public class SkylarkNativeModule {
}
};
- @SkylarkBuiltin(name = "exports_files", objectType = SkylarkNativeModule.class,
+ @SkylarkSignature(name = "exports_files", objectType = SkylarkNativeModule.class,
+ returnType = Environment.NoneType.class,
doc = "Specifies a list of files belonging to this package that are exported to other "
+ "packages but not otherwise mentioned.",
- mandatoryParams = {
+ mandatoryPositionals = {
@Param(name = "srcs", type = SkylarkList.class, generic1 = String.class,
doc = "The list of files to export.")},
- optionalParams = {
- @Param(name = "visibility", type = SkylarkList.class, generic1 = String.class,
+ optionalPositionals = {
+ // TODO(bazel-team): make it possible to express the precise type ListOf(LabelDesignator)
+ @Param(name = "visibility", type = SkylarkList.class,
+ noneable = true,
doc = "A visibility declaration can to be specified. The files will be visible to the "
+ "targets specified. If no visibility is specified, the files will be visible to "
+ "every package."),
- @Param(name = "licenses", type = SkylarkList.class, generic1 = String.class,
- doc = "Lincenses to be specified.")})
+ @Param(name = "licenses", type = SkylarkList.class, generic1 = String.class, noneable = true,
+ doc = "Licenses to be specified.")},
+ useAst = true, useEnvironment = true)
private static final SkylarkFunction exportsFiles = new SkylarkFunction("exports_files") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
index 549e0252af..408c4841b7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
@@ -26,13 +26,13 @@ import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.Label;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin.Param;
import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.syntax.SkylarkFunction;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkModule;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
import com.google.devtools.build.lib.syntax.UserDefinedFunction;
import com.google.devtools.build.lib.util.FileTypeSet;
@@ -153,16 +153,20 @@ public final class SkylarkAttr {
}
}
- @SkylarkBuiltin(name = "int", doc =
+ @SkylarkSignature(name = "int", doc =
"Creates an attribute of type int.",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", type = Integer.class,
- doc = DEFAULT_DOC + " If not specified, default is 0."),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ @Param(name = "default", type = Integer.class, defaultValue = "0",
+ doc = DEFAULT_DOC + " If not specified, default is 0."),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "mandatory", type = Boolean.class, defaultValue = "False",
+ doc = MANDATORY_DOC),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction integer = new SkylarkFunction("int") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -171,16 +175,20 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "string", doc =
+ @SkylarkSignature(name = "string", doc =
"Creates an attribute of type string.",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", type = String.class,
- doc = DEFAULT_DOC + " If not specified, default is \"\"."),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ @Param(name = "default", type = String.class,
+ defaultValue = "\"\"", doc = DEFAULT_DOC + " If not specified, default is \"\"."),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "mandatory", type = Boolean.class,
+ defaultValue = "False", doc = MANDATORY_DOC),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction string = new SkylarkFunction("string") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -189,29 +197,35 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "label", doc =
+ @SkylarkSignature(name = "label", doc =
"Creates an attribute of type Label. "
+ "It is the only way to specify a dependency to another target. "
+ "If you need a dependency that the user cannot overwrite, make the attribute "
+ "private (starts with <code>_</code>).",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", type = Label.class, callbackEnabled = true,
- doc = DEFAULT_DOC + " If not specified, default is None. "
- + "Use the <code>Label</code> function to specify a default value."),
- @Param(name = "executable", type = Boolean.class, doc = EXECUTABLE_DOC),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "allow_files", doc = ALLOW_FILES_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "providers", type = SkylarkList.class, generic1 = String.class,
- doc = "mandatory providers every dependency has to have"),
- @Param(name = "allow_rules", type = SkylarkList.class, generic1 = String.class,
- doc = ALLOW_RULES_DOC),
- @Param(name = "single_file", doc =
- "if True, the label must correspond to a single File. "
- + "Access it through <code>ctx.file.&lt;attribute_name&gt;</code>."),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ @Param(name = "default", type = Label.class, callbackEnabled = true, noneable = true,
+ defaultValue = "None",
+ doc = DEFAULT_DOC + " If not specified, default is None. "
+ + "Use the <code>Label</code> function to specify a default value."),
+ @Param(name = "executable", type = Boolean.class, defaultValue = "False",
+ doc = EXECUTABLE_DOC),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "allow_files", defaultValue = "False", doc = ALLOW_FILES_DOC),
+ @Param(name = "mandatory", type = Boolean.class, defaultValue = "False",
+ doc = MANDATORY_DOC),
+ @Param(name = "providers", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = "mandatory providers every dependency has to have"),
+ @Param(name = "allow_rules", type = SkylarkList.class, generic1 = String.class,
+ noneable = true, defaultValue = "None", doc = ALLOW_RULES_DOC),
+ @Param(name = "single_file", type = Boolean.class, defaultValue = "False",
+ doc = "if True, the label must correspond to a single File. "
+ + "Access it through <code>ctx.file.&lt;attribute_name&gt;</code>."),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction label = new SkylarkFunction("label") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -220,11 +234,11 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "string_list", doc =
+ @SkylarkSignature(name = "string_list", doc =
"Creates an attribute of type list of strings",
objectType = SkylarkAttr.class,
returnType = Attribute.class,
- optionalParams = {
+ optionalPositionals = {
@Param(name = "default", type = SkylarkList.class, generic1 = String.class,
doc = DEFAULT_DOC + " If not specified, default is []."),
@Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
@@ -240,25 +254,31 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "label_list", doc =
+ @SkylarkSignature(name = "label_list", doc =
"Creates an attribute of type list of labels. "
+ "See <a href=\"#modules.attr.label\">label</a> for more information.",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", type = SkylarkList.class, generic1 = Label.class,
- callbackEnabled = true,
- doc = DEFAULT_DOC + " If not specified, default is []. "
- + "Use the <code>Label</code> function to specify a default value."),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "allow_files", doc = ALLOW_FILES_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "allow_rules", type = SkylarkList.class, generic1 = String.class,
- doc = ALLOW_RULES_DOC),
- @Param(name = "non_empty", type = Boolean.class, doc = NON_EMPTY_DOC),
- @Param(name = "providers", type = SkylarkList.class, generic1 = String.class,
- doc = "mandatory providers every dependency has to have"),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ @Param(name = "default", type = SkylarkList.class, generic1 = Label.class,
+ callbackEnabled = true, defaultValue = "[]",
+ doc = DEFAULT_DOC + " If not specified, default is []. "
+ + "Use the <code>Label</code> function to specify a default value."),
+ @Param(name = "allow_files", // bool or FileType filter
+ defaultValue = "False", doc = ALLOW_FILES_DOC),
+ @Param(name = "allow_rules", type = SkylarkList.class, generic1 = String.class,
+ noneable = true, defaultValue = "None", doc = ALLOW_RULES_DOC),
+ @Param(name = "providers", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = "mandatory providers every dependency has to have"),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "mandatory", type = Boolean.class, defaultValue = "False",
+ doc = MANDATORY_DOC),
+ @Param(name = "non_empty", type = Boolean.class, defaultValue = "False",
+ doc = NON_EMPTY_DOC),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction labelList = new SkylarkFunction("label_list") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -267,15 +287,20 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "bool", doc =
+ @SkylarkSignature(name = "bool", doc =
"Creates an attribute of type bool. Its default value is False.",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", type = Boolean.class, doc = DEFAULT_DOC),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ @Param(name = "default", type = Boolean.class,
+ defaultValue = "False", doc = DEFAULT_DOC),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "mandatory", type = Boolean.class, defaultValue = "False",
+ doc = MANDATORY_DOC),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction bool = new SkylarkFunction("bool") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -284,17 +309,22 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "output", doc =
+ @SkylarkSignature(name = "output", doc =
"Creates an attribute of type output. Its default value is None. "
+ "The user provides a file name (string) and the rule must create an action that "
+ "generates the file.",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", type = Label.class, doc = DEFAULT_DOC),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ @Param(name = "default", type = Label.class, noneable = true,
+ defaultValue = "None", doc = DEFAULT_DOC),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "mandatory", type = Boolean.class, defaultValue = "False",
+ doc = MANDATORY_DOC),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction output = new SkylarkFunction("output") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -303,17 +333,23 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "output_list", doc =
+ @SkylarkSignature(name = "output_list", doc =
"Creates an attribute of type list of outputs. Its default value is <code>[]</code>. "
+ "See <a href=\"#modules.attr.output\">output</a> above for more information.",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", type = SkylarkList.class, generic1 = Label.class, doc = DEFAULT_DOC),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "non_empty", type = Boolean.class, doc = NON_EMPTY_DOC),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ @Param(name = "default", type = SkylarkList.class, generic1 = Label.class,
+ defaultValue = "[]", doc = DEFAULT_DOC),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "mandatory", type = Boolean.class,
+ defaultValue = "False", doc = MANDATORY_DOC),
+ @Param(name = "non_empty", type = Boolean.class, defaultValue = "False",
+ doc = NON_EMPTY_DOC),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction outputList = new SkylarkFunction("output_list") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -322,17 +358,23 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "string_dict", doc =
+ @SkylarkSignature(name = "string_dict", doc =
"Creates an attribute of type dictionary, mapping from string to string. "
- + "Its default value is {}.",
+ + "Its default value is dict().",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", type = Map.class, doc = DEFAULT_DOC),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "non_empty", type = Boolean.class, doc = NON_EMPTY_DOC),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ @Param(name = "default", type = Map.class,
+ defaultValue = "{}", doc = DEFAULT_DOC),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "mandatory", type = Boolean.class, defaultValue = "False",
+ doc = MANDATORY_DOC),
+ @Param(name = "non_empty", type = Boolean.class, defaultValue = "False",
+ doc = NON_EMPTY_DOC),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction stringDict = new SkylarkFunction("string_dict") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
@@ -341,16 +383,22 @@ public final class SkylarkAttr {
}
};
- @SkylarkBuiltin(name = "license", doc =
+ @SkylarkSignature(name = "license", doc =
"Creates an attribute of type license. Its default value is NO_LICENSE.",
// TODO(bazel-team): Implement proper license support for Skylark.
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
- optionalParams = {
- @Param(name = "default", doc = DEFAULT_DOC),
- @Param(name = "flags", type = SkylarkList.class, generic1 = String.class, doc = FLAGS_DOC),
- @Param(name = "mandatory", type = Boolean.class, doc = MANDATORY_DOC),
- @Param(name = "cfg", type = ConfigurationTransition.class, doc = CONFIGURATION_DOC)})
+ returnType = Attribute.Builder.class,
+ optionalNamedOnly = {
+ // TODO(bazel-team): ensure this is the correct default value
+ @Param(name = "default", defaultValue = "None", noneable = true,
+ doc = DEFAULT_DOC),
+ @Param(name = "flags", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = FLAGS_DOC),
+ @Param(name = "mandatory", type = Boolean.class, defaultValue = "False",
+ doc = MANDATORY_DOC),
+ @Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
+ defaultValue = "None", doc = CONFIGURATION_DOC)},
+ useAst = true, useEnvironment = true)
private static SkylarkFunction license = new SkylarkFunction("license") {
@Override
public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkCommandLine.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkCommandLine.java
index dbf72184a0..260c7e4a8f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkCommandLine.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkCommandLine.java
@@ -20,12 +20,12 @@ import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.syntax.EvalException;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin.Param;
import com.google.devtools.build.lib.syntax.SkylarkFunction.SimpleSkylarkFunction;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkModule;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
import java.util.Map;
@@ -36,12 +36,12 @@ import java.util.Map;
doc = "Module for creating memory efficient command lines.")
public class SkylarkCommandLine {
- @SkylarkBuiltin(name = "join_paths",
+ @SkylarkSignature(name = "join_paths",
doc = "Creates a single command line argument joining the paths of a set "
+ "of files on the separator string.",
objectType = SkylarkCommandLine.class,
returnType = String.class,
- mandatoryParams = {
+ mandatoryPositionals = {
@Param(name = "separator", type = String.class, doc = "the separator string to join on"),
@Param(name = "files", type = SkylarkNestedSet.class, generic1 = Artifact.class,
doc = "the files to concatenate")})
@@ -59,11 +59,11 @@ public class SkylarkCommandLine {
};
// TODO(bazel-team): this method should support sets of objects and substitute all struct fields.
- @SkylarkBuiltin(name = "template",
+ @SkylarkSignature(name = "template",
doc = "Transforms a set of files to a list of strings using the template string.",
objectType = SkylarkCommandLine.class,
returnType = SkylarkList.class,
- mandatoryParams = {
+ mandatoryPositionals = {
@Param(name = "items", type = SkylarkNestedSet.class, generic1 = Artifact.class,
doc = "The set of structs to transform."),
@Param(name = "template", type = String.class,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
index 7ab0cee813..226ceebee3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
@@ -24,10 +24,10 @@ import com.google.devtools.build.lib.packages.SkylarkNativeModule;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvaluationContext;
import com.google.devtools.build.lib.syntax.Function;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.syntax.SkylarkFunction;
import com.google.devtools.build.lib.syntax.SkylarkModule;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
import com.google.devtools.build.lib.syntax.ValidationEnvironment;
import java.lang.reflect.Field;
@@ -150,11 +150,11 @@ public class SkylarkModules {
ImmutableList.Builder<Function> functions, ImmutableMap.Builder<String, Object> objects) {
try {
for (Field field : type.getDeclaredFields()) {
- if (field.isAnnotationPresent(SkylarkBuiltin.class)) {
+ if (field.isAnnotationPresent(SkylarkSignature.class)) {
// Fields in Skylark modules are sometimes private.
- // Nevertheless they have to be annotated with SkylarkBuiltin.
+ // Nevertheless they have to be annotated with SkylarkSignature.
field.setAccessible(true);
- SkylarkBuiltin annotation = field.getAnnotation(SkylarkBuiltin.class);
+ SkylarkSignature annotation = field.getAnnotation(SkylarkSignature.class);
Object value = field.get(null);
if (SkylarkFunction.class.isAssignableFrom(field.getType())) {
SkylarkFunction function = (SkylarkFunction) value;
@@ -179,8 +179,8 @@ public class SkylarkModules {
*/
private static void collectSkylarkTypesFromFields(Class<?> classObject, Set<String> builtIn) {
for (Field field : classObject.getDeclaredFields()) {
- if (field.isAnnotationPresent(SkylarkBuiltin.class)) {
- SkylarkBuiltin annotation = field.getAnnotation(SkylarkBuiltin.class);
+ if (field.isAnnotationPresent(SkylarkSignature.class)) {
+ SkylarkSignature annotation = field.getAnnotation(SkylarkSignature.class);
if (SkylarkFunction.class.isAssignableFrom(field.getType())) {
// Ignore non-global values.
if (annotation.objectType().equals(Object.class)) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index 68e9cfe53d..3cb4e28f96 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -55,6 +55,7 @@ import com.google.devtools.build.lib.packages.TestSize;
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.packages.Type.ConversionException;
import com.google.devtools.build.lib.syntax.AbstractFunction;
+import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.ClassObject;
import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
import com.google.devtools.build.lib.syntax.Environment;
@@ -64,13 +65,13 @@ import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.Function;
import com.google.devtools.build.lib.syntax.Label;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin.Param;
import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.syntax.SkylarkFunction;
import com.google.devtools.build.lib.syntax.SkylarkFunction.SimpleSkylarkFunction;
import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
import com.google.devtools.build.lib.syntax.UserDefinedFunction;
import java.util.List;
@@ -84,11 +85,11 @@ import java.util.concurrent.ExecutionException;
public class SkylarkRuleClassFunctions {
//TODO(bazel-team): proper enum support
- @SkylarkBuiltin(name = "DATA_CFG", returnType = ConfigurationTransition.class,
+ @SkylarkSignature(name = "DATA_CFG", returnType = ConfigurationTransition.class,
doc = "Experimental. Specifies a transition to the data configuration.")
private static final Object dataTransition = ConfigurationTransition.DATA;
- @SkylarkBuiltin(name = "HOST_CFG", returnType = ConfigurationTransition.class,
+ @SkylarkSignature(name = "HOST_CFG", returnType = ConfigurationTransition.class,
doc = "Specifies a transition to the host configuration.")
private static final Object hostTransition = ConfigurationTransition.HOST;
@@ -177,39 +178,42 @@ public class SkylarkRuleClassFunctions {
// TODO(bazel-team): implement attribute copy and other rule properties
- @SkylarkBuiltin(name = "rule", doc =
+ @SkylarkSignature(name = "rule", doc =
"Creates a new rule. Store it in a global value, so that it can be loaded and called "
+ "from BUILD files.",
onlyLoadingPhase = true,
- returnType = Function.class,
- mandatoryParams = {
- @Param(name = "implementation", type = UserDefinedFunction.class,
- doc = "the function implementing this rule, has to have exactly one parameter: "
- + "<code>ctx</code>. The function is called during analysis phase for each "
- + "instance of the rule. It can access the attributes provided by the user. "
- + "It must create actions to generate all the declared outputs.")
+ returnType = BaseFunction.class,
+ mandatoryPositionals = {
+ @Param(name = "implementation", type = Function.class,
+ doc = "the function implementing this rule, has to have exactly one parameter: "
+ + "<code>ctx</code>. The function is called during analysis phase for each "
+ + "instance of the rule. It can access the attributes provided by the user. "
+ + "It must create actions to generate all the declared outputs.")
},
- optionalParams = {
- @Param(name = "test", type = Boolean.class, doc = "Whether this rule is a test rule. "
- + "If True, the rule must end with <code>_test</code> (otherwise it cannot)."),
- @Param(name = "attrs", type = Map.class, doc =
- "dictionary to declare all the attributes of the rule. It maps from an attribute name "
- + "to an attribute object (see <a href=\"#modules.attr\">attr</a> module). "
- + "Attributes starting with <code>_</code> are private, and can be used to add "
- + "an implicit dependency on a label."),
- @Param(name = "outputs", doc = "outputs of this rule. "
- + "It is a dictionary mapping from string to a template name. "
- + "For example: <code>{\"ext\": \"${name}.ext\"}</code>. <br>"
- + "The dictionary key becomes a field in <code>ctx.outputs</code>. "
- // TODO(bazel-team): Make doc more clear, wrt late-bound attributes.
- + "It may also be a function (which receives <code>ctx.attr</code> as argument) "
- + "returning such a dictionary."),
- @Param(name = "executable", type = Boolean.class,
- doc = "whether this rule always outputs an executable of the same name or not. If True, "
- + "there must be an action that generates <code>ctx.outputs.executable</code>."),
- @Param(name = "output_to_genfiles", type = Boolean.class,
- doc = "If true, the files will be generated in the genfiles directory instead of the "
- + "bin directory. This is used for compatibility with existing rules.")})
+ optionalPositionals = {
+ @Param(name = "test", type = Boolean.class, defaultValue = "False",
+ doc = "Whether this rule is a test rule. "
+ + "If True, the rule must end with <code>_test</code> (otherwise it cannot)."),
+ @Param(name = "attrs", type = Map.class, noneable = true, defaultValue = "None", doc =
+ "dictionary to declare all the attributes of the rule. It maps from an attribute name "
+ + "to an attribute object (see <a href=\"#modules.attr\">attr</a> module). "
+ + "Attributes starting with <code>_</code> are private, and can be used to add "
+ + "an implicit dependency on a label."),
+ @Param(name = "outputs", type = Map.class, callbackEnabled = true, noneable = true,
+ defaultValue = "None", doc = "outputs of this rule. "
+ + "It is a dictionary mapping from string to a template name. "
+ + "For example: <code>{\"ext\": \"${name}.ext\"}</code>. <br>"
+ + "The dictionary key becomes a field in <code>ctx.outputs</code>. "
+ // TODO(bazel-team): Make doc more clear, wrt late-bound attributes.
+ + "It may also be a function (which receives <code>ctx.attr</code> as argument) "
+ + "returning such a dictionary."),
+ @Param(name = "executable", type = Boolean.class, defaultValue = "False",
+ doc = "whether this rule always outputs an executable of the same name or not. If "
+ + "True, there must be an action that generates <code>ctx.outputs.executable</code>."),
+ @Param(name = "output_to_genfiles", type = Boolean.class, defaultValue = "False",
+ doc = "If true, the files will be generated in the genfiles directory instead of the "
+ + "bin directory. This is used for compatibility with existing rules.")},
+ useAst = true, useEnvironment = true)
private static final SkylarkFunction rule = new SkylarkFunction("rule") {
@Override
@@ -313,12 +317,13 @@ public class SkylarkRuleClassFunctions {
}
}
- @SkylarkBuiltin(name = "Label", doc = "Creates a Label referring to a BUILD target. Use "
+ @SkylarkSignature(name = "Label", doc = "Creates a Label referring to a BUILD target. Use "
+ "this function only when you want to give a default value for the label attributes. "
+ "Example: <br><pre class=language-python>Label(\"//tools:default\")</pre>",
returnType = Label.class,
- mandatoryParams = {@Param(name = "label_string", type = String.class,
- doc = "the label string")})
+ mandatoryPositionals = {@Param(name = "label_string", type = String.class,
+ doc = "the label string")},
+ useLocation = true)
private static final SkylarkFunction label = new SimpleSkylarkFunction("Label") {
@Override
public Object call(Map<String, Object> arguments, Location loc) throws EvalException,
@@ -332,11 +337,11 @@ public class SkylarkRuleClassFunctions {
}
};
- @SkylarkBuiltin(name = "FileType",
+ @SkylarkSignature(name = "FileType",
doc = "Creates a file filter from a list of strings. For example, to match files ending "
+ "with .cc or .cpp, use: <pre class=language-python>FileType([\".cc\", \".cpp\"])</pre>",
returnType = SkylarkFileType.class,
- mandatoryParams = {
+ mandatoryPositionals = {
@Param(name = "types", type = SkylarkList.class, generic1 = String.class,
doc = "a list of the accepted file extensions")})
private static final SkylarkFunction fileType = new SimpleSkylarkFunction("FileType") {
@@ -347,7 +352,7 @@ public class SkylarkRuleClassFunctions {
}
};
- @SkylarkBuiltin(name = "to_proto",
+ @SkylarkSignature(name = "to_proto",
doc = "Creates a text message from the struct parameter. This method only works if all "
+ "struct elements (recursively) are strings, ints, booleans, other structs or a "
+ "list of these types. Quotes and new lines in strings are escaped. "
@@ -362,7 +367,12 @@ public class SkylarkRuleClassFunctions {
+ "# key {\n# inner_key: 1\n# }\n# key {\n# inner_key: 2\n# }\n\n"
+ "struct(key=struct(inner_key=struct(inner_inner_key='text'))).to_proto()\n"
+ "# key {\n# inner_key {\n# inner_inner_key: \"text\"\n# }\n# }\n</pre>",
- objectType = SkylarkClassObject.class, returnType = String.class)
+ objectType = SkylarkClassObject.class, returnType = String.class,
+ mandatoryPositionals = {
+ // TODO(bazel-team): shouldn't we accept any ClassObject?
+ @Param(name = "self", type = SkylarkClassObject.class,
+ doc = "this struct")},
+ useLocation = true)
private static final SkylarkFunction toProto = new SimpleSkylarkFunction("to_proto") {
@Override
public Object call(Map<String, Object> arguments, Location loc) throws EvalException,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
index cc582ab17e..0019fe8683 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
@@ -36,12 +36,12 @@ import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.Label;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin.Param;
import com.google.devtools.build.lib.syntax.SkylarkFunction;
import com.google.devtools.build.lib.syntax.SkylarkFunction.SimpleSkylarkFunction;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.Map;
@@ -69,32 +69,43 @@ public class SkylarkRuleImplementationFunctions {
* command = 'command',
* )
*/
- @SkylarkBuiltin(name = "action",
+ @SkylarkSignature(name = "action",
doc = "Creates an action that runs an executable or a shell command.",
objectType = SkylarkRuleContext.class,
returnType = Environment.NoneType.class,
- mandatoryParams = {
- @Param(name = "outputs", type = SkylarkList.class, generic1 = Artifact.class,
- doc = "list of the output files of the action")},
- optionalParams = {
- @Param(name = "inputs", type = SkylarkList.class, generic1 = Artifact.class,
- doc = "list of the input files of the action"),
- @Param(name = "executable", doc = "the executable file to be called by the action"),
- @Param(name = "arguments", type = SkylarkList.class, generic1 = String.class,
- doc = "command line arguments of the action"),
- @Param(name = "mnemonic", type = String.class, doc = "mnemonic"),
- @Param(name = "command", doc = "shell command to execute"),
- @Param(name = "progress_message", type = String.class,
- doc = "progress message to show to the user during the build, e.g. \"Compiling foo.cc to"
- + " create foo.o\""),
- @Param(name = "use_default_shell_env", type = Boolean.class,
- doc = "whether the action should use the built in shell environment or not"),
- @Param(name = "env", type = Map.class, doc = "sets the dictionary of environment variables"),
- @Param(name = "execution_requirements", type = Map.class,
- doc = "information for scheduling the action"),
- @Param(name = "input_manifests", type = Map.class,
- doc = "sets the map of input manifests files; "
- + "they are typicially generated by the command_helper")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = SkylarkRuleContext.class, doc = "This RuleContext.")},
+ mandatoryNamedOnly = {
+ @Param(name = "outputs", type = SkylarkList.class, generic1 = Artifact.class,
+ doc = "list of the output files of the action")},
+ optionalNamedOnly = {
+ @Param(name = "inputs", type = SkylarkList.class, generic1 = Artifact.class,
+ defaultValue = "[]", doc = "list of the input files of the action"),
+ @Param(name = "executable", type = Object.class, // File or PathFragment or None
+ defaultValue = "None",
+ doc = "the executable file to be called by the action"),
+ @Param(name = "arguments", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = "command line arguments of the action"),
+ @Param(name = "mnemonic", type = String.class, noneable = true,
+ defaultValue = "None", doc = "mnemonic"),
+ @Param(name = "command", type = Object.class, // string or ListOf(string) or NoneType
+ defaultValue = "None", doc = "shell command to execute"),
+ @Param(name = "progress_message", type = String.class, noneable = true,
+ defaultValue = "None",
+ doc = "progress message to show to the user during the build, "
+ + "e.g. \"Compiling foo.cc to create foo.o\""),
+ @Param(name = "use_default_shell_env", type = Boolean.class, defaultValue = "False",
+ doc = "whether the action should use the built in shell environment or not"),
+ @Param(name = "env", type = Map.class, noneable = true, defaultValue = "None",
+ doc = "sets the dictionary of environment variables"),
+ @Param(name = "execution_requirements", type = Map.class, noneable = true,
+ defaultValue = "None",
+ doc = "information for scheduling the action"),
+ @Param(name = "input_manifests", type = Map.class, noneable = true,
+ defaultValue = "None",
+ doc = "sets the map of input manifests files; "
+ + "they are typicially generated by the command_helper")},
+ useLocation = true)
private static final SkylarkFunction createSpawnAction =
new SimpleSkylarkFunction("action") {
@@ -175,17 +186,17 @@ public class SkylarkRuleImplementationFunctions {
};
// TODO(bazel-team): improve this method to be more memory friendly
- @SkylarkBuiltin(name = "file_action",
+ @SkylarkSignature(name = "file_action",
doc = "Creates a file write action.",
objectType = SkylarkRuleContext.class,
- returnType = Environment.NoneType.class,
- optionalParams = {
- @Param(name = "executable", type = Boolean.class,
- doc = "whether the output file should be executable (default is False)"),
- },
- mandatoryParams = {
+ returnType = FileWriteAction.class,
+ mandatoryPositionals = {
+ @Param(name = "self", type = SkylarkRuleContext.class, doc = "this context"),
@Param(name = "output", type = Artifact.class, doc = "the output file"),
- @Param(name = "content", type = String.class, doc = "the contents of the file")})
+ @Param(name = "content", type = String.class, doc = "the contents of the file")},
+ optionalPositionals = {
+ @Param(name = "executable", type = Boolean.class,
+ doc = "whether the output file should be executable (default is False)")})
private static final SkylarkFunction createFileWriteAction =
new SimpleSkylarkFunction("file_action") {
@@ -204,18 +215,22 @@ public class SkylarkRuleImplementationFunctions {
}
};
- @SkylarkBuiltin(name = "template_action",
+ @SkylarkSignature(name = "template_action",
doc = "Creates a template expansion action.",
objectType = SkylarkRuleContext.class,
- returnType = Environment.NoneType.class,
- mandatoryParams = {
- @Param(name = "template", type = Artifact.class, doc = "the template file"),
- @Param(name = "output", type = Artifact.class, doc = "the output file"),
- @Param(name = "substitutions", type = Map.class,
- doc = "substitutions to make when expanding the template")},
- optionalParams = {
- @Param(name = "executable", type = Boolean.class,
- doc = "whether the output file should be executable (default is False)")})
+ returnType = TemplateExpansionAction.class,
+ mandatoryPositionals = {
+ @Param(name = "self", type = SkylarkRuleContext.class, doc = "this context")},
+ mandatoryNamedOnly = {
+ @Param(name = "template", type = Artifact.class,
+ doc = "the template file"),
+ @Param(name = "output", type = Artifact.class,
+ doc = "the output file"),
+ @Param(name = "substitutions", type = Map.class,
+ doc = "substitutions to make when expanding the template")},
+ optionalNamedOnly = {
+ @Param(name = "executable", type = Boolean.class,
+ doc = "whether the output file should be executable (default is False)")})
private static final SkylarkFunction createTemplateAction =
new SimpleSkylarkFunction("template_action") {
@@ -245,12 +260,13 @@ public class SkylarkRuleImplementationFunctions {
* A built in Skylark helper function to access the
* Transitive info providers of Transitive info collections.
*/
- @SkylarkBuiltin(name = "provider",
+ @SkylarkSignature(name = "provider",
doc = "Returns the transitive info provider provided by the target.",
- mandatoryParams = {
- @Param(name = "target", type = TransitiveInfoCollection.class,
- doc = "the configured target which provides the provider"),
- @Param(name = "type", type = String.class, doc = "the class type of the provider")})
+ mandatoryPositionals = {
+ @Param(name = "target", type = TransitiveInfoCollection.class,
+ doc = "the configured target which provides the provider"),
+ @Param(name = "type", type = String.class, doc = "the class type of the provider")},
+ useLocation = true)
private static final SkylarkFunction provider = new SimpleSkylarkFunction("provider") {
@Override
public Object call(Map<String, Object> params, Location loc) throws EvalException {
@@ -271,21 +287,28 @@ public class SkylarkRuleImplementationFunctions {
};
// TODO(bazel-team): Remove runfile states from Skylark.
- @SkylarkBuiltin(name = "runfiles",
+ @SkylarkSignature(name = "runfiles",
doc = "Creates a runfiles object.",
objectType = SkylarkRuleContext.class,
returnType = Runfiles.class,
- optionalParams = {
- @Param(name = "files", type = SkylarkList.class, generic1 = Artifact.class,
- doc = "The list of files to be added to the runfiles."),
- // TODO(bazel-team): If we have a memory efficient support for lazy list containing NestedSets
- // we can remove this and just use files = [file] + list(set)
- @Param(name = "transitive_files", type = SkylarkNestedSet.class, generic1 = Artifact.class,
- doc = "The (transitive) set of files to be added to the runfiles."),
- @Param(name = "collect_data", type = Boolean.class, doc = "Whether to collect the data "
- + "runfiles from the dependencies in srcs, data and deps attributes."),
- @Param(name = "collect_default", type = Boolean.class, doc = "Whether to collect the default "
- + "runfiles from the dependencies in srcs, data and deps attributes.")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = SkylarkRuleContext.class, doc = "This context.")},
+ optionalPositionals = {
+ @Param(name = "files", type = SkylarkList.class, generic1 = Artifact.class,
+ defaultValue = "[]", doc = "The list of files to be added to the runfiles."),
+ // TODO(bazel-team): If we have a memory efficient support for lazy list containing
+ // NestedSets we can remove this and just use files = [file] + list(set)
+ // Also, allow empty set for init
+ @Param(name = "transitive_files", type = SkylarkNestedSet.class, generic1 = Artifact.class,
+ noneable = true, defaultValue = "None",
+ doc = "The (transitive) set of files to be added to the runfiles."),
+ @Param(name = "collect_data", type = Boolean.class, defaultValue = "False",
+ doc = "Whether to collect the data "
+ + "runfiles from the dependencies in srcs, data and deps attributes."),
+ @Param(name = "collect_default", type = Boolean.class, defaultValue = "False",
+ doc = "Whether to collect the default "
+ + "runfiles from the dependencies in srcs, data and deps attributes.")},
+ useLocation = true)
private static final SkylarkFunction runfiles = new SimpleSkylarkFunction("runfiles") {
@Override
public Object call(Map<String, Object> params, Location loc) throws EvalException,
@@ -309,15 +332,16 @@ public class SkylarkRuleImplementationFunctions {
}
};
- @SkylarkBuiltin(name = "command_helper", doc = "Experimental. Creates a command helper class.",
+ @SkylarkSignature(name = "command_helper", doc = "Experimental. Creates a command helper class.",
objectType = SkylarkRuleContext.class,
returnType = CommandHelper.class,
- mandatoryParams = {
- @Param(name = "tools", type = SkylarkList.class, generic1 = TransitiveInfoCollection.class,
- doc = "list of tools (list of targets)"),
- @Param(name = "label_dict", type = Map.class,
- doc = "dictionary of resolved labels and the corresponding list of Files "
- + "(a dict of Label : list of Files)")})
+ mandatoryPositionals = {
+ @Param(name = "self", type = SkylarkRuleContext.class, doc = "this RuleContext"),
+ @Param(name = "tools", type = SkylarkList.class, generic1 = TransitiveInfoCollection.class,
+ doc = "list of tools (list of targets)"),
+ @Param(name = "label_dict", type = Map.class, defaultValue = "{}",
+ doc = "dictionary of resolved labels and the corresponding list of Files "
+ + "(a dict of Label : list of Files)")})
private static final SkylarkFunction createCommandHelper =
new SimpleSkylarkFunction("command_helper") {
@SuppressWarnings("unchecked")
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
index fb9e2fdabb..08ea8ee3c1 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
@@ -16,6 +16,7 @@ package com.google.devtools.build.lib.syntax;
import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.Type.ConversionException;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEitherList;
import com.google.devtools.build.lib.syntax.SkylarkType.SkylarkFunctionType;
import java.lang.reflect.InvocationTargetException;
@@ -59,6 +60,9 @@ public class BuiltinFunction extends BaseFunction {
// to be used as size of argument array by the outer call method.
private int innerArgumentCount;
+ // The returnType of the method.
+ private Class<?> returnType;
+
/** Create unconfigured function from its name */
public BuiltinFunction(String name) {
@@ -202,6 +206,7 @@ public class BuiltinFunction extends BaseFunction {
enforcedArgumentTypes = new ArrayList<>();
this.extraArgs = SkylarkSignatureProcessor.getExtraArgs(annotation);
super.configure(annotation);
+ this.returnType = annotation.returnType();
}
// finds the method and makes it accessible (which is needed to find it, and later to use it)
@@ -236,8 +241,6 @@ public class BuiltinFunction extends BaseFunction {
"bad argument count for %s: method has %s arguments, type list has %s",
getName(), innerArgumentCount, parameterTypes.length);
- // TODO(bazel-team): also grab the returnType from the annotations,
- // and check it against method return type
if (enforcedArgumentTypes != null) {
for (int i = 0; i < arguments; i++) {
SkylarkType enforcedType = enforcedArgumentTypes.get(i);
@@ -254,8 +257,7 @@ public class BuiltinFunction extends BaseFunction {
// No need to enforce Simple types on the Skylark side, the JVM will do it for us.
enforcedArgumentTypes.set(i, null);
} else if (enforcedType instanceof SkylarkType.Combination) {
- Preconditions.checkArgument(
- enforcedType.getType() == parameterType, msg);
+ Preconditions.checkArgument(enforcedType.getType() == parameterType, msg);
} else {
Preconditions.checkArgument(
parameterType == Object.class || parameterType == null, msg);
@@ -265,6 +267,14 @@ public class BuiltinFunction extends BaseFunction {
}
// No need for the enforcedArgumentTypes List if all the types were Simple
enforcedArgumentTypes = FunctionSignature.<SkylarkType>valueListOrNull(enforcedArgumentTypes);
+
+ if (returnType != null) {
+ Class<?> type = returnType;
+ if (type == HackHackEitherList.class) {
+ type = Object.class;
+ }
+ Preconditions.checkArgument(type == invokeMethod.getReturnType());
+ }
}
/** Configure by copying another function's configuration */
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
index bd595127fc..a4a4bce771 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
@@ -37,14 +37,15 @@ import javax.annotation.Nullable;
*/
public class Environment {
- @SkylarkBuiltin(name = "True", returnType = Boolean.class, doc = "Literal for the boolean true.")
+ @SkylarkSignature(name = "True", returnType = Boolean.class,
+ doc = "Literal for the boolean true.")
private static final Boolean TRUE = true;
- @SkylarkBuiltin(name = "False", returnType = Boolean.class,
+ @SkylarkSignature(name = "False", returnType = Boolean.class,
doc = "Literal for the boolean false.")
private static final Boolean FALSE = false;
- @SkylarkBuiltin(name = "PACKAGE_NAME", returnType = String.class,
+ @SkylarkSignature(name = "PACKAGE_NAME", returnType = String.class,
doc = "The name of the package the rule or build extension is called from. "
+ "This variable is special, because its value comes from outside of the extension "
+ "module (it comes from the BUILD file), so it can only be accessed in functions "
@@ -65,7 +66,7 @@ public class Environment {
private NoneType() {}
}
- @SkylarkBuiltin(name = "None", returnType = NoneType.class, doc = "Literal for the None value.")
+ @SkylarkSignature(name = "None", returnType = NoneType.class, doc = "Literal for the None value.")
public static final NoneType NONE = new NoneType();
protected final Map<String, Object> env = new HashMap<>();
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
index 79f2efa677..f32dcdf9ce 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.syntax;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@@ -458,7 +459,8 @@ public final class FuncallExpression extends Expression {
}
}
- static boolean isNamespace(Class<?> classObject) {
+ @VisibleForTesting
+ public static boolean isNamespace(Class<?> classObject) {
return classObject.isAnnotationPresent(SkylarkModule.class)
&& classObject.getAnnotation(SkylarkModule.class).namespace();
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java b/src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java
index 49398f576b..3792e21fbc 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/FunctionSignature.java
@@ -194,7 +194,7 @@ public abstract class FunctionSignature implements Serializable {
*
* <p>V is the class of defaultValues and T is the class of types.
* When parsing a function definition at compile-time, they are &lt;Expression, Expression&gt;;
- * when processing a @SkylarkBuiltin annotation at build-time, &lt;Object, SkylarkType&gt;.
+ * when processing a @SkylarkSignature annotation at build-time, &lt;Object, SkylarkType&gt;.
*/
@AutoValue
public abstract static class WithValues<V, T> implements Serializable {
@@ -247,7 +247,7 @@ public abstract class FunctionSignature implements Serializable {
/**
* Parse a list of Parameter into a FunctionSignature.
*
- * <p>To be used both by the Parser and by the SkylarkBuiltin annotation processor.
+ * <p>To be used both by the Parser and by the SkylarkSignature annotation processor.
*/
public static <V, T> WithValues<V, T> of(Iterable<Parameter<V, T>> parameters)
throws SignatureException {
@@ -512,7 +512,7 @@ public abstract class FunctionSignature implements Serializable {
return of(0, 0, numMandatory, false, false, names);
}
- /** Invalid signature from Parser or from SkylarkBuiltin annotations */
+ /** Invalid signature from Parser or from SkylarkSignature annotations */
protected static class SignatureException extends Exception {
@Nullable private final Parameter<?, ?> parameter;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkBuiltin.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkBuiltin.java
deleted file mode 100644
index 894a77a9ea..0000000000
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkBuiltin.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.syntax;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-
-/**
- * An annotation to mark built-in keyword argument methods accessible from Skylark.
- */
-@Target({ElementType.FIELD})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface SkylarkBuiltin {
-
- String name();
-
- String doc();
-
- Param[] mandatoryParams() default {};
-
- Param[] optionalParams() default {};
-
- boolean documented() default true;
-
- Class<?> objectType() default Object.class;
-
- Class<?> returnType() default Object.class;
-
- boolean onlyLoadingPhase() default false;
-
- /**
- * An annotation for parameters of Skylark built-in functions.
- */
- @Retention(RetentionPolicy.RUNTIME)
- public @interface Param {
-
- String name();
-
- String doc();
-
- Class<?> type() default Object.class;
-
- Class<?> generic1() default Object.class;
-
- boolean callbackEnabled() default false;
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkFunction.java
index b5aa6c9729..c90a4efbeb 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkFunction.java
@@ -31,10 +31,10 @@ import java.util.concurrent.ExecutionException;
* All usable arguments have to be specified. In case of ambiguous arguments (a parameter is
* specified as positional and keyword arguments in the function call) an exception is thrown.
*/
-public abstract class SkylarkFunction extends AbstractFunction {
+public abstract class SkylarkFunction extends BaseFunction {
private ImmutableList<String> parameters;
- private ImmutableMap<String, SkylarkBuiltin.Param> parameterTypes;
+ private ImmutableMap<String, SkylarkSignature.Param> parameterTypes;
private int mandatoryParamNum;
private boolean configured = false;
private Class<?> objectType;
@@ -50,19 +50,37 @@ public abstract class SkylarkFunction extends AbstractFunction {
/**
* Configures the parameter of this Skylark function using the annotation.
*/
- public void configure(SkylarkBuiltin annotation) {
+ public void configure(SkylarkSignature annotation) {
Preconditions.checkState(!configured);
Preconditions.checkArgument(
getName().equals(annotation.name()), "%s != %s", getName(), annotation.name());
+ Preconditions.checkArgument(
+ annotation.optionalPositionals().length == 0 || annotation.mandatoryNamedOnly().length == 0,
+ "SkylarkFunction %s: forbidden simultaneous optionalPositionals and mandatoryNamedOnly",
+ getName());
+ Preconditions.checkArgument(
+ annotation.extraPositionals().length == 0 && annotation.extraKeywords().length == 0,
+ "SkylarkFunction %s: forbidden extra arguments", getName());
mandatoryParamNum = 0;
ImmutableList.Builder<String> paramListBuilder = ImmutableList.builder();
- ImmutableMap.Builder<String, SkylarkBuiltin.Param> paramTypeBuilder = ImmutableMap.builder();
- for (SkylarkBuiltin.Param param : annotation.mandatoryParams()) {
+ ImmutableMap.Builder<String, SkylarkSignature.Param> paramTypeBuilder = ImmutableMap.builder();
+ for (SkylarkSignature.Param param : annotation.mandatoryPositionals()) {
+ if (!param.name().equals("self")) {
+ paramListBuilder.add(param.name());
+ paramTypeBuilder.put(param.name(), param);
+ mandatoryParamNum++;
+ }
+ }
+ for (SkylarkSignature.Param param : annotation.optionalPositionals()) {
+ paramListBuilder.add(param.name());
+ paramTypeBuilder.put(param.name(), param);
+ }
+ for (SkylarkSignature.Param param : annotation.mandatoryNamedOnly()) {
paramListBuilder.add(param.name());
paramTypeBuilder.put(param.name(), param);
mandatoryParamNum++;
}
- for (SkylarkBuiltin.Param param : annotation.optionalParams()) {
+ for (SkylarkSignature.Param param : annotation.optionalNamedOnly()) {
paramListBuilder.add(param.name());
paramTypeBuilder.put(param.name(), param);
}
@@ -152,7 +170,7 @@ public abstract class SkylarkFunction extends AbstractFunction {
private void checkTypeAndAddArg(String paramName, Object value,
ImmutableMap.Builder<String, Object> arguments, Location loc) throws EvalException {
- SkylarkBuiltin.Param param = parameterTypes.get(paramName);
+ SkylarkSignature.Param param = parameterTypes.get(paramName);
if (param.callbackEnabled() && value instanceof Function) {
// If we pass a function as an argument we trust the Function implementation with the type
// check. It's OK since the function needs to be called manually anyway.
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
index bacb78a7dc..1d9cd818bd 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
@@ -115,6 +115,18 @@ public class SkylarkSignatureProcessor {
}
/**
+ * Fake class to use in SkylarkSignature annotations to indicate that either List or SkylarkList
+ * may be used, depending on whether the Build language or Skylark is being evaluated.
+ */
+ // TODO(bazel-team): either make SkylarkList a subclass of List (mutable or immutable throwing
+ // runtime exceptions), or have the Build language use immutable SkylarkList, but either way,
+ // do away with this hack.
+ public static class HackHackEitherList {
+ private HackHackEitherList() { }
+ }
+
+
+ /**
* Configures the parameter of this Skylark function using the annotation.
*/
// TODO(bazel-team): Maybe have the annotation be a string representing the
@@ -134,7 +146,7 @@ public class SkylarkSignatureProcessor {
return new Parameter.Star<>(null);
}
if (param.type() != Object.class) {
- if (param.type() == List.class) {
+ if (param.type() == HackHackEitherList.class) {
// NB: a List in the annotation actually indicates either a List or a SkylarkList
// and we trust the BuiltinFunction to do the enforcement.
// For automatic document generation purpose, we lie and just say it's a list;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
index 01fb872a0e..f07fd61914 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
@@ -836,9 +836,9 @@ public abstract class SkylarkType {
}
/**
- * Creates a SkylarkType from the SkylarkBuiltin annotation.
+ * Creates a SkylarkType from the SkylarkSignature annotation.
*/
- public static SkylarkType getReturnType(SkylarkBuiltin annotation) {
+ public static SkylarkType getReturnType(SkylarkSignature annotation) {
if (Function.class.isAssignableFrom(annotation.returnType())) {
return SkylarkFunctionType.of(annotation.name());
} else {