diff options
author | cparsons <cparsons@google.com> | 2018-06-21 12:04:59 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-06-21 12:06:20 -0700 |
commit | 474d4a1bd59a1c41d6c23b1ee7fce08df903afc7 (patch) | |
tree | 6609c315bee8cd3639ab6dc9533ec7f66abe1f8f /src/main/java/com/google/devtools/build/lib/syntax | |
parent | f24479d495df540bae634b5ff2dde3177585c2a3 (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.java | 69 |
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)); + } + } + } } |