Move global objects to Runtime

Move away global constants and global namespaces out of Environment
and into a new file Runtime.

--
MOS_MIGRATED_REVID=101940218
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 0000000..50ef2546
--- /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);
+    }
+  }
+}