// Copyright 2020 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.skyframe;

import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import net.starlark.java.eval.StarlarkSemantics;

/**
 * A Skyframe value representing the result of evaluating the {@code @_builtins} pseudo-repository.
 *
 * <p>To avoid unnecessary Skyframe edges, the {@code StarlarkSemantics} are included in this value,
 * so that a caller who obtains a StarlarkBuiltinsValue can also access the StarlarkSemantics
 * without an additional dependency.
 *
 * <p>These are parsed from {@code @_builtins//:exports.bzl}.
 */
public final class StarlarkBuiltinsValue implements SkyValue {

  static final String BUILTINS_NAME = "@_builtins";

  /**
   * The builtins pseudo-repository.
   *
   * <p>It is illegal to declare a repository in WORKSPACE whose name collides with this one.
   * Whether a collision has in fact occurred is determined by {@link RepositoryName#equals}, and
   * hence depends on the OS path policy (i.e. the case sensitivity of the host system).
   *
   * <p>Regardless of path policy, all actual uses of the builtins pseudo-repo are case sensitive
   * and must match {@link #BUILTINS_NAME} exactly.
   */
  // TODO(#11437): Add actual enforcement that users cannot define a repo named "@_builtins".
  @SerializationConstant static final RepositoryName BUILTINS_REPO;

  /** Reports whether the given repository is the special builtins pseudo-repository. */
  static boolean isBuiltinsRepo(RepositoryName repo) {
    // Use String.equals(), not RepositoryName.equals(), to force case sensitivity.
    return repo.getName().equals(BUILTINS_NAME);
  }

  static {
    try {
      BUILTINS_REPO = RepositoryName.create(BUILTINS_NAME);
    } catch (LabelSyntaxException e) {
      throw new IllegalStateException(e);
    }
  }

  // These are all (except transitiveDigest) deeply immutable since the Starlark values are already
  // frozen, so let's skip the accessors and mutators.

  /**
   * Top-level predeclared symbols for a .bzl file loaded on behalf of a BUILD file, after builtins
   * injection has been applied.
   */
  public final ImmutableMap<String, Object> predeclaredForBuildBzl;

  /**
   * Top-level predeclared symbols for a BUILD file, after builtins injection but before any prelude
   * file has been applied.
   */
  public final ImmutableMap<String, Object> predeclaredForBuild;

  /** Contents of the {@code exported_to_java} dict. */
  public final ImmutableMap<String, Object> exportedToJava;

  /** Transitive digest of all .bzl files in {@code @_builtins}. */
  public final byte[] transitiveDigest;

  /** The StarlarkSemantics used for {@code @_builtins} evaluation. */
  public final StarlarkSemantics starlarkSemantics;

  private StarlarkBuiltinsValue(
      ImmutableMap<String, Object> predeclaredForBuildBzl,
      ImmutableMap<String, Object> predeclaredForBuild,
      ImmutableMap<String, Object> exportedToJava,
      byte[] transitiveDigest,
      StarlarkSemantics starlarkSemantics) {
    this.predeclaredForBuildBzl = predeclaredForBuildBzl;
    this.predeclaredForBuild = predeclaredForBuild;
    this.exportedToJava = exportedToJava;
    this.transitiveDigest = transitiveDigest;
    this.starlarkSemantics = starlarkSemantics;
  }

  public static StarlarkBuiltinsValue create(
      ImmutableMap<String, Object> predeclaredForBuildBzl,
      ImmutableMap<String, Object> predeclaredForBuild,
      ImmutableMap<String, Object> exportedToJava,
      byte[] transitiveDigest,
      StarlarkSemantics starlarkSemantics) {
    return new StarlarkBuiltinsValue(
        predeclaredForBuildBzl,
        predeclaredForBuild,
        exportedToJava,
        transitiveDigest,
        starlarkSemantics);
  }

  /**
   * Constructs a placeholder builtins value to be used when builtins injection is disabled, or for
   * use within builtins evaluation itself.
   *
   * <p>The placeholder simply wraps the StarlarkSemantics object. This lets code paths that don't
   * use injection still conveniently access the semantics without incurring a separate Skyframe
   * edge.
   */
  public static StarlarkBuiltinsValue createEmpty(StarlarkSemantics starlarkSemantics) {
    return new StarlarkBuiltinsValue(
        /*predeclaredForBuildBzl=*/ ImmutableMap.of(),
        /*predeclaredForBuild=*/ ImmutableMap.of(),
        /*exportedToJava=*/ ImmutableMap.of(),
        /*transitiveDigest=*/ new byte[] {},
        starlarkSemantics);
  }

  /** Returns the singleton SkyKey for this type of value. */
  public static Key key() {
    return Key.INSTANCE;
  }

  /**
   * Skyframe key for retrieving the {@code @_builtins} definitions.
   *
   * <p>This has no fields since there is only one {@code StarlarkBuiltinsValue} at a time.
   */
  static final class Key implements SkyKey {

    private static final Key INSTANCE = new Key();

    private Key() {}

    @Override
    public SkyFunctionName functionName() {
      return SkyFunctions.STARLARK_BUILTINS;
    }

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

    @Override
    public boolean equals(Object other) {
      return other instanceof Key;
    }

    @Override
    public int hashCode() {
      return 7727; // more or less xkcd/221
    }
  }
}
