8686import net .starlark .java .syntax .StringLiteral ;
8787
8888/**
89- * A Skyframe function to look up and load a single .bzl module.
89+ * A Skyframe function to look up and load a single .bzl (or .scl) module.
90+ *
91+ * <p>Note: Historically, all modules had the .bzl suffix, but this is no longer true now that Bazel
92+ * supports the .scl dialect. In identifiers, code comments, and documentation, you should generally
93+ * assume any "bzl" term could mean a .scl file as well.
9094 *
9195 * <p>Given a {@link Label} referencing a .bzl file, attempts to locate the file and load it. The
9296 * Label must be absolute, and must not reference the special {@code external} package. If loading
@@ -736,6 +740,14 @@ private BzlLoadValue computeInternalWithCompiledBzl(
736740 Label label = key .getLabel ();
737741 PackageIdentifier pkg = label .getPackageIdentifier ();
738742
743+ boolean isSclFlagEnabled =
744+ builtins .starlarkSemantics .getBool (BuildLanguageOptions .EXPERIMENTAL_ENABLE_SCL_DIALECT );
745+ if (key .isSclDialect () && !isSclFlagEnabled ) {
746+ throw new BzlLoadFailedException (
747+ "loading .scl files requires setting --experimental_enable_scl_dialect" ,
748+ Code .PARSE_ERROR );
749+ }
750+
739751 // Determine dependency BzlLoadValue keys for the load statements in this bzl.
740752 // Labels are resolved relative to the current repo mapping.
741753 RepositoryMapping repoMapping = getRepositoryMapping (key , builtins .starlarkSemantics , env );
@@ -744,7 +756,13 @@ private BzlLoadValue computeInternalWithCompiledBzl(
744756 }
745757 ImmutableList <Pair <String , Location >> programLoads = getLoadsFromProgram (prog );
746758 ImmutableList <Label > loadLabels =
747- getLoadLabels (env .getListener (), programLoads , pkg , repoMapping );
759+ getLoadLabels (
760+ env .getListener (),
761+ programLoads ,
762+ pkg ,
763+ repoMapping ,
764+ key .isSclDialect (),
765+ isSclFlagEnabled );
748766 if (loadLabels == null ) {
749767 throw new BzlLoadFailedException (
750768 String .format (
@@ -933,11 +951,59 @@ private static RepositoryMapping getRepositoryMapping(
933951 return repositoryMappingValue .getRepositoryMapping ();
934952 }
935953
936- public static void checkValidLoadLabel (Label label , boolean fromBuiltinsRepo )
954+ /**
955+ * Validates a label appearing in a {@code load()} statement, throwing {@link
956+ * LabelSyntaxException} on failure.
957+ *
958+ * <p>Different restrictions apply depending on what type of source file the load appears in. For
959+ * all kinds of files, {@code label}:
960+ *
961+ * <ul>
962+ * <li>may not be within {@code @//external}.
963+ * <li>must end with either {@code .bzl} or {@code .scl}.
964+ * </ul>
965+ *
966+ * <p>For source files appearing within {@code @_builtins}, {@code label} must also be within
967+ * {@code @_builtins}. (The reverse, that those files may not be loaded by user-defined files, is
968+ * enforced by the fact that the {@code @_builtins} pseudorepo cannot be resolved as an ordinary
969+ * repo.)
970+ *
971+ * <p>For .scl files only, {@code label} must end with {@code .scl} (not {@code .bzl}). (Loads in
972+ * .scl also should always begin with {@code //}, but that's syntactic and can't be enforced in
973+ * this method.)
974+ *
975+ * @param label the label to validate
976+ * @param fromBuiltinsRepo true if the file containing the load is within {@code @_builtins}
977+ * @param withinSclDialect true if the file containing the load is a .scl file
978+ * @param mentionSclInErrorMessage true if ".scl" should be advertised as a possible extension in
979+ * error messaging
980+ */
981+ private static void checkValidLoadLabel (
982+ Label label ,
983+ boolean fromBuiltinsRepo ,
984+ boolean withinSclDialect ,
985+ boolean mentionSclInErrorMessage )
937986 throws LabelSyntaxException {
938- if (!label .getName ().endsWith (".bzl" )) {
939- throw new LabelSyntaxException ("The label must reference a file with extension '.bzl'" );
987+ // Check file extension.
988+ String baseName = label .getName ();
989+ if (withinSclDialect ) {
990+ if (!baseName .endsWith (".scl" )) {
991+ String msg = "The label must reference a file with extension \" .scl\" " ;
992+ if (baseName .endsWith (".bzl" )) {
993+ msg += " (.scl files cannot load .bzl files)" ;
994+ }
995+ throw new LabelSyntaxException (msg );
996+ }
997+ } else {
998+ if (!(baseName .endsWith (".scl" ) || baseName .endsWith (".bzl" ))) {
999+ String msg = "The label must reference a file with extension \" .bzl\" " ;
1000+ if (mentionSclInErrorMessage ) {
1001+ msg += " or \" .scl\" " ;
1002+ }
1003+ throw new LabelSyntaxException (msg );
1004+ }
9401005 }
1006+
9411007 if (label .getPackageIdentifier ().equals (LabelConstants .EXTERNAL_PACKAGE_IDENTIFIER )) {
9421008 throw new LabelSyntaxException (
9431009 "Starlark files may not be loaded from the //external package" );
@@ -948,35 +1014,57 @@ public static void checkValidLoadLabel(Label label, boolean fromBuiltinsRepo)
9481014 }
9491015 }
9501016
1017+ /**
1018+ * Validates a label appearing in a {@code load()} statement, throwing {@link
1019+ * LabelSyntaxException} on failure.
1020+ */
1021+ public static void checkValidLoadLabel (Label label , StarlarkSemantics starlarkSemantics )
1022+ throws LabelSyntaxException {
1023+ checkValidLoadLabel (
1024+ label ,
1025+ /* fromBuiltinsRepo= */ false ,
1026+ /* withinSclDialect= */ false ,
1027+ /* mentionSclInErrorMessage= */ starlarkSemantics .getBool (
1028+ BuildLanguageOptions .EXPERIMENTAL_ENABLE_SCL_DIALECT ));
1029+ }
1030+
9511031 /**
9521032 * Given a list of {@code load("module")} strings and their locations, in source order, returns a
9531033 * corresponding list of Labels they each resolve to. Labels are resolved relative to {@code
9541034 * base}, the file's package. If any label is malformed, the function reports one or more errors
9551035 * to the handler and returns null.
1036+ *
1037+ * <p>If {@code withinSclDialect} is true, the labels are validated according to the rules of the
1038+ * .scl dialect: Only strings beginning with {@code //} are allowed (no repo syntax, no relative
1039+ * labels), and only .scl files may be loaded (not .bzl). If {@code isSclFlagEnabled} is true,
1040+ * then ".scl" is mentioned as a possible file extension in error messages.
9561041 */
9571042 @ Nullable
958- static ImmutableList <Label > getLoadLabels (
1043+ private static ImmutableList <Label > getLoadLabels (
9591044 EventHandler handler ,
9601045 ImmutableList <Pair <String , Location >> loads ,
9611046 PackageIdentifier base ,
962- RepositoryMapping repoMapping ) {
963- // It's redundant that getRelativeWithRemapping needs a Label;
964- // a PackageIdentifier should suffice. Make one here.
965- Label buildLabel = getBUILDLabel (base );
966-
1047+ RepositoryMapping repoMapping ,
1048+ boolean withinSclDialect ,
1049+ boolean isSclFlagEnabled ) {
9671050 boolean ok = true ;
9681051
9691052 ImmutableList .Builder <Label > loadLabels = ImmutableList .builderWithExpectedSize (loads .size ());
9701053 for (Pair <String , Location > load : loads ) {
971- // Parse the load statement's module string as a label.
972- // It must end in .bzl and not be in package "//external".
1054+ // Parse the load statement's module string as a label. Validate the unparsed string for
1055+ // syntax and the parsed label for structure.
1056+ String unparsedLabel = load .first ;
9731057 try {
1058+ if (withinSclDialect && !unparsedLabel .startsWith ("//" )) {
1059+ throw new LabelSyntaxException ("in .scl files, load labels must begin with \" //\" " );
1060+ }
9741061 Label label =
975- Label .parseWithPackageContext (
976- load .first , PackageContext .of (buildLabel .getPackageIdentifier (), repoMapping ));
1062+ Label .parseWithPackageContext (unparsedLabel , PackageContext .of (base , repoMapping ));
9771063 checkValidLoadLabel (
9781064 label ,
979- /* fromBuiltinsRepo= */ StarlarkBuiltinsValue .isBuiltinsRepo (base .getRepository ()));
1065+ /* fromBuiltinsRepo= */ StarlarkBuiltinsValue .isBuiltinsRepo (base .getRepository ()),
1066+ /* withinSclDialect= */ withinSclDialect ,
1067+ /* mentionSclInErrorMessage= */ isSclFlagEnabled );
9801068 loadLabels .add (label );
9811069 } catch (LabelSyntaxException ex ) {
9821070 handler .handle (Event .error (load .second , "in load statement: " + ex .getMessage ()));
@@ -986,6 +1074,29 @@ static ImmutableList<Label> getLoadLabels(
9861074 return ok ? loadLabels .build () : null ;
9871075 }
9881076
1077+ /**
1078+ * Given a list of {@code load("module")} strings and their locations, in source order, returns a
1079+ * corresponding list of Labels they each resolve to. Labels are resolved relative to {@code
1080+ * base}, the file's package. If any label is malformed, the function reports one or more errors
1081+ * to the handler and returns null.
1082+ */
1083+ @ Nullable
1084+ static ImmutableList <Label > getLoadLabels (
1085+ EventHandler handler ,
1086+ ImmutableList <Pair <String , Location >> loads ,
1087+ PackageIdentifier base ,
1088+ RepositoryMapping repoMapping ,
1089+ StarlarkSemantics starlarkSemantics ) {
1090+ return getLoadLabels (
1091+ handler ,
1092+ loads ,
1093+ base ,
1094+ repoMapping ,
1095+ /* withinSclDialect= */ false ,
1096+ /* isSclFlagEnabled= */ starlarkSemantics .getBool (
1097+ BuildLanguageOptions .EXPERIMENTAL_ENABLE_SCL_DIALECT ));
1098+ }
1099+
9891100 /** Extracts load statements from compiled program (see {@link #getLoadLabels}). */
9901101 static ImmutableList <Pair <String , Location >> getLoadsFromProgram (Program prog ) {
9911102 int n = prog .getLoads ().size ();
@@ -1010,15 +1121,6 @@ static ImmutableList<Pair<String, Location>> getLoadsFromStarlarkFiles(List<Star
10101121 return loads .build ();
10111122 }
10121123
1013- private static Label getBUILDLabel (PackageIdentifier pkgid ) {
1014- try {
1015- return Label .create (pkgid , "BUILD" );
1016- } catch (LabelSyntaxException e ) {
1017- // Shouldn't happen; the Label is well-formed by construction.
1018- throw new IllegalStateException (e );
1019- }
1020- }
1021-
10221124 /**
10231125 * Computes the BzlLoadValue for all given .bzl load keys using ordinary Skyframe evaluation,
10241126 * returning {@code null} if Skyframe deps were missing and have been requested. {@code
0 commit comments