aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java
diff options
context:
space:
mode:
authorGravatar Francois-Rene Rideau <tunes@google.com>2015-04-22 06:47:31 +0000
committerGravatar Laurent Le Brun <laurentlb@google.com>2015-04-22 12:42:37 +0000
commit537a90b5b90856788412c962de61ece14e83274b (patch)
tree08b489df7f200b6fa59fee0adc857245f78f88e2 /src/main/java
parent443aaae842aaf5009c2972277a1089c504873877 (diff)
Use BuiltinFunction for all builtins
Replace the uses of AbstractFunction, MixedModeFunction, SkylarkFunction and SimpleSkylarkFunction by BuiltinFunction. -- MOS_MIGRATED_REVID=91763158
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java750
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java443
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/RuleClass.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java63
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java162
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkCommandLine.java35
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java38
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java258
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java225
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java4
12 files changed, 972 insertions, 1030 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 07988a9374..9d7faa82da 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java
@@ -14,19 +14,15 @@
package com.google.devtools.build.lib.packages;
-import static com.google.devtools.build.lib.syntax.SkylarkFunction.cast;
-
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
-import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.Type.ConversionException;
-import com.google.devtools.build.lib.syntax.AbstractFunction;
-import com.google.devtools.build.lib.syntax.AbstractFunction.NoArgFunction;
+import com.google.devtools.build.lib.syntax.BuiltinFunction;
import com.google.devtools.build.lib.syntax.ClassObject;
import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
import com.google.devtools.build.lib.syntax.DotExpression;
@@ -35,7 +31,6 @@ import com.google.devtools.build.lib.syntax.EvalException;
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.MixedModeFunction;
import com.google.devtools.build.lib.syntax.SelectorList;
import com.google.devtools.build.lib.syntax.SelectorValue;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
@@ -44,11 +39,12 @@ 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;
import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEitherList;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -106,7 +102,7 @@ public class MethodLibrary {
return str.substring(start, stop);
}
- public static int getListIndex(Object key, int listSize, FuncallExpression ast)
+ public static int getListIndex(Object key, int listSize, Location loc)
throws ConversionException, EvalException {
// Get the nth element in the list
int index = Type.INTEGER.convert(key, "index operand");
@@ -114,7 +110,7 @@ public class MethodLibrary {
index += listSize;
}
if (index < 0 || index >= listSize) {
- throw new EvalException(ast.getLocation(), "List index out of range (index is "
+ throw new EvalException(loc, "List index out of range (index is "
+ index + ", but list has " + listSize + " elements)");
}
return index;
@@ -129,25 +125,20 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
- String thisString = Type.STRING.convert(args[0], "'join' operand");
- List<?> seq = Type.OBJECT_LIST.convert(args[1], "'join' argument");
- return Joiner.on(thisString).join(seq);
- }};
+ private static BuiltinFunction join = new BuiltinFunction("join") {
+ public String invoke(String self, Object elements) throws ConversionException {
+ List<?> seq = Type.OBJECT_LIST.convert(elements, "'join.elements' argument");
+ return Joiner.on(self).join(seq);
+ }
+ };
@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 {
- String thiz = Type.STRING.convert(args[0], "'lower' operand");
- return thiz.toLowerCase();
+ private static BuiltinFunction lower = new BuiltinFunction("lower") {
+ public String invoke(String self) {
+ return self.toLowerCase();
}
};
@@ -155,12 +146,9 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
- String thiz = Type.STRING.convert(args[0], "'upper' operand");
- return thiz.toUpperCase();
+ private static BuiltinFunction upper = new BuiltinFunction("upper") {
+ public String invoke(String self) {
+ return self.toUpperCase();
}
};
@@ -176,26 +164,20 @@ public class MethodLibrary {
@Param(name = "maxsplit", type = Integer.class, noneable = true, defaultValue = "None",
doc = "The maximum number of replacements.")},
useLocation = true)
- private static Function replace =
- new MixedModeFunction("replace", ImmutableList.of("this", "old", "new", "maxsplit"), 3, false) {
- @Override
- public Object call(Object[] args, FuncallExpression ast) throws EvalException,
- ConversionException {
- String thiz = Type.STRING.convert(args[0], "'replace' operand");
- String old = Type.STRING.convert(args[1], "'replace' argument");
- String neww = Type.STRING.convert(args[2], "'replace' argument");
- int maxsplit =
- args[3] != null ? Type.INTEGER.convert(args[3], "'replace' argument")
- : Integer.MAX_VALUE;
+ private static BuiltinFunction replace = new BuiltinFunction("replace") {
+ public String invoke(String self, String oldString, String newString, Object maxSplitO,
+ Location loc) throws EvalException, ConversionException {
StringBuffer sb = new StringBuffer();
+ Integer maxSplit = Type.INTEGER.convertOptional(
+ maxSplitO, "'maxsplit' argument of 'replace'", /*label*/null, Integer.MAX_VALUE);
try {
- Matcher m = Pattern.compile(old, Pattern.LITERAL).matcher(thiz);
- for (int i = 0; i < maxsplit && m.find(); i++) {
- m.appendReplacement(sb, Matcher.quoteReplacement(neww));
+ Matcher m = Pattern.compile(oldString, Pattern.LITERAL).matcher(self);
+ for (int i = 0; i < maxSplit && m.find(); i++) {
+ m.appendReplacement(sb, Matcher.quoteReplacement(newString));
}
m.appendTail(sb);
} catch (IllegalStateException e) {
- throw new EvalException(ast.getLocation(), e.getMessage() + " in call to replace");
+ throw new EvalException(loc, e.getMessage() + " in call to replace");
}
return sb.toString();
}
@@ -213,20 +195,14 @@ public class MethodLibrary {
@Param(name = "maxsplit", type = Integer.class, noneable = true, defaultValue = "None",
doc = "The maximum number of splits.")},
useEnvironment = true)
- private static Function split = new MixedModeFunction("split",
- ImmutableList.of("this", "sep", "maxsplit"), 1, false) {
- @Override
- public Object call(Object[] args, FuncallExpression ast, Environment env)
- throws ConversionException {
- String thiz = Type.STRING.convert(args[0], "'split' operand");
- String sep = args[1] != null
- ? Type.STRING.convert(args[1], "'split' argument")
- : " ";
- int maxsplit = args[2] != null
- ? Type.INTEGER.convert(args[2], "'split' argument") + 1 // last is remainder
- : -1;
- String[] ss = Pattern.compile(sep, Pattern.LITERAL).split(thiz, maxsplit);
- List<String> result = java.util.Arrays.asList(ss);
+ private static BuiltinFunction split = new BuiltinFunction("split") {
+ public Object invoke(String self, String sep, Object maxSplitO,
+ Environment env) throws ConversionException {
+ int maxSplit = Type.INTEGER.convertOptional(
+ maxSplitO, "'split' argument of 'split'", /*label*/null, -2);
+ // + 1 because the last result is the remainder, and default of -2 so that after +1 it's -1
+ String[] ss = Pattern.compile(sep, Pattern.LITERAL).split(self, maxSplit + 1);
+ List<String> result = Arrays.<String>asList(ss);
return env.isSkylarkEnabled() ? SkylarkList.list(result, String.class) : result;
}
};
@@ -244,19 +220,6 @@ public class MethodLibrary {
return subpos < 0 ? subpos : subpos + start;
}
- // Common implementation for find, rfind, index, rindex.
- // forward is true iff we want to return the last matching index.
- private static int stringFind(String functionName, boolean forward, Object[] args)
- throws ConversionException {
- String thiz = Type.STRING.convert(args[0], functionName + " operand");
- String sub = Type.STRING.convert(args[1], functionName + " argument");
- int start = 0;
- if (!EvalUtils.isNullOrNone(args[2])) {
- start = Type.INTEGER.convert(args[2], functionName + " argument");
- }
- return stringFind(forward, thiz, sub, start, args[3], functionName + " argument");
- }
-
@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 "
@@ -270,13 +233,12 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
- return stringFind("rfind", false, args);
- }
- };
+ private static BuiltinFunction rfind = new BuiltinFunction("rfind") {
+ public Integer invoke(String self, String sub, Integer start, Object end)
+ throws ConversionException {
+ return stringFind(false, self, sub, start, end, "'end' argument to rfind");
+ }
+ };
@SkylarkSignature(name = "find", objectType = StringModule.class, returnType = Integer.class,
doc = "Returns the first index where <code>sub</code> is found, "
@@ -291,14 +253,12 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast)
- throws ConversionException {
- return stringFind("find", true, args);
- }
- };
+ private static BuiltinFunction find = new BuiltinFunction("find") {
+ public Integer invoke(String self, String sub, Integer start, Object end)
+ throws ConversionException {
+ return stringFind(true, self, sub, start, end, "'end' argument to find");
+ }
+ };
@SkylarkSignature(name = "rindex", objectType = StringModule.class, returnType = Integer.class,
doc = "Returns the last index where <code>sub</code> is found, "
@@ -314,20 +274,17 @@ public class MethodLibrary {
@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
- public Object call(Object[] args, FuncallExpression ast)
- throws EvalException, ConversionException {
- int res = stringFind("rindex", false, args);
- if (res < 0) {
- throw new EvalException(ast.getLocation(),
- "substring " + EvalUtils.prettyPrintValue(args[1])
- + " not found in " + EvalUtils.prettyPrintValue(args[0]));
- }
- return res;
- }
- };
+ private static BuiltinFunction rindex = new BuiltinFunction("rindex") {
+ public Integer invoke(String self, String sub, Integer start, Object end,
+ Location loc) throws EvalException, ConversionException {
+ int res = stringFind(false, self, sub, start, end, "'end' argument to rindex");
+ if (res < 0) {
+ throw new EvalException(loc, String.format("substring %s not found in %s",
+ EvalUtils.prettyPrintValue(sub), EvalUtils.prettyPrintValue(self)));
+ }
+ return res;
+ }
+ };
@SkylarkSignature(name = "index", objectType = StringModule.class, returnType = Integer.class,
doc = "Returns the first index where <code>sub</code> is found, "
@@ -343,20 +300,17 @@ public class MethodLibrary {
@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
- public Object call(Object[] args, FuncallExpression ast)
- throws EvalException, ConversionException {
- int res = stringFind("index", true, args);
- if (res < 0) {
- throw new EvalException(ast.getLocation(),
- "substring " + EvalUtils.prettyPrintValue(args[1])
- + " not found in " + EvalUtils.prettyPrintValue(args[0]));
- }
- return res;
- }
- };
+ private static BuiltinFunction index = new BuiltinFunction("index") {
+ public Integer invoke(String self, String sub, Integer start, Object end,
+ Location loc) throws EvalException, ConversionException {
+ int res = stringFind(true, self, sub, start, end, "'end' argument to index");
+ if (res < 0) {
+ throw new EvalException(loc, String.format("substring %s not found in %s",
+ EvalUtils.prettyPrintValue(sub), EvalUtils.prettyPrintValue(self)));
+ }
+ return res;
+ }
+ };
@SkylarkSignature(name = "count", objectType = StringModule.class, returnType = Integer.class,
doc = "Returns the number of (non-overlapping) occurrences of substring <code>sub</code> in "
@@ -370,30 +324,22 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast)
- throws ConversionException {
- String thiz = Type.STRING.convert(args[0], "'count' operand");
- String sub = Type.STRING.convert(args[1], "'count' argument");
- int start = 0;
- if (args[2] != null) {
- start = Type.INTEGER.convert(args[2], "'count' argument");
- }
- String str = pythonSubstring(thiz, start, args[3], "'end' argument to 'count'");
- if (sub.isEmpty()) {
- return str.length() + 1;
- }
- int count = 0;
- int index = -1;
- while ((index = str.indexOf(sub)) >= 0) {
- count++;
- str = str.substring(index + sub.length());
- }
- return count;
- }
- };
+ private static BuiltinFunction count = new BuiltinFunction("count") {
+ public Integer invoke(String self, String sub, Integer start, Object end)
+ throws ConversionException {
+ String str = pythonSubstring(self, start, end, "'end' operand of 'find'");
+ if (sub.isEmpty()) {
+ return str.length() + 1;
+ }
+ int count = 0;
+ int index = -1;
+ while ((index = str.indexOf(sub)) >= 0) {
+ count++;
+ str = str.substring(index + sub.length());
+ }
+ return count;
+ }
+ };
@SkylarkSignature(name = "endswith", objectType = StringModule.class, returnType = Boolean.class,
doc = "Returns True if the string ends with <code>sub</code>, "
@@ -407,21 +353,13 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast)
- throws ConversionException {
- String thiz = Type.STRING.convert(args[0], "'endswith' operand");
- String sub = Type.STRING.convert(args[1], "'endswith' argument");
- int start = 0;
- if (args[2] != null) {
- start = Type.INTEGER.convert(args[2], "'endswith' argument");
- }
- return pythonSubstring(thiz, start, args[3], "'end' argument to 'endswith'")
- .endsWith(sub);
- }
- };
+ private static BuiltinFunction endswith = new BuiltinFunction(
+ "endswith", SkylarkList.tuple(0, Environment.NONE)) {
+ public Boolean invoke(String self, String sub, Integer start, Object end)
+ throws ConversionException {
+ return pythonSubstring(self, start, end, "'end' operand of 'endswith'").endsWith(sub);
+ }
+ };
@SkylarkSignature(name = "startswith", objectType = StringModule.class,
returnType = Boolean.class,
@@ -436,18 +374,10 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
- String thiz = Type.STRING.convert(args[0], "'startswith' operand");
- String sub = Type.STRING.convert(args[1], "'startswith' argument");
- int start = 0;
- if (args[2] != null) {
- start = Type.INTEGER.convert(args[2], "'startswith' argument");
- }
- return pythonSubstring(thiz, start, args[3], "'end' argument to 'startswith'")
- .startsWith(sub);
+ private static BuiltinFunction startswith = new BuiltinFunction("startswith") {
+ public Boolean invoke(String self, String sub, Integer start, Object end)
+ throws ConversionException {
+ return pythonSubstring(self, start, end, "'end' operand of 'startswith'").startsWith(sub);
}
};
@@ -457,15 +387,11 @@ public class MethodLibrary {
+ "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
- public Object call(Object[] args, FuncallExpression ast)
- throws ConversionException {
- String operand = Type.STRING.convert(args[0], "'strip' operand");
- return operand.trim();
- }
- };
+ private static BuiltinFunction strip = new BuiltinFunction("strip") {
+ public String invoke(String self) {
+ return self.trim();
+ }
+ };
// slice operator
@SkylarkSignature(name = "$slice", documented = false,
@@ -475,30 +401,22 @@ public class MethodLibrary {
@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
- public Object call(Object[] args, FuncallExpression ast, Environment env)
- throws EvalException, ConversionException {
- int left = Type.INTEGER.convert(args[1], "start operand");
- int right = Type.INTEGER.convert(args[2], "end operand");
-
+ private static BuiltinFunction slice = new BuiltinFunction("$slice") {
+ public Object invoke(Object self, Integer left, Integer right,
+ Location loc, Environment env) throws EvalException, ConversionException {
// Substring
- if (args[0] instanceof String) {
- String thiz = Type.STRING.convert(args[0], "substring operand");
- return pythonSubstring(thiz, left, right, "");
+ if (self instanceof String) {
+ return pythonSubstring((String) self, left, right, "");
}
// List slice
- List<Object> list = Type.OBJECT_LIST.convert(args[0], "list operand");
+ List<Object> list = Type.OBJECT_LIST.convert(self, "list operand");
left = clampIndex(left, list.size());
right = clampIndex(right, list.size());
-
- List<Object> result = Lists.newArrayList();
- for (int i = left; i < right; i++) {
- result.add(list.get(i));
+ if (left > right) {
+ left = right;
}
- return convert(result, env, ast.getLocation());
+ return convert(list.subList(left, right), env, loc);
}
};
@@ -508,18 +426,16 @@ public class MethodLibrary {
mandatoryPositionals = {
@Param(name = "self", type = HackHackEitherList.class, doc = "This list.")},
useLocation = true, useEnvironment = true)
- private static Function sorted = new MixedModeFunction("sorted",
- ImmutableList.of("self"), 1, false) {
- @Override
- public Object call(Object[] args, FuncallExpression ast, Environment env)
+ private static BuiltinFunction sorted = new BuiltinFunction("sorted") {
+ public Object invoke(Object self, Location loc, Environment env)
throws EvalException, ConversionException {
- List<Object> self = Type.OBJECT_LIST.convert(args[0], "'sorted' operand");
+ List<Object> list = Type.OBJECT_LIST.convert(self, "'sorted' operand");
try {
- self = Ordering.from(EvalUtils.SKYLARK_COMPARATOR).sortedCopy(self);
+ list = Ordering.from(EvalUtils.SKYLARK_COMPARATOR).sortedCopy(list);
} catch (EvalUtils.ComparisonException e) {
- throw new EvalException(ast.getLocation(), e);
+ throw new EvalException(loc, e);
}
- return convert(self, env, ast.getLocation());
+ return convert(list, env, loc);
}
};
@@ -531,13 +447,10 @@ public class MethodLibrary {
@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
- public Object call(Object[] args, FuncallExpression ast) throws EvalException,
- ConversionException {
- List<Object> thiz = Type.OBJECT_LIST.convert(args[0], "'append' operand");
- thiz.add(args[1]);
+ private static BuiltinFunction append = new BuiltinFunction("append") {
+ public Environment.NoneType invoke(List<Object> self, Object item,
+ Location loc, Environment env) throws EvalException, ConversionException {
+ self.add(item);
return Environment.NONE;
}
};
@@ -550,14 +463,10 @@ public class MethodLibrary {
@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
- public Object call(Object[] args, FuncallExpression ast) throws EvalException,
- ConversionException {
- List<Object> thiz = Type.OBJECT_LIST.convert(args[0], "'extend' operand");
- List<Object> l = Type.OBJECT_LIST.convert(args[1], "'extend' argument");
- thiz.addAll(l);
+ private static BuiltinFunction extend = new BuiltinFunction("extend") {
+ public Environment.NoneType invoke(List<Object> self, List<Object> items,
+ Location loc, Environment env) throws EvalException, ConversionException {
+ self.addAll(items);
return Environment.NONE;
}
};
@@ -570,50 +479,43 @@ public class MethodLibrary {
@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
- public Object call(Object[] args, FuncallExpression ast) throws EvalException,
- ConversionException {
- Object collectionCandidate = args[0];
- Object key = args[1];
-
- if (collectionCandidate instanceof Map<?, ?>) {
- Map<?, ?> dictionary = (Map<?, ?>) collectionCandidate;
- if (!dictionary.containsKey(key)) {
- throw new EvalException(ast.getLocation(),
- "Key " + EvalUtils.prettyPrintValue(key) + " not found in dictionary");
+ private static BuiltinFunction indexOperator = new BuiltinFunction("$index") {
+ public Object invoke(Object self, Object key,
+ Location loc) throws EvalException, ConversionException {
+ if (self instanceof SkylarkList) {
+ SkylarkList list = (SkylarkList) self;
+ if (list.isEmpty()) {
+ throw new EvalException(loc, "List is empty");
}
- return dictionary.get(key);
- } else if (collectionCandidate instanceof List<?>) {
+ int index = getListIndex(key, list.size(), loc);
+ return list.get(index);
- List<Object> list = Type.OBJECT_LIST.convert(collectionCandidate, "index operand");
-
- if (!list.isEmpty()) {
- int index = getListIndex(key, list.size(), ast);
- return list.get(index);
+ } else if (self instanceof Map<?, ?>) {
+ Map<?, ?> dictionary = (Map<?, ?>) self;
+ if (!dictionary.containsKey(key)) {
+ throw new EvalException(loc, String.format("Key %s not found in dictionary",
+ EvalUtils.prettyPrintValue(key)));
}
+ return dictionary.get(key);
- throw new EvalException(ast.getLocation(), "List is empty");
- } else if (collectionCandidate instanceof SkylarkList) {
- SkylarkList list = (SkylarkList) collectionCandidate;
-
- if (!list.isEmpty()) {
- int index = getListIndex(key, list.size(), ast);
- return list.get(index);
+ } else if (self instanceof List<?>) {
+ List<Object> list = Type.OBJECT_LIST.convert(self, "index operand");
+ if (list.isEmpty()) {
+ throw new EvalException(loc, "List is empty");
}
+ int index = getListIndex(key, list.size(), loc);
+ return list.get(index);
- throw new EvalException(ast.getLocation(), "List is empty");
- } else if (collectionCandidate instanceof String) {
- String str = (String) collectionCandidate;
- int index = getListIndex(key, str.length(), ast);
+ } else if (self instanceof String) {
+ String str = (String) self;
+ int index = getListIndex(key, str.length(), loc);
return str.substring(index, index + 1);
} else {
// TODO(bazel-team): This is dead code, get rid of it.
- throw new EvalException(ast.getLocation(), String.format(
+ throw new EvalException(loc, String.format(
"Unsupported datatype (%s) for indexing, only works for dict and list",
- EvalUtils.getDataTypeName(collectionCandidate)));
+ EvalUtils.getDataTypeName(self)));
}
}
};
@@ -625,13 +527,12 @@ public class MethodLibrary {
+ "{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)
- throws EvalException, InterruptedException {
+ private static BuiltinFunction values = new BuiltinFunction("values") {
+ public Object invoke(Map<?, ?> self,
+ Location loc, Environment env) throws EvalException, ConversionException {
// Use a TreeMap to ensure consistent ordering.
- Map<?, ?> dict = new TreeMap<>((Map<?, ?>) self);
- return convert(dict.values(), env, ast.getLocation());
+ Map<?, ?> dict = new TreeMap<>(self);
+ return convert(dict.values(), env, loc);
}
};
@@ -644,20 +545,19 @@ public class MethodLibrary {
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)
- throws EvalException, InterruptedException {
+ private static BuiltinFunction items = new BuiltinFunction("items") {
+ public Object invoke(Map<?, ?> self,
+ Location loc, Environment env) throws EvalException, ConversionException {
// Use a TreeMap to ensure consistent ordering.
- Map<?, ?> dict = new TreeMap<>((Map<?, ?>) self);
+ Map<?, ?> dict = new TreeMap<>(self);
List<Object> list = Lists.newArrayListWithCapacity(dict.size());
for (Map.Entry<?, ?> entries : dict.entrySet()) {
List<?> item = ImmutableList.of(entries.getKey(), entries.getValue());
list.add(env.isSkylarkEnabled() ? SkylarkList.tuple(item) : item);
}
- return convert(list, env, ast.getLocation());
- }
- };
+ return convert(list, env, loc);
+ }
+ };
@SkylarkSignature(name = "keys", objectType = DictModule.class,
returnType = HackHackEitherList.class,
@@ -667,14 +567,12 @@ public class MethodLibrary {
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
- // allowed keys are all Comparable... if not mutually, it's OK to get a runtime exception.
- public Object call(Object self, FuncallExpression ast, Environment env)
- throws EvalException, InterruptedException {
- Map<Comparable<?>, Object> dict = (Map<Comparable<?>, Object>) self;
- return convert(Ordering.natural().sortedCopy(dict.keySet()), env, ast.getLocation());
+ // Skylark will only call this on a dict; and
+ // allowed keys are all Comparable... if not mutually, it's OK to get a runtime exception.
+ private static BuiltinFunction keys = new BuiltinFunction("keys") {
+ public Object invoke(Map<Comparable<?>, ?> dict,
+ Location loc, Environment env) throws EvalException {
+ return convert(Ordering.natural().sortedCopy(dict.keySet()), env, loc);
}
};
@@ -688,19 +586,12 @@ public class MethodLibrary {
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) {
- @Override
- public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
- Map<?, ?> dict = (Map<?, ?>) args[0];
- Object key = args[1];
- if (dict.containsKey(key)) {
- return dict.get(key);
- }
- if (args[2] == null) {
- return Environment.NONE;
+ private static BuiltinFunction get = new BuiltinFunction("get") {
+ public Object invoke(Map<?, ?> self, Object key, Object defaultValue) {
+ if (self.containsKey(key)) {
+ return self.get(key);
}
- return args[2];
+ return defaultValue;
}
};
@@ -716,13 +607,12 @@ public class MethodLibrary {
}
// unary minus
- @SkylarkSignature(name = "-", documented = false, doc = "Unary minus operator.",
+ @SkylarkSignature(name = "-", returnType = Integer.class,
+ 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 {
- int num = Type.INTEGER.convert(args[0], "'unary minus' argument");
+ private static BuiltinFunction minus = new BuiltinFunction("-") {
+ public Integer invoke(Integer num) throws ConversionException {
return -num;
}
};
@@ -734,12 +624,9 @@ public class MethodLibrary {
+ "list({5: \"a\", 2: \"b\", 4: \"c\"}) == [2, 4, 5]</pre>",
mandatoryPositionals = {@Param(name = "x", doc = "The object to convert.")},
useLocation = true)
- private static Function list = new MixedModeFunction("list",
- ImmutableList.of("list"), 1, false) {
- @Override
- public Object call(Object[] args, FuncallExpression ast) throws EvalException {
- Location loc = ast.getLocation();
- return SkylarkList.list(EvalUtils.toCollection(args[0], loc), loc);
+ private static BuiltinFunction list = new BuiltinFunction("list") {
+ public SkylarkList invoke(Object x, Location loc) throws EvalException {
+ return SkylarkList.list(EvalUtils.toCollection(x, loc), loc);
}
};
@@ -747,16 +634,11 @@ public class MethodLibrary {
"Returns the length of a string, list, tuple, set, or dictionary.",
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) {
-
- @Override
- public Object call(Object[] args, FuncallExpression ast) throws EvalException {
- Object arg = args[0];
- int l = EvalUtils.size(arg);
+ private static BuiltinFunction len = new BuiltinFunction("len") {
+ public Integer invoke(Object x, Location loc) throws EvalException {
+ int l = EvalUtils.size(x);
if (l == -1) {
- throw new EvalException(ast.getLocation(),
- EvalUtils.getDataTypeName(arg) + " is not iterable");
+ throw new EvalException(loc, EvalUtils.getDataTypeName(x) + " is not iterable");
}
return l;
}
@@ -765,10 +647,9 @@ public class MethodLibrary {
@SkylarkSignature(name = "str", returnType = String.class, doc =
"Converts any object to string. This is useful for debugging.",
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 {
- return EvalUtils.printValue(args[0]);
+ private static BuiltinFunction str = new BuiltinFunction("str") {
+ public String invoke(Object x) throws EvalException {
+ return EvalUtils.printValue(x);
}
};
@@ -778,11 +659,9 @@ public class MethodLibrary {
+ "empty collection. Otherwise, it returns True. Similarly to Python <code>bool</code> "
+ "is also a type.",
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 {
- return EvalUtils.toBoolean(args[0]);
+ private static BuiltinFunction bool = new BuiltinFunction("bool") {
+ public Boolean invoke(Object x) throws EvalException {
+ return EvalUtils.toBoolean(x);
}
};
@@ -792,20 +671,16 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast)
- throws EvalException, ConversionException {
- String str = Type.STRING.convert(args[0], "'int' operand");
- try {
- return Integer.parseInt(str);
- } catch (NumberFormatException e) {
- throw new EvalException(ast.getLocation(),
- "invalid literal for int(): " + EvalUtils.prettyPrintValue(str));
- }
- }
- };
+ private static BuiltinFunction int_ = new BuiltinFunction("int") {
+ public Integer invoke(String x, Location loc) throws EvalException {
+ try {
+ return Integer.parseInt(x);
+ } catch (NumberFormatException e) {
+ throw new EvalException(loc,
+ "invalid literal for int(): " + EvalUtils.prettyPrintValue(x));
+ }
+ }
+ };
@SkylarkSignature(name = "struct", returnType = SkylarkClassObject.class, doc =
"Creates an immutable struct using the keyword arguments as fields. It is used to group "
@@ -815,14 +690,11 @@ public class MethodLibrary {
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 {
- if (!args.isEmpty()) {
- throw new EvalException(ast.getLocation(), "struct only supports keyword arguments");
- }
- return new SkylarkClassObject(kwargs, ast.getLocation());
+ private static BuiltinFunction struct = new BuiltinFunction("struct") {
+ @SuppressWarnings("unchecked")
+ public SkylarkClassObject invoke(Map<String, Object> kwargs, Location loc)
+ throws EvalException, InterruptedException {
+ return new SkylarkClassObject(kwargs, loc);
}
};
@@ -841,16 +713,10 @@ public class MethodLibrary {
+ "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
- public Object call(Object[] args, FuncallExpression ast) throws EvalException,
- ConversionException {
- Order order = SkylarkNestedSet.parseOrder((String) args[1], ast.getLocation());
- if (args[0] == null) {
- return new SkylarkNestedSet(order, SkylarkList.EMPTY_LIST, ast.getLocation());
- }
- return new SkylarkNestedSet(order, args[0], ast.getLocation());
+ private static final BuiltinFunction set = new BuiltinFunction("set") {
+ public SkylarkNestedSet invoke(Object items, String order,
+ Location loc) throws EvalException, ConversionException {
+ return new SkylarkNestedSet(SkylarkNestedSet.parseOrder(order, loc), items, loc);
}
};
@@ -860,21 +726,16 @@ public class MethodLibrary {
+ "enumerate([24, 21, 84]) == [[0, 24], [1, 21], [2, 84]]</pre>\n",
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
- public Object call(Object[] args, FuncallExpression ast) throws EvalException,
- ConversionException {
- // Note that enumerate is only available in Skylark.
- SkylarkList input = cast(
- args[0], SkylarkList.class, "enumerate operand", ast.getLocation());
- List<SkylarkList> result = Lists.newArrayList();
+ private static BuiltinFunction enumerate = new BuiltinFunction("enumerate") {
+ public SkylarkList invoke(SkylarkList input, Location loc)
+ throws EvalException, ConversionException, InterruptedException {
int count = 0;
+ List<SkylarkList> result = Lists.newArrayList();
for (Object obj : input) {
- result.add(SkylarkList.tuple(Lists.newArrayList(count, obj)));
+ result.add(SkylarkList.tuple(count, obj));
count++;
}
- return SkylarkList.list(result, ast.getLocation());
+ return SkylarkList.list(result, loc);
}
};
@@ -886,34 +747,31 @@ public class MethodLibrary {
+ "range(3, 9, 2) == [3, 5, 7]\n"
+ "range(3, 0, -1) == [3, 2, 1]</pre>",
mandatoryPositionals = {
- @Param(name = "start", type = Integer.class,
- doc = "Value of the first element if stop is provided, "
+ @Param(name = "start_or_stop", type = Integer.class,
+ doc = "Value of the start element if stop is provided, "
+ "otherwise value of stop and the actual start is 0"),
},
optionalPositionals = {
- @Param(name = "stop", type = Integer.class, noneable = true, defaultValue = "None",
+ @Param(name = "stop_or_none", type = Integer.class, noneable = true, defaultValue = "None",
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, defaultValue = "1",
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
- public Object call(Object[] args, FuncallExpression ast) throws EvalException,
- ConversionException {
+ private static final BuiltinFunction range = new BuiltinFunction("range") {
+ public SkylarkList invoke(Integer startOrStop, Object stopOrNone, Integer step, Location loc)
+ throws EvalException, ConversionException, InterruptedException {
int start;
int stop;
- if (args[1] == null) {
+ if (stopOrNone == Environment.NONE) {
start = 0;
- stop = Type.INTEGER.convert(args[0], "stop");
+ stop = startOrStop;
} else {
- start = Type.INTEGER.convert(args[0], "start");
- stop = Type.INTEGER.convert(args[1], "stop");
+ start = startOrStop;
+ stop = Type.INTEGER.convert(stopOrNone, "'stop' operand of 'range'");
}
- int step = args[2] == null ? 1 : Type.INTEGER.convert(args[2], "step");
if (step == 0) {
- throw new EvalException(ast.getLocation(), "step cannot be 0");
+ throw new EvalException(loc, "step cannot be 0");
}
List<Integer> result = Lists.newArrayList();
if (step > 0) {
@@ -939,19 +797,11 @@ public class MethodLibrary {
doc = "Creates a SelectorValue from the dict parameter.",
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
- public Object call(Object[] args, FuncallExpression ast)
- throws EvalException, ConversionException {
- Object dict = args[0];
- if (!(dict instanceof Map<?, ?>)) {
- throw new EvalException(ast.getLocation(),
- "select({...}) argument isn't a dictionary");
- }
- return SelectorList.of(new SelectorValue((Map<?, ?>) dict));
- }
- };
+ private static final BuiltinFunction select = new BuiltinFunction("select") {
+ public Object invoke(Map<?, ?> dict) throws EvalException, InterruptedException {
+ return SelectorList.of(new SelectorValue(dict));
+ }
+ };
/**
* Returns true if the object has a field of the given name, otherwise false.
@@ -964,18 +814,12 @@ public class MethodLibrary {
@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 {
- Object obj = args[0];
- String name = cast(args[1], String.class, "name", ast.getLocation());
-
+ private static final BuiltinFunction hasattr = new BuiltinFunction("hasattr") {
+ public Boolean invoke(Object obj, String name,
+ Location loc, Environment env) throws EvalException, ConversionException {
if (obj instanceof ClassObject && ((ClassObject) obj).getValue(name) != null) {
return true;
}
-
if (env.getFunctionNames(obj.getClass()).contains(name)) {
return true;
}
@@ -984,7 +828,7 @@ public class MethodLibrary {
return FuncallExpression.getMethodNames(obj.getClass()).contains(name);
} catch (ExecutionException e) {
// This shouldn't happen
- throw new EvalException(ast.getLocation(), e.getMessage());
+ throw new EvalException(loc, e.getMessage());
}
}
};
@@ -1004,20 +848,15 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast, Environment env)
- throws EvalException {
- Object obj = args[0];
- String name = cast(args[1], String.class, "name", ast.getLocation());
- Object result = DotExpression.eval(obj, name, ast.getLocation());
+ private static final BuiltinFunction getattr = new BuiltinFunction("getattr") {
+ public Object invoke(Object obj, String name, Object defaultValue,
+ Location loc) throws EvalException, ConversionException {
+ Object result = DotExpression.eval(obj, name, loc);
if (result == null) {
- if (args[2] != null) {
- return args[2];
+ if (defaultValue != Environment.NONE) {
+ return defaultValue;
} else {
- throw new EvalException(ast.getLocation(),
- String.format("Object of type '%s' has no field %s",
+ throw new EvalException(loc, String.format("Object of type '%s' has no field %s",
EvalUtils.getDataTypeName(obj), EvalUtils.prettyPrintValue(name)));
}
}
@@ -1030,23 +869,20 @@ public class MethodLibrary {
+ "methods of the parameter object.",
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
- public Object call(Object[] args, FuncallExpression ast, Environment env)
- throws EvalException {
- Object obj = args[0];
+ private static final BuiltinFunction dir = new BuiltinFunction("dir") {
+ public SkylarkList invoke(Object object,
+ Location loc, Environment env) throws EvalException, ConversionException {
// Order the fields alphabetically.
Set<String> fields = new TreeSet<>();
- if (obj instanceof ClassObject) {
- fields.addAll(((ClassObject) obj).getKeys());
+ if (object instanceof ClassObject) {
+ fields.addAll(((ClassObject) object).getKeys());
}
- fields.addAll(env.getFunctionNames(obj.getClass()));
+ fields.addAll(env.getFunctionNames(object.getClass()));
try {
- fields.addAll(FuncallExpression.getMethodNames(obj.getClass()));
+ fields.addAll(FuncallExpression.getMethodNames(object.getClass()));
} catch (ExecutionException e) {
// This shouldn't happen
- throw new EvalException(ast.getLocation(), e.getMessage());
+ throw new EvalException(loc, e.getMessage());
}
return SkylarkList.list(fields, String.class);
}
@@ -1055,12 +891,10 @@ public class MethodLibrary {
@SkylarkSignature(name = "type", returnType = String.class,
doc = "Returns the type name of its argument.",
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
- public Object call(Object[] args, FuncallExpression ast) throws EvalException {
+ private static final BuiltinFunction type = new BuiltinFunction("type") {
+ public String invoke(Object object) {
// There is no 'type' type in Skylark, so we return a string with the type name.
- return EvalUtils.getDataTypeName(args[0], false);
+ return EvalUtils.getDataTypeName(object, false);
}
};
@@ -1074,17 +908,13 @@ public class MethodLibrary {
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
- public Object call(Object[] args, FuncallExpression ast, Environment env)
- throws EvalException {
- String msg = cast(args[0], String.class, "msg", ast.getLocation());
- if (args[1] != null) {
- msg = "attribute " + cast(args[1], String.class, "attr", ast.getLocation())
- + ": " + msg;
+ private static final BuiltinFunction fail = new BuiltinFunction("fail") {
+ public Environment.NoneType invoke(String msg, Object attr,
+ Location loc) throws EvalException, ConversionException {
+ if (attr != Environment.NONE) {
+ msg = String.format("attribute %s: %s", attr, msg);
}
- throw new EvalException(ast.getLocation(), msg);
+ throw new EvalException(loc, msg);
}
};
@@ -1096,30 +926,16 @@ public class MethodLibrary {
// 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,
- Environment env) throws EvalException, InterruptedException {
- String sep = " ";
- int count = 0;
- if (kwargs.containsKey("sep")) {
- sep = cast(kwargs.get("sep"), String.class, "sep", ast.getLocation());
- count = 1;
- }
- if (kwargs.size() > count) {
- kwargs = new HashMap<>(kwargs);
- kwargs.remove("sep");
- List<String> bad = Ordering.natural().sortedCopy(kwargs.keySet());
- throw new EvalException(ast.getLocation(), "unexpected keywords: '" + bad + "'");
- }
- String msg = Joiner.on(sep).join(Iterables.transform(args,
- new com.google.common.base.Function<Object, String>() {
- @Override
- public String apply(Object input) {
- return EvalUtils.printValue(input);
- }
- }));
- ((SkylarkEnvironment) env).handleEvent(Event.warn(ast.getLocation(), msg));
+ private static final BuiltinFunction print = new BuiltinFunction("print") {
+ public Environment.NoneType invoke(String sep, SkylarkList starargs,
+ Location loc, SkylarkEnvironment env) throws EvalException {
+ String msg = Joiner.on(sep).join(Iterables.transform(starargs,
+ new com.google.common.base.Function<Object, String>() {
+ @Override
+ public String apply(Object input) {
+ return EvalUtils.printValue(input);
+ }}));
+ env.handleEvent(Event.warn(loc, msg));
return Environment.NONE;
}
};
@@ -1136,13 +952,12 @@ public class MethodLibrary {
+ "zip([1, 2], [3, 4, 5]) # == [(1, 3), (2, 4)]</pre>",
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,
- Environment env) throws EvalException, InterruptedException {
+ private static final BuiltinFunction zip = new BuiltinFunction("zip") {
+ public SkylarkList invoke(SkylarkList args, Location loc)
+ throws EvalException, InterruptedException {
Iterator<?>[] iterators = new Iterator<?>[args.size()];
for (int i = 0; i < args.size(); i++) {
- iterators[i] = EvalUtils.toIterable(args.get(i), ast.getLocation()).iterator();
+ iterators[i] = EvalUtils.toIterable(args.get(i), loc).iterator();
}
List<SkylarkList> result = new ArrayList<SkylarkList>();
boolean allHasNext;
@@ -1160,7 +975,7 @@ public class MethodLibrary {
result.add(SkylarkList.tuple(elem));
}
} while (allHasNext);
- return SkylarkList.list(result, ast.getLocation());
+ return SkylarkList.list(result, loc);
}
};
@@ -1209,18 +1024,21 @@ public class MethodLibrary {
+ "</pre>")
public static final class DictModule {}
- public static final List<Function> stringFunctions = ImmutableList.of(
+ public static final List<Function> stringFunctions = ImmutableList.<Function>of(
count, endswith, find, index, join, lower, replace, rfind,
rindex, slice, split, startswith, strip, upper);
- public static final List<Function> listPureFunctions = ImmutableList.of(slice);
+ public static final List<Function> listPureFunctions = ImmutableList.<Function>of(
+ slice);
- public static final List<Function> listFunctions = ImmutableList.of(append, extend);
+ public static final List<Function> listFunctions = ImmutableList.<Function>of(
+ append, extend);
- public static final List<Function> dictFunctions = ImmutableList.of(items, get, keys, values);
+ public static final List<Function> dictFunctions = ImmutableList.<Function>of(
+ items, get, keys, values);
- private static final List<Function> pureGlobalFunctions =
- ImmutableList.of(bool, int_, len, minus, select, sorted, str);
+ private static final List<Function> pureGlobalFunctions = ImmutableList.<Function>of(
+ bool, int_, len, minus, select, sorted, str);
private static final List<Function> skylarkGlobalFunctions = ImmutableList
.<Function>builder()
@@ -1273,4 +1091,8 @@ public class MethodLibrary {
builtIn.add(function.getName());
}
}
+
+ static {
+ SkylarkSignatureProcessor.configureSkylarkFunctions(MethodLibrary.class);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
index ac669e64de..b4d4a6df17 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
@@ -30,21 +30,27 @@ import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.packages.GlobCache.BadGlobException;
import com.google.devtools.build.lib.packages.License.DistributionType;
import com.google.devtools.build.lib.packages.Type.ConversionException;
-import com.google.devtools.build.lib.syntax.AbstractFunction;
import com.google.devtools.build.lib.syntax.AssignmentStatement;
+import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.BuildFileAST;
+import com.google.devtools.build.lib.syntax.BuiltinFunction;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.Environment.NoSuchVariableException;
import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.Expression;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.Function;
+import com.google.devtools.build.lib.syntax.FunctionSignature;
import com.google.devtools.build.lib.syntax.GlobList;
import com.google.devtools.build.lib.syntax.Ident;
import com.google.devtools.build.lib.syntax.Label;
-import com.google.devtools.build.lib.syntax.MixedModeFunction;
import com.google.devtools.build.lib.syntax.ParserInputSource;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
+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;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEitherList;
import com.google.devtools.build.lib.syntax.Statement;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.Path;
@@ -52,7 +58,6 @@ import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.UnixGlob;
import java.io.IOException;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -149,8 +154,6 @@ public final class PackageFactory {
Iterable<PackageArgument<?>> getPackageArguments();
}
- private static final int EXCLUDE_DIR_DEFAULT = 1;
-
private static class DefaultVisibility extends PackageArgument<List<Label>> {
private DefaultVisibility() {
super("default_visibility", Type.LABEL_LIST);
@@ -452,21 +455,38 @@ public final class PackageFactory {
* @param async if true, start globs in the background but don't block on their completion.
* Only use this for heuristic preloading.
*/
- private static Function newGlobFunction(
- final PackageContext originalContext, final boolean async) {
- List<String> params = ImmutableList.of("include", "exclude", "exclude_directories");
- return new MixedModeFunction("glob", params, 1, false) {
- @Override
- public Object call(Object[] namedArguments, FuncallExpression ast, Environment env)
+ @SkylarkSignature(name = "glob", objectType = Object.class, returnType = GlobList.class,
+ doc = "Returns a list of files that match glob search pattern",
+ mandatoryPositionals = {
+ @Param(name = "include", type = HackHackEitherList.class, generic1 = String.class,
+ doc = "a list of strings specifying patterns of files to include.")},
+ optionalPositionals = {
+ @Param(name = "exclude", type = HackHackEitherList.class, generic1 = String.class,
+ defaultValue = "[]",
+ doc = "a list of strings specifying patterns of files to exclude."),
+ // TODO(bazel-team): migrate all existing code to use boolean instead?
+ @Param(name = "exclude_directories", type = Integer.class, defaultValue = "1",
+ doc = "a integer that if non-zero indicates directories should not be matched.")},
+ documented = false, useAst = true, useEnvironment = true)
+ private static final BuiltinFunction.Factory newGlobFunction =
+ new BuiltinFunction.Factory("glob") {
+ public BuiltinFunction create(final PackageContext originalContext, final boolean async) {
+ return new BuiltinFunction("glob", this) {
+ public GlobList<String> invoke(
+ Object include, Object exclude, Integer excludeDirectories,
+ FuncallExpression ast, Environment env)
throws EvalException, ConversionException, InterruptedException {
- return callGlob(originalContext, async, ast, env, namedArguments);
+ return callGlob(
+ originalContext, async, include, exclude, excludeDirectories != 0, ast, env);
+ }
+ };
}
};
- }
- static GlobList<String> callGlob(@Nullable PackageContext originalContext, boolean async,
- FuncallExpression ast, Environment env, Object[] namedArguments)
- throws EvalException, ConversionException, InterruptedException {
+ protected static GlobList<String> callGlob(@Nullable PackageContext originalContext,
+ boolean async, Object include, Object exclude, boolean excludeDirs,
+ FuncallExpression ast, Environment env)
+ throws EvalException, ConversionException, InterruptedException {
// Skylark build extensions need to get the PackageContext from the Environment;
// async glob functions cannot do the same because the Environment is not thread safe.
PackageContext context;
@@ -477,23 +497,18 @@ public final class PackageFactory {
context = originalContext;
}
- List<String> includes = Type.STRING_LIST.convert(namedArguments[0], "'glob' argument");
- List<String> excludes = namedArguments[1] == null
- ? Collections.<String>emptyList()
- : Type.STRING_LIST.convert(namedArguments[1], "'glob' argument");
- int excludeDirs = namedArguments[2] == null
- ? EXCLUDE_DIR_DEFAULT
- : Type.INTEGER.convert(namedArguments[2], "'glob' argument");
+ List<String> includes = Type.STRING_LIST.convert(include, "'glob' argument");
+ List<String> excludes = Type.STRING_LIST.convert(exclude, "'glob' argument");
if (async) {
try {
- context.globber.runAsync(includes, excludes, excludeDirs != 0);
+ context.globber.runAsync(includes, excludes, excludeDirs);
} catch (GlobCache.BadGlobException e) {
// Ignore: errors will appear during the actual evaluation of the package.
}
return GlobList.captureResults(includes, excludes, ImmutableList.<String>of());
} else {
- return handleGlob(includes, excludes, excludeDirs != 0, context, ast);
+ return handleGlob(includes, excludes, excludeDirs, context, ast);
}
}
@@ -531,44 +546,57 @@ public final class PackageFactory {
* seen by the parser, because the presence of "subinclude" triggers
* preprocessing.)
*/
- private static Function newMockSubincludeFunction(final PackageContext context) {
- return new MixedModeFunction("mocksubinclude", ImmutableList.of("label", "path"), 2, false) {
- @Override
- public Object call(Object[] args, FuncallExpression ast)
- throws ConversionException {
- Label label = Type.LABEL.convert(args[0], "'mocksubinclude' argument",
- context.pkgBuilder.getBuildFileLabel());
- String pathString = Type.STRING.convert(args[1], "'mocksubinclude' argument");
- Path path = pathString.isEmpty()
- ? null
- : context.pkgBuilder.getFilename().getRelative(pathString);
- // A subinclude within a package counts as a file declaration.
- if (label.getPackageIdentifier().equals(context.pkgBuilder.getPackageIdentifier())) {
- Location location = ast.getLocation();
- if (location == null) {
- location = Location.fromFile(context.pkgBuilder.getFilename());
+ @SkylarkSignature(name = "mocksubinclude", returnType = Environment.NoneType.class,
+ doc = "implement the mocksubinclude function emitted by the PythonPreprocessor",
+ mandatoryPositionals = {
+ @Param(name = "label", type = Object.class,
+ doc = "a label designator."),
+ @Param(name = "path", type = String.class,
+ doc = "a path.")},
+ documented = false, useLocation = true)
+ protected static final BuiltinFunction.Factory newMockSubincludeFunction =
+ new BuiltinFunction.Factory("mocksubinclude") {
+ public BuiltinFunction create(final PackageContext context) {
+ return new BuiltinFunction("mocksubinclude", this) {
+ public Environment.NoneType invoke(Object labelO, String pathString,
+ Location loc) throws ConversionException {
+ Label label = Type.LABEL.convert(labelO, "'mocksubinclude' argument",
+ context.pkgBuilder.getBuildFileLabel());
+ Path path = pathString.isEmpty()
+ ? null : context.pkgBuilder.getFilename().getRelative(pathString);
+ // A subinclude within a package counts as a file declaration.
+ if (label.getPackageIdentifier().equals(context.pkgBuilder.getPackageIdentifier())) {
+ if (loc == null) {
+ loc = Location.fromFile(context.pkgBuilder.getFilename());
+ }
+ context.pkgBuilder.createInputFileMaybe(label, loc);
+ }
+
+ context.pkgBuilder.addSubinclude(label, path);
+ return Environment.NONE;
}
- context.pkgBuilder.createInputFileMaybe(label, location);
- }
-
- context.pkgBuilder.addSubinclude(label, path);
- return Environment.NONE;
+ };
}
};
- }
/**
* Fake function: subinclude calls are ignored
* They will disappear after the Python preprocessing.
*/
- private static Function newSubincludeFunction() {
- return new MixedModeFunction("subinclude", ImmutableList.of("file"), 1, false) {
- @Override
- public Object call(Object[] args, FuncallExpression ast) {
- return Environment.NONE;
+ @SkylarkSignature(name = "subinclude", returnType = Environment.NoneType.class,
+ mandatoryPositionals = {@Param(name = "file", doc = "(ignored)")},
+ doc = "fake function to skip over subinclude statements",
+ documented = false)
+ private static BuiltinFunction.Factory newSubincludeFunction =
+ new BuiltinFunction.Factory("subinclude") {
+ public BuiltinFunction create() {
+ return new BuiltinFunction("subinclude", this) {
+ public Environment.NoneType invoke(Object file) {
+ return Environment.NONE;
+ }
+ };
}
};
- }
/**
* Returns a function value implementing "environment_group" in the specified package context.
@@ -585,64 +613,90 @@ public final class PackageFactory {
* <p>Where ":env1", "env2", ... are all environment rules declared in the same package. All
* parameters are mandatory.
*/
- private static Function newEnvironmentGroupFunction(final PackageContext context) {
- List<String> params = ImmutableList.of("name", "environments", "defaults");
- return new MixedModeFunction("environment_group", params, params.size(), true) {
- @Override
- public Object call(Object[] namedArgs, FuncallExpression ast)
- throws EvalException, ConversionException {
- Preconditions.checkState(namedArgs[0] != null);
- String name = Type.STRING.convert(namedArgs[0], "'environment_group' argument");
- Preconditions.checkState(namedArgs[1] != null);
- List<Label> environments = Type.LABEL_LIST.convert(
- namedArgs[1], "'environment_group argument'", context.pkgBuilder.getBuildFileLabel());
- Preconditions.checkState(namedArgs[2] != null);
- List<Label> defaults = Type.LABEL_LIST.convert(
- namedArgs[2], "'environment_group argument'", context.pkgBuilder.getBuildFileLabel());
-
- try {
- context.pkgBuilder.addEnvironmentGroup(name, environments, defaults,
- context.eventHandler, ast.getLocation());
- return Environment.NONE;
- } catch (Label.SyntaxException e) {
- throw new EvalException(ast.getLocation(),
- "environment group has invalid name: " + name + ": " + e.getMessage());
- } catch (Package.NameConflictException e) {
- throw new EvalException(ast.getLocation(), e.getMessage());
- }
+ @SkylarkSignature(name = "environment_group", returnType = Environment.NoneType.class,
+ doc = "Defines a cc_library, by wrapping around the usual library "
+ + "and also defining a headers target.",
+ mandatoryNamedOnly = {
+ @Param(name = "name", type = String.class,
+ doc = "The name of the rule."),
+ // Both parameter below are lists of label designators
+ @Param(name = "environments", type = HackHackEitherList.class, generic1 = Object.class,
+ doc = "A list of Labels for the environments to be grouped, from the same package."),
+ @Param(name = "defaults", type = HackHackEitherList.class, generic1 = Object.class,
+ doc = "A list of Labels.")}, // TODO(bazel-team): document what that is
+ documented = false, useLocation = true)
+ protected static final BuiltinFunction.Factory newEnvironmentGroupFunction =
+ new BuiltinFunction.Factory("environment_group") {
+ public BuiltinFunction create(final PackageContext context) {
+ return new BuiltinFunction("environment_group", this) {
+ public Environment.NoneType invoke(String name, Object environmentsO, Object defaultsO,
+ Location loc) throws EvalException, ConversionException {
+ List<Label> environments = Type.LABEL_LIST.convert(environmentsO,
+ "'environment_group argument'", context.pkgBuilder.getBuildFileLabel());
+ List<Label> defaults = Type.LABEL_LIST.convert(defaultsO,
+ "'environment_group argument'", context.pkgBuilder.getBuildFileLabel());
+
+ try {
+ context.pkgBuilder.addEnvironmentGroup(name, environments, defaults,
+ context.eventHandler, loc);
+ return Environment.NONE;
+ } catch (Label.SyntaxException e) {
+ throw new EvalException(loc,
+ "environment group has invalid name: " + name + ": " + e.getMessage());
+ } catch (Package.NameConflictException e) {
+ throw new EvalException(loc, e.getMessage());
+ }
+ }
+ };
}
};
- }
/**
* Returns a function-value implementing "exports_files" in the specified
* package context.
*/
- private static Function newExportsFilesFunction() {
- List<String> params = ImmutableList.of("srcs", "visibility", "licenses");
- return new MixedModeFunction("exports_files", params, 1, false) {
- @Override
- public Object call(Object[] namedArgs, FuncallExpression ast, Environment env)
- throws EvalException, ConversionException {
- return callExportsFiles(ast, env, namedArgs);
- }
- };
- }
+ @SkylarkSignature(name = "exports_files", returnType = Environment.NoneType.class,
+ doc = "Declare a set of files as exported",
+ mandatoryPositionals = {
+ @Param(name = "srcs", type = HackHackEitherList.class, generic1 = String.class,
+ doc = "A list of strings, the names of the files to export.")},
+ optionalPositionals = {
+ // TODO(blaze-team): make it possible to express a list of label designators,
+ // i.e. a java List or Skylark list of Label or String.
+ @Param(name = "visibility", type = HackHackEitherList.class, noneable = true,
+ defaultValue = "None",
+ doc = "A list of Labels specifying the visibility of the exported files "
+ + "(defaults to public)"),
+ @Param(name = "licenses", type = HackHackEitherList.class, generic1 = String.class,
+ noneable = true, defaultValue = "None",
+ doc = "A list of strings specifying the licenses used in the exported code.")},
+ documented = false, useAst = true, useEnvironment = true)
+ protected static final BuiltinFunction.Factory newExportsFilesFunction =
+ new BuiltinFunction.Factory("exports_files") {
+ public BuiltinFunction create () {
+ return new BuiltinFunction("exports_files", this) {
+ public Environment.NoneType invoke(Object srcs, Object visibility, Object licenses,
+ FuncallExpression ast, Environment env)
+ throws EvalException, ConversionException {
+ return callExportsFiles(srcs, visibility, licenses, ast, env);
+ }
+ };
+ }
+ };
- static Object callExportsFiles(FuncallExpression ast, Environment env, Object[] namedArgs)
- throws EvalException, ConversionException {
+ static Environment.NoneType callExportsFiles(Object srcs, Object visibilityO, Object licensesO,
+ FuncallExpression ast, Environment env) throws EvalException, ConversionException {
Package.LegacyBuilder pkgBuilder = getContext(env, ast).pkgBuilder;
- List<String> files = Type.STRING_LIST.convert(namedArgs[0], "'exports_files' operand");
+ List<String> files = Type.STRING_LIST.convert(srcs, "'exports_files' operand");
- RuleVisibility visibility = namedArgs[1] == null
+ RuleVisibility visibility = EvalUtils.isNullOrNone(visibilityO)
? ConstantRuleVisibility.PUBLIC
: getVisibility(Type.LABEL_LIST.convert(
- namedArgs[1],
- "'exports_files' operand",
- pkgBuilder.getBuildFileLabel()));
- License license = namedArgs[2] == null
- ? null
- : Type.LICENSE.convert(namedArgs[2], "'exports_files' operand");
+ visibilityO,
+ "'exports_files' operand",
+ pkgBuilder.getBuildFileLabel()));
+ // TODO(bazel-team): is licenses plural or singular?
+ License license = Type.LICENSE.convertOptional(licensesO, "'exports_files' operand");
for (String file : files) {
String errorMessage = LabelValidator.validateTargetName(file);
@@ -683,67 +737,94 @@ public final class PackageFactory {
* context.
* TODO(bazel-team): Remove in favor of package.licenses.
*/
- private static Function newLicensesFunction(final PackageContext context) {
- return new MixedModeFunction("licenses", ImmutableList.of("object"), 1, false) {
- @Override
- public Object call(Object[] args, FuncallExpression ast) {
- try {
- License license = Type.LICENSE.convert(args[0], "'licenses' operand");
- context.pkgBuilder.setDefaultLicense(license);
- } catch (ConversionException e) {
- context.eventHandler.handle(Event.error(ast.getLocation(), e.getMessage()));
- context.pkgBuilder.setContainsErrors();
- }
- return Environment.NONE;
+ @SkylarkSignature(name = "licenses", returnType = Environment.NoneType.class,
+ doc = "Declare the license(s) for the code in the current package.",
+ mandatoryPositionals = {
+ @Param(name = "license_strings", type = HackHackEitherList.class, generic1 = String.class,
+ doc = "A list of strings, the names of the licenses used.")},
+ documented = false, useLocation = true)
+ protected static final BuiltinFunction.Factory newLicensesFunction =
+ new BuiltinFunction.Factory("licenses") {
+ public BuiltinFunction create(final PackageContext context) {
+ return new BuiltinFunction("licenses", this) {
+ public Environment.NoneType invoke(Object licensesO, Location loc) {
+ try {
+ License license = Type.LICENSE.convert(licensesO, "'licenses' operand");
+ context.pkgBuilder.setDefaultLicense(license);
+ } catch (ConversionException e) {
+ context.eventHandler.handle(Event.error(loc, e.getMessage()));
+ context.pkgBuilder.setContainsErrors();
+ }
+ return Environment.NONE;
+ }
+ };
}
};
- }
/**
* Returns a function-value implementing "distribs" in the specified package
* context.
* TODO(bazel-team): Remove in favor of package.distribs.
*/
- private static Function newDistribsFunction(final PackageContext context) {
- return new MixedModeFunction("distribs", ImmutableList.of("object"), 1, false) {
- @Override
- public Object call(Object[] args, FuncallExpression ast) {
- try {
- Set<DistributionType> distribs = Type.DISTRIBUTIONS.convert(args[0],
- "'distribs' operand");
- context.pkgBuilder.setDefaultDistribs(distribs);
- } catch (ConversionException e) {
- context.eventHandler.handle(Event.error(ast.getLocation(), e.getMessage()));
- context.pkgBuilder.setContainsErrors();
- }
- return Environment.NONE;
+ @SkylarkSignature(name = "distribs", returnType = Environment.NoneType.class,
+ doc = "Declare the distribution(s) for the code in the current package.",
+ mandatoryPositionals = {
+ @Param(name = "distribution_strings", type = Object.class,
+ doc = "The distributions.")},
+ documented = false, useLocation = true)
+ protected static final BuiltinFunction.Factory newDistribsFunction =
+ new BuiltinFunction.Factory("distribs") {
+ public BuiltinFunction create(final PackageContext context) {
+ return new BuiltinFunction("distribs", this) {
+ public Environment.NoneType invoke(Object object, Location loc) {
+ try {
+ Set<DistributionType> distribs = Type.DISTRIBUTIONS.convert(object,
+ "'distribs' operand");
+ context.pkgBuilder.setDefaultDistribs(distribs);
+ } catch (ConversionException e) {
+ context.eventHandler.handle(Event.error(loc, e.getMessage()));
+ context.pkgBuilder.setContainsErrors();
+ }
+ return Environment.NONE;
+ }
+ };
}
};
- }
- private static Function newPackageGroupFunction() {
- List<String> params = ImmutableList.of("name", "packages", "includes");
- return new MixedModeFunction("package_group", params, 1, true) {
- @Override
- public Object call(Object[] namedArgs, FuncallExpression ast, Environment env)
- throws EvalException, ConversionException {
- return callPackageFunction(ast, env, namedArgs);
+ @SkylarkSignature(name = "package_group", returnType = Environment.NoneType.class,
+ doc = "Declare a set of files as exported",
+ mandatoryNamedOnly = {
+ @Param(name = "name", type = String.class,
+ doc = "The name of the rule.")},
+ optionalNamedOnly = {
+ @Param(name = "packages", type = HackHackEitherList.class, generic1 = String.class,
+ defaultValue = "[]",
+ doc = "A list of Strings specifying the packages grouped."),
+ // java list or list of label designators: Label or String
+ @Param(name = "includes", type = HackHackEitherList.class, generic1 = Object.class,
+ defaultValue = "[]",
+ doc = "A list of Label specifiers for the files to include.")},
+ documented = false, useAst = true, useEnvironment = true)
+ protected static final BuiltinFunction.Factory newPackageGroupFunction =
+ new BuiltinFunction.Factory("package_group") {
+ public BuiltinFunction create() {
+ return new BuiltinFunction("package_group", this) {
+ public Environment.NoneType invoke(String name, Object packages, Object includes,
+ FuncallExpression ast, Environment env) throws EvalException, ConversionException {
+ return callPackageFunction(name, packages, includes, ast, env);
+ }
+ };
}
};
- }
- static Object callPackageFunction(FuncallExpression ast, Environment env, Object[] namedArgs)
- throws EvalException, ConversionException {
+ static Environment.NoneType callPackageFunction(String name, Object packagesO, Object includesO,
+ FuncallExpression ast, Environment env) throws EvalException, ConversionException {
PackageContext context = getContext(env, ast);
- Preconditions.checkState(namedArgs[0] != null);
- String name = Type.STRING.convert(namedArgs[0], "'package_group' argument");
- List<String> packages = namedArgs[1] == null
- ? Collections.<String>emptyList()
- : Type.STRING_LIST.convert(namedArgs[1], "'package_group' argument");
- List<Label> includes = namedArgs[2] == null
- ? Collections.<Label>emptyList()
- : Type.LABEL_LIST.convert(namedArgs[2], "'package_group argument'",
- context.pkgBuilder.getBuildFileLabel());
+
+ List<String> packages = Type.STRING_LIST.convert(
+ packagesO, "'package_group.packages argument'");
+ List<Label> includes = Type.LABEL_LIST.convert(includesO,
+ "'package_group.includes argument'", context.pkgBuilder.getBuildFileLabel());
try {
context.pkgBuilder.addPackageGroup(name, packages, includes, context.eventHandler,
@@ -774,10 +855,23 @@ public final class PackageFactory {
* context.
*/
private static Function newPackageFunction(
- final Map<String, PackageArgument<?>> packageArguments) {
- return new MixedModeFunction("package", packageArguments.keySet(), 0, true) {
+ final ImmutableMap<String, PackageArgument<?>> packageArguments) {
+ // Flatten the map of argument name of PackageArgument specifier in two co-indexed arrays:
+ // one for the argument names, to create a FunctionSignature when we create the function,
+ // one of the PackageArgument specifiers, over which to iterate at every function invocation
+ // at the same time that we iterate over the function arguments.
+ final int numArgs = packageArguments.size();
+ final String[] argumentNames = new String[numArgs];
+ final PackageArgument<?>[] argumentSpecifiers = new PackageArgument<?>[numArgs];
+ int i = 0;
+ for (Map.Entry<String, PackageArgument<?>> entry : packageArguments.entrySet()) {
+ argumentNames[i] = entry.getKey();
+ argumentSpecifiers[i++] = entry.getValue();
+ }
+
+ return new BaseFunction("package", FunctionSignature.namedOnly(0, argumentNames)) {
@Override
- public Object call(Object[] namedArguments, FuncallExpression ast, Environment env)
+ public Object call(Object[] arguments, FuncallExpression ast, Environment env)
throws EvalException, ConversionException {
Package.LegacyBuilder pkgBuilder = getContext(env, ast).pkgBuilder;
@@ -792,16 +886,12 @@ public final class PackageFactory {
// Parse params
boolean foundParameter = false;
- int argNumber = 0;
- for (Map.Entry<String, PackageArgument<?>> entry : packageArguments.entrySet()) {
- Object arg = namedArguments[argNumber];
- argNumber += 1;
- if (arg == null) {
- continue;
+ for (int i = 0; i < numArgs; i++) {
+ Object value = arguments[i];
+ if (value != null) {
+ foundParameter = true;
+ argumentSpecifiers[i].convertAndProcess(pkgBuilder, ast.getLocation(), value);
}
-
- foundParameter = true;
- entry.getValue().convertAndProcess(pkgBuilder, ast.getLocation(), arg);
}
if (!foundParameter) {
@@ -852,18 +942,13 @@ public final class PackageFactory {
* Returns a function-value implementing the build rule "ruleClass" (e.g. cc_library) in the
* specified package context.
*/
- private static Function newRuleFunction(final RuleFactory ruleFactory,
- final String ruleClass) {
- return new AbstractFunction(ruleClass) {
- @Override
- public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
- Environment env)
+ private static BuiltinFunction newRuleFunction(
+ final RuleFactory ruleFactory, final String ruleClass) {
+ return new BuiltinFunction(ruleClass, FunctionSignature.KWARGS, BuiltinFunction.USE_AST_ENV) {
+ @SuppressWarnings("unchecked")
+ public Environment.NoneType invoke(Map<String, Object> kwargs,
+ FuncallExpression ast, Environment env)
throws EvalException {
- if (!args.isEmpty()) {
- throw new EvalException(ast.getLocation(),
- "build rules do not accept positional parameters");
- }
-
try {
addRule(ruleFactory, ruleClass, getContext(env, ast), kwargs, ast);
} catch (RuleFactory.InvalidRuleException | Package.NameConflictException e) {
@@ -1117,15 +1202,15 @@ public final class PackageFactory {
private void buildPkgEnv(Environment pkgEnv, String packageName,
PackageContext context, RuleFactory ruleFactory) {
- pkgEnv.update("distribs", newDistribsFunction(context));
- pkgEnv.update("glob", newGlobFunction(context, /*async=*/false));
- pkgEnv.update("mocksubinclude", newMockSubincludeFunction(context));
- pkgEnv.update("licenses", newLicensesFunction(context));
- pkgEnv.update("exports_files", newExportsFilesFunction());
- pkgEnv.update("package_group", newPackageGroupFunction());
+ pkgEnv.update("distribs", newDistribsFunction.apply(context));
+ pkgEnv.update("glob", newGlobFunction.apply(context, /*async=*/false));
+ pkgEnv.update("mocksubinclude", newMockSubincludeFunction.apply(context));
+ pkgEnv.update("licenses", newLicensesFunction.apply(context));
+ pkgEnv.update("exports_files", newExportsFilesFunction.apply());
+ pkgEnv.update("package_group", newPackageGroupFunction.apply());
pkgEnv.update("package", newPackageFunction(packageArguments));
- pkgEnv.update("subinclude", newSubincludeFunction());
- pkgEnv.update("environment_group", newEnvironmentGroupFunction(context));
+ pkgEnv.update("subinclude", newSubincludeFunction.apply());
+ pkgEnv.update("environment_group", newEnvironmentGroupFunction.apply(context));
pkgEnv.update("PACKAGE_NAME", packageName);
@@ -1251,7 +1336,7 @@ public final class PackageFactory {
// Stuff that closes over the package context:
PackageContext context = new PackageContext(pkgBuilder, globber, NullEventHandler.INSTANCE);
buildPkgEnv(pkgEnv, packageId.toString(), context, ruleFactory);
- pkgEnv.update("glob", newGlobFunction(context, /*async=*/true));
+ pkgEnv.update("glob", newGlobFunction.apply(context, /*async=*/true));
// The Fileset function is heavyweight in that it can run glob(). Avoid this during the
// preloading phase.
pkgEnv.remove("FilesetEntry");
@@ -1301,4 +1386,8 @@ public final class PackageFactory {
}
return true;
}
+
+ static {
+ SkylarkSignatureProcessor.configureSkylarkFunctions(PackageFactory.class);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index b4273c5d4e..c604fff3e2 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -31,11 +31,11 @@ import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.syntax.Argument;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.Function;
import com.google.devtools.build.lib.syntax.GlobList;
import com.google.devtools.build.lib.syntax.Label;
import com.google.devtools.build.lib.syntax.Label.SyntaxException;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
-import com.google.devtools.build.lib.syntax.UserDefinedFunction;
import com.google.devtools.build.lib.util.StringUtil;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -427,7 +427,7 @@ public final class RuleClass {
PredicatesWithMessage.<Rule>alwaysTrue();
private Predicate<String> preferredDependencyPredicate = Predicates.alwaysFalse();
private List<Class<?>> advertisedProviders = new ArrayList<>();
- private UserDefinedFunction configuredTargetFunction = null;
+ private Function configuredTargetFunction = null;
private SkylarkEnvironment ruleDefinitionEnvironment = null;
private Set<Class<?>> configurationFragments = new LinkedHashSet<>();
private boolean failIfMissingConfigurationFragment;
@@ -681,7 +681,7 @@ public final class RuleClass {
/**
* Sets the rule implementation function. Meant for Skylark usage.
*/
- public Builder setConfiguredTargetFunction(UserDefinedFunction func) {
+ public Builder setConfiguredTargetFunction(Function func) {
this.configuredTargetFunction = func;
return this;
}
@@ -834,7 +834,7 @@ public final class RuleClass {
/**
* The Skylark rule implementation of this RuleClass. Null for non Skylark executable RuleClasses.
*/
- @Nullable private final UserDefinedFunction configuredTargetFunction;
+ @Nullable private final Function configuredTargetFunction;
/**
* The Skylark rule definition environment of this RuleClass.
@@ -895,7 +895,7 @@ public final class RuleClass {
ConfiguredTargetFactory<?, ?> configuredTargetFactory,
PredicateWithMessage<Rule> validityPredicate, Predicate<String> preferredDependencyPredicate,
ImmutableSet<Class<?>> advertisedProviders,
- @Nullable UserDefinedFunction configuredTargetFunction,
+ @Nullable Function configuredTargetFunction,
@Nullable SkylarkEnvironment ruleDefinitionEnvironment,
Set<Class<?>> allowedConfigurationFragments, boolean failIfMissingConfigurationFragment,
boolean supportsConstraintChecking,
@@ -1503,7 +1503,7 @@ public final class RuleClass {
/**
* Returns this RuleClass's custom Skylark rule implementation.
*/
- @Nullable public UserDefinedFunction getConfiguredTargetFunction() {
+ @Nullable public Function getConfiguredTargetFunction() {
return configuredTargetFunction;
}
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 a5b438c3f2..1965b9d91c 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
@@ -15,17 +15,16 @@
package com.google.devtools.build.lib.packages;
import com.google.devtools.build.lib.packages.Type.ConversionException;
+import com.google.devtools.build.lib.syntax.BuiltinFunction;
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.GlobList;
-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;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
/**
* A class for the Skylark native module.
@@ -37,6 +36,7 @@ import java.util.Map;
+ "Extra helper functions:")
public class SkylarkNativeModule {
+ // TODO(bazel-team): shouldn't we return a SkylarkList instead?
@SkylarkSignature(name = "glob", objectType = SkylarkNativeModule.class,
returnType = GlobList.class,
doc = "Glob returns a list of every file in the current package that:<ul>\n"
@@ -55,17 +55,15 @@ public class SkylarkNativeModule {
@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)
+ private static final BuiltinFunction glob = new BuiltinFunction("glob") {
+ public GlobList<String> invoke(
+ SkylarkList includes, SkylarkList excludes, Integer excludeDirectories,
+ 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")
- });
- }
- };
+ return PackageFactory.callGlob(
+ null, false, includes, excludes, excludeDirectories != 0, ast, env);
+ }
+ };
@SkylarkSignature(name = "package_group", objectType = SkylarkNativeModule.class,
returnType = Environment.NoneType.class,
@@ -82,17 +80,12 @@ public class SkylarkNativeModule {
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)
- throws EvalException, ConversionException {
- return PackageFactory.callPackageFunction(ast, env, new Object[] {
- kwargs.get("name"),
- kwargs.get("packages"),
- kwargs.get("includes")
- });
- }
- };
+ private static final BuiltinFunction packageGroup = new BuiltinFunction("package_group") {
+ public Environment.NoneType invoke(String name, SkylarkList packages, SkylarkList includes,
+ FuncallExpression ast, Environment env) throws EvalException, ConversionException {
+ return PackageFactory.callPackageFunction(name, packages, includes, ast, env);
+ }
+ };
@SkylarkSignature(name = "exports_files", objectType = SkylarkNativeModule.class,
returnType = Environment.NoneType.class,
@@ -111,17 +104,17 @@ public class SkylarkNativeModule {
@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)
- throws EvalException, ConversionException {
- return PackageFactory.callExportsFiles(ast, env, new Object[] {
- kwargs.get("srcs"),
- kwargs.get("visibility"),
- kwargs.get("licenses")
- });
- }
- };
+ private static final BuiltinFunction exportsFiles = new BuiltinFunction("exports_files") {
+ public Environment.NoneType invoke(SkylarkList srcs, Object visibility, Object licenses,
+ FuncallExpression ast, Environment env)
+ throws EvalException, ConversionException {
+ return PackageFactory.callExportsFiles(srcs, visibility, licenses, ast, env);
+ }
+ };
public static final SkylarkNativeModule NATIVE_MODULE = new SkylarkNativeModule();
+
+ static {
+ SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkNativeModule.class);
+ }
}
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 7d39e0dcfa..46d31e225d 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
@@ -21,6 +21,7 @@ import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
import com.google.devtools.build.lib.packages.Attribute.SkylarkLateBound;
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.packages.Type.ConversionException;
+import com.google.devtools.build.lib.syntax.BuiltinFunction;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalUtils;
@@ -28,11 +29,11 @@ import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.Label;
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.SkylarkSignatureProcessor;
import com.google.devtools.build.lib.syntax.UserDefinedFunction;
import com.google.devtools.build.lib.util.FileTypeSet;
@@ -171,11 +172,14 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.INTEGER, ast, env);
+ private static BuiltinFunction integer = new BuiltinFunction("int") {
+ public Attribute.Builder<?> invoke(Integer defaultInt,
+ SkylarkList flags, Boolean mandatory, Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap(
+ "default", defaultInt, "flags", flags, "mandatory", mandatory, "cfg", cfg),
+ Type.INTEGER, ast, env);
}
};
@@ -193,11 +197,14 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.STRING, ast, env);
+ private static BuiltinFunction string = new BuiltinFunction("string") {
+ public Attribute.Builder<?> invoke(String defaultString,
+ SkylarkList flags, Boolean mandatory, Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap(
+ "default", defaultString, "flags", flags, "mandatory", mandatory, "cfg", cfg),
+ Type.STRING, ast, env);
}
};
@@ -230,18 +237,31 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.LABEL, ast, env);
+ private static BuiltinFunction label = new BuiltinFunction("label") {
+ public Attribute.Builder<?> invoke(
+ Object defaultO,
+ Boolean executable,
+ SkylarkList flags,
+ Object allowFiles,
+ Boolean mandatory,
+ SkylarkList providers,
+ Object allowRules,
+ Boolean singleFile,
+ Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap(
+ "default", defaultO, "executable", executable, "flags", flags,
+ "allow_files", allowFiles, "mandatory", mandatory, "providers", providers,
+ "allow_rules", allowRules, "single_file", singleFile, "cfg", cfg),
+ Type.LABEL, ast, env);
}
};
@SkylarkSignature(name = "string_list", doc =
"Creates an attribute of type list of strings",
objectType = SkylarkAttr.class,
- returnType = Attribute.class,
+ returnType = Attribute.Builder.class,
optionalPositionals = {
@Param(name = "default", type = SkylarkList.class, generic1 = String.class,
defaultValue = "[]",
@@ -255,11 +275,19 @@ public final class SkylarkAttr {
@Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
defaultValue = "None", doc = CONFIGURATION_DOC)},
useAst = true, useEnvironment = true)
- private static SkylarkFunction stringList = new SkylarkFunction("string_list") {
- @Override
- public Object call(Map<String, Object> kwargs, FuncallExpression ast, Environment env)
- throws EvalException {
- return createAttribute(kwargs, Type.STRING_LIST, ast, env);
+ private static BuiltinFunction stringList = new BuiltinFunction("string_list") {
+ public Attribute.Builder<?> invoke(
+ SkylarkList defaultList,
+ SkylarkList flags,
+ Boolean mandatory,
+ Boolean nonEmpty,
+ Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap(
+ "default", defaultList,
+ "flags", flags, "mandatory", mandatory, "non_empty", nonEmpty, "cfg", cfg),
+ Type.STRING_LIST, ast, env);
}
};
@@ -288,11 +316,22 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.LABEL_LIST, ast, env);
+ private static BuiltinFunction labelList = new BuiltinFunction("label_list") {
+ public Attribute.Builder<?> invoke(
+ Object defaultList,
+ Object allowFiles,
+ Object allowRules,
+ SkylarkList providers,
+ SkylarkList flags,
+ Boolean mandatory,
+ Boolean nonEmpty,
+ Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap("default", defaultList,
+ "allow_files", allowFiles, "allow_rules", allowRules, "providers", providers,
+ "flags", flags, "mandatory", mandatory, "non_empty", nonEmpty, "cfg", cfg),
+ Type.LABEL_LIST, ast, env);
}
};
@@ -310,11 +349,14 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.BOOLEAN, ast, env);
+ private static BuiltinFunction bool = new BuiltinFunction("bool") {
+ public Attribute.Builder<?> invoke(Boolean defaultBool,
+ SkylarkList flags, Boolean mandatory, Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap(
+ "default", defaultBool, "flags", flags, "mandatory", mandatory, "cfg", cfg),
+ Type.BOOLEAN, ast, env);
}
};
@@ -334,11 +376,14 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.OUTPUT, ast, env);
+ private static BuiltinFunction output = new BuiltinFunction("output") {
+ public Attribute.Builder<?> invoke(Object defaultO,
+ SkylarkList flags, Boolean mandatory, Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap(
+ "default", defaultO, "flags", flags, "mandatory", mandatory, "cfg", cfg),
+ Type.OUTPUT, ast, env);
}
};
@@ -359,11 +404,14 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.OUTPUT_LIST, ast, env);
+ private static BuiltinFunction outputList = new BuiltinFunction("output_list") {
+ public Attribute.Builder<?> invoke(SkylarkList defaultList,
+ SkylarkList flags, Boolean mandatory, Boolean nonEmpty, Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap("default", defaultList,
+ "flags", flags, "mandatory", mandatory, "non_empty", nonEmpty, "cfg", cfg),
+ Type.OUTPUT_LIST, ast, env);
}
};
@@ -384,11 +432,14 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.STRING_DICT, ast, env);
+ private static BuiltinFunction stringDict = new BuiltinFunction("string_dict") {
+ public Attribute.Builder<?> invoke(Map<?, ?> defaultO,
+ SkylarkList flags, Boolean mandatory, Boolean nonEmpty, Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap("default", defaultO,
+ "flags", flags, "mandatory", mandatory, "non_empty", nonEmpty, "cfg", cfg),
+ Type.STRING_DICT, ast, env);
}
};
@@ -408,11 +459,18 @@ public final class SkylarkAttr {
@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)
- throws EvalException {
- return createAttribute(kwargs, Type.LICENSE, ast, env);
+ private static BuiltinFunction license = new BuiltinFunction("license") {
+ public Attribute.Builder<?> invoke(Object defaultO,
+ SkylarkList flags, Boolean mandatory, Object cfg,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return createAttribute(
+ EvalUtils.optionMap(
+ "default", defaultO, "flags", flags, "mandatory", mandatory, "cfg", cfg),
+ Type.LICENSE, ast, env);
}
};
+
+ static {
+ SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkAttr.class);
+ }
}
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 260c7e4a8f..a26248656f 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
@@ -18,16 +18,13 @@ import com.google.common.base.Function;
import com.google.common.collect.Iterables;
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.SkylarkFunction.SimpleSkylarkFunction;
+import com.google.devtools.build.lib.syntax.BuiltinFunction;
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;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
/**
* A Skylark module class to create memory efficient command lines.
@@ -36,23 +33,17 @@ import java.util.Map;
doc = "Module for creating memory efficient command lines.")
public class SkylarkCommandLine {
- @SkylarkSignature(name = "join_paths",
+ @SkylarkSignature(name = "join_paths", objectType = SkylarkCommandLine.class,
+ returnType = String.class,
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,
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")})
- private static SimpleSkylarkFunction joinPaths =
- new SimpleSkylarkFunction("join_paths") {
- @Override
- public Object call(Map<String, Object> params, Location loc)
- throws EvalException {
- final String separator = (String) params.get("separator");
- final NestedSet<Artifact> artifacts =
- ((SkylarkNestedSet) params.get("files")).getSet(Artifact.class);
+ private static BuiltinFunction joinPaths = new BuiltinFunction("join_paths") {
+ public String invoke(String separator, SkylarkNestedSet files) {
+ NestedSet<Artifact> artifacts = files.getSet(Artifact.class);
// TODO(bazel-team): lazy evaluate
return Artifact.joinExecPaths(separator, artifacts);
}
@@ -70,12 +61,8 @@ public class SkylarkCommandLine {
doc = "The template to use for the transformation, <code>%{path}</code> and "
+ "<code>%{short_path}</code> being substituted with the corresponding fields of each"
+ " file.")})
- private static SimpleSkylarkFunction template = new SimpleSkylarkFunction("template") {
- @Override
- public Object call(Map<String, Object> params, Location loc)
- throws EvalException {
- final String template = (String) params.get("template");
- SkylarkNestedSet items = (SkylarkNestedSet) params.get("items");
+ private static BuiltinFunction template = new BuiltinFunction("template") {
+ public SkylarkList invoke(final SkylarkNestedSet items, final String template) {
return SkylarkList.lazyList(Iterables.transform(items, new Function<Object, String>() {
@Override
public String apply(Object input) {
@@ -87,4 +74,8 @@ public class SkylarkCommandLine {
}), String.class);
}
};
+
+ static {
+ SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkCommandLine.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 226ceebee3..fdb69a3250 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
@@ -21,11 +21,10 @@ import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.MethodLibrary;
import com.google.devtools.build.lib.packages.SkylarkNativeModule;
+import com.google.devtools.build.lib.syntax.BaseFunction;
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.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;
@@ -43,9 +42,11 @@ import java.util.Set;
public class SkylarkModules {
/**
- * The list of built in Skylark modules. Documentation is generated automatically for all these
- * modules. They are also registered with the {@link ValidationEnvironment} and the
- * {@link SkylarkEnvironment}. Note that only {@link SkylarkFunction}s are handled properly.
+ * The list of built in Skylark modules.
+ * Documentation is generated automatically for all these modules.
+ * They are also registered with the {@link ValidationEnvironment}
+ * and the {@link SkylarkEnvironment}.
+ * Note that only functions with a {@link SkylarkSignature} annotations are handled properly.
*/
// TODO(bazel-team): find a more general, more automated way of registering classes and building
// initial environments. And don't give syntax.Environment and packages.MethodLibrary a special
@@ -57,19 +58,20 @@ public class SkylarkModules {
SkylarkRuleClassFunctions.class,
SkylarkRuleImplementationFunctions.class);
- private static final ImmutableMap<Class<?>, ImmutableList<Function>> FUNCTION_MAP;
+ private static final ImmutableMap<Class<?>, ImmutableList<BaseFunction>> FUNCTION_MAP;
private static final ImmutableMap<String, Object> OBJECTS;
static {
try {
- ImmutableMap.Builder<Class<?>, ImmutableList<Function>> functionMap = ImmutableMap.builder();
+ ImmutableMap.Builder<Class<?>, ImmutableList<BaseFunction>> functionMap =
+ ImmutableMap.builder();
ImmutableMap.Builder<String, Object> objects = ImmutableMap.builder();
for (Class<?> moduleClass : MODULES) {
if (moduleClass.isAnnotationPresent(SkylarkModule.class)) {
objects.put(moduleClass.getAnnotation(SkylarkModule.class).name(),
moduleClass.newInstance());
}
- ImmutableList.Builder<Function> functions = ImmutableList.builder();
+ ImmutableList.Builder<BaseFunction> functions = ImmutableList.builder();
collectSkylarkFunctionsAndObjectsFromFields(moduleClass, functions, objects);
functionMap.put(moduleClass, functions.build());
}
@@ -97,8 +99,8 @@ public class SkylarkModules {
private static void setupEnvironment(Environment env) {
MethodLibrary.setupMethodEnvironment(env);
- for (Map.Entry<Class<?>, ImmutableList<Function>> entry : FUNCTION_MAP.entrySet()) {
- for (Function function : entry.getValue()) {
+ for (Map.Entry<Class<?>, ImmutableList<BaseFunction>> entry : FUNCTION_MAP.entrySet()) {
+ for (BaseFunction function : entry.getValue()) {
if (function.getObjectType() != null) {
env.registerFunction(function.getObjectType(), function.getName(), function);
} else {
@@ -143,11 +145,11 @@ public class SkylarkModules {
}
/**
- * Collects the Functions from the fields of the class of the object parameter
+ * Collects the BaseFunctions from the fields of the class of the object parameter
* and adds them into the builder.
*/
private static void collectSkylarkFunctionsAndObjectsFromFields(Class<?> type,
- ImmutableList.Builder<Function> functions, ImmutableMap.Builder<String, Object> objects) {
+ ImmutableList.Builder<BaseFunction> functions, ImmutableMap.Builder<String, Object> objects) {
try {
for (Field field : type.getDeclaredFields()) {
if (field.isAnnotationPresent(SkylarkSignature.class)) {
@@ -156,12 +158,8 @@ public class SkylarkModules {
field.setAccessible(true);
SkylarkSignature annotation = field.getAnnotation(SkylarkSignature.class);
Object value = field.get(null);
- if (SkylarkFunction.class.isAssignableFrom(field.getType())) {
- SkylarkFunction function = (SkylarkFunction) value;
- if (!function.isConfigured()) {
- function.configure(annotation);
- }
- functions.add(function);
+ if (BaseFunction.class.isAssignableFrom(field.getType())) {
+ functions.add((BaseFunction) value);
} else {
objects.put(annotation.name(), value);
}
@@ -174,14 +172,14 @@ public class SkylarkModules {
}
/**
- * Collects the Functions from the fields of the class of the object parameter
+ * Collects the BaseFunctions from the fields of the class of the object parameter
* and adds their class and their corresponding return value to the builder.
*/
private static void collectSkylarkTypesFromFields(Class<?> classObject, Set<String> builtIn) {
for (Field field : classObject.getDeclaredFields()) {
if (field.isAnnotationPresent(SkylarkSignature.class)) {
SkylarkSignature annotation = field.getAnnotation(SkylarkSignature.class);
- if (SkylarkFunction.class.isAssignableFrom(field.getType())) {
+ if (BaseFunction.class.isAssignableFrom(field.getType())) {
// Ignore non-global values.
if (annotation.objectType().equals(Object.class)) {
builtIn.add(annotation.name());
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 3cb4e28f96..14bdcd7bbc 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
@@ -54,8 +54,8 @@ import com.google.devtools.build.lib.packages.TargetUtils;
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.BuiltinFunction;
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,17 +64,15 @@ import com.google.devtools.build.lib.syntax.EvalException;
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.FunctionSignature;
import com.google.devtools.build.lib.syntax.Label;
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 com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@@ -182,7 +180,7 @@ public class SkylarkRuleClassFunctions {
"Creates a new rule. Store it in a global value, so that it can be loaded and called "
+ "from BUILD files.",
onlyLoadingPhase = true,
- returnType = BaseFunction.class,
+ returnType = Function.class,
mandatoryPositionals = {
@Param(name = "implementation", type = Function.class,
doc = "the function implementing this rule, has to have exactly one parameter: "
@@ -214,85 +212,85 @@ public class SkylarkRuleClassFunctions {
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
- @SuppressWarnings({"rawtypes", "unchecked"}) // castMap produces
- // an Attribute.Builder instead of a Attribute.Builder<?> but it's OK.
- public Object call(Map<String, Object> arguments, FuncallExpression ast,
- Environment funcallEnv) throws EvalException, ConversionException {
- final Location loc = ast.getLocation();
-
- RuleClassType type = RuleClassType.NORMAL;
- if (arguments.containsKey("test") && EvalUtils.toBoolean(arguments.get("test"))) {
- type = RuleClassType.TEST;
- }
-
- // We'll set the name later, pass the empty string for now.
- final RuleClass.Builder builder = type == RuleClassType.TEST
- ? new RuleClass.Builder("", type, true, testBaseRule)
- : new RuleClass.Builder("", type, true, baseRule);
-
- for (Map.Entry<String, Attribute.Builder> attr : castMap(arguments.get("attrs"),
- String.class, Attribute.Builder.class, "attrs").entrySet()) {
- Attribute.Builder<?> attrBuilder = attr.getValue();
- String attrName = attributeToNative(attr.getKey(), loc,
+ private static final BuiltinFunction rule = new BuiltinFunction("rule") {
+ @SuppressWarnings({"rawtypes", "unchecked"}) // castMap produces
+ // an Attribute.Builder instead of a Attribute.Builder<?> but it's OK.
+ public Function invoke(Function implementation, Boolean test,
+ Object attrs, Object implicitOutputs, Boolean executable, Boolean outputToGenfiles,
+ FuncallExpression ast, Environment funcallEnv)
+ throws EvalException, ConversionException {
+
+ RuleClassType type = test ? RuleClassType.TEST : RuleClassType.NORMAL;
+
+ // We'll set the name later, pass the empty string for now.
+ RuleClass.Builder builder = test
+ ? new RuleClass.Builder("", type, true, testBaseRule)
+ : new RuleClass.Builder("", type, true, baseRule);
+
+ if (attrs != Environment.NONE) {
+ for (Map.Entry<String, Attribute.Builder> attr : castMap(
+ attrs, String.class, Attribute.Builder.class, "attrs").entrySet()) {
+ Attribute.Builder<?> attrBuilder = (Attribute.Builder<?>) attr.getValue();
+ String attrName = attributeToNative(attr.getKey(), ast.getLocation(),
attrBuilder.hasLateBoundValue());
builder.addOrOverrideAttribute(attrBuilder.build(attrName));
}
- if (arguments.containsKey("executable") && (Boolean) arguments.get("executable")) {
- builder.addOrOverrideAttribute(
- attr("$is_executable", BOOLEAN).value(true)
- .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target")
- .build());
- builder.setOutputsDefaultExecutable();
- }
+ }
+ if (executable) {
+ builder.addOrOverrideAttribute(
+ attr("$is_executable", BOOLEAN).value(true)
+ .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target")
+ .build());
+ builder.setOutputsDefaultExecutable();
+ }
- if (arguments.containsKey("outputs")) {
- final Object implicitOutputs = arguments.get("outputs");
- if (implicitOutputs instanceof UserDefinedFunction) {
- UserDefinedFunction func = (UserDefinedFunction) implicitOutputs;
- final SkylarkCallbackFunction callback =
- new SkylarkCallbackFunction(func, ast, (SkylarkEnvironment) funcallEnv);
- builder.setImplicitOutputsFunction(
- new SkylarkImplicitOutputsFunctionWithCallback(callback, loc));
- } else {
- builder.setImplicitOutputsFunction(new SkylarkImplicitOutputsFunctionWithMap(
- ImmutableMap.copyOf(castMap(arguments.get("outputs"), String.class, String.class,
- "implicit outputs of the rule class"))));
+ if (!(funcallEnv instanceof SkylarkEnvironment)) {
+ System.out.println("rule called from non-Skylark environment!");
+ // throw new EvaluationException("rule not accessible at the toplevel");
+ }
+
+ if (implicitOutputs != Environment.NONE) {
+ if (implicitOutputs instanceof Function) {
+ Function func = (Function) implicitOutputs;
+ final SkylarkCallbackFunction callback =
+ new SkylarkCallbackFunction(func, ast, (SkylarkEnvironment) funcallEnv);
+ builder.setImplicitOutputsFunction(
+ new SkylarkImplicitOutputsFunctionWithCallback(callback, ast.getLocation()));
+ } else {
+ builder.setImplicitOutputsFunction(new SkylarkImplicitOutputsFunctionWithMap(
+ ImmutableMap.copyOf(castMap(implicitOutputs, String.class, String.class,
+ "implicit outputs of the rule class"))));
}
- }
+ }
- if (arguments.containsKey("output_to_genfiles")
- && (Boolean) arguments.get("output_to_genfiles")) {
- builder.setOutputToGenfiles();
- }
+ if (outputToGenfiles) {
+ builder.setOutputToGenfiles();
+ }
- builder.setConfiguredTargetFunction(
- (UserDefinedFunction) arguments.get("implementation"));
- builder.setRuleDefinitionEnvironment((SkylarkEnvironment) funcallEnv);
- return new RuleFunction(builder, type);
+ builder.setConfiguredTargetFunction(implementation);
+ builder.setRuleDefinitionEnvironment((SkylarkEnvironment) funcallEnv);
+ return new RuleFunction(builder, type);
}
};
// This class is needed for testing
- static final class RuleFunction extends AbstractFunction {
+ static final class RuleFunction extends BaseFunction {
// Note that this means that we can reuse the same builder.
// This is fine since we don't modify the builder from here.
private final RuleClass.Builder builder;
private final RuleClassType type;
public RuleFunction(Builder builder, RuleClassType type) {
- super("rule");
+ super("rule", FunctionSignature.KWARGS);
this.builder = builder;
this.type = type;
}
+ @Override
@SuppressWarnings("unchecked") // the magic hidden $pkg_context variable is guaranteed
// to be a PackageContext
- @Override
- public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
- Environment env) throws EvalException, InterruptedException {
+ public Object call(Object[] args, FuncallExpression ast, Environment env)
+ throws EvalException, InterruptedException, ConversionException {
try {
String ruleClassName = ast.getFunction().getName();
if (ruleClassName.startsWith("_")) {
@@ -305,7 +303,8 @@ public class SkylarkRuleClassFunctions {
}
RuleClass ruleClass = builder.build(ruleClassName);
PackageContext pkgContext = (PackageContext) env.lookup(PackageFactory.PKG_CONTEXT);
- return RuleFactory.createAndAddRule(pkgContext, ruleClass, kwargs, ast);
+ return RuleFactory.createAndAddRule(
+ pkgContext, ruleClass, (Map<String, Object>) args[0], ast);
} catch (InvalidRuleException | NameConflictException | NoSuchVariableException e) {
throw new EvalException(ast.getLocation(), e.getMessage());
}
@@ -324,33 +323,29 @@ public class SkylarkRuleClassFunctions {
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,
- ConversionException {
- String labelString = (String) arguments.get("label_string");
+ private static final BuiltinFunction label = new BuiltinFunction("Label") {
+ public Label invoke(String labelString,
+ Location loc) throws EvalException, ConversionException {
try {
return labelCache.get(labelString);
} catch (ExecutionException e) {
throw new EvalException(loc, "Illegal absolute label syntax: " + labelString);
}
- }
- };
+ }
+ };
@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,
mandatoryPositionals = {
- @Param(name = "types", type = SkylarkList.class, generic1 = String.class,
+ @Param(name = "types", type = SkylarkList.class, generic1 = String.class, defaultValue = "[]",
doc = "a list of the accepted file extensions")})
- private static final SkylarkFunction fileType = new SimpleSkylarkFunction("FileType") {
- @Override
- public Object call(Map<String, Object> arguments, Location loc) throws EvalException,
- ConversionException {
- return SkylarkFileType.of(castList(arguments.get("types"), String.class));
- }
- };
+ private static final BuiltinFunction fileType = new BuiltinFunction("FileType") {
+ public SkylarkFileType invoke(SkylarkList types) throws ConversionException {
+ return SkylarkFileType.of(castList(types, String.class));
+ }
+ };
@SkylarkSignature(name = "to_proto",
doc = "Creates a text message from the struct parameter. This method only works if all "
@@ -373,68 +368,69 @@ public class SkylarkRuleClassFunctions {
@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,
- ConversionException {
- ClassObject self = (ClassObject) arguments.get("self");
- StringBuilder sb = new StringBuilder();
- printTextMessage(self, sb, 0, loc);
- return sb.toString();
- }
-
- private void printTextMessage(ClassObject object, StringBuilder sb,
- int indent, Location loc) throws EvalException {
- for (String key : object.getKeys()) {
- printTextMessage(key, object.getValue(key), sb, indent, loc);
+ private static final BuiltinFunction toProto = new BuiltinFunction("to_proto") {
+ public String invoke(SkylarkClassObject self, Location loc) throws EvalException {
+ StringBuilder sb = new StringBuilder();
+ printTextMessage(self, sb, 0, loc);
+ return sb.toString();
}
- }
- private void printSimpleTextMessage(String key, Object value, StringBuilder sb,
- int indent, Location loc, String container) throws EvalException {
- if (value instanceof ClassObject) {
- print(sb, key + " {", indent);
- printTextMessage((ClassObject) value, sb, indent + 1, loc);
- print(sb, "}", indent);
- } else if (value instanceof String) {
- print(sb, key + ": \"" + escape((String) value) + "\"", indent);
- } else if (value instanceof Integer) {
- print(sb, key + ": " + value, indent);
- } else if (value instanceof Boolean) {
- // We're relying on the fact that Java converts Booleans to Strings in the same way
- // as the protocol buffers do.
- print(sb, key + ": " + value, indent);
- } else {
- throw new EvalException(loc,
- "Invalid text format, expected a struct, a string, a bool, or an int but got a "
- + EvalUtils.getDataTypeName(value) + " for " + container + " '" + key + "'");
+ private void printTextMessage(ClassObject object, StringBuilder sb,
+ int indent, Location loc) throws EvalException {
+ for (String key : object.getKeys()) {
+ printTextMessage(key, object.getValue(key), sb, indent, loc);
+ }
}
- }
- private void printTextMessage(String key, Object value, StringBuilder sb,
- int indent, Location loc) throws EvalException {
- if (value instanceof SkylarkList) {
- for (Object item : ((SkylarkList) value)) {
- // TODO(bazel-team): There should be some constraint on the fields of the structs
- // in the same list but we ignore that for now.
- printSimpleTextMessage(key, item, sb, indent, loc, "list element in struct field");
+ private void printSimpleTextMessage(String key, Object value, StringBuilder sb,
+ int indent, Location loc, String container) throws EvalException {
+ if (value instanceof ClassObject) {
+ print(sb, key + " {", indent);
+ printTextMessage((ClassObject) value, sb, indent + 1, loc);
+ print(sb, "}", indent);
+ } else if (value instanceof String) {
+ print(sb, key + ": \"" + escape((String) value) + "\"", indent);
+ } else if (value instanceof Integer) {
+ print(sb, key + ": " + value, indent);
+ } else if (value instanceof Boolean) {
+ // We're relying on the fact that Java converts Booleans to Strings in the same way
+ // as the protocol buffers do.
+ print(sb, key + ": " + value, indent);
+ } else {
+ throw new EvalException(loc,
+ "Invalid text format, expected a struct, a string, a bool, or an int but got a "
+ + EvalUtils.getDataTypeName(value) + " for " + container + " '" + key + "'");
}
- } else {
- printSimpleTextMessage(key, value, sb, indent, loc, "struct field");
}
- }
- private String escape(String string) {
- // TODO(bazel-team): use guava's SourceCodeEscapers when it's released.
- return string.replace("\"", "\\\"").replace("\n", "\\n");
- }
+ private void printTextMessage(String key, Object value, StringBuilder sb,
+ int indent, Location loc) throws EvalException {
+ if (value instanceof SkylarkList) {
+ for (Object item : ((SkylarkList) value)) {
+ // TODO(bazel-team): There should be some constraint on the fields of the structs
+ // in the same list but we ignore that for now.
+ printSimpleTextMessage(key, item, sb, indent, loc, "list element in struct field");
+ }
+ } else {
+ printSimpleTextMessage(key, value, sb, indent, loc, "struct field");
+ }
+ }
- private void print(StringBuilder sb, String text, int indent) {
- for (int i = 0; i < indent; i++) {
- sb.append(" ");
+ private String escape(String string) {
+ // TODO(bazel-team): use guava's SourceCodeEscapers when it's released.
+ return string.replace("\"", "\\\"").replace("\n", "\\n");
}
+
+ private void print(StringBuilder sb, String text, int indent) {
+ for (int i = 0; i < indent; i++) {
+ sb.append(" ");
+ }
sb.append(text);
sb.append("\n");
- }
- };
+ }
+ };
+
+ static {
+ SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkRuleClassFunctions.class);
+ }
}
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 0019fe8683..03e2bce974 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
@@ -32,18 +32,19 @@ import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.Type.ConversionException;
+import com.google.devtools.build.lib.syntax.BuiltinFunction;
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.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.syntax.SkylarkSignatureProcessor;
import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@@ -106,75 +107,79 @@ public class SkylarkRuleImplementationFunctions {
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") {
-
- @Override
- public Object call(Map<String, Object> params, Location loc) throws EvalException,
- ConversionException {
- SkylarkRuleContext ctx = (SkylarkRuleContext) params.get("self");
+ private static final BuiltinFunction createSpawnAction = new BuiltinFunction("action") {
+ public Environment.NoneType invoke(
+ SkylarkRuleContext ctx,
+ SkylarkList outputs,
+ SkylarkList inputs,
+ Object executableO,
+ SkylarkList arguments,
+ Object mnemonicO,
+ Object commandO,
+ Object progressMessage,
+ Boolean useDefaultShellEnv,
+ Object envO,
+ Object executionRequirementsO,
+ Object inputManifestsO,
+ Location loc) throws EvalException, ConversionException {
SpawnAction.Builder builder = new SpawnAction.Builder();
// TODO(bazel-team): builder still makes unnecessary copies of inputs, outputs and args.
- builder.addInputs(castList(params.get("inputs"), Artifact.class));
- builder.addOutputs(castList(params.get("outputs"), Artifact.class));
- builder.addArguments(castList(params.get("arguments"), String.class));
- if (params.containsKey("executable")) {
- Object exe = params.get("executable");
- if (exe instanceof Artifact) {
- Artifact executable = (Artifact) exe;
+ builder.addInputs(castList(inputs, Artifact.class));
+ builder.addOutputs(castList(outputs, Artifact.class));
+ builder.addArguments(castList(arguments, String.class));
+ if (executableO != Environment.NONE) {
+ if (executableO instanceof Artifact) {
+ Artifact executable = (Artifact) executableO;
builder.addInput(executable);
FilesToRunProvider provider = ctx.getExecutableRunfiles(executable);
if (provider == null) {
- builder.setExecutable((Artifact) exe);
+ builder.setExecutable(executable);
} else {
builder.setExecutable(provider);
}
- } else if (exe instanceof PathFragment) {
- builder.setExecutable((PathFragment) exe);
+ } else if (executableO instanceof PathFragment) {
+ builder.setExecutable((PathFragment) executableO);
} else {
throw new EvalException(loc, "expected file or PathFragment for "
- + "executable but got " + EvalUtils.getDataTypeName(exe) + " instead");
+ + "executable but got " + EvalUtils.getDataTypeName(executableO) + " instead");
}
}
- if (params.containsKey("command") == params.containsKey("executable")) {
+ if ((commandO == Environment.NONE) == (executableO == Environment.NONE)) {
throw new EvalException(loc, "You must specify either 'command' or 'executable' argument");
}
- if (params.containsKey("command")) {
- Object command = params.get("command");
- if (command instanceof String) {
- builder.setShellCommand((String) command);
- } else if (command instanceof SkylarkList) {
- SkylarkList commandList = (SkylarkList) command;
+ if (commandO != Environment.NONE) {
+ if (commandO instanceof String) {
+ builder.setShellCommand((String) commandO);
+ } else if (commandO instanceof SkylarkList) {
+ SkylarkList commandList = (SkylarkList) commandO;
if (commandList.size() < 3) {
throw new EvalException(loc, "'command' list has to be of size at least 3");
}
builder.setShellCommand(castList(commandList, String.class, "command"));
} else {
throw new EvalException(loc, "expected string or list of strings for "
- + "command instead of " + EvalUtils.getDataTypeName(command));
+ + "command instead of " + EvalUtils.getDataTypeName(commandO));
}
}
- if (params.containsKey("mnemonic")) {
- builder.setMnemonic((String) params.get("mnemonic"));
+ if (mnemonicO != Environment.NONE) {
+ builder.setMnemonic((String) mnemonicO);
}
- if (params.containsKey("env")) {
+ if (envO != Environment.NONE) {
builder.setEnvironment(ImmutableMap.copyOf(
- castMap(params.get("env"), String.class, String.class, "env")));
+ castMap(envO, String.class, String.class, "env")));
}
- if (params.containsKey("progress_message")) {
- builder.setProgressMessage((String) params.get("progress_message"));
+ if (progressMessage != Environment.NONE) {
+ builder.setProgressMessage((String) progressMessage);
}
- if (params.containsKey("use_default_shell_env")
- && EvalUtils.toBoolean(params.get("use_default_shell_env"))) {
+ if (EvalUtils.toBoolean(useDefaultShellEnv)) {
builder.useDefaultShellEnvironment();
}
- if (params.containsKey("execution_requirements")) {
+ if (executionRequirementsO != Environment.NONE) {
builder.setExecutionInfo(ImmutableMap.copyOf(castMap(
- params.get("execution_requirements"),
- String.class, String.class, "execution_requirements")));
+ executionRequirementsO, String.class, String.class, "execution_requirements")));
}
- if (params.containsKey("input_manifests")) {
- for (Map.Entry<PathFragment, Artifact> entry : castMap(params.get("input_manifests"),
+ if (inputManifestsO != Environment.NONE) {
+ for (Map.Entry<PathFragment, Artifact> entry : castMap(inputManifestsO,
PathFragment.class, Artifact.class, "input manifest file map").entrySet()) {
builder.addInputManifest(entry.getValue(), entry.getKey());
}
@@ -195,25 +200,19 @@ public class SkylarkRuleImplementationFunctions {
@Param(name = "output", type = Artifact.class, doc = "the output file"),
@Param(name = "content", type = String.class, doc = "the contents of the file")},
optionalPositionals = {
- @Param(name = "executable", type = Boolean.class,
+ @Param(name = "executable", type = Boolean.class, defaultValue = "False",
doc = "whether the output file should be executable (default is False)")})
- private static final SkylarkFunction createFileWriteAction =
- new SimpleSkylarkFunction("file_action") {
-
- @Override
- public Object call(Map<String, Object> params, Location loc) throws EvalException,
- ConversionException {
- SkylarkRuleContext ctx = (SkylarkRuleContext) params.get("self");
- boolean executable = params.containsKey("executable") && (Boolean) params.get("executable");
- FileWriteAction action = new FileWriteAction(
- ctx.getRuleContext().getActionOwner(),
- (Artifact) params.get("output"),
- (String) params.get("content"),
- executable);
- ctx.getRuleContext().registerAction(action);
- return action;
- }
- };
+ private static final BuiltinFunction createFileWriteAction =
+ new BuiltinFunction("file_action") {
+ public FileWriteAction invoke(SkylarkRuleContext ctx,
+ Artifact output, String content, Boolean executable)
+ throws EvalException, ConversionException {
+ FileWriteAction action = new FileWriteAction(
+ ctx.getRuleContext().getActionOwner(), output, content, executable);
+ ctx.getRuleContext().registerAction(action);
+ return action;
+ }
+ };
@SkylarkSignature(name = "template_action",
doc = "Creates a template expansion action.",
@@ -231,30 +230,26 @@ public class SkylarkRuleImplementationFunctions {
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") {
-
- @Override
- public Object call(Map<String, Object> params, Location loc) throws EvalException,
- ConversionException {
- SkylarkRuleContext ctx = (SkylarkRuleContext) params.get("self");
- ImmutableList.Builder<Substitution> substitutions = ImmutableList.builder();
- for (Map.Entry<String, String> substitution : castMap(
- params.get("substitutions"), String.class, String.class, "substitutions").entrySet()) {
- substitutions.add(Substitution.of(substitution.getKey(), substitution.getValue()));
- }
-
- boolean executable = params.containsKey("executable") && (Boolean) params.get("executable");
- TemplateExpansionAction action = new TemplateExpansionAction(
- ctx.getRuleContext().getActionOwner(),
- (Artifact) params.get("template"),
- (Artifact) params.get("output"),
- substitutions.build(),
- executable);
- ctx.getRuleContext().registerAction(action);
- return action;
- }
- };
+ private static final BuiltinFunction createTemplateAction =
+ new BuiltinFunction("template_action", Arrays.<Object>asList(false)) {
+ public TemplateExpansionAction invoke(SkylarkRuleContext ctx,
+ Artifact template, Artifact output, Map<?, ?> substitutionsO, Boolean executable)
+ throws EvalException, ConversionException {
+ ImmutableList.Builder<Substitution> substitutions = ImmutableList.builder();
+ for (Map.Entry<String, String> substitution : castMap(
+ substitutionsO, String.class, String.class, "substitutions").entrySet()) {
+ substitutions.add(Substitution.of(substitution.getKey(), substitution.getValue()));
+ }
+ TemplateExpansionAction action = new TemplateExpansionAction(
+ ctx.getRuleContext().getActionOwner(),
+ template,
+ output,
+ substitutions.build(),
+ executable);
+ ctx.getRuleContext().registerAction(action);
+ return action;
+ }
+ };
/**
* A built in Skylark helper function to access the
@@ -267,11 +262,9 @@ public class SkylarkRuleImplementationFunctions {
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 {
- TransitiveInfoCollection target = (TransitiveInfoCollection) params.get("target");
- String type = (String) params.get("type");
+ private static final BuiltinFunction provider = new BuiltinFunction("provider") {
+ public Object invoke(TransitiveInfoCollection target, String type,
+ Location loc) throws EvalException {
try {
Class<?> classType = SkylarkRuleContext.classCache.get(type);
Class<? extends TransitiveInfoProvider> convertedClass =
@@ -309,24 +302,22 @@ public class SkylarkRuleImplementationFunctions {
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,
- ConversionException {
- SkylarkRuleContext ctx = (SkylarkRuleContext) params.get("self");
+ private static final BuiltinFunction runfiles = new BuiltinFunction("runfiles") {
+ public Runfiles invoke(SkylarkRuleContext ctx, SkylarkList files, Object transitiveFiles,
+ Boolean collectData, Boolean collectDefault,
+ Location loc) throws EvalException, ConversionException {
Runfiles.Builder builder = new Runfiles.Builder();
- if (params.containsKey("collect_data") && (Boolean) params.get("collect_data")) {
+ if (EvalUtils.toBoolean(collectData)) {
builder.addRunfiles(ctx.getRuleContext(), RunfilesProvider.DATA_RUNFILES);
}
- if (params.containsKey("collect_default") && (Boolean) params.get("collect_default")) {
+ if (EvalUtils.toBoolean(collectDefault)) {
builder.addRunfiles(ctx.getRuleContext(), RunfilesProvider.DEFAULT_RUNFILES);
}
- if (params.containsKey("files")) {
- builder.addArtifacts(castList(params.get("files"), Artifact.class));
+ if (!files.isEmpty()) {
+ builder.addArtifacts(castList(files, Artifact.class));
}
- if (params.containsKey("transitive_files")) {
- builder.addTransitiveArtifacts(((SkylarkNestedSet) params.get("transitive_files"))
- .getSet(Artifact.class));
+ if (transitiveFiles != Environment.NONE) {
+ builder.addTransitiveArtifacts(((SkylarkNestedSet) transitiveFiles).getSet(Artifact.class));
}
return builder.build();
}
@@ -342,20 +333,22 @@ public class SkylarkRuleImplementationFunctions {
@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")
- @Override
- protected Object call(Map<String, Object> params, Location loc)
- throws ConversionException, EvalException {
- SkylarkRuleContext ctx = (SkylarkRuleContext) params.get("self");
- return new CommandHelper(ctx.getRuleContext(),
- AnalysisUtils.getProviders(
- castList(params.get("tools"), TransitiveInfoCollection.class),
- FilesToRunProvider.class),
- // TODO(bazel-team): this cast to Map is unchecked and is not safe.
- // The best way to fix this probably is to convert CommandHelper to Skylark.
- ImmutableMap.copyOf((Map<Label, Iterable<Artifact>>) params.get("label_dict")));
- }
- };
+ private static final BuiltinFunction createCommandHelper = new BuiltinFunction("command_helper") {
+ @SuppressWarnings("unchecked")
+ // TODO(bazel-team): this cast to Map is unchecked and is not safe.
+ // The best way to fix this probably is to convert CommandHelper to Skylark.
+ public CommandHelper invoke(
+ SkylarkRuleContext ctx, SkylarkList tools, Map<Label, Iterable<Artifact>> labelDict)
+ throws ConversionException, EvalException {
+ return new CommandHelper(ctx.getRuleContext(),
+ AnalysisUtils.getProviders(
+ castList(tools, TransitiveInfoCollection.class),
+ FilesToRunProvider.class),
+ ImmutableMap.copyOf(labelDict));
+ }
+ };
+
+ static {
+ SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkRuleImplementationFunctions.class);
+ }
}
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 08ea8ee3c1..af33276aa7 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
@@ -205,8 +205,8 @@ public class BuiltinFunction extends BaseFunction {
Preconditions.checkState(!isConfigured()); // must not be configured yet
enforcedArgumentTypes = new ArrayList<>();
this.extraArgs = SkylarkSignatureProcessor.getExtraArgs(annotation);
- super.configure(annotation);
this.returnType = annotation.returnType();
+ super.configure(annotation);
}
// finds the method and makes it accessible (which is needed to find it, and later to use it)
@@ -273,7 +273,10 @@ public class BuiltinFunction extends BaseFunction {
if (type == HackHackEitherList.class) {
type = Object.class;
}
- Preconditions.checkArgument(type == invokeMethod.getReturnType());
+ Class<?> methodReturnType = invokeMethod.getReturnType();
+ Preconditions.checkArgument(type == methodReturnType,
+ "signature for function %s says it returns %s but its invoke method returns %s",
+ getName(), returnType, methodReturnType);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
index 2e94be8706..bff06d5348 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
@@ -15,17 +15,16 @@ package com.google.devtools.build.lib.syntax;
import com.google.common.collect.ImmutableList;
-
/**
* A helper class for calling Skylark functions from Java.
*/
public class SkylarkCallbackFunction {
- private final UserDefinedFunction callback;
+ private final Function callback;
private final FuncallExpression ast;
private final SkylarkEnvironment funcallEnv;
- public SkylarkCallbackFunction(UserDefinedFunction callback, FuncallExpression ast,
+ public SkylarkCallbackFunction(Function callback, FuncallExpression ast,
SkylarkEnvironment funcallEnv) {
this.callback = callback;
this.ast = ast;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
index b264dd699b..11e35227b7 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
@@ -205,8 +205,8 @@ public class SkylarkEnvironment extends Environment implements Serializable {
List<Class<?>> modulesToRemove = new ArrayList<>();
for (Map.Entry<String, Object> entry : env.entrySet()) {
Object object = entry.getValue();
- if (object instanceof SkylarkFunction) {
- if (((SkylarkFunction) object).isOnlyLoadingPhase()) {
+ if (object instanceof BaseFunction) {
+ if (((BaseFunction) object).isOnlyLoadingPhase()) {
objectsToRemove.add(entry.getKey());
}
} else if (object.getClass().isAnnotationPresent(SkylarkModule.class)) {