aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/syntax
diff options
context:
space:
mode:
authorGravatar cparsons <cparsons@google.com>2018-06-21 12:04:59 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-06-21 12:06:20 -0700
commit474d4a1bd59a1c41d6c23b1ee7fce08df903afc7 (patch)
tree6609c315bee8cd3639ab6dc9533ec7f66abe1f8f /src/main/java/com/google/devtools/build/lib/syntax
parentf24479d495df540bae634b5ff2dde3177585c2a3 (diff)
Create a method for initializing build API libraries using object instances instead of object classes.
This allows the caller to, for example, initialize the global library before adding it to a global frame. The skylark interpreter will no longer require that global libraries have a zero-arg constructor. RELNOTES: None. PiperOrigin-RevId: 201563608
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/syntax')
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Runtime.java69
1 files changed, 56 insertions, 13 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
index 48129f4955..08c9a2a1cf 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
@@ -330,9 +330,12 @@ public final class Runtime {
* Convenience overload of {@link #setupModuleGlobals(ImmutableMap.Builder, Class)} to add
* bindings directly to an {@link Environment}.
*
- * @param env the Environment into which to register fields.
- * @param moduleClass the Class object containing globals.
+ * @param env the Environment into which to register fields
+ * @param moduleClass the Class object containing globals
+ * @deprecated use {@link #setupSkylarkLibrary} instead (and {@link SkylarkCallable} instead of
+ * {@link SkylarkSignature})
*/
+ @Deprecated
public static void setupModuleGlobals(Environment env, Class<?> moduleClass) {
ImmutableMap.Builder<String, Object> envBuilder = ImmutableMap.builder();
@@ -365,15 +368,16 @@ public final class Runtime {
* @param builder the builder for the "bindings" map, which maps from symbol names to objects,
* and which will be built into a global frame
* @param moduleClass the Class object containing globals
+ * @deprecated use {@link #setupSkylarkLibrary} instead (and {@link SkylarkCallable} instead of
+ * {@link SkylarkSignature})
*/
+ @Deprecated
public static void setupModuleGlobals(ImmutableMap.Builder<String, Object> builder,
Class<?> moduleClass) {
try {
- SkylarkModule skylarkModule = SkylarkInterfaceUtils.getSkylarkModule(moduleClass);
- if (skylarkModule != null) {
- builder.put(
- skylarkModule.name(),
- moduleClass.getConstructor().newInstance());
+ if (SkylarkInterfaceUtils.getSkylarkModule(moduleClass) != null
+ || SkylarkInterfaceUtils.hasSkylarkGlobalLibrary(moduleClass)) {
+ setupSkylarkLibrary(builder, moduleClass.getConstructor().newInstance());
}
for (Field field : moduleClass.getDeclaredFields()) {
if (field.isAnnotationPresent(SkylarkSignature.class)) {
@@ -390,14 +394,53 @@ public final class Runtime {
}
}
}
- if (SkylarkInterfaceUtils.hasSkylarkGlobalLibrary(moduleClass)) {
- Object moduleInstance = moduleClass.getConstructor().newInstance();
- for (String methodName : FuncallExpression.getMethodNames(moduleClass)) {
- builder.put(methodName, FuncallExpression.getBuiltinCallable(moduleInstance, methodName));
- }
- }
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
+
+ /**
+ * Adds global (top-level) symbols, provided by the given object, to the given bindings
+ * builder.
+ *
+ * <p>Global symbols may be provided by the given object in the following ways:
+ * <ul>
+ * <li>If its class is annotated with {@link SkylarkModule}, an instance of that object is
+ * a global object with the module's name.</li>
+ * <li>If its class is annotated with {@link SkylarkGlobalLibrary}, then all of its methods
+ * which are annotated with
+ * {@link com.google.devtools.build.lib.skylarkinterface.SkylarkCallable} are global
+ * callables.</li>
+ * </ul>
+ *
+ * <p>On collisions, this method throws an {@link AssertionError}. Collisions may occur if
+ * multiple global libraries have functions of the same name, two modules of the same name
+ * are given, or if two subclasses of the same module are given.
+ *
+ * @param builder the builder for the "bindings" map, which maps from symbol names to objects,
+ * and which will be built into a global frame
+ * @param moduleInstance the object containing globals
+ * @throws AssertionError if there are name collisions
+ * @throws IllegalArgumentException if {@code moduleInstance} is not annotated with
+ * {@link SkylarkGlobalLibrary} nor {@link SkylarkModule}
+ */
+ public static void setupSkylarkLibrary(ImmutableMap.Builder<String, Object> builder,
+ Object moduleInstance) {
+ Class<?> moduleClass = moduleInstance.getClass();
+ SkylarkModule skylarkModule = SkylarkInterfaceUtils.getSkylarkModule(moduleClass);
+ boolean hasSkylarkGlobalLibrary = SkylarkInterfaceUtils.hasSkylarkGlobalLibrary(moduleClass);
+
+ Preconditions.checkArgument(hasSkylarkGlobalLibrary || skylarkModule != null,
+ "%s must be annotated with @SkylarkGlobalLibrary or @SkylarkModule",
+ moduleClass);
+
+ if (skylarkModule != null) {
+ builder.put(skylarkModule.name(), moduleInstance);
+ }
+ if (hasSkylarkGlobalLibrary) {
+ for (String methodName : FuncallExpression.getMethodNames(moduleClass)) {
+ builder.put(methodName, FuncallExpression.getBuiltinCallable(moduleInstance, methodName));
+ }
+ }
+ }
}