aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/syntax/Runtime.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Runtime.java176
1 files changed, 176 insertions, 0 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
new file mode 100644
index 0000000000..50ef2546d5
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
@@ -0,0 +1,176 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.syntax;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Global constants and support for global namespaces of runtime functions.
+ */
+public final class Runtime {
+
+ private Runtime() {}
+
+ @SkylarkSignature(name = "True", returnType = Boolean.class,
+ doc = "Literal for the boolean true.")
+ static final Boolean TRUE = true;
+
+ @SkylarkSignature(name = "False", returnType = Boolean.class,
+ doc = "Literal for the boolean false.")
+ static final Boolean FALSE = false;
+
+ /**
+ * There should be only one instance of this type to allow "== None" tests.
+ */
+ @Immutable
+ public static final class NoneType {
+ @Override
+ public String toString() { return "None"; }
+ private NoneType() {}
+ }
+
+ @SkylarkSignature(name = "None", returnType = NoneType.class,
+ doc = "Literal for the None value.")
+ public static final NoneType NONE = new NoneType();
+
+
+ @SkylarkSignature(name = "PACKAGE_NAME", returnType = String.class,
+ doc = "The name of the package the rule or build extension is called from. "
+ + "For example, in the BUILD file <code>some/package/BUILD</code>, its value "
+ + "will be <code>some/package</code>. "
+ + "This variable is special, because its value comes from outside of the extension "
+ + "module (it comes from the BUILD file), so it can only be accessed in functions "
+ + "(transitively) called from BUILD files. For example:<br>"
+ + "<pre class=language-python>def extension():\n"
+ + " return PACKAGE_NAME</pre>"
+ + "In this case calling <code>extension()</code> works from the BUILD file (if the "
+ + "function is loaded), but not as a top level function call in the extension module.")
+ public static final String PKG_NAME = "PACKAGE_NAME";
+
+ /**
+ * Set up a given environment for supported class methods.
+ */
+ static Environment setupConstants(Environment env) throws EvalException {
+ // In Python 2.x, True and False are global values and can be redefined by the user.
+ // In Python 3.x, they are keywords. We implement them as values, for the sake of
+ // simplicity. We define them as Boolean objects.
+ return env.update("False", FALSE).update("True", TRUE).update("None", NONE);
+ }
+
+
+ /** Global registry of functions associated to a class or namespace */
+ private static final Map<Class<?>, Map<String, BaseFunction>> functions = new HashMap<>();
+
+ /**
+ * Registers a function with namespace to this global environment.
+ */
+ public static void registerFunction(Class<?> nameSpace, BaseFunction function) {
+ Preconditions.checkNotNull(nameSpace);
+ // TODO(bazel-team): fix our code so that the two checks below work.
+ // Preconditions.checkArgument(function.getObjectType().equals(nameSpace));
+ // Preconditions.checkArgument(nameSpace.equals(getCanonicalRepresentation(nameSpace)));
+ nameSpace = getCanonicalRepresentation(nameSpace);
+ if (!functions.containsKey(nameSpace)) {
+ functions.put(nameSpace, new HashMap<String, BaseFunction>());
+ }
+ functions.get(nameSpace).put(function.getName(), function);
+ }
+
+ static Map<String, BaseFunction> getNamespaceFunctions(Class<?> nameSpace) {
+ return functions.get(getCanonicalRepresentation(nameSpace));
+ }
+
+ /**
+ * Returns the canonical representation of the given class, i.e. the super class for which any
+ * functions were registered.
+ *
+ * <p>Currently, this is only necessary for mapping the different subclasses of {@link
+ * java.util.Map} to the interface.
+ */
+ public static Class<?> getCanonicalRepresentation(Class<?> clazz) {
+ if (Map.class.isAssignableFrom(clazz)) {
+ return MethodLibrary.DictModule.class;
+ }
+ if (String.class.isAssignableFrom(clazz)) {
+ return MethodLibrary.StringModule.class;
+ }
+ if (List.class.isAssignableFrom(clazz)) {
+ return List.class;
+ }
+ return clazz;
+ }
+
+ /**
+ * Registers global fields with SkylarkSignature into the specified Environment.
+ * @param env the Environment into which to register fields.
+ * @param moduleClass the Class object containing globals.
+ */
+ public static void registerModuleGlobals(Environment env, Class<?> moduleClass) {
+ try {
+ if (moduleClass.isAnnotationPresent(SkylarkModule.class)) {
+ env.update(
+ moduleClass.getAnnotation(SkylarkModule.class).name(), moduleClass.newInstance());
+ }
+ for (Field field : moduleClass.getDeclaredFields()) {
+ if (field.isAnnotationPresent(SkylarkSignature.class)) {
+ // Fields in Skylark modules are sometimes private.
+ // Nevertheless they have to be annotated with SkylarkSignature.
+ field.setAccessible(true);
+ SkylarkSignature annotation = field.getAnnotation(SkylarkSignature.class);
+ Object value = field.get(null);
+ // Ignore function factories and non-global functions
+ if (!(value instanceof BuiltinFunction.Factory
+ || (value instanceof BaseFunction
+ && !annotation.objectType().equals(Object.class)))) {
+ env.update(annotation.name(), value);
+ }
+ }
+ }
+ } catch (IllegalAccessException | InstantiationException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
+ * Returns the function of the namespace of the given name or null of it does not exists.
+ */
+ public static BaseFunction getFunction(Class<?> nameSpace, String name) {
+ Map<String, BaseFunction> nameSpaceFunctions = getNamespaceFunctions(nameSpace);
+ return nameSpaceFunctions != null ? nameSpaceFunctions.get(name) : null;
+ }
+
+ /**
+ * Returns the function names registered with the namespace.
+ */
+ public static Set<String> getFunctionNames(Class<?> nameSpace) {
+ Map<String, BaseFunction> nameSpaceFunctions = getNamespaceFunctions(nameSpace);
+ return nameSpaceFunctions != null ? nameSpaceFunctions.keySet() : ImmutableSet.<String>of();
+ }
+
+ static void setupMethodEnvironment(
+ Environment env, Iterable<BaseFunction> functions) throws EvalException {
+ for (BaseFunction function : functions) {
+ env.update(function.getName(), function);
+ }
+ }
+}