aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java
diff options
context:
space:
mode:
authorGravatar Francois-Rene Rideau <tunes@google.com>2015-08-31 16:16:21 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2015-08-31 19:21:24 +0000
commit0f7ba34748579faea70e42dfdf60a9625a88f425 (patch)
tree3f67a3c68e08f0a2dcfcf13b5d31b411dc97a70f /src/main/java
parent6c29d57b6ddef8a6e7ac39b09e9338f616e78e4d (diff)
Move global objects to Runtime
Move away global constants and global namespaces out of Environment and into a new file Runtime. -- MOS_MIGRATED_REVID=101940218
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.java24
-rw-r--r--src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java87
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/RuleClass.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java11
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java89
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java34
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java15
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Environment.java93
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java352
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Printer.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Runtime.java176
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java2
25 files changed, 503 insertions, 452 deletions
diff --git a/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.java b/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.java
index f7ae83b0e4..a2e7b64857 100644
--- a/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.java
+++ b/src/main/java/com/google/devtools/build/docgen/SkylarkDocumentationCollector.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.docgen;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.docgen.skylark.SkylarkBuiltinMethodDoc;
import com.google.devtools.build.docgen.skylark.SkylarkJavaMethodDoc;
@@ -21,9 +22,9 @@ import com.google.devtools.build.docgen.skylark.SkylarkModuleDoc;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.rules.SkylarkModules;
import com.google.devtools.build.lib.rules.SkylarkRuleContext;
-import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.MethodLibrary;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkCallable;
import com.google.devtools.build.lib.syntax.SkylarkModule;
import com.google.devtools.build.lib.syntax.SkylarkSignature;
@@ -34,6 +35,7 @@ import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -130,7 +132,7 @@ final class SkylarkDocumentationCollector {
private static Map<String, SkylarkModuleDoc> collectBuiltinModules() {
Map<String, SkylarkModuleDoc> modules = new HashMap<>();
- collectBuiltinDoc(modules, Environment.class.getDeclaredFields());
+ collectBuiltinDoc(modules, Runtime.class.getDeclaredFields());
collectBuiltinDoc(modules, MethodLibrary.class.getDeclaredFields());
for (Class<?> moduleClass : SkylarkModules.MODULES) {
collectBuiltinDoc(modules, moduleClass.getDeclaredFields());
@@ -145,13 +147,19 @@ final class SkylarkDocumentationCollector {
Class<?> moduleClass = skylarkSignature.objectType();
SkylarkModule skylarkModule = moduleClass.equals(Object.class)
? getTopLevelModule()
- : moduleClass.getAnnotation(SkylarkModule.class);
- if (!modules.containsKey(skylarkModule.name())) {
- modules.put(skylarkModule.name(), new SkylarkModuleDoc(skylarkModule, moduleClass));
+ : Runtime.getCanonicalRepresentation(moduleClass).getAnnotation(SkylarkModule.class);
+ if (skylarkModule == null) {
+ // TODO(bazel-team): we currently have undocumented methods on undocumented data
+ // structures, namely java.util.List. Remove this case when we are done.
+ Preconditions.checkState(!skylarkSignature.documented());
+ Preconditions.checkState(moduleClass == List.class);
+ } else {
+ if (!modules.containsKey(skylarkModule.name())) {
+ modules.put(skylarkModule.name(), new SkylarkModuleDoc(skylarkModule, moduleClass));
+ }
+ SkylarkModuleDoc module = modules.get(skylarkModule.name());
+ module.addMethod(new SkylarkBuiltinMethodDoc(module, skylarkSignature, field.getType()));
}
-
- SkylarkModuleDoc module = modules.get(skylarkModule.name());
- module.addMethod(new SkylarkBuiltinMethodDoc(module, skylarkSignature, field.getType()));
}
}
}
diff --git a/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java
index 065ab68c0c..da77f73b87 100644
--- a/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java
+++ b/src/main/java/com/google/devtools/build/docgen/skylark/SkylarkDoc.java
@@ -13,9 +13,9 @@
// limitations under the License.
package com.google.devtools.build.docgen.skylark;
-import com.google.devtools.build.lib.syntax.Environment.NoneType;
import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.Runtime.NoneType;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkModule;
import com.google.devtools.build.lib.syntax.SkylarkSignature;
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
index bc1c9eb701..b89cf72b58 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
@@ -46,10 +46,10 @@ import com.google.devtools.build.lib.rules.test.TestActionBuilder;
import com.google.devtools.build.lib.rules.test.TestProvider;
import com.google.devtools.build.lib.rules.test.TestProvider.TestParams;
import com.google.devtools.build.lib.syntax.ClassObject;
-import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
@@ -420,7 +420,7 @@ public final class RuleConfiguredTargetBuilder {
|| type.equals(Boolean.class)
|| Artifact.class.isAssignableFrom(type)
|| type.equals(Label.class)
- || type.equals(Environment.NoneType.class);
+ || type.equals(Runtime.NoneType.class);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java b/src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java
index b05082ade0..12d02c6d0c 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java
@@ -27,9 +27,9 @@ import com.google.common.escape.Escapers;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.syntax.ClassObject;
import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
-import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction;
import com.google.devtools.build.lib.util.StringUtil;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -91,7 +91,7 @@ public abstract class ImplicitOutputsFunction {
// since we don't yet have a build configuration.
if (!map.isConfigurable(attrName, attrType)) {
Object value = map.get(attrName, attrType);
- attrValues.put(attrName, value == null ? Environment.NONE : value);
+ attrValues.put(attrName, value == null ? Runtime.NONE : value);
}
}
ClassObject attrs = new SkylarkClassObject(attrValues, "Attribute '%s' either doesn't exist "
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
index 64e1fe657e..b94147dc54 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
@@ -35,6 +35,7 @@ import com.google.devtools.build.lib.syntax.AssignmentStatement;
import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.BuildFileAST;
import com.google.devtools.build.lib.syntax.BuiltinFunction;
+import com.google.devtools.build.lib.syntax.ClassObject;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.Environment.NoSuchVariableException;
import com.google.devtools.build.lib.syntax.EvalException;
@@ -47,6 +48,7 @@ import com.google.devtools.build.lib.syntax.Identifier;
import com.google.devtools.build.lib.syntax.Label;
import com.google.devtools.build.lib.syntax.MethodLibrary;
import com.google.devtools.build.lib.syntax.ParserInputSource;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.syntax.SkylarkSignature;
import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
@@ -373,6 +375,7 @@ public final class PackageFactory {
threadPool.allowCoreThreadTimeOut(true);
this.environmentExtensions = ImmutableList.copyOf(environmentExtensions);
this.packageArguments = createPackageArguments();
+ this.nativeModule = newNativeModule();
}
/**
@@ -556,7 +559,7 @@ public final class PackageFactory {
* seen by the parser, because the presence of "subinclude" triggers
* preprocessing.)
*/
- @SkylarkSignature(name = "mocksubinclude", returnType = Environment.NoneType.class,
+ @SkylarkSignature(name = "mocksubinclude", returnType = Runtime.NoneType.class,
doc = "implement the mocksubinclude function emitted by the PythonPreprocessor",
mandatoryPositionals = {
@Param(name = "label", type = Object.class,
@@ -568,7 +571,7 @@ public final class PackageFactory {
new BuiltinFunction.Factory("mocksubinclude") {
public BuiltinFunction create(final PackageContext context) {
return new BuiltinFunction("mocksubinclude", this) {
- public Environment.NoneType invoke(Object labelO, String pathString,
+ public Runtime.NoneType invoke(Object labelO, String pathString,
Location loc) throws ConversionException {
Label label = Type.LABEL.convert(labelO, "'mocksubinclude' argument",
context.pkgBuilder.getBuildFileLabel());
@@ -583,7 +586,7 @@ public final class PackageFactory {
}
context.pkgBuilder.addSubinclude(label, path);
- return Environment.NONE;
+ return Runtime.NONE;
}
};
}
@@ -604,7 +607,7 @@ public final class PackageFactory {
* <p>Where ":env1", "env2", ... are all environment rules declared in the same package. All
* parameters are mandatory.
*/
- @SkylarkSignature(name = "environment_group", returnType = Environment.NoneType.class,
+ @SkylarkSignature(name = "environment_group", returnType = Runtime.NoneType.class,
doc = "Defines a cc_library, by wrapping around the usual library "
+ "and also defining a headers target.",
mandatoryNamedOnly = {
@@ -620,7 +623,7 @@ public final class PackageFactory {
new BuiltinFunction.Factory("environment_group") {
public BuiltinFunction create(final PackageContext context) {
return new BuiltinFunction("environment_group", this) {
- public Environment.NoneType invoke(String name, Object environmentsO, Object defaultsO,
+ public Runtime.NoneType invoke(String name, Object environmentsO, Object defaultsO,
Location loc) throws EvalException, ConversionException {
List<Label> environments = Type.LABEL_LIST.convert(environmentsO,
"'environment_group argument'", context.pkgBuilder.getBuildFileLabel());
@@ -630,7 +633,7 @@ public final class PackageFactory {
try {
context.pkgBuilder.addEnvironmentGroup(name, environments, defaults,
context.eventHandler, loc);
- return Environment.NONE;
+ return Runtime.NONE;
} catch (Label.SyntaxException e) {
throw new EvalException(loc,
"environment group has invalid name: " + name + ": " + e.getMessage());
@@ -646,7 +649,7 @@ public final class PackageFactory {
* Returns a function-value implementing "exports_files" in the specified
* package context.
*/
- @SkylarkSignature(name = "exports_files", returnType = Environment.NoneType.class,
+ @SkylarkSignature(name = "exports_files", returnType = Runtime.NoneType.class,
doc = "Declare a set of files as exported",
mandatoryPositionals = {
@Param(name = "srcs", type = HackHackEitherList.class, generic1 = String.class,
@@ -666,7 +669,7 @@ public final class PackageFactory {
new BuiltinFunction.Factory("exports_files") {
public BuiltinFunction create () {
return new BuiltinFunction("exports_files", this) {
- public Environment.NoneType invoke(Object srcs, Object visibility, Object licenses,
+ public Runtime.NoneType invoke(Object srcs, Object visibility, Object licenses,
FuncallExpression ast, Environment env)
throws EvalException, ConversionException {
return callExportsFiles(srcs, visibility, licenses, ast, env);
@@ -675,7 +678,7 @@ public final class PackageFactory {
}
};
- static Environment.NoneType callExportsFiles(Object srcs, Object visibilityO, Object licensesO,
+ static Runtime.NoneType callExportsFiles(Object srcs, Object visibilityO, Object licensesO,
FuncallExpression ast, Environment env) throws EvalException, ConversionException {
Package.LegacyBuilder pkgBuilder = getContext(env, ast).pkgBuilder;
List<String> files = Type.STRING_LIST.convert(srcs, "'exports_files' operand");
@@ -720,7 +723,7 @@ public final class PackageFactory {
throw new EvalException(ast.getLocation(), e.getMessage());
}
}
- return Environment.NONE;
+ return Runtime.NONE;
}
/**
@@ -728,7 +731,7 @@ public final class PackageFactory {
* context.
* TODO(bazel-team): Remove in favor of package.licenses.
*/
- @SkylarkSignature(name = "licenses", returnType = Environment.NoneType.class,
+ @SkylarkSignature(name = "licenses", returnType = Runtime.NoneType.class,
doc = "Declare the license(s) for the code in the current package.",
mandatoryPositionals = {
@Param(name = "license_strings", type = HackHackEitherList.class, generic1 = String.class,
@@ -738,7 +741,7 @@ public final class PackageFactory {
new BuiltinFunction.Factory("licenses") {
public BuiltinFunction create(final PackageContext context) {
return new BuiltinFunction("licenses", this) {
- public Environment.NoneType invoke(Object licensesO, Location loc) {
+ public Runtime.NoneType invoke(Object licensesO, Location loc) {
try {
License license = Type.LICENSE.convert(licensesO, "'licenses' operand");
context.pkgBuilder.setDefaultLicense(license);
@@ -746,7 +749,7 @@ public final class PackageFactory {
context.eventHandler.handle(Event.error(loc, e.getMessage()));
context.pkgBuilder.setContainsErrors();
}
- return Environment.NONE;
+ return Runtime.NONE;
}
};
}
@@ -755,9 +758,12 @@ public final class PackageFactory {
/**
* Returns a function-value implementing "distribs" in the specified package
* context.
- * TODO(bazel-team): Remove in favor of package.distribs.
*/
- @SkylarkSignature(name = "distribs", returnType = Environment.NoneType.class,
+ // TODO(bazel-team): Remove in favor of package.distribs.
+ // TODO(bazel-team): Remove all these new*Function-s and/or have static functions
+ // that consult the context dynamically via getContext(env, ast) since we have that,
+ // and share the functions with the native package... which requires unifying the List types.
+ @SkylarkSignature(name = "distribs", returnType = Runtime.NoneType.class,
doc = "Declare the distribution(s) for the code in the current package.",
mandatoryPositionals = {
@Param(name = "distribution_strings", type = Object.class,
@@ -767,7 +773,7 @@ public final class PackageFactory {
new BuiltinFunction.Factory("distribs") {
public BuiltinFunction create(final PackageContext context) {
return new BuiltinFunction("distribs", this) {
- public Environment.NoneType invoke(Object object, Location loc) {
+ public Runtime.NoneType invoke(Object object, Location loc) {
try {
Set<DistributionType> distribs = Type.DISTRIBUTIONS.convert(object,
"'distribs' operand");
@@ -776,13 +782,13 @@ public final class PackageFactory {
context.eventHandler.handle(Event.error(loc, e.getMessage()));
context.pkgBuilder.setContainsErrors();
}
- return Environment.NONE;
+ return Runtime.NONE;
}
};
}
};
- @SkylarkSignature(name = "package_group", returnType = Environment.NoneType.class,
+ @SkylarkSignature(name = "package_group", returnType = Runtime.NoneType.class,
doc = "Declare a set of files as exported",
mandatoryNamedOnly = {
@Param(name = "name", type = String.class,
@@ -800,7 +806,7 @@ public final class PackageFactory {
new BuiltinFunction.Factory("package_group") {
public BuiltinFunction create() {
return new BuiltinFunction("package_group", this) {
- public Environment.NoneType invoke(String name, Object packages, Object includes,
+ public Runtime.NoneType invoke(String name, Object packages, Object includes,
FuncallExpression ast, Environment env) throws EvalException, ConversionException {
return callPackageFunction(name, packages, includes, ast, env);
}
@@ -808,7 +814,7 @@ public final class PackageFactory {
}
};
- static Environment.NoneType callPackageFunction(String name, Object packagesO, Object includesO,
+ static Runtime.NoneType callPackageFunction(String name, Object packagesO, Object includesO,
FuncallExpression ast, Environment env) throws EvalException, ConversionException {
PackageContext context = getContext(env, ast);
@@ -820,7 +826,7 @@ public final class PackageFactory {
try {
context.pkgBuilder.addPackageGroup(name, packages, includes, context.eventHandler,
ast.getLocation());
- return Environment.NONE;
+ return Runtime.NONE;
} catch (Label.SyntaxException e) {
throw new EvalException(ast.getLocation(),
"package group has invalid name: " + name + ": " + e.getMessage());
@@ -890,7 +896,7 @@ public final class PackageFactory {
"at least one argument must be given to the 'package' function");
}
- return Environment.NONE;
+ return Runtime.NONE;
}
};
}
@@ -937,7 +943,7 @@ public final class PackageFactory {
final RuleFactory ruleFactory, final String ruleClass) {
return new BuiltinFunction(ruleClass, FunctionSignature.KWARGS, BuiltinFunction.USE_AST_ENV) {
@SuppressWarnings("unchecked")
- public Environment.NoneType invoke(Map<String, Object> kwargs,
+ public Runtime.NoneType invoke(Map<String, Object> kwargs,
FuncallExpression ast, Environment env)
throws EvalException {
env.checkLoadingPhase(ruleClass, ast.getLocation());
@@ -946,7 +952,7 @@ public final class PackageFactory {
} catch (RuleFactory.InvalidRuleException | Package.NameConflictException e) {
throw new EvalException(ast.getLocation(), e.getMessage());
}
- return Environment.NONE;
+ return Runtime.NONE;
}
};
}
@@ -1171,23 +1177,40 @@ public final class PackageFactory {
}
}
+ private final ClassObject nativeModule;
+
+ /** @return the Skylark struct to bind to "native" */
+ public ClassObject getNativeModule() {
+ return nativeModule;
+ }
+
/**
- * Returns the list of native rule functions created using the {@link RuleClassProvider}
+ * Returns a native module with the functions created using the {@link RuleClassProvider}
* of this {@link PackageFactory}.
*/
- public ImmutableList<BaseFunction> collectNativeRuleFunctions() {
- ImmutableList.Builder<BaseFunction> builder = ImmutableList.builder();
+ private ClassObject newNativeModule() {
+ ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
+ for (String nativeFunction : Runtime.getFunctionNames(SkylarkNativeModule.class)) {
+ builder.put(nativeFunction, Runtime.getFunction(SkylarkNativeModule.class, nativeFunction));
+ }
for (String ruleClass : ruleFactory.getRuleClassNames()) {
- builder.add(newRuleFunction(ruleFactory, ruleClass));
+ builder.put(ruleClass, newRuleFunction(ruleFactory, ruleClass));
}
- builder.add(newPackageFunction(packageArguments));
+ builder.put("package", newPackageFunction(packageArguments));
for (EnvironmentExtension extension : environmentExtensions) {
- builder.addAll(extension.nativeModuleFunctions());
+ for (BaseFunction function : extension.nativeModuleFunctions()) {
+ builder.put(function.getName(), function);
+ }
}
- return builder.build();
+ return new ClassObject.SkylarkClassObject(builder.build(), "no native function or rule '%s'");
}
private void buildPkgEnv(Environment pkgEnv, PackageContext context, RuleFactory ruleFactory) {
+ // TODO(bazel-team): remove the naked functions that are redundant with the nativeModule,
+ // or if not possible, at least make them straight copies from the native module variant.
+ // or better, use a common Environment.Frame for these common bindings
+ // (that shares a backing ImmutableMap for the bindings?)
+ pkgEnv.update("native", nativeModule);
pkgEnv.update("distribs", newDistribsFunction.apply(context));
pkgEnv.update("glob", newGlobFunction.apply(context, /*async=*/false));
pkgEnv.update("mocksubinclude", newMockSubincludeFunction.apply(context));
@@ -1269,7 +1292,7 @@ public final class PackageFactory {
pkgEnv.setImportedExtensions(imports);
pkgEnv.updateAndPropagate(PKG_CONTEXT, context);
- pkgEnv.updateAndPropagate(Environment.PKG_NAME, packageId.toString());
+ pkgEnv.updateAndPropagate(Runtime.PKG_NAME, packageId.toString());
if (!validateAssignmentStatements(pkgEnv, buildFileAST, eventHandler)) {
pkgBuilder.setContainsErrors();
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index ee1fce3bb8..ddbda142b7 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -34,12 +34,12 @@ import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
import com.google.devtools.build.lib.syntax.Argument;
import com.google.devtools.build.lib.syntax.BaseFunction;
-import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.FragmentClassNameResolver;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.GlobList;
import com.google.devtools.build.lib.syntax.Label;
import com.google.devtools.build.lib.syntax.Label.SyntaxException;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.util.StringUtil;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -1394,7 +1394,7 @@ public final class RuleClass {
for (Map.Entry<String, Object> entry : attributeValues.entrySet()) {
String attributeName = entry.getKey();
Object attributeValue = entry.getValue();
- if (attributeValue == Environment.NONE) { // Ignore all None values.
+ if (attributeValue == Runtime.NONE) { // Ignore all None values.
continue;
}
Integer attrIndex = setRuleAttributeValue(rule, eventHandler, attributeName, attributeValue);
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
index 1f32cbd0b2..02752f552c 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
@@ -20,6 +20,7 @@ import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.GlobList;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkModule;
import com.google.devtools.build.lib.syntax.SkylarkSignature;
@@ -73,7 +74,7 @@ public class SkylarkNativeModule {
};
@SkylarkSignature(name = "package_group", objectType = SkylarkNativeModule.class,
- returnType = Environment.NoneType.class,
+ returnType = Runtime.NoneType.class,
doc = "This function defines a set of packages and assigns a label to the group. "
+ "The label can be referenced in <code>visibility</code> attributes.",
mandatoryNamedOnly = {
@@ -88,7 +89,7 @@ public class SkylarkNativeModule {
doc = "Other package groups that are included in this one.")},
useAst = true, useEnvironment = true)
private static final BuiltinFunction packageGroup = new BuiltinFunction("package_group") {
- public Environment.NoneType invoke(String name, SkylarkList packages, SkylarkList includes,
+ public Runtime.NoneType invoke(String name, SkylarkList packages, SkylarkList includes,
FuncallExpression ast, Environment env) throws EvalException, ConversionException {
env.checkLoadingPhase("native.package_group", ast.getLocation());
return PackageFactory.callPackageFunction(name, packages, includes, ast, env);
@@ -96,7 +97,7 @@ public class SkylarkNativeModule {
};
@SkylarkSignature(name = "exports_files", objectType = SkylarkNativeModule.class,
- returnType = Environment.NoneType.class,
+ returnType = Runtime.NoneType.class,
doc = "Specifies a list of files belonging to this package that are exported to other "
+ "packages but not otherwise mentioned.",
mandatoryPositionals = {
@@ -113,10 +114,10 @@ public class SkylarkNativeModule {
doc = "Licenses to be specified.")},
useAst = true, useEnvironment = true)
private static final BuiltinFunction exportsFiles = new BuiltinFunction("exports_files") {
- public Environment.NoneType invoke(SkylarkList srcs, Object visibility, Object licenses,
+ public Runtime.NoneType invoke(SkylarkList srcs, Object visibility, Object licenses,
FuncallExpression ast, Environment env)
throws EvalException, ConversionException {
- env.checkLoadingPhase("native.exports_file", ast.getLocation());
+ env.checkLoadingPhase("native.exports_files", ast.getLocation());
return PackageFactory.callExportsFiles(srcs, visibility, licenses, ast, env);
}
};
diff --git a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
index 4a312f718e..054865fafd 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
@@ -14,7 +14,7 @@
package com.google.devtools.build.lib.packages;
-import static com.google.devtools.build.lib.syntax.Environment.NONE;
+import static com.google.devtools.build.lib.syntax.Runtime.NONE;
import com.google.devtools.build.lib.cmdline.LabelValidator;
import com.google.devtools.build.lib.events.Event;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
index 635b1ed37e..75afd45413 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
@@ -29,6 +29,7 @@ import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.syntax.SkylarkList;
@@ -100,7 +101,7 @@ public final class SkylarkAttr {
+ "value is given.";
private static boolean containsNonNoneKey(Map<String, Object> arguments, String key) {
- return arguments.containsKey(key) && arguments.get(key) != Environment.NONE;
+ return arguments.containsKey(key) && arguments.get(key) != Runtime.NONE;
}
private static Attribute.Builder<?> createAttribute(
@@ -160,7 +161,7 @@ public final class SkylarkAttr {
}
Object ruleClassesObj = arguments.get(ALLOW_RULES_ARG);
- if (ruleClassesObj != null && ruleClassesObj != Environment.NONE) {
+ if (ruleClassesObj != null && ruleClassesObj != Runtime.NONE) {
builder.allowedRuleClasses(
castList(ruleClassesObj, String.class, "allowed rule classes for attribute definition"));
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
index df4876c599..c52c58c88c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
@@ -16,38 +16,27 @@ package com.google.devtools.build.lib.rules;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.SkylarkNativeModule;
-import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvaluationContext;
import com.google.devtools.build.lib.syntax.MethodLibrary;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
-import com.google.devtools.build.lib.syntax.SkylarkModule;
-import com.google.devtools.build.lib.syntax.SkylarkSignature;
import com.google.devtools.build.lib.syntax.ValidationEnvironment;
-import java.lang.reflect.Field;
-import java.util.Map;
-
/**
- * A class to handle all Skylark modules, to create and setup Validation and regular Environments.
+ * The basis for a Skylark Environment with all build-related modules registered.
*/
-// TODO(bazel-team): move that to the syntax package and
-// let each extension register itself in a static { } statement.
-public class SkylarkModules {
+public final class SkylarkModules {
+
+ private SkylarkModules() { }
/**
* The list of built in Skylark modules.
* Documentation is generated automatically for all these modules.
- * They are also registered with the {@link ValidationEnvironment}
- * and the {@link SkylarkEnvironment}.
- * Note that only functions with a {@link SkylarkSignature} annotations are handled properly.
+ * They are also registered with the {@link Environment}.
*/
- // TODO(bazel-team): find a more general, more automated way of registering classes and building
- // initial environments. And don't give syntax.Environment and packages.MethodLibrary a special
- // treatment, have them use the same registration mechanism as other classes currently below.
public static final ImmutableList<Class<?>> MODULES = ImmutableList.of(
SkylarkAttr.class,
SkylarkCommandLine.class,
@@ -55,30 +44,6 @@ public class SkylarkModules {
SkylarkRuleClassFunctions.class,
SkylarkRuleImplementationFunctions.class);
- private static final ImmutableMap<Class<?>, ImmutableList<BaseFunction>> FUNCTION_MAP;
- private static final ImmutableMap<String, Object> OBJECTS;
-
- static {
- try {
- ImmutableMap.Builder<Class<?>, ImmutableList<BaseFunction>> functionMap =
- ImmutableMap.builder();
- ImmutableMap.Builder<String, Object> objects = ImmutableMap.builder();
- for (Class<?> moduleClass : MODULES) {
- if (moduleClass.isAnnotationPresent(SkylarkModule.class)) {
- objects.put(moduleClass.getAnnotation(SkylarkModule.class).name(),
- moduleClass.newInstance());
- }
- ImmutableList.Builder<BaseFunction> functions = ImmutableList.builder();
- collectSkylarkFunctionsAndObjectsFromFields(moduleClass, functions, objects);
- functionMap.put(moduleClass, functions.build());
- }
- FUNCTION_MAP = functionMap.build();
- OBJECTS = objects.build();
- } catch (InstantiationException | IllegalAccessException e) {
- throw new RuntimeException(e);
- }
- }
-
/**
* Returns a new SkylarkEnvironment with the elements of the Skylark modules.
*/
@@ -96,21 +61,12 @@ public class SkylarkModules {
private static void setupEnvironment(Environment env) {
MethodLibrary.setupMethodEnvironment(env);
- for (Map.Entry<Class<?>, ImmutableList<BaseFunction>> entry : FUNCTION_MAP.entrySet()) {
- for (BaseFunction function : entry.getValue()) {
- if (function.getObjectType() != null) {
- env.registerFunction(function.getObjectType(), function.getName(), function);
- } else {
- env.update(function.getName(), function);
- }
- }
- }
- for (Map.Entry<String, Object> entry : OBJECTS.entrySet()) {
- env.update(entry.getKey(), entry.getValue());
+ for (Class<?> moduleClass : MODULES) {
+ Runtime.registerModuleGlobals(env, moduleClass);
}
// Even though PACKAGE_NAME has no value _now_ and will be bound later,
// it needs to be visible for the ValidationEnvironment to be happy.
- env.update(Environment.PKG_NAME, Environment.NONE);
+ env.update(Runtime.PKG_NAME, Runtime.NONE);
}
/**
@@ -125,31 +81,4 @@ public class SkylarkModules {
return EvaluationContext.newSkylarkContext(
getNewEnvironment(eventHandler), getValidationEnvironment());
}
-
- /**
- * Collects the BaseFunctions from the fields of the class of the object parameter
- * and adds them into the builder.
- */
- private static void collectSkylarkFunctionsAndObjectsFromFields(Class<?> type,
- ImmutableList.Builder<BaseFunction> functions, ImmutableMap.Builder<String, Object> objects) {
- try {
- for (Field field : type.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);
- if (BaseFunction.class.isAssignableFrom(field.getType())) {
- functions.add((BaseFunction) value);
- } else {
- objects.put(annotation.name(), value);
- }
- }
- }
- } catch (IllegalArgumentException | IllegalAccessException e) {
- // This should never happen.
- throw new RuntimeException(e);
- }
- }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index 1ca229c11a..4c070b4309 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -68,6 +68,7 @@ import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.FunctionSignature;
import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.syntax.SkylarkList;
@@ -250,7 +251,7 @@ public class SkylarkRuleClassFunctions {
// We'll set the name later, pass the empty string for now.
RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent);
- if (attrs != Environment.NONE) {
+ if (attrs != Runtime.NONE) {
for (Map.Entry<String, Attribute.Builder> attr : castMap(
attrs, String.class, Attribute.Builder.class, "attrs").entrySet()) {
Attribute.Builder<?> attrBuilder = (Attribute.Builder<?>) attr.getValue();
@@ -267,7 +268,7 @@ public class SkylarkRuleClassFunctions {
builder.setOutputsDefaultExecutable();
}
- if (implicitOutputs != Environment.NONE) {
+ if (implicitOutputs != Runtime.NONE) {
if (implicitOutputs instanceof BaseFunction) {
BaseFunction func = (BaseFunction) implicitOutputs;
final SkylarkCallbackFunction callback =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
index a7c9b4f91e..409b4087a4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
@@ -34,10 +34,10 @@ import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.ClassObject;
import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
-import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalExceptionWithStackTrace;
import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
import com.google.devtools.build.lib.syntax.SkylarkType;
@@ -64,7 +64,7 @@ public final class SkylarkRuleConfiguredTargetBuilder {
if (ruleContext.hasErrors()) {
return null;
- } else if (!(target instanceof SkylarkClassObject) && target != Environment.NONE) {
+ } else if (!(target instanceof SkylarkClassObject) && target != Runtime.NONE) {
ruleContext.ruleError("Rule implementation doesn't return a struct");
return null;
} else if (!expectFailure.isEmpty()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index dbaf2c8f64..bf115153db 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -44,10 +44,10 @@ import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.shell.ShellUtils;
import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException;
import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
-import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression.FuncallException;
import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkCallable;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkModule;
@@ -159,7 +159,7 @@ public final class SkylarkRuleContext {
if (artifacts.size() == 1) {
addOutput(outputsBuilder, attrName, Iterables.getOnlyElement(artifacts));
} else {
- addOutput(outputsBuilder, attrName, Environment.NONE);
+ addOutput(outputsBuilder, attrName, Runtime.NONE);
}
} else if (type == Type.OUTPUT_LIST) {
addOutput(outputsBuilder, attrName,
@@ -182,7 +182,7 @@ public final class SkylarkRuleContext {
Type<?> type = a.getType();
Object val = ruleContext.attributes().get(a.getName(), type);
if (type != Type.LABEL && type != Type.LABEL_LIST) {
- attrBuilder.put(a.getPublicName(), val == null ? Environment.NONE
+ attrBuilder.put(a.getPublicName(), val == null ? Runtime.NONE
// Attribute values should be type safe
: SkylarkType.convertToSkylark(val, null));
continue;
@@ -197,7 +197,7 @@ public final class SkylarkRuleContext {
executableBuilder.put(skyname, executable);
executableRunfilesbuilder.put(executable, provider);
} else {
- executableBuilder.put(skyname, Environment.NONE);
+ executableBuilder.put(skyname, Runtime.NONE);
}
}
if (a.isSingleArtifact()) {
@@ -206,7 +206,7 @@ public final class SkylarkRuleContext {
if (artifact != null) {
fileBuilder.put(skyname, artifact);
} else {
- fileBuilder.put(skyname, Environment.NONE);
+ fileBuilder.put(skyname, Runtime.NONE);
}
}
filesBuilder.put(skyname, ruleContext.getPrerequisiteArtifacts(a.getName(), mode).list());
@@ -214,7 +214,7 @@ public final class SkylarkRuleContext {
if (type == Type.LABEL) {
Object prereq = ruleContext.getPrerequisite(a.getName(), mode);
if (prereq == null) {
- prereq = Environment.NONE;
+ prereq = Runtime.NONE;
}
attrBuilder.put(skyname, prereq);
} else {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
index fb53cfd700..b6417d4422 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
@@ -47,10 +47,10 @@ import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.Type.ConversionException;
import com.google.devtools.build.lib.syntax.BuiltinFunction;
import com.google.devtools.build.lib.syntax.Environment;
-import com.google.devtools.build.lib.syntax.Environment.NoneType;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
import com.google.devtools.build.lib.syntax.SkylarkSignature;
@@ -90,7 +90,7 @@ public class SkylarkRuleImplementationFunctions {
doc = "Creates an action that runs an executable or a shell command. You must specify either "
+ "<code>command</code> or <code>executable</code>.",
objectType = SkylarkRuleContext.class,
- returnType = Environment.NoneType.class,
+ returnType = Runtime.NoneType.class,
mandatoryPositionals = {
@Param(name = "self", type = SkylarkRuleContext.class, doc = "This RuleContext.")},
mandatoryNamedOnly = {
@@ -128,7 +128,7 @@ public class SkylarkRuleImplementationFunctions {
+ "they are typicially generated by the command_helper")},
useLocation = true)
private static final BuiltinFunction createSpawnAction = new BuiltinFunction("action") {
- public Environment.NoneType invoke(
+ public Runtime.NoneType invoke(
SkylarkRuleContext ctx,
SkylarkList outputs,
SkylarkList inputs,
@@ -144,7 +144,7 @@ public class SkylarkRuleImplementationFunctions {
Location loc) throws EvalException, ConversionException {
SpawnAction.Builder builder = new SpawnAction.Builder();
// TODO(bazel-team): builder still makes unnecessary copies of inputs, outputs and args.
- boolean hasCommand = commandO != Environment.NONE;
+ boolean hasCommand = commandO != Runtime.NONE;
Iterable<Artifact> actualInputs = castList(inputs, Artifact.class);
builder.addInputs(actualInputs);
@@ -157,7 +157,7 @@ public class SkylarkRuleImplementationFunctions {
builder.addArgument("");
}
builder.addArguments(castList(arguments, String.class));
- if (executableO != Environment.NONE) {
+ if (executableO != Runtime.NONE) {
if (executableO instanceof Artifact) {
Artifact executable = (Artifact) executableO;
builder.addInput(executable);
@@ -174,7 +174,7 @@ public class SkylarkRuleImplementationFunctions {
+ "executable but got " + EvalUtils.getDataTypeName(executableO) + " instead");
}
}
- if ((commandO == Environment.NONE) == (executableO == Environment.NONE)) {
+ if ((commandO == Runtime.NONE) == (executableO == Runtime.NONE)) {
throw new EvalException(loc, "You must specify either 'command' or 'executable' argument");
}
if (hasCommand) {
@@ -196,24 +196,24 @@ public class SkylarkRuleImplementationFunctions {
// HOST configuration to the action as a precaution.
addRequiredIndirectRunfiles(ctx, builder);
}
- if (mnemonicO != Environment.NONE) {
+ if (mnemonicO != Runtime.NONE) {
builder.setMnemonic((String) mnemonicO);
}
- if (envO != Environment.NONE) {
+ if (envO != Runtime.NONE) {
builder.setEnvironment(ImmutableMap.copyOf(
castMap(envO, String.class, String.class, "env")));
}
- if (progressMessage != Environment.NONE) {
+ if (progressMessage != Runtime.NONE) {
builder.setProgressMessage((String) progressMessage);
}
if (EvalUtils.toBoolean(useDefaultShellEnv)) {
builder.useDefaultShellEnvironment();
}
- if (executionRequirementsO != Environment.NONE) {
+ if (executionRequirementsO != Runtime.NONE) {
builder.setExecutionInfo(ImmutableMap.copyOf(castMap(
executionRequirementsO, String.class, String.class, "execution_requirements")));
}
- if (inputManifestsO != Environment.NONE) {
+ if (inputManifestsO != Runtime.NONE) {
for (Map.Entry<PathFragment, Artifact> entry : castMap(inputManifestsO,
PathFragment.class, Artifact.class, "input manifest file map").entrySet()) {
builder.addInputManifest(entry.getValue(), entry.getKey());
@@ -221,7 +221,7 @@ public class SkylarkRuleImplementationFunctions {
}
// Always register the action
ctx.getRuleContext().registerAction(builder.build(ctx.getRuleContext()));
- return Environment.NONE;
+ return Runtime.NONE;
}
};
@@ -322,7 +322,7 @@ public class SkylarkRuleImplementationFunctions {
doc =
"Creates an empty action that neither executes a command nor produces any "
+ "output, but that is useful for inserting 'extra actions'.",
- objectType = SkylarkRuleContext.class, returnType = NoneType.class,
+ objectType = SkylarkRuleContext.class, returnType = Runtime.NoneType.class,
mandatoryPositionals = {
@Param(name = "self", type = SkylarkRuleContext.class, doc = "this context"),
},
@@ -336,7 +336,7 @@ public class SkylarkRuleImplementationFunctions {
})
private static final BuiltinFunction createEmptyAction = new BuiltinFunction("empty_action") {
@SuppressWarnings("unused")
- public NoneType invoke(SkylarkRuleContext ctx, String mnemonic, SkylarkList inputs)
+ public Runtime.NoneType invoke(SkylarkRuleContext ctx, String mnemonic, SkylarkList inputs)
throws EvalException, ConversionException {
RuleContext ruleContext = ctx.getRuleContext();
Action action = new PseudoAction<SpawnInfo>(generateUuid(ruleContext),
@@ -344,7 +344,7 @@ public class SkylarkRuleImplementationFunctions {
mnemonic, SpawnInfo.spawnInfo, createEmptySpawnInfo());
ruleContext.registerAction(action);
- return Environment.NONE;
+ return Runtime.NONE;
}
private NestedSet<Artifact> convertInputs(SkylarkList inputs) {
@@ -436,7 +436,7 @@ public class SkylarkRuleImplementationFunctions {
Class<? extends TransitiveInfoProvider> convertedClass =
classType.asSubclass(TransitiveInfoProvider.class);
Object result = target.getProvider(convertedClass);
- return result == null ? Environment.NONE : result;
+ return result == null ? Runtime.NONE : result;
} catch (ExecutionException e) {
throw new EvalException(loc, "Unknown class type " + type);
} catch (ClassCastException e) {
@@ -482,7 +482,7 @@ public class SkylarkRuleImplementationFunctions {
if (!files.isEmpty()) {
builder.addArtifacts(castList(files, Artifact.class));
}
- if (transitiveFiles != Environment.NONE) {
+ if (transitiveFiles != Runtime.NONE) {
builder.addTransitiveArtifacts(((SkylarkNestedSet) transitiveFiles).getSet(Artifact.class));
}
return builder.build();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
index 52a0c498d4..1eb86cde0a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
@@ -22,10 +22,8 @@ import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
import com.google.devtools.build.lib.packages.PackageFactory;
import com.google.devtools.build.lib.packages.RuleClassProvider;
-import com.google.devtools.build.lib.packages.SkylarkNativeModule;
import com.google.devtools.build.lib.rules.SkylarkRuleClassFunctions;
import com.google.devtools.build.lib.skyframe.ASTFileLookupValue.ASTLookupInputException;
-import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.BuildFileAST;
import com.google.devtools.build.lib.syntax.Label;
import com.google.devtools.build.lib.syntax.Label.SyntaxException;
@@ -46,12 +44,12 @@ import java.util.Map;
public class SkylarkImportLookupFunction implements SkyFunction {
private final RuleClassProvider ruleClassProvider;
- private final ImmutableList<BaseFunction> nativeRuleFunctions;
+ private final PackageFactory packageFactory;
public SkylarkImportLookupFunction(
- RuleClassProvider ruleClassProvider, PackageFactory packageFactory) {
+ RuleClassProvider ruleClassProvider, PackageFactory packageFactory) {
this.ruleClassProvider = ruleClassProvider;
- this.nativeRuleFunctions = packageFactory.collectNativeRuleFunctions();
+ this.packageFactory = packageFactory;
}
@Override
@@ -181,12 +179,7 @@ public class SkylarkImportLookupFunction implements SkyFunction {
// the transitive closure of the accessible AST nodes.
SkylarkEnvironment extensionEnv = ruleClassProvider
.createSkylarkRuleClassEnvironment(eventHandler, ast.getContentHashCode());
- // Adding native rules module for build extensions.
- // TODO(bazel-team): this might not be the best place to do this.
- for (BaseFunction function : nativeRuleFunctions) {
- extensionEnv.registerFunction(
- SkylarkNativeModule.class, function.getName(), function);
- }
+ extensionEnv.update("native", packageFactory.getNativeModule());
extensionEnv.setImportedExtensions(importMap);
ast.exec(extensionEnv, eventHandler);
SkylarkRuleClassFunctions.exportRuleFunctions(extensionEnv, file);
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 3b4342a5e5..f16d35ec82 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
@@ -17,8 +17,6 @@ package com.google.devtools.build.lib.syntax;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -38,45 +36,8 @@ import javax.annotation.Nullable;
*/
public class Environment {
- @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;
-
- @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 <code>some/package/BUILD</code>, its value "
- + "will be <code>some/package</code>. "
- + "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:<br>"
- + "<pre class=language-python>def extension():\n"
- + " return PACKAGE_NAME</pre>"
- + "In this case calling <code>extension()</code> 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";
-
- /**
- * 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();
-
protected final Map<String, Object> env = new HashMap<>();
- // BaseFunctions with namespaces. Works only in the global environment.
- protected final Map<Class<?>, Map<String, BaseFunction>> functions = new HashMap<>();
-
/**
* The parent environment. For Skylark it's the global environment,
* used for global read only variable lookup.
@@ -178,9 +139,9 @@ public class Environment {
// 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.
- update("False", FALSE);
- update("True", TRUE);
- update("None", NONE);
+ update("False", Runtime.FALSE);
+ update("True", Runtime.TRUE);
+ update("None", Runtime.NONE);
}
public boolean isSkylark() {
@@ -341,54 +302,6 @@ public class Environment {
}
/**
- * Registers a function with namespace to this global environment.
- */
- public void registerFunction(Class<?> nameSpace, String name, BaseFunction function) {
- nameSpace = getCanonicalRepresentation(nameSpace);
- Preconditions.checkArgument(parent == null);
- if (!functions.containsKey(nameSpace)) {
- functions.put(nameSpace, new HashMap<String, BaseFunction>());
- }
- functions.get(nameSpace).put(name, function);
- }
-
- private Map<String, BaseFunction> getNamespaceFunctions(Class<?> nameSpace) {
- nameSpace = getCanonicalRepresentation(nameSpace);
- Environment topLevel = this;
- while (topLevel.parent != null) {
- topLevel = topLevel.parent;
- }
- return topLevel.functions.get(nameSpace);
- }
-
- /**
- * Returns the canonical representation of the given class, i.e. the super class for which any
- * functions were registered.
- *
- * <p>Currently, this is only necessary for mapping the different subclasses of {@link
- * java.util.Map} to the interface.
- */
- private Class<?> getCanonicalRepresentation(Class<?> clazz) {
- return Map.class.isAssignableFrom(clazz) ? Map.class : clazz;
- }
-
- /**
- * Returns the function of the namespace of the given name or null of it does not exists.
- */
- public BaseFunction getFunction(Class<?> nameSpace, String name) {
- Map<String, BaseFunction> nameSpaceFunctions = getNamespaceFunctions(nameSpace);
- return nameSpaceFunctions != null ? nameSpaceFunctions.get(name) : null;
- }
-
- /**
- * Returns the function names registered with the namespace.
- */
- public Set<String> getFunctionNames(Class<?> nameSpace) {
- Map<String, BaseFunction> nameSpaceFunctions = getNamespaceFunctions(nameSpace);
- return nameSpaceFunctions != null ? nameSpaceFunctions.keySet() : ImmutableSet.<String>of();
- }
-
- /**
* Return the current stack trace (list of functions).
*/
public ImmutableList<BaseFunction> getStackTrace() {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
index e16ffa28b9..ca5f4684f1 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
@@ -274,7 +274,8 @@ public abstract class EvalUtils {
return "int";
} else if (c.equals(Boolean.class)) {
return "bool";
- } else if (c.equals(Void.TYPE) || c.equals(Environment.NoneType.class)) {
+ } else if (c.equals(Void.TYPE) || c.equals(Runtime.NoneType.class)) {
+ // TODO(bazel-team): no one should be seeing Void at all.
return "NoneType";
} else if (List.class.isAssignableFrom(c)) {
// NB: the capital here is a subtle way to distinguish java Tuple and java List
@@ -292,6 +293,7 @@ public abstract class EvalUtils {
} else if (c.equals(SelectorValue.class)) {
return "select";
} else if (NestedSet.class.isAssignableFrom(c) || SkylarkNestedSet.class.isAssignableFrom(c)) {
+ // TODO(bazel-team): no one should be seeing naked NestedSet at all.
return "set";
} else if (ClassObject.SkylarkClassObject.class.isAssignableFrom(c)) {
return "struct";
@@ -332,7 +334,7 @@ public abstract class EvalUtils {
* http://docs.python.org/2/library/stdtypes.html#truth-value-testing
*/
public static boolean toBoolean(Object o) {
- if (o == null || o == Environment.NONE) {
+ if (o == null || o == Runtime.NONE) {
return false;
} else if (o instanceof Boolean) {
return (Boolean) o;
@@ -415,7 +417,7 @@ public abstract class EvalUtils {
/** @return true if x is Java null or Skylark None */
public static boolean isNullOrNone(Object x) {
- return x == null || x == Environment.NONE;
+ return x == null || x == Runtime.NONE;
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
index 73e8d10c4f..e09dc2aa89 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
@@ -317,11 +317,11 @@ public final class FuncallExpression extends Expression {
method.setAccessible(true);
Object result = method.invoke(obj, args);
if (method.getReturnType().equals(Void.TYPE)) {
- return Environment.NONE;
+ return Runtime.NONE;
}
if (result == null) {
if (methodDescriptor.getAnnotation().allowReturnNones()) {
- return Environment.NONE;
+ return Runtime.NONE;
} else {
throw new EvalException(loc,
"Method invocation returned None, please contact Skylark developers: " + methodName
@@ -507,7 +507,7 @@ public final class FuncallExpression extends Expression {
// MethodLibrary.
// For other classes, we can call the Java methods.
BaseFunction function =
- env.getFunction(EvalUtils.getSkylarkType(objValue.getClass()), func.getName());
+ Runtime.getFunction(EvalUtils.getSkylarkType(objValue.getClass()), func.getName());
if (function != null) {
if (!isNamespace(objValue.getClass())) {
// Add self as an implicit parameter in front.
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 93a01e97bf..ef958d356f 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
@@ -90,7 +90,7 @@ public class MethodLibrary {
return str.substring(start, stop);
}
- public static int getListIndex(Object key, int listSize, Location loc)
+ private static int getListIndex(Object key, int listSize, Location loc)
throws ConversionException, EvalException {
// Get the nth element in the list
int index = Type.INTEGER.convert(key, "index operand");
@@ -583,7 +583,7 @@ public class MethodLibrary {
@Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
doc = "optional position at which to stop comparing.")})
private static BuiltinFunction endswith = new BuiltinFunction(
- "endswith", SkylarkList.tuple(0, Environment.NONE)) {
+ "endswith", SkylarkList.tuple(0, Runtime.NONE)) {
public Boolean invoke(String self, String sub, Integer start, Object end)
throws ConversionException {
return pythonSubstring(self, start, end, "'end' operand of 'endswith'").endsWith(sub);
@@ -658,38 +658,57 @@ public class MethodLibrary {
};
// slice operator
- @SkylarkSignature(
- name = "$slice",
- documented = false,
- mandatoryPositionals = {
- @Param(name = "self", type = Object.class, doc = "This string, list or tuple."),
- @Param(name = "start", type = Integer.class, doc = "start position of the slice."),
- @Param(name = "end", type = Integer.class, doc = "end position of the slice.")
- },
- doc = "x[<code>start</code>:<code>end</code>] returns a slice or a list slice.",
- useLocation = true,
- useEnvironment = true
- )
- private static BuiltinFunction slice =
- new BuiltinFunction("$slice") {
- public Object invoke(
- Object self, Integer left, Integer right, Location loc, Environment env)
- throws EvalException, ConversionException {
- // Substring
- if (self instanceof String) {
- return pythonSubstring((String) self, left, right, "");
- }
+ @SkylarkSignature(name = "$slice", objectType = String.class,
+ documented = false,
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "start", type = Integer.class, doc = "start position of the slice."),
+ @Param(name = "end", type = Integer.class, doc = "end position of the slice.")},
+ doc = "x[<code>start</code>:<code>end</code>] returns a slice or a list slice.")
+ private static BuiltinFunction stringSlice = new BuiltinFunction("$slice") {
+ public Object invoke(String self, Integer left, Integer right)
+ throws EvalException, ConversionException {
+ return pythonSubstring(self, left, right, "");
+ }
+ };
- // List slice
- List<Object> list = Type.OBJECT_LIST.convert(self, "list operand");
- left = clampIndex(left, list.size());
- right = clampIndex(right, list.size());
- if (left > right) {
- left = right;
- }
- return convert(list.subList(left, right), env, loc);
- }
- };
+ @SkylarkSignature(name = "$slice", objectType = List.class,
+ documented = false,
+ mandatoryPositionals = {
+ @Param(name = "self", type = List.class, doc = "This list or tuple."),
+ @Param(name = "start", type = Integer.class, doc = "start position of the slice."),
+ @Param(name = "end", type = Integer.class, doc = "end position of the slice.")},
+ doc = "x[<code>start</code>:<code>end</code>] returns a slice or a list slice.")
+ private static BuiltinFunction listSlice = new BuiltinFunction("$slice") {
+ public Object invoke(List<Object> self, Integer left, Integer right)
+ throws EvalException, ConversionException {
+ return sliceList(self, left, right);
+ }
+ };
+
+ @SkylarkSignature(name = "$slice", objectType = SkylarkList.class,
+ documented = false,
+ mandatoryPositionals = {
+ @Param(name = "self", type = SkylarkList.class, doc = "This list or tuple."),
+ @Param(name = "start", type = Integer.class, doc = "start position of the slice."),
+ @Param(name = "end", type = Integer.class, doc = "end position of the slice.")},
+ doc = "x[<code>start</code>:<code>end</code>] returns a slice or a list slice.",
+ useLocation = true)
+ private static BuiltinFunction skylarkListSlice = new BuiltinFunction("$slice") {
+ public Object invoke(SkylarkList self, Integer left, Integer right,
+ Location loc) throws EvalException, ConversionException {
+ return SkylarkList.list(sliceList(self.toList(), left, right), loc);
+ }
+ };
+
+ private static List<Object> sliceList(List<Object> list, Integer left, Integer right) {
+ left = clampIndex(left, list.size());
+ right = clampIndex(right, list.size());
+ if (left > right) {
+ left = right;
+ }
+ return list.subList(left, right);
+ }
// supported list methods
@SkylarkSignature(
@@ -720,7 +739,8 @@ public class MethodLibrary {
// This function has a SkylarkSignature but is only used by the Build language, not Skylark.
@SkylarkSignature(
name = "append",
- returnType = Environment.NoneType.class,
+ objectType = List.class,
+ returnType = Runtime.NoneType.class,
documented = false,
doc = "Adds an item to the end of the list.",
mandatoryPositionals = {
@@ -729,83 +749,123 @@ public class MethodLibrary {
@Param(name = "item", type = Object.class, doc = "Item to add at the end.")
},
useLocation = true,
- useEnvironment = true
- )
+ useEnvironment = true)
private static BuiltinFunction append =
new BuiltinFunction("append") {
- public Environment.NoneType invoke(
- List<Object> self, Object item, Location loc, Environment env)
- throws EvalException, ConversionException {
+ public Runtime.NoneType invoke(List<Object> self, Object item,
+ Location loc, Environment env) throws EvalException, ConversionException {
+ if (env.isSkylark()) {
+ throw new EvalException(loc,
+ "function 'append' is not available in Skylark");
+ }
+ if (EvalUtils.isTuple(self)) {
+ throw new EvalException(loc,
+ "function 'append' is not defined on object of type 'Tuple'");
+ }
self.add(item);
- return Environment.NONE;
+ return Runtime.NONE;
}
};
// This function has a SkylarkSignature but is only used by the Build language, not Skylark.
- @SkylarkSignature(name = "extend", returnType = Environment.NoneType.class, documented = false,
- doc = "Adds all items to the end of the list.",
- mandatoryPositionals = {
- // we use List rather than SkylarkList because this is actually for use *outside* Skylark
- @Param(name = "self", type = List.class, doc = "This list."),
- @Param(name = "items", type = List.class, doc = "Items to add at the end.")},
- useLocation = true, useEnvironment = true)
- private static BuiltinFunction extend = new BuiltinFunction("extend") {
- public Environment.NoneType invoke(List<Object> self, List<Object> items,
- Location loc, Environment env) throws EvalException, ConversionException {
- self.addAll(items);
- return Environment.NONE;
- }
- };
+ @SkylarkSignature(
+ name = "extend",
+ objectType = List.class,
+ returnType = Runtime.NoneType.class,
+ documented = false,
+ doc = "Adds all items to the end of the list.",
+ mandatoryPositionals = {
+ // we use List rather than SkylarkList because this is actually for use *outside* Skylark
+ @Param(name = "self", type = List.class, doc = "This list."),
+ @Param(name = "items", type = List.class, doc = "Items to add at the end.")},
+ useLocation = true,
+ useEnvironment = true)
+ private static BuiltinFunction extend =
+ new BuiltinFunction("extend") {
+ public Runtime.NoneType invoke(List<Object> self, List<Object> items,
+ Location loc, Environment env) throws EvalException, ConversionException {
+ if (env.isSkylark()) {
+ throw new EvalException(loc,
+ "function 'append' is not available in Skylark");
+ }
+ if (EvalUtils.isTuple(self)) {
+ throw new EvalException(loc,
+ "function 'extend' is not defined on object of type 'Tuple'");
+ }
+ self.addAll(items);
+ return Runtime.NONE;
+ }
+ };
// dictionary access operator
- @SkylarkSignature(name = "$index", documented = false,
- doc = "Returns the nth element of a list or string, "
- + "or looks up a value in a dictionary.",
+ @SkylarkSignature(name = "$index", documented = false, objectType = Map.class,
+ doc = "Looks up a value in a dictionary.",
mandatoryPositionals = {
- @Param(name = "self", type = Object.class, doc = "This object."),
+ @Param(name = "self", type = Map.class, doc = "This object."),
@Param(name = "key", type = Object.class, doc = "The index or key to access.")},
useLocation = true)
private static BuiltinFunction indexOperator = new BuiltinFunction("$index") {
- public Object invoke(Object self, Object key,
+ public Object invoke(Map<?, ?> self, Object key,
Location loc) throws EvalException, ConversionException {
- if (self instanceof SkylarkList) {
- SkylarkList list = (SkylarkList) self;
- if (list.isEmpty()) {
- throw new EvalException(loc, "List is empty");
- }
- int index = getListIndex(key, list.size(), loc);
- return list.get(index);
-
- } else if (self instanceof Map<?, ?>) {
- Map<?, ?> dictionary = (Map<?, ?>) self;
- if (!dictionary.containsKey(key)) {
- throw new EvalException(loc, Printer.format("Key %r not found in dictionary", key));
- }
- return dictionary.get(key);
+ if (!self.containsKey(key)) {
+ throw new EvalException(loc, Printer.format("Key %r not found in dictionary", key));
+ }
+ return self.get(key);
+ }
+ };
- } else if (self instanceof List<?>) {
- List<Object> list = Type.OBJECT_LIST.convert(self, "index operand");
- if (list.isEmpty()) {
- throw new EvalException(loc, "List is empty");
- }
- int index = getListIndex(key, list.size(), loc);
- return list.get(index);
+ // list access operator
+ @SkylarkSignature(name = "$index", documented = false, objectType = SkylarkList.class,
+ doc = "Returns the nth element of a list.",
+ mandatoryPositionals = {
+ @Param(name = "self", type = SkylarkList.class, doc = "This object."),
+ @Param(name = "key", type = Object.class, doc = "The index or key to access.")},
+ useLocation = true)
+ private static BuiltinFunction skylarkListIndexOperator = new BuiltinFunction("$index") {
+ public Object invoke(SkylarkList self, Object key,
+ Location loc) throws EvalException, ConversionException {
+ if (self.isEmpty()) {
+ throw new EvalException(loc, "List is empty");
+ }
+ int index = getListIndex(key, self.size(), loc);
+ return self.get(index);
+ }
+ };
- } else if (self instanceof String) {
- String str = (String) self;
- int index = getListIndex(key, str.length(), loc);
- return str.substring(index, index + 1);
- } else {
- // TODO(bazel-team): This is dead code, get rid of it.
- throw new EvalException(loc, String.format(
- "Unsupported datatype (%s) for indexing, only works for dict and list",
- EvalUtils.getDataTypeName(self)));
+ // list access operator
+ @SkylarkSignature(name = "$index", documented = false, objectType = List.class,
+ doc = "Returns the nth element of a list.",
+ mandatoryPositionals = {
+ @Param(name = "self", type = List.class, doc = "This object."),
+ @Param(name = "key", type = Object.class, doc = "The index or key to access.")},
+ useLocation = true)
+ private static BuiltinFunction listIndexOperator = new BuiltinFunction("$index") {
+ public Object invoke(List<?> self, Object key,
+ Location loc) throws EvalException, ConversionException {
+ if (self.isEmpty()) {
+ throw new EvalException(loc, "List is empty");
}
+ int index = getListIndex(key, self.size(), loc);
+ return self.get(index);
}
};
- @SkylarkSignature(name = "values", objectType = DictModule.class,
+ @SkylarkSignature(name = "$index", documented = false, objectType = String.class,
+ doc = "Returns the nth element of a string.",
+ mandatoryPositionals = {
+ @Param(name = "self", type = String.class, doc = "This string."),
+ @Param(name = "key", type = Object.class, doc = "The index or key to access.")},
+ useLocation = true)
+ private static BuiltinFunction stringIndexOperator = new BuiltinFunction("$index") {
+ public Object invoke(String self, Object key,
+ Location loc) throws EvalException, ConversionException {
+ int index = getListIndex(key, self.length(), loc);
+ return self.substring(index, index + 1);
+ }
+ };
+
+ @SkylarkSignature(name = "values", objectType = Map.class,
returnType = HackHackEitherList.class,
doc = "Return the list of values. Dictionaries are always sorted by their keys:"
+ "<pre class=\"language-python\">"
@@ -821,7 +881,7 @@ public class MethodLibrary {
}
};
- @SkylarkSignature(name = "items", objectType = DictModule.class,
+ @SkylarkSignature(name = "items", objectType = Map.class,
returnType = HackHackEitherList.class,
doc = "Return the list of key-value tuples. Dictionaries are always sorted by their keys:"
+ "<pre class=\"language-python\">"
@@ -840,11 +900,11 @@ public class MethodLibrary {
List<?> item = ImmutableList.of(entries.getKey(), entries.getValue());
list.add(env.isSkylark() ? SkylarkList.tuple(item) : item);
}
- return convert(list, env, loc);
- }
- };
+ return convert(list, env, loc);
+ }
+ };
- @SkylarkSignature(name = "keys", objectType = DictModule.class,
+ @SkylarkSignature(name = "keys", objectType = Map.class,
returnType = HackHackEitherList.class,
doc = "Return the list of keys. Dictionaries are always sorted by their keys:"
+ "<pre class=\"language-python\">{2: \"a\", 4: \"b\", 1: \"c\"}.keys() == [1, 2, 4]"
@@ -861,7 +921,7 @@ public class MethodLibrary {
}
};
- @SkylarkSignature(name = "get", objectType = DictModule.class,
+ @SkylarkSignature(name = "get", objectType = Map.class,
doc = "Return the value for <code>key</code> if <code>key</code> is in the dictionary, "
+ "else <code>default</code>. If <code>default</code> is not given, it defaults to "
+ "<code>None</code>, so that this method never throws an error.",
@@ -893,7 +953,8 @@ public class MethodLibrary {
// unary minus
@SkylarkSignature(name = "-", returnType = Integer.class,
- documented = false, doc = "Unary minus operator.",
+ documented = false,
+ doc = "Unary minus operator.",
mandatoryPositionals = {
@Param(name = "num", type = Integer.class, doc = "The number to negate.")})
private static BuiltinFunction minus = new BuiltinFunction("-") {
@@ -1089,7 +1150,7 @@ public class MethodLibrary {
}
};
- @SkylarkSignature(name = "enumerate", returnType = HackHackEitherList.class,
+ @SkylarkSignature(name = "enumerate", returnType = HackHackEitherList.class,
doc = "Return a list of pairs (two-element tuples), with the index (int) and the item from"
+ " the input list.\n<pre class=\"language-python\">"
+ "enumerate([24, 21, 84]) == [(0, 24), (1, 21), (2, 84)]</pre>\n",
@@ -1137,7 +1198,7 @@ public class MethodLibrary {
throws EvalException, ConversionException, InterruptedException {
int start;
int stop;
- if (stopOrNone == Environment.NONE) {
+ if (stopOrNone == Runtime.NONE) {
start = 0;
stop = startOrStop;
} else {
@@ -1194,7 +1255,7 @@ public class MethodLibrary {
if (obj instanceof ClassObject && ((ClassObject) obj).getValue(name) != null) {
return true;
}
- if (env.getFunctionNames(obj.getClass()).contains(name)) {
+ if (Runtime.getFunctionNames(obj.getClass()).contains(name)) {
return true;
}
@@ -1226,7 +1287,7 @@ public class MethodLibrary {
Location loc) throws EvalException, ConversionException {
Object result = DotExpression.eval(obj, name, loc);
if (result == null) {
- if (defaultValue != Environment.NONE) {
+ if (defaultValue != Runtime.NONE) {
return defaultValue;
} else {
throw new EvalException(loc, Printer.format("Object of type '%s' has no attribute %r",
@@ -1250,7 +1311,7 @@ public class MethodLibrary {
if (object instanceof ClassObject) {
fields.addAll(((ClassObject) object).getKeys());
}
- fields.addAll(env.getFunctionNames(object.getClass()));
+ fields.addAll(Runtime.getFunctionNames(object.getClass()));
try {
fields.addAll(FuncallExpression.getMethodNames(object.getClass()));
} catch (ExecutionException e) {
@@ -1274,7 +1335,7 @@ public class MethodLibrary {
@SkylarkSignature(name = "fail",
doc = "Raises an error that cannot be intercepted. It can be used anywhere, "
+ "both in the loading phase and in the analysis phase.",
- returnType = Environment.NoneType.class,
+ returnType = Runtime.NoneType.class,
mandatoryPositionals = {
@Param(name = "msg", type = String.class, doc = "Error message to display for the user")},
optionalPositionals = {
@@ -1284,16 +1345,16 @@ public class MethodLibrary {
+ "error reporting.")},
useLocation = true)
private static final BuiltinFunction fail = new BuiltinFunction("fail") {
- public Environment.NoneType invoke(String msg, Object attr,
+ public Runtime.NoneType invoke(String msg, Object attr,
Location loc) throws EvalException, ConversionException {
- if (attr != Environment.NONE) {
+ if (attr != Runtime.NONE) {
msg = String.format("attribute %s: %s", attr, msg);
}
throw new EvalException(loc, msg);
}
};
- @SkylarkSignature(name = "print", returnType = Environment.NoneType.class,
+ @SkylarkSignature(name = "print", returnType = Runtime.NoneType.class,
doc = "Prints <code>msg</code> to the console.",
optionalNamedOnly = {
@Param(name = "sep", type = String.class, defaultValue = "' '",
@@ -1302,7 +1363,7 @@ public class MethodLibrary {
extraPositionals = {@Param(name = "args", doc = "The objects to print.")},
useLocation = true, useEnvironment = true)
private static final BuiltinFunction print = new BuiltinFunction("print") {
- public Environment.NoneType invoke(String sep, SkylarkList starargs,
+ public Runtime.NoneType invoke(String sep, SkylarkList starargs,
Location loc, SkylarkEnvironment env) throws EvalException {
String msg = Joiner.on(sep).join(Iterables.transform(starargs,
new com.google.common.base.Function<Object, String>() {
@@ -1311,7 +1372,7 @@ public class MethodLibrary {
return Printer.str(input);
}}));
env.handleEvent(Event.warn(loc, msg));
- return Environment.NONE;
+ return Runtime.NONE;
}
};
@@ -1373,7 +1434,7 @@ public class MethodLibrary {
+ "x = [s for s in \"abc\"] # x == [\"a\", \"b\", \"c\"]</pre>\n"
+ "Implicit concatenation of strings is not allowed; use the <code>+</code> "
+ "operator instead.")
- public static final class StringModule {}
+ static final class StringModule {}
/**
* Skylark Dict module.
@@ -1397,82 +1458,23 @@ public class MethodLibrary {
+ "Example:<br>"
+ "<pre class=\"language-python\">\"a\" in {\"a\" : 2, \"b\" : 5} # evaluates as True"
+ "</pre>")
- public static final class DictModule {}
-
- public static final List<BaseFunction> stringFunctions =
- ImmutableList.<BaseFunction>of(
- capitalize,
- count,
- endswith,
- find,
- index,
- format,
- join,
- lower,
- partition,
- replace,
- rfind,
- rindex,
- rpartition,
- rsplit,
- slice,
- split,
- startswith,
- strip,
- title,
- upper);
-
- public static final List<BaseFunction> listPureFunctions = ImmutableList.<BaseFunction>of(
- slice);
-
- public static final List<BaseFunction> listFunctions = ImmutableList.<BaseFunction>of(
- append, extend);
-
- public static final List<BaseFunction> setFunctions = ImmutableList.<BaseFunction>of(union);
-
- public static final List<BaseFunction> dictFunctions = ImmutableList.<BaseFunction>of(
- items, get, keys, values);
-
- private static final List<BaseFunction> pureGlobalFunctions = ImmutableList.<BaseFunction>of(
+ static final class DictModule {}
+
+ static final List<BaseFunction> buildGlobalFunctions = ImmutableList.<BaseFunction>of(
bool, dict, enumerate, int_, len, list, minus, range, repr, select, sorted, str, zip);
- private static final List<BaseFunction> skylarkGlobalFunctions =
+ static final List<BaseFunction> skylarkGlobalFunctions =
ImmutableList.<BaseFunction>builder()
- .addAll(pureGlobalFunctions)
+ .addAll(buildGlobalFunctions)
.add(dir, fail, getattr, hasattr, print, set, struct, type)
.build();
+
/**
* Set up a given environment for supported class methods.
*/
public static void setupMethodEnvironment(Environment env) {
- env.registerFunction(Map.class, indexOperator.getName(), indexOperator);
- setupMethodEnvironment(env, Map.class, dictFunctions);
- env.registerFunction(String.class, indexOperator.getName(), indexOperator);
- setupMethodEnvironment(env, String.class, stringFunctions);
- setupMethodEnvironment(env, List.class, listPureFunctions);
- setupMethodEnvironment(env, SkylarkList.class, listPureFunctions);
- setupMethodEnvironment(env, SkylarkNestedSet.class, setFunctions);
- // TODO(bazel-team): Simplify when list types are unified.
- env.registerFunction(SkylarkList.class, indexOperator.getName(), indexOperator);
- env.registerFunction(List.class, indexOperator.getName(), indexOperator);
- env.registerFunction(ImmutableList.class, indexOperator.getName(), indexOperator);
-
- if (env.isSkylark()) {
- setupMethodEnvironment(env, skylarkGlobalFunctions);
- } else {
- // TODO(bazel-team): listFunctions are not allowed in Skylark extensions (use += instead).
- // It is allowed in BUILD files only for backward-compatibility.
- setupMethodEnvironment(env, List.class, listFunctions);
- setupMethodEnvironment(env, pureGlobalFunctions);
- }
- }
-
- private static void setupMethodEnvironment(
- Environment env, Class<?> nameSpace, Iterable<BaseFunction> functions) {
- for (BaseFunction function : functions) {
- env.registerFunction(nameSpace, function.getName(), function);
- }
+ setupMethodEnvironment(env, env.isSkylark() ? skylarkGlobalFunctions : buildGlobalFunctions);
}
private static void setupMethodEnvironment(Environment env, Iterable<BaseFunction> functions) {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Printer.java b/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
index 7e5e9e0991..4792b25436 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
@@ -114,7 +114,7 @@ public final class Printer {
} else if (o instanceof Integer || o instanceof Double) {
append(buffer, o.toString());
- } else if (o == Environment.NONE) {
+ } else if (o == Runtime.NONE) {
append(buffer, "None");
} else if (o == Boolean.TRUE) {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
new file mode 100644
index 0000000000..50ef2546d5
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java
@@ -0,0 +1,176 @@
+// 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.")
+ static final Boolean TRUE = true;
+
+ @SkylarkSignature(name = "False", returnType = Boolean.class,
+ doc = "Literal for the boolean false.")
+ 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 <code>some/package/BUILD</code>, its value "
+ + "will be <code>some/package</code>. "
+ + "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:<br>"
+ + "<pre class=language-python>def extension():\n"
+ + " return PACKAGE_NAME</pre>"
+ + "In this case calling <code>extension()</code> 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) throws EvalException {
+ // 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.update("False", FALSE).update("True", TRUE).update("None", NONE);
+ }
+
+
+ /** Global registry of functions associated to a class or namespace */
+ private static final Map<Class<?>, Map<String, BaseFunction>> functions = new HashMap<>();
+
+ /**
+ * Registers a function with namespace to this global environment.
+ */
+ public static void registerFunction(Class<?> nameSpace, BaseFunction function) {
+ Preconditions.checkNotNull(nameSpace);
+ // TODO(bazel-team): fix our code so that the two checks below work.
+ // Preconditions.checkArgument(function.getObjectType().equals(nameSpace));
+ // Preconditions.checkArgument(nameSpace.equals(getCanonicalRepresentation(nameSpace)));
+ nameSpace = getCanonicalRepresentation(nameSpace);
+ if (!functions.containsKey(nameSpace)) {
+ functions.put(nameSpace, new HashMap<String, BaseFunction>());
+ }
+ functions.get(nameSpace).put(function.getName(), function);
+ }
+
+ static Map<String, BaseFunction> getNamespaceFunctions(Class<?> nameSpace) {
+ return functions.get(getCanonicalRepresentation(nameSpace));
+ }
+
+ /**
+ * Returns the canonical representation of the given class, i.e. the super class for which any
+ * functions were registered.
+ *
+ * <p>Currently, 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.update(
+ 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.update(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<String, BaseFunction> nameSpaceFunctions = getNamespaceFunctions(nameSpace);
+ return nameSpaceFunctions != null ? nameSpaceFunctions.get(name) : null;
+ }
+
+ /**
+ * Returns the function names registered with the namespace.
+ */
+ public static Set<String> getFunctionNames(Class<?> nameSpace) {
+ Map<String, BaseFunction> nameSpaceFunctions = getNamespaceFunctions(nameSpace);
+ return nameSpaceFunctions != null ? nameSpaceFunctions.keySet() : ImmutableSet.<String>of();
+ }
+
+ static void setupMethodEnvironment(
+ Environment env, Iterable<BaseFunction> functions) throws EvalException {
+ for (BaseFunction function : functions) {
+ env.update(function.getName(), function);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
index cc238179d8..bbf8be7d4c 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
@@ -23,7 +23,6 @@ import com.google.devtools.build.lib.util.Fingerprint;
import java.io.Serializable;
import java.util.HashSet;
-import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -125,9 +124,6 @@ public class SkylarkEnvironment extends Environment implements Serializable {
for (Entry<String, Object> entry : env.entrySet()) {
newEnv.env.put(entry.getKey(), entry.getValue());
}
- for (Map.Entry<Class<?>, Map<String, BaseFunction>> functionMap : functions.entrySet()) {
- newEnv.functions.put(functionMap.getKey(), functionMap.getValue());
- }
return newEnv;
}
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 d114dc7992..bf3c8321c0 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
@@ -202,7 +202,7 @@ public class SkylarkSignatureProcessor {
if (iterator != null) {
return iterator.next();
} else if (param.defaultValue().isEmpty()) {
- return Environment.NONE;
+ return Runtime.NONE;
} else {
try {
return EvaluationContext.SKYLARK_INITIALIZATION.evalExpression(param.defaultValue());
@@ -258,6 +258,12 @@ public class SkylarkSignatureProcessor {
if (!function.isConfigured()) {
function.configure(annotation);
}
+ Class<?> nameSpace = function.getObjectType();
+ if (nameSpace != null) {
+ Preconditions.checkState(!(function instanceof BuiltinFunction.Factory));
+ nameSpace = Runtime.getCanonicalRepresentation(nameSpace);
+ Runtime.registerFunction(nameSpace, function);
+ }
}
} catch (IllegalAccessException e) {
throw new RuntimeException(String.format(
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
index 020cc8c7bf..96aaaa9b8c 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
@@ -152,7 +152,7 @@ public abstract class SkylarkType {
// by declaring its type as TOP instead of NONE, even though at runtime,
// we reject None from all types but NONE, and in particular from e.g. lists of Files.
// TODO(bazel-team): resolve this inconsistency, one way or the other.
- public static final Simple NONE = Simple.of(Environment.NoneType.class);
+ public static final Simple NONE = Simple.of(Runtime.NoneType.class);
private static final class Global {}
/** The STRING type, for strings */
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java
index f9719ae15d..360688dc85 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java
@@ -80,7 +80,7 @@ public class UserDefinedFunction extends BaseFunction {
} finally {
Profiler.instance().logSimpleTask(startTimeProfiler, ProfilerTask.SKYLARK_USER_FN, getName());
}
- return Environment.NONE;
+ return Runtime.NONE;
}
/**