Make Skylark interpreter read Skylark command-line flags

This is the second of two CLs for making command line options able to affect the Skylark interpreter. For the main kinds of evaluation contexts -- package loading, .bzl loading, rule analysis, aspect analysis, and computed defaults -- the SkylarkSemanticsOptions object is retrieved from Skyframe and passed along to the Environment builder. For other contexts such as tests, default values of builtin functions, and standalone Skylark, flags are currently not processed.

In the future, we may want to split into separate files the options that affect "pure" Skylark vs the options that affect Bazel-flavored Skylark. One possibility is to subclass SkylarkSemanticsOptions into SkylarkBazelSemanticsOptions, and go through an indirection in SkylarkUtils.

We could also pass SkylarkSemanticsOptions to the parser, to support --incompatible_* changes that alter Skylark's syntax. I don't think that's needed at the moment.

RELNOTES: None
PiperOrigin-RevId: 154628391
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
index 9ac4789..6550ca2 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
@@ -27,6 +27,7 @@
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.SpellChecker;
+import com.google.devtools.common.options.Options;
 import java.io.Serializable;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -306,6 +307,11 @@
   private final Frame dynamicFrame;
 
   /**
+   * The semantics options that affect how Skylark code is evaluated.
+   */
+  private final SkylarkSemanticsOptions semantics;
+
+  /**
    * An EventHandler for errors and warnings. This is not used in the BUILD language,
    * however it might be used in Skylark code called from the BUILD language, so shouldn't be null.
    */
@@ -472,6 +478,7 @@
   private Environment(
       Frame globalFrame,
       Frame dynamicFrame,
+      SkylarkSemanticsOptions semantics,
       EventHandler eventHandler,
       Map<String, Extension> importedExtensions,
       @Nullable String fileContentHashCode,
@@ -481,6 +488,7 @@
     this.dynamicFrame = Preconditions.checkNotNull(dynamicFrame);
     Preconditions.checkArgument(globalFrame.mutability().isMutable());
     Preconditions.checkArgument(dynamicFrame.mutability().isMutable());
+    this.semantics = semantics;
     this.eventHandler = eventHandler;
     this.importedExtensions = importedExtensions;
     this.phase = phase;
@@ -496,6 +504,7 @@
     private final Mutability mutability;
     private Phase phase = Phase.ANALYSIS;
     @Nullable private Frame parent;
+    @Nullable private SkylarkSemanticsOptions semantics;
     @Nullable private EventHandler eventHandler;
     @Nullable private Map<String, Extension> importedExtensions;
     @Nullable private String fileContentHashCode;
@@ -527,6 +536,11 @@
       return this;
     }
 
+    public Builder setSemantics(SkylarkSemanticsOptions semantics) {
+      this.semantics = semantics;
+      return this;
+    }
+
     /** Sets an EventHandler for errors and warnings. */
     public Builder setEventHandler(EventHandler eventHandler) {
       Preconditions.checkState(this.eventHandler == null);
@@ -555,12 +569,16 @@
       }
       Frame globalFrame = new Frame(mutability, parent);
       Frame dynamicFrame = new Frame(mutability, null);
+      if (semantics == null) {
+        semantics = Options.getDefaults(SkylarkSemanticsOptions.class);
+      }
       if (importedExtensions == null) {
         importedExtensions = ImmutableMap.of();
       }
       return new Environment(
           globalFrame,
           dynamicFrame,
+          semantics,
           eventHandler,
           importedExtensions,
           fileContentHashCode,
@@ -723,6 +741,10 @@
     return knownGlobalVariables != null && knownGlobalVariables.contains(varname);
   }
 
+  public SkylarkSemanticsOptions getSemantics() {
+    return semantics;
+  }
+
   public void handleEvent(Event event) {
     eventHandler.handle(event);
   }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
index b3f1e6b..d84fbc4 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
@@ -2080,6 +2080,12 @@
                 public String apply(Object input) {
                   return Printer.str(input);
                 }}));
+      // As part of the integration test "skylark_flag_test.sh", if the
+      // "--internal_skylark_flag_test_canary" flag is enabled, append an extra marker string to the
+      // output.
+      if (env.getSemantics().skylarkFlagTestCanary) {
+        msg += "<== skylark flag test ==>";
+      }
       env.handleEvent(Event.warn(loc, msg));
       return Runtime.NONE;
     }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
index 6eb95ff..4d04ebd 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
@@ -40,6 +40,7 @@
       throws EvalException, InterruptedException {
     try (Mutability mutability = Mutability.create("callback %s", callback)) {
       Environment env = Environment.builder(mutability)
+          .setSemantics(funcallEnv.getSemantics())
           .setEventHandler(funcallEnv.getEventHandler())
           .setGlobals(funcallEnv.getGlobals())
           .build();
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemanticsOptions.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemanticsOptions.java
index 32a15fc..eb1fd0d 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemanticsOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemanticsOptions.java
@@ -14,7 +14,9 @@
 
 package com.google.devtools.build.lib.syntax;
 
+import com.google.devtools.common.options.Option;
 import com.google.devtools.common.options.OptionsBase;
+import com.google.devtools.common.options.OptionsParser.OptionUsageRestrictions;
 import com.google.devtools.common.options.UsesOnlyCoreTypes;
 import java.io.Serializable;
 
@@ -33,5 +35,11 @@
  */
 @UsesOnlyCoreTypes
 public class SkylarkSemanticsOptions extends OptionsBase implements Serializable {
-
+  // Used in an integration test to confirm that flags are visible to the interpreter.
+  @Option(
+      name = "internal_skylark_flag_test_canary",
+      defaultValue = "false",
+      optionUsageRestrictions = OptionUsageRestrictions.UNDOCUMENTED
+  )
+  public boolean skylarkFlagTestCanary;
 }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
index add8601..6e76520 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
@@ -175,6 +175,7 @@
       return Runtime.NONE;
     } else {
       try (Mutability mutability = Mutability.create("initialization")) {
+        // Note that this Skylark environment ignores command line flags.
         Environment env =
             Environment.builder(mutability)
                 .setGlobals(Environment.CONSTANTS_ONLY)