diff options
author | 2016-08-05 08:38:26 +0000 | |
---|---|---|
committer | 2016-08-05 13:32:33 +0000 | |
commit | cdb6ef554397c1d3da7ee9921305f646bec5ae16 (patch) | |
tree | 23cde8c143ecf6496570bf56ace1c6f405acbd35 /src/main/java/com/google/devtools/build/lib/syntax | |
parent | 6df3e71eb05493fa421121fa73e607a6fbf458c3 (diff) |
Make SkylarkClassObject "Bazel-specific".
This in preparation to DeclaredProviders implementation.
--
MOS_MIGRATED_REVID=129420617
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/syntax')
7 files changed, 52 insertions, 190 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java index a31b037601..131ee54772 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java @@ -18,7 +18,7 @@ import static com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils.append import com.google.common.base.Strings; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.events.Location; -import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject; +import com.google.devtools.build.lib.syntax.Concatable.Concatter; import com.google.devtools.build.lib.syntax.SkylarkList.MutableList; import com.google.devtools.build.lib.syntax.SkylarkList.Tuple; import com.google.devtools.build.lib.syntax.compiler.ByteCodeMethodCalls; @@ -29,17 +29,15 @@ import com.google.devtools.build.lib.syntax.compiler.Jump; import com.google.devtools.build.lib.syntax.compiler.Jump.PrimitiveComparison; import com.google.devtools.build.lib.syntax.compiler.LabelAdder; import com.google.devtools.build.lib.syntax.compiler.VariableScope; - -import net.bytebuddy.implementation.bytecode.ByteCodeAppender; -import net.bytebuddy.implementation.bytecode.Duplication; -import net.bytebuddy.implementation.bytecode.Removal; -import net.bytebuddy.implementation.bytecode.StackManipulation; - import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.IllegalFormatException; import java.util.List; +import net.bytebuddy.implementation.bytecode.ByteCodeAppender; +import net.bytebuddy.implementation.bytecode.Duplication; +import net.bytebuddy.implementation.bytecode.Removal; +import net.bytebuddy.implementation.bytecode.StackManipulation; /** * Syntax node for a binary operator expression. @@ -338,9 +336,15 @@ public final class BinaryOperatorExpression extends Expression { return SkylarkDict.plus((SkylarkDict<?, ?>) lval, (SkylarkDict<?, ?>) rval, env); } - if (lval instanceof SkylarkClassObject && rval instanceof SkylarkClassObject) { - return SkylarkClassObject.concat( - (SkylarkClassObject) lval, (SkylarkClassObject) rval, location); + if (lval instanceof Concatable && rval instanceof Concatable) { + Concatable lobj = (Concatable) lval; + Concatable robj = (Concatable) rval; + Concatter concatter = lobj.getConcatter(); + if (concatter != null && concatter.equals(robj.getConcatter())) { + return concatter.concat(lobj, robj, location); + } else { + throw typeException(lval, rval, Operator.PLUS, location); + } } // TODO(bazel-team): Remove this case. Union of sets should use '|' instead of '+'. diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java b/src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java index 79c19610e0..8ea9aa1372 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/ClassObject.java @@ -13,21 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.syntax; -import com.google.common.base.Joiner; import com.google.common.collect.ImmutableCollection; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Ordering; -import com.google.common.collect.Sets; -import com.google.common.collect.Sets.SetView; -import com.google.devtools.build.lib.events.Location; -import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; -import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; -import com.google.devtools.build.lib.skylarkinterface.SkylarkValue; -import com.google.devtools.build.lib.util.Preconditions; - -import java.io.Serializable; -import java.util.Map; - import javax.annotation.Nullable; /** @@ -53,140 +39,4 @@ public interface ClassObject { * of this struct, or returns null to use the default error message. */ @Nullable String errorMessage(String name); - - /** An implementation class of ClassObject for structs created in Skylark code. */ - // TODO(bazel-team): maybe move the SkylarkModule annotation to the ClassObject interface? - @SkylarkModule( - name = "struct", - category = SkylarkModuleCategory.BUILTIN, - doc = - "A special language element to support structs (i.e. simple value objects). " - + "See the global <a href=\"globals.html#struct\">struct</a> function " - + "for more details." - ) - public class SkylarkClassObject implements ClassObject, SkylarkValue, Serializable { - /** Error message to use when errorMessage argument is null. */ - private static final String DEFAULT_ERROR_MESSAGE = "'struct' object has no attribute '%s'"; - - private final ImmutableMap<String, Object> values; - private final Location creationLoc; - private final String errorMessage; - - /** - * Primarily for testing purposes where no location is available and the default - * errorMessage suffices. - */ - public SkylarkClassObject(Map<String, Object> values) { - this.values = copyValues(values); - this.creationLoc = null; - this.errorMessage = DEFAULT_ERROR_MESSAGE; - } - - /** - * 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) { - this.values = copyValues(values); - this.creationLoc = null; - this.errorMessage = Preconditions.checkNotNull(errorMessage); - } - - public SkylarkClassObject(Map<String, Object> values, Location creationLoc) { - this.values = copyValues(values); - this.creationLoc = Preconditions.checkNotNull(creationLoc); - this.errorMessage = DEFAULT_ERROR_MESSAGE; - } - - // Ensure that values are all acceptable to Skylark before to stuff them in a ClassObject - private ImmutableMap<String, Object> copyValues(Map<String, Object> values) { - ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder(); - for (Map.Entry<String, Object> e : values.entrySet()) { - builder.put(e.getKey(), SkylarkType.convertToSkylark(e.getValue(), null)); - } - return builder.build(); - } - - @Override - public Object getValue(String name) { - return values.get(name); - } - - /** - * Returns a value and try to cast it into specified type - */ - public <TYPE> TYPE getValue(String key, Class<TYPE> type) throws EvalException { - Object obj = values.get(key); - if (obj == null) { - return null; - } - SkylarkType.checkType(obj, type, key); - return type.cast(obj); - } - - @Override - public ImmutableCollection<String> getKeys() { - return values.keySet(); - } - - public Location getCreationLoc() { - return Preconditions.checkNotNull(creationLoc, - "This struct was not created in a Skylark code"); - } - - static SkylarkClassObject concat( - SkylarkClassObject lval, SkylarkClassObject rval, Location loc) throws EvalException { - SetView<String> commonFields = Sets.intersection(lval.values.keySet(), rval.values.keySet()); - if (!commonFields.isEmpty()) { - 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); - } - - @Override - public String errorMessage(String name) { - String suffix = - "Available attributes: " - + Joiner.on(", ").join(Ordering.natural().sortedCopy(values.keySet())); - return String.format(errorMessage, name) + "\n" + suffix; - } - - @Override - public boolean isImmutable() { - for (Object item : values.values()) { - if (!EvalUtils.isImmutable(item)) { - return false; - } - } - return true; - } - - /** - * Convert the object to string using Skylark syntax. The output tries to be - * reversible (but there is no guarantee, it depends on the actual values). - */ - @Override - public void write(Appendable buffer, char quotationMark) { - boolean first = true; - Printer.append(buffer, "struct("); - // Sort by key to ensure deterministic output. - for (String key : Ordering.natural().sortedCopy(values.keySet())) { - if (!first) { - Printer.append(buffer, ", "); - } - first = false; - Printer.append(buffer, key); - Printer.append(buffer, " = "); - Printer.write(buffer, values.get(key), quotationMark); - } - Printer.append(buffer, ")"); - } - - @Override - public String toString() { - return Printer.repr(this); - } - } } diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Concatable.java b/src/main/java/com/google/devtools/build/lib/syntax/Concatable.java new file mode 100644 index 0000000000..81f489f7bf --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/syntax/Concatable.java @@ -0,0 +1,36 @@ +// 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.syntax; + +import com.google.devtools.build.lib.events.Location; +import javax.annotation.Nullable; + +/** + * Skylark values that support '+' operator should implement this interface. + */ +public interface Concatable { + + /** + * Implements 'plus' operator on ClassObjects. + */ + interface Concatter { + Concatable concat(Concatable lval, Concatable rval, Location loc) throws EvalException; + } + + /* Returns a concatter for this {@link Concatable}. + * Two {@link Concatable}s can be added together if their concatters are equal. + */ + @Nullable + Concatter getConcatter(); +} 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 4a661896b6..386a9aefeb 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 @@ -26,12 +26,10 @@ import com.google.devtools.build.lib.skylarkinterface.SkylarkValue; import com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.vfs.PathFragment; - -import net.bytebuddy.implementation.bytecode.StackManipulation; - import java.util.Collection; import java.util.List; import java.util.Map; +import net.bytebuddy.implementation.bytecode.StackManipulation; /** * Utilities used by the evaluator. @@ -280,8 +278,6 @@ public final class EvalUtils { } 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"; } else { if (c.getSimpleName().isEmpty()) { return c.getName(); 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 f103211379..4b39a7d1c6 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 @@ -29,11 +29,9 @@ import com.google.devtools.build.lib.skylarkinterface.Param; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature; -import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject; import com.google.devtools.build.lib.syntax.SkylarkList.MutableList; import com.google.devtools.build.lib.syntax.SkylarkList.Tuple; import com.google.devtools.build.lib.syntax.Type.ConversionException; - import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; @@ -1850,21 +1848,6 @@ public class MethodLibrary { } }; - @SkylarkSignature(name = "struct", returnType = SkylarkClassObject.class, doc = - "Creates an immutable struct using the keyword arguments as attributes. It is used to group " - + "multiple values together.Example:<br>" - + "<pre class=\"language-python\">s = struct(x = 2, y = 3)\n" - + "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); - } - }; - @SkylarkSignature( name = "set", returnType = SkylarkNestedSet.class, @@ -2345,7 +2328,7 @@ public class MethodLibrary { static final List<BaseFunction> skylarkGlobalFunctions = ImmutableList.<BaseFunction>builder() .addAll(buildGlobalFunctions) - .add(dir, fail, getattr, hasattr, hash, print, struct, type) + .add(dir, fail, getattr, hasattr, hash, print, type) .build(); /** diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java index 0f8a3d31bc..2a64d7931d 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java @@ -24,13 +24,11 @@ import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; import com.google.devtools.build.lib.skylarkinterface.SkylarkValue; import com.google.devtools.build.lib.util.Preconditions; - import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; - import javax.annotation.Nullable; /** A generic type safe NestedSet wrapper for Skylark. */ 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 f662ea13b4..e73672a93b 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 @@ -27,7 +27,6 @@ import com.google.devtools.build.lib.skylarkinterface.SkylarkValue; import com.google.devtools.build.lib.syntax.SkylarkList.MutableList; import com.google.devtools.build.lib.syntax.SkylarkList.Tuple; import com.google.devtools.build.lib.util.Preconditions; - import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; @@ -37,7 +36,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; - import javax.annotation.Nullable; /** @@ -168,9 +166,6 @@ public abstract class SkylarkType implements Serializable { /** The BOOLEAN type, that contains TRUE and FALSE */ public static final Simple BOOL = Simple.of(Boolean.class); - /** The STRUCT type, for all Struct's */ - public static final Simple STRUCT = Simple.of(ClassObject.SkylarkClassObject.class); - /** The FUNCTION type, that contains all functions, otherwise dynamically typed at call-time */ public static final SkylarkFunctionType FUNCTION = new SkylarkFunctionType("unknown", TOP); |