// Copyright 2015 Google Inc. 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 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.
*/
@Immutable
public static final class NoneType {
@Override
public String toString() { return "None"; }
private NoneType() {}
}
@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";
/**
* 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