diff options
Diffstat (limited to 'src/main/java/com/google/devtools')
12 files changed, 124 insertions, 26 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java index f8d10cfab5..4ed66e965b 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java @@ -26,6 +26,7 @@ import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.packages.AggregatingAttributeMapper; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor; import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException; import com.google.devtools.build.lib.skyframe.FileSymlinkException; import com.google.devtools.build.lib.skyframe.FileValue; @@ -108,7 +109,8 @@ public class SkylarkRepositoryContext { : SkylarkType.convertToSkylark(val, null)); } } - attrObject = new SkylarkClassObject(attrBuilder.build(), "No such attribute '%s'"); + attrObject = SkylarkClassObjectConstructor.STRUCT.create( + attrBuilder.build(), "No such attribute '%s'"); } @SkylarkCallable( diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java index f2fb3355e9..996371494d 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java +++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java @@ -1250,7 +1250,8 @@ public final class Attribute implements Comparable<Attribute> { } } } - ClassObject attrs = new SkylarkClassObject(attrValues, + ClassObject attrs = SkylarkClassObjectConstructor.STRUCT.create( + attrValues, "No such regular (non late-bound) attribute '%s'."); return callback.call(attrs, o); } 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 3789091663..8ddffdd764 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 @@ -94,7 +94,9 @@ public abstract class ImplicitOutputsFunction { attrValues.put(attrName, value == null ? Runtime.NONE : value); } } - ClassObject attrs = new SkylarkClassObject(attrValues, "Attribute '%s' either doesn't exist " + ClassObject attrs = SkylarkClassObjectConstructor.STRUCT.create( + attrValues, + "Attribute '%s' either doesn't exist " + "or uses a select() (i.e. could have multiple values)"); try { ImmutableMap.Builder<String, String> builder = ImmutableMap.builder(); 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 7b8e57f500..df26e80295 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 @@ -1526,7 +1526,8 @@ public final class PackageFactory { builder.put(function.getName(), function); } } - return new SkylarkClassObject(builder.build(), "no native function or rule '%s'"); + return SkylarkClassObjectConstructor.STRUCT.create( + builder.build(), "no native function or rule '%s'"); } private void buildPkgEnv(Environment pkgEnv, PackageContext context, RuleFactory ruleFactory) { diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java index d28146a526..f5190965b7 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java +++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObject.java @@ -46,6 +46,7 @@ public class SkylarkClassObject implements ClassObject, SkylarkValue, Concatable /** Error message to use when errorMessage argument is null. */ private static final String DEFAULT_ERROR_MESSAGE = "'struct' object has no attribute '%s'"; + private final SkylarkClassObjectConstructor constructor; private final ImmutableMap<String, Object> values; private final Location creationLoc; private final String errorMessage; @@ -54,7 +55,9 @@ public class SkylarkClassObject implements ClassObject, SkylarkValue, Concatable * Primarily for testing purposes where no location is available and the default * errorMessage suffices. */ - public SkylarkClassObject(Map<String, Object> values) { + public SkylarkClassObject(SkylarkClassObjectConstructor constructor, + Map<String, Object> values) { + this.constructor = constructor; this.values = copyValues(values); this.creationLoc = null; this.errorMessage = DEFAULT_ERROR_MESSAGE; @@ -64,13 +67,17 @@ public class SkylarkClassObject implements ClassObject, SkylarkValue, Concatable * Creates a built-in struct (i.e. without creation loc). The errorMessage has to have * exactly one '%s' parameter to substitute the struct field name. */ - public SkylarkClassObject(Map<String, Object> values, String errorMessage) { + public SkylarkClassObject(SkylarkClassObjectConstructor constructor, + Map<String, Object> values, String errorMessage) { + this.constructor = constructor; this.values = copyValues(values); this.creationLoc = null; this.errorMessage = Preconditions.checkNotNull(errorMessage); } - public SkylarkClassObject(Map<String, Object> values, Location creationLoc) { + public SkylarkClassObject(SkylarkClassObjectConstructor constructor, + Map<String, Object> values, Location creationLoc) { + this.constructor = constructor; this.values = copyValues(values); this.creationLoc = Preconditions.checkNotNull(creationLoc); this.errorMessage = DEFAULT_ERROR_MESSAGE; @@ -133,8 +140,12 @@ public class SkylarkClassObject implements ClassObject, SkylarkValue, Concatable throw new EvalException(loc, "Cannot concat structs with common field(s): " + Joiner.on(",").join(commonFields)); } - return new SkylarkClassObject(ImmutableMap.<String, Object>builder() - .putAll(lval.values).putAll(rval.values).build(), loc); + return new SkylarkClassObject(lval.constructor, + ImmutableMap.<String, Object>builder() + .putAll(lval.values) + .putAll(rval.values) + .build(), + loc); } } @@ -163,7 +174,8 @@ public class SkylarkClassObject implements ClassObject, SkylarkValue, Concatable @Override public void write(Appendable buffer, char quotationMark) { boolean first = true; - Printer.append(buffer, "struct("); + Printer.append(buffer, constructor.getName()); + Printer.append(buffer, "("); // Sort by key to ensure deterministic output. for (String key : Ordering.natural().sortedCopy(values.keySet())) { if (!first) { diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObjectConstructor.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObjectConstructor.java new file mode 100644 index 0000000000..b451efe583 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkClassObjectConstructor.java @@ -0,0 +1,76 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.devtools.build.lib.packages; + +import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.syntax.BaseFunction; +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.FunctionSignature; +import com.google.devtools.build.lib.syntax.FunctionSignature.WithValues; +import com.google.devtools.build.lib.syntax.SkylarkType; +import com.google.devtools.build.lib.syntax.Type.ConversionException; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * A constructor for {@link SkylarkClassObject}. + */ +public final class SkylarkClassObjectConstructor extends BaseFunction { + /** + * "struct" function. + */ + public static final SkylarkClassObjectConstructor STRUCT = + new SkylarkClassObjectConstructor("struct"); + + + private static final FunctionSignature.WithValues<Object, SkylarkType> SIGNATURE = + WithValues.create(FunctionSignature.KWARGS); + + public SkylarkClassObjectConstructor(String name, Location location) { + super(name, SIGNATURE, location); + } + + public SkylarkClassObjectConstructor(String name) { + this(name, Location.BUILTIN); + } + + @Override + protected Object call(Object[] args, @Nullable FuncallExpression ast, @Nullable Environment env) + throws EvalException, ConversionException, InterruptedException { + @SuppressWarnings("unchecked") + Map<String, Object> kwargs = (Map<String, Object>) args[0]; + return new SkylarkClassObject(this, kwargs, ast != null ? ast.getLocation() : Location.BUILTIN); + } + + /** + * Creates a built-in class object (i.e. without creation loc). The errorMessage has to have + * exactly one '%s' parameter to substitute the field name. + */ + public SkylarkClassObject create(Map<String, Object> values, String message) { + return new SkylarkClassObject(this, values, message); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(@Nullable Object other) { + return other == this; + } +} 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 54b393a7dc..12c5caa66b 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 @@ -454,7 +454,8 @@ public class WorkspaceFactory { } builder.put("bazel_version", version); - return new SkylarkClassObject(builder.build(), "no native function or rule '%s'"); + return SkylarkClassObjectConstructor.STRUCT.create( + builder.build(), "no native function or rule '%s'"); } public static ClassObject newNativeModule(RuleClassProvider ruleClassProvider, String version) { 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 cb22b50ba3..9433807410 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 @@ -63,6 +63,7 @@ import com.google.devtools.build.lib.packages.RuleFactory.BuildLangTypedAttribut import com.google.devtools.build.lib.packages.RuleFactory.InvalidRuleException; import com.google.devtools.build.lib.packages.SkylarkAspect; import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.packages.TestSize; import com.google.devtools.build.lib.rules.SkylarkAttr.Descriptor; @@ -199,13 +200,8 @@ public class SkylarkRuleClassFunctions { + "return s.x + getattr(s, \"y\") # returns 5</pre>", extraKeywords = @Param(name = "kwargs", doc = "the struct attributes"), useLocation = true) - private static final BuiltinFunction struct = new BuiltinFunction("struct") { - @SuppressWarnings("unchecked") - public SkylarkClassObject invoke(SkylarkDict<String, Object> kwargs, Location loc) - throws EvalException { - return new SkylarkClassObject(kwargs, loc); - } - }; + private static final SkylarkClassObjectConstructor struct = + SkylarkClassObjectConstructor.STRUCT; // TODO(bazel-team): implement attribute copy and other rule properties 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 248bbfd33b..b95554cfe8 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 @@ -43,6 +43,7 @@ import com.google.devtools.build.lib.packages.OutputFile; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.RawAttributeMapper; import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor; import com.google.devtools.build.lib.shell.ShellUtils; import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; @@ -219,7 +220,7 @@ public final class SkylarkRuleContext { this.artifactsLabelMap = artifactLabelMapBuilder.build(); this.outputsObject = - new SkylarkClassObject( + SkylarkClassObjectConstructor.STRUCT.create( outputsBuilder, "No attribute '%s' in outputs. Make sure you declared a rule output with this name."); @@ -351,21 +352,21 @@ public final class SkylarkRuleContext { ImmutableMap<Artifact, FilesToRunProvider> executableRunfilesMap) { this.ruleClassName = ruleClassName; attrObject = - new SkylarkClassObject( + SkylarkClassObjectConstructor.STRUCT.create( attrs, "No attribute '%s' in attr. Make sure you declared a rule attribute with this name."); executableObject = - new SkylarkClassObject( + SkylarkClassObjectConstructor.STRUCT.create( executables, "No attribute '%s' in executable. Make sure there is a label type attribute marked " + "as 'executable' with this name"); fileObject = - new SkylarkClassObject( + SkylarkClassObjectConstructor.STRUCT.create( singleFiles, "No attribute '%s' in file. Make sure there is a label type attribute marked " + "as 'single_file' with this name"); filesObject = - new SkylarkClassObject( + SkylarkClassObjectConstructor.STRUCT.create( files, "No attribute '%s' in files. Make sure there is a label or label_list type attribute " + "with this name"); diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java index 8249fd121a..4051f81ff5 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor; import com.google.devtools.build.lib.rules.cpp.CppModuleMap; import com.google.devtools.build.lib.rules.cpp.LinkerInputs; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; @@ -416,12 +417,15 @@ public final class ObjcProvider extends SkylarkClassObject implements Transitive // Items which should be passed to strictly direct dependers, but not transitive dependers. private final ImmutableMap<Key<?>, NestedSet<?>> strictDependencyItems; + private static final SkylarkClassObjectConstructor OBJC_PROVIDER = + new SkylarkClassObjectConstructor("objc_provider"); + private ObjcProvider( ImmutableMap<Key<?>, NestedSet<?>> items, ImmutableMap<Key<?>, NestedSet<?>> nonPropagatedItems, ImmutableMap<Key<?>, NestedSet<?>> strictDependencyItems, ImmutableMap<String, Object> skylarkFields) { - super(skylarkFields, "ObjcProvider field %s could not be instantiated"); + super(OBJC_PROVIDER, skylarkFields, "ObjcProvider field %s could not be instantiated"); this.items = Preconditions.checkNotNull(items); this.nonPropagatedItems = Preconditions.checkNotNull(nonPropagatedItems); this.strictDependencyItems = Preconditions.checkNotNull(strictDependencyItems); diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProviderSkylarkConverters.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProviderSkylarkConverters.java index 727891e820..caf0021c8c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProviderSkylarkConverters.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProviderSkylarkConverters.java @@ -25,6 +25,7 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor; import com.google.devtools.build.lib.rules.objc.ObjcProvider.Key; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.EvalUtils; @@ -133,7 +134,7 @@ public class ObjcProviderSkylarkConverters { public Object valueForSkylark(Key<?> javaKey, NestedSet<?> javaValue) { NestedSetBuilder<SkylarkClassObject> result = NestedSetBuilder.stableOrder(); for (BundleableFile bundleableFile : (Iterable<BundleableFile>) javaValue) { - result.add(new SkylarkClassObject( + result.add(SkylarkClassObjectConstructor.STRUCT.create( ImmutableMap.<String, Object>of( BUNDLED_FIELD, bundleableFile.getBundled(), BUNDLE_PATH_FIELD, bundleableFile.getBundlePath() diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java index 842e9b7d7b..d03f380e9d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java @@ -44,6 +44,7 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor; import com.google.devtools.build.lib.rules.cpp.CppFileTypes; import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector; import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector.LocalMetadataCollector; @@ -161,7 +162,7 @@ public final class PyCommon { */ public static SkylarkClassObject createSourceProvider( NestedSet<Artifact> transitivePythonSources, boolean isUsingSharedLibrary) { - return new SkylarkClassObject( + return SkylarkClassObjectConstructor.STRUCT.create( ImmutableMap.<String, Object>of( TRANSITIVE_PYTHON_SRCS, SkylarkNestedSet.of(Artifact.class, transitivePythonSources), |