// Copyright 2015 The Bazel Authors. 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.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary;
import com.google.devtools.build.lib.skylarkinterface.SkylarkInterfaceUtils;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import javax.annotation.Nullable;

/** Global constants and support for static registration of builtin symbols. */
// TODO(adonovan): migrate None and Unbound to Starlark.java. Get rid of the rest.
public final class Runtime {

  private Runtime() {}

  // (for documentation only)
  @SkylarkSignature(name = "True", returnType = Boolean.class, doc = "The Boolean true value.")
  private static final Boolean TRUE = true;

  // (for documentation only)
  @SkylarkSignature(name = "False", returnType = Boolean.class, doc = "The Boolean false value.")
  private static final Boolean FALSE = false;

  /** There should be only one instance of this type to allow "== None" tests. */
  @SkylarkModule(
    name = "NoneType",
    documented = false,
    doc = "Unit type, containing the unique value None."
  )
  @Immutable
  public static final class NoneType implements SkylarkValue {
    private NoneType() {}

    @Override
    public String toString() {
      return "None";
    }

    @Override
    public boolean isImmutable() {
      return true;
    }

    @Override
    public boolean truth() {
      return false;
    }

    @Override
    public void repr(SkylarkPrinter printer) {
      printer.append("None");
    }
  }

  /** Marker for unbound variables in cases where neither Java null nor Skylark None is suitable. */
  @Immutable
  public static final class UnboundMarker implements SkylarkValue {
    private UnboundMarker() {}

    @Override
    public String toString() {
      return "<unbound>";
    }

    @Override
    public boolean isImmutable() {
      return true;
    }

    @Override
    public void repr(SkylarkPrinter printer) {
      printer.append("<unbound>");
    }
  }

  @SkylarkSignature(
      name = "<unbound>",
      returnType = UnboundMarker.class,
      documented = false,
      doc = "Marker for unbound values in cases where neither Starlark None nor Java null can do.")
  public static final UnboundMarker UNBOUND = new UnboundMarker();

  @SkylarkSignature(name = "None", returnType = NoneType.class,
      doc = "Literal for the None value.")
  public static final NoneType NONE = new NoneType();

  // (for documentation only)
  @SkylarkSignature(
      name = "PACKAGE_NAME",
      returnType = String.class,
      doc =
          "<b>Deprecated. Use <a href=\"native.html#package_name\">package_name()</a> instead.</b>"
              + " The name of the package being evaluated. For example, in the BUILD file"
              + " <code>some/package/BUILD</code>, its value will be <code>some/package</code>. If"
              + " the BUILD file calls a function defined in a .bzl file, PACKAGE_NAME will match"
              + " the caller BUILD file package. In .bzl files, do not access PACKAGE_NAME at the"
              + " file-level (outside of functions), either directly or by calling a function at"
              + " the file-level that accesses PACKAGE_NAME (PACKAGE_NAME is only defined during"
              + " BUILD file evaluation).Here is an example of a .bzl file:<br><pre"
              + " class=language-python># a = PACKAGE_NAME  # not allowed outside functions\n"
              + "def extension():\n"
              + "  return PACKAGE_NAME</pre>In this case, <code>extension()</code> can be called"
              + " from a BUILD file (even indirectly), but not in a file-level expression in the"
              + " .bzl file. When implementing a rule, use <a"
              + " href=\"ctx.html#label\">ctx.label</a> to know where the rule comes from. ")
  private final String unusedPackageName = "PACKAGE_NAME";

  // (for documentation only)
  @SkylarkSignature(
      name = "REPOSITORY_NAME",
      returnType = String.class,
      doc =
          "<b>Deprecated. Use <a href=\"native.html#repository_name\">repository_name()</a> "
              + "instead.</b> The name of the repository the rule or build extension is called "
              + "from. "
              + "For example, in packages that are called into existence by the WORKSPACE stanza "
              + "<code>local_repository(name='local', path=...)</code> it will be set to "
              + "<code>@local</code>. In packages in the main repository, it will be set to "
              + "<code>@</code>. It can only be accessed in functions (transitively) called from "
              + "BUILD files, i.e. it follows the same restrictions as "
              + "<a href=\"#PACKAGE_NAME\">PACKAGE_NAME</a>.")
  private final String unusedRepositoryName = "REPOSITORY_NAME";

  /**
   * Returns the canonical class representing the namespace associated with the given class, i.e.,
   * the class under which builtins should be registered.
   */
  private static Class<?> getSkylarkNamespace(Class<?> clazz) {
    return String.class.isAssignableFrom(clazz)
        ? StringModule.class
        : EvalUtils.getSkylarkType(clazz);
  }

  /**
   * A registry of builtins, including both global builtins and builtins that are under some
   * namespace.
   *
   * <p>The registry contains Starlark universal builtins (None, len, etc), core build-language
   * functions (depset, select, glob, etc), members of the native module (FilesetEntry,
   * local_repository, vardef, ...), but not the native rules (cc_library, etc) nor other built-ins
   * (CcCompilationInfo, java_common.JavaRuntimeInfo, etc).
   *
   * <p>Concurrency model: This object is thread-safe. Read accesses are always allowed, while write
   * accesses are only allowed before this object has been frozen ({@link #freeze}). Prior to
   * freezing, all operations are synchronized, while after freezing they are lockless.
   */
  @Deprecated
  public static class BuiltinRegistry {

    /**
     * Whether the registry's construction has completed.
     *
     * <p>Mutating methods may only be called while this is still false. Accessor methods may be
     * called at any time.
     *
     * <p>We use {@code volatile} rather than {@link AtomicBoolean} because the bit flip only
     * happens once, and doesn't require correlated reads and writes.
     */
    private volatile boolean frozen = false;

    /**
     * All registered builtins, keyed and sorted by an identifying (but otherwise unimportant)
     * string.
     *
     * <p>The string is typically formed from the builtin's simple name and the Java class in which
     * it is defined. The Java class need not correspond to a namespace. (This map includes global
     * builtins that have no namespace.)
     */
    private final Map<String, Object> allBuiltins = new TreeMap<>();

    /** All non-global builtin functions, keyed by their namespace class and their name. */
    private final Map<Class<?>, Map<String, BaseFunction>> functions = new HashMap<>();

    /**
     * Marks the registry as initialized, if it wasn't already.
     *
     * <p>It is guaranteed that after this method returns, all accessor methods are safe without
     * synchronization; i.e. no mutation operation can touch the data structures.
     */
    public void freeze() {
      // Similar to double-checked locking, but no need to check again on the inside since we don't
      // care if two threads set the bit at once. The synchronized block is only to provide
      // exclusion with mutations.
      if (!this.frozen) {
        synchronized (this) {
          this.frozen = true;
        }
      }
    }

    /** Registers a builtin with the given simple name, that was defined in the given Java class. */
    public synchronized void registerBuiltin(Class<?> definingClass, String name, Object builtin) {
      String key = String.format("%s.%s", definingClass.getName(), name);
      Preconditions.checkArgument(
          !allBuiltins.containsKey(key),
          "Builtin '%s' registered multiple times",
          key);

      Preconditions.checkState(
          !frozen,
          "Attempted to register builtin '%s' after registry has already been frozen",
          key);

      allBuiltins.put(key, builtin);
    }

    /**
     * Registers a function underneath a namespace.
     *
     * <p>This is independent of {@link #registerBuiltin}.
     */
    synchronized void registerFunction(Class<?> namespace, BaseFunction function) {
      Preconditions.checkNotNull(namespace);
      Preconditions.checkNotNull(function.getObjectType());
      Class<?> skylarkNamespace = getSkylarkNamespace(namespace);
      Preconditions.checkArgument(skylarkNamespace.equals(namespace));
      Class<?> objType = getSkylarkNamespace(function.getObjectType());
      Preconditions.checkArgument(objType.equals(skylarkNamespace));

      Preconditions.checkState(
          !frozen,
          "Attempted to register function '%s' in namespace '%s' after registry has already been "
              + "frozen",
          function,
          namespace);

      functions.computeIfAbsent(namespace, k -> new HashMap<>());
      functions.get(namespace).put(function.getName(), function);
    }

    /** Returns a list of all registered builtins, in a deterministic order. */
    public ImmutableList<Object> getBuiltins() {
      if (frozen) {
        return ImmutableList.copyOf(allBuiltins.values());
      } else {
        synchronized (this) {
          return ImmutableList.copyOf(allBuiltins.values());
        }
      }
    }

    @Nullable
    private Map<String, BaseFunction> getFunctionsInNamespace(Class<?> namespace) {
      return functions.get(getSkylarkNamespace(namespace));
    }

    /**
     * Given a namespace, returns the function with the given name.
     *
     * <p>If the namespace does not exist or has no function with that name, returns null.
     */
    BaseFunction getFunction(Class<?> namespace, String name) {
      if (frozen) {
        Map<String, BaseFunction> namespaceFunctions = getFunctionsInNamespace(namespace);
        return namespaceFunctions != null ? namespaceFunctions.get(name) : null;
      } else {
        synchronized (this) {
          Map<String, BaseFunction> namespaceFunctions = getFunctionsInNamespace(namespace);
          return namespaceFunctions != null ? namespaceFunctions.get(name) : null;
        }
      }
    }

    /**
     * Given a namespace, returns all function names.
     *
     * <p>If the namespace does not exist, returns an empty set.
     */
    ImmutableSet<String> getFunctionNames(Class<?> namespace) {
      if (frozen) {
        Map<String, BaseFunction> namespaceFunctions = getFunctionsInNamespace(namespace);
        if (namespaceFunctions == null) {
          return ImmutableSet.of();
        }
        return ImmutableSet.copyOf(namespaceFunctions.keySet());
      } else {
        synchronized (this) {
          Map<String, BaseFunction> namespaceFunctions = getFunctionsInNamespace(namespace);
          if (namespaceFunctions == null) {
            return ImmutableSet.of();
          }
          return ImmutableSet.copyOf(namespaceFunctions.keySet());
        }
      }
    }
  }

  /**
   * All Skylark builtins.
   *
   * <p>Note that just because a symbol is registered here does not necessarily mean that it is
   * accessible in a particular {@link StarlarkThread}. This registry should include any builtin
   * that is available in any environment.
   *
   * <p>Thread safety: This object is unsynchronized. The register functions are typically called
   * from within static initializer blocks, which should be fine.
   */
  private static final BuiltinRegistry builtins = new BuiltinRegistry();

  /**
   * Retrieve the static instance containing information on all known Skylark builtins.
   *
   * @deprecated do not use a static singleton registry -- instead set up the Skylark environment
   *     with 'global' objects
   */
  @Deprecated
  public static BuiltinRegistry getBuiltinRegistry() {
    return builtins;
  }

  /**
   * 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 : CallUtils.getMethodNames(moduleClass)) {
        builder.put(methodName, CallUtils.getBuiltinCallable(moduleInstance, methodName));
      }
    }
  }
}
