blob: d70e2b82af615d8443bc8556d863ed636a1bf1c3 [file] [log] [blame]
Googler09eef852024-01-11 09:06:55 -08001// Copyright 2024 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.packages;
16
Googler11f06202024-04-11 20:50:39 -070017import com.google.auto.value.AutoValue;
Googler09eef852024-01-11 09:06:55 -080018import com.google.common.base.Preconditions;
Googler11f06202024-04-11 20:50:39 -070019import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Googler0287d922024-01-26 13:12:20 -080020import com.google.devtools.build.lib.events.Event;
21import com.google.devtools.build.lib.server.FailureDetails.PackageLoading.Code;
Googler09eef852024-01-11 09:06:55 -080022import com.google.errorprone.annotations.CanIgnoreReturnValue;
23import javax.annotation.Nullable;
Googler0287d922024-01-26 13:12:20 -080024import net.starlark.java.eval.EvalException;
25import net.starlark.java.eval.Mutability;
26import net.starlark.java.eval.Starlark;
Googler09eef852024-01-11 09:06:55 -080027import net.starlark.java.eval.StarlarkFunction;
Googler0287d922024-01-26 13:12:20 -080028import net.starlark.java.eval.StarlarkSemantics;
29import net.starlark.java.eval.StarlarkThread;
Googler11f06202024-04-11 20:50:39 -070030import net.starlark.java.eval.SymbolGenerator;
Googler09eef852024-01-11 09:06:55 -080031
32/**
33 * Represents a symbolic macro, defined in a .bzl file, that may be instantiated during Package
34 * evaluation.
35 *
36 * <p>This is analogous to {@link RuleClass}. In essence, a {@code MacroClass} consists of the
37 * macro's schema and its implementation function.
38 */
39public final class MacroClass {
40
41 private final String name;
42 private final StarlarkFunction implementation;
43
44 public MacroClass(String name, StarlarkFunction implementation) {
45 this.name = name;
46 this.implementation = implementation;
47 }
48
49 /** Returns the macro's exported name. */
50 public String getName() {
51 return name;
52 }
53
54 public StarlarkFunction getImplementation() {
55 return implementation;
56 }
57
58 /** Builder for {@link MacroClass}. */
59 public static final class Builder {
60 private final StarlarkFunction implementation;
61 @Nullable private String name = null;
62
63 public Builder(StarlarkFunction implementation) {
64 this.implementation = implementation;
65 }
66
67 @CanIgnoreReturnValue
68 public Builder setName(String name) {
69 this.name = name;
70 return this;
71 }
72
73 public MacroClass build() {
74 Preconditions.checkNotNull(name);
75 return new MacroClass(name, implementation);
76 }
77 }
Googler0287d922024-01-26 13:12:20 -080078
79 /**
80 * Executes a symbolic macro's implementation function, in a new Starlark thread, mutating the
81 * given package under construction.
82 */
83 // TODO: #19922 - Take a new type, PackagePiece.Builder, in place of Package.Builder. PackagePiece
84 // would represent the collection of targets/macros instantiated by expanding a single symbolic
85 // macro.
86 public static void executeMacroImplementation(
87 MacroInstance macro, Package.Builder builder, StarlarkSemantics semantics)
88 throws InterruptedException {
89 try (Mutability mu =
90 Mutability.create("macro", builder.getPackageIdentifier(), macro.getName())) {
Googler11f06202024-04-11 20:50:39 -070091 StarlarkThread thread =
92 StarlarkThread.create(
93 mu,
94 semantics,
95 /* contextDescription= */ "",
96 SymbolGenerator.create(
97 MacroId.create(builder.getPackageIdentifier(), macro.getName())));
Googler0287d922024-01-26 13:12:20 -080098 thread.setPrintHandler(Event.makeDebugPrintHandler(builder.getLocalEventHandler()));
99
Googler19f31542024-01-28 10:02:23 -0800100 // TODO: #19922 - Technically the embedded SymbolGenerator field should use a different key
101 // than the one in the main BUILD thread, but that'll be fixed when we change the type to
102 // PackagePiece.Builder.
103 builder.storeInThread(thread);
Googler0287d922024-01-26 13:12:20 -0800104
105 // TODO: #19922 - If we want to support creating analysis_test rules inside symbolic macros,
106 // we'd need to call `thread.setThreadLocal(RuleDefinitionEnvironment.class,
107 // ruleClassProvider)`. In that case we'll need to consider how to get access to the
108 // ConfiguredRuleClassProvider. For instance, we could put it in the builder.
109
110 try {
111 Starlark.fastcall(
112 thread,
113 macro.getMacroClass().getImplementation(),
114 /* positional= */ new Object[] {},
115 /* named= */ new Object[] {"name", macro.getName()});
116 } catch (EvalException ex) {
117 builder
118 .getLocalEventHandler()
119 .handle(
120 Package.error(
121 /* location= */ null, ex.getMessageWithStack(), Code.STARLARK_EVAL_ERROR));
122 builder.setContainsErrors();
123 }
124 }
125 }
Googler11f06202024-04-11 20:50:39 -0700126
127 @AutoValue
128 abstract static class MacroId {
129 static MacroId create(PackageIdentifier id, String name) {
130 return new AutoValue_MacroClass_MacroId(id, name);
131 }
132
133 abstract PackageIdentifier packageId();
134
135 abstract String name();
136 }
Googler09eef852024-01-11 09:06:55 -0800137}