// 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.ImmutableSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils; import net.bytebuddy.implementation.bytecode.StackManipulation; import java.lang.reflect.Field; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * Global constants and support for global namespaces of runtime functions. */ public final class Runtime { private Runtime() {} @SkylarkSignature(name = "True", returnType = Boolean.class, doc = "Literal for the boolean true.") private static final Boolean TRUE = true; @SkylarkSignature(name = "False", returnType = Boolean.class, doc = "Literal for the boolean false.") 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 void write(Appendable buffer, char quotationMark) { Printer.append(buffer, "None"); } } /** * Load {@link #NONE} on the stack. *
Kept close to the definition to avoid reflection errors when changing it.
*/
public static final StackManipulation GET_NONE = ByteCodeUtils.getField(Runtime.class, "NONE");
@SkylarkSignature(name = "None", returnType = NoneType.class,
doc = "Literal for the None value.")
public static final NoneType NONE = new NoneType();
@SkylarkSignature(name = "PACKAGE_NAME", returnType = String.class,
doc = "The name of the package the rule or build extension is called from. "
+ "For example, in the BUILD file some/package/BUILD
, its value "
+ "will be some/package
. "
+ "This variable is special, because its value comes from outside of the extension "
+ "module (it comes from the BUILD file), so it can only be accessed in functions "
+ "(transitively) called from BUILD files. For example:
"
+ "
def extension():\n" + " return PACKAGE_NAME" + "In this case calling
extension()
works from the BUILD file (if the "
+ "function is loaded), but not as a top level function call in the extension module.")
public static final String PKG_NAME = "PACKAGE_NAME";
@SkylarkSignature(name = "REPOSITORY_NAME", returnType = String.class,
doc = "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 "
+ "local_repository(name='local', path=...)
it will be set to "
+ "@local
. In packages in the main repository, it will be empty. "
+ "It can only be accessed in functions (transitively) called from BUILD files.")
public static final String REPOSITORY_NAME = "REPOSITORY_NAME";
/**
* Set up a given environment for supported class methods.
*/
static Environment setupConstants(Environment env) {
// In Python 2.x, True and False are global values and can be redefined by the user.
// In Python 3.x, they are keywords. We implement them as values, for the sake of
// simplicity. We define them as Boolean objects.
return env.setup("False", FALSE).setup("True", TRUE).setup("None", NONE);
}
/** Global registry of functions associated to a class or namespace */
private static final MapCurrently, this is only necessary for mapping the different subclasses of {@link
* java.util.Map} to the interface.
*/
public static Class> getCanonicalRepresentation(Class> clazz) {
if (Map.class.isAssignableFrom(clazz)) {
return MethodLibrary.DictModule.class;
}
if (String.class.isAssignableFrom(clazz)) {
return MethodLibrary.StringModule.class;
}
if (List.class.isAssignableFrom(clazz)) {
return List.class;
}
return clazz;
}
/**
* Registers global fields with SkylarkSignature into the specified Environment.
* @param env the Environment into which to register fields.
* @param moduleClass the Class object containing globals.
*/
public static void registerModuleGlobals(Environment env, Class> moduleClass) {
try {
if (moduleClass.isAnnotationPresent(SkylarkModule.class)) {
env.setup(
moduleClass.getAnnotation(SkylarkModule.class).name(), moduleClass.newInstance());
}
for (Field field : moduleClass.getDeclaredFields()) {
if (field.isAnnotationPresent(SkylarkSignature.class)) {
// Fields in Skylark modules are sometimes private.
// Nevertheless they have to be annotated with SkylarkSignature.
field.setAccessible(true);
SkylarkSignature annotation = field.getAnnotation(SkylarkSignature.class);
Object value = field.get(null);
// Ignore function factories and non-global functions
if (!(value instanceof BuiltinFunction.Factory
|| (value instanceof BaseFunction
&& !annotation.objectType().equals(Object.class)))) {
env.setup(annotation.name(), value);
}
}
}
} catch (IllegalAccessException | InstantiationException e) {
throw new AssertionError(e);
}
}
/**
* Returns the function of the namespace of the given name or null of it does not exists.
*/
public static BaseFunction getFunction(Class> nameSpace, String name) {
Map