diff options
author | Dmitry Lomov <dslomov@google.com> | 2015-11-26 10:07:32 +0000 |
---|---|---|
committer | Philipp Wollermann <philwo@google.com> | 2015-11-26 13:19:28 +0000 |
commit | 7b599453389b3a00eebf25c58cde322a0e7bdf02 (patch) | |
tree | b3c5860bf77e7d7665319316701f472c5f345a7e /src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java | |
parent | c89366f6d7fe092af74f25949f00ed409a86caab (diff) |
Refactor Skylark rules and attributes in preparation to Skylark aspects.
1. attr.<type> functions return a wrapper object instead of
Attribute.Builder dierctly.
2. RuleClass is created once per the life-time of RuleFunction, during
export
3. Attributes are added to the RuleClass at exporting.
--
MOS_MIGRATED_REVID=108774581
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java | 80 |
1 files changed, 51 insertions, 29 deletions
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 ed5892486a..63b6307525 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 @@ -84,6 +84,7 @@ import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor; import com.google.devtools.build.lib.syntax.SkylarkValue; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.syntax.Type.ConversionException; +import com.google.devtools.build.lib.util.Pair; import java.util.HashMap; import java.util.Map; @@ -264,18 +265,22 @@ public class SkylarkRuleClassFunctions { // We'll set the name later, pass the empty string for now. RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent); + ImmutableList.Builder<Pair<String, SkylarkAttr.Descriptor>> attributes = + ImmutableList.builder(); 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(); + for (Map.Entry<String, SkylarkAttr.Descriptor> attr : + castMap(attrs, String.class, SkylarkAttr.Descriptor.class, "attrs").entrySet()) { + SkylarkAttr.Descriptor attrDescriptor = attr.getValue(); String attrName = - attributeToNative(attr.getKey(), ast.getLocation(), attrBuilder.hasLateBoundValue()); - addAttribute(builder, attrBuilder.build(attrName)); + attributeToNative(attr.getKey(), ast.getLocation(), + attrDescriptor.getAttributeBuilder().hasLateBoundValue()); + attributes.add(Pair.of(attrName, attrDescriptor)); } } if (executable || test) { addAttribute( + ast.getLocation(), builder, attr("$is_executable", BOOLEAN) .value(true) @@ -307,16 +312,9 @@ public class SkylarkRuleClassFunctions { registerRequiredFragments(fragments, hostFragments, builder); builder.setConfiguredTargetFunction(implementation); builder.setRuleDefinitionEnvironment(funcallEnv); - return new RuleFunction(builder, type); + return new RuleFunction(builder, type, attributes.build(), ast.getLocation()); } - private void addAttribute(RuleClass.Builder builder, Attribute attribute) throws EvalException { - try { - builder.addOrOverrideAttribute(attribute); - } catch (IllegalArgumentException ex) { - throw new EvalException(location, ex); - } - } private void registerRequiredFragments( SkylarkList fragments, SkylarkList hostFragments, RuleClass.Builder builder) @@ -336,6 +334,16 @@ public class SkylarkRuleClassFunctions { } }; + private static void addAttribute( + Location location, RuleClass.Builder builder, Attribute attribute) throws EvalException { + try { + builder.addOrOverrideAttribute(attribute); + } catch (IllegalArgumentException ex) { + throw new EvalException(location, ex); + } + } + + @SkylarkSignature( name = "aspect", returnType = SkylarkAspect.class, @@ -367,17 +375,22 @@ public class SkylarkRuleClassFunctions { /** The implementation for the magic function "rule" that creates Skylark rule classes */ public static final class RuleFunction extends BaseFunction { - // Note that this means that we can reuse the same builder. - // This is fine since we don't modify the builder from here. - private final RuleClass.Builder builder; + private RuleClass.Builder builder; + + private RuleClass ruleClass; private final RuleClassType type; + private ImmutableList<Pair<String, SkylarkAttr.Descriptor>> attributes; + private final Location definitionLocation; private Label skylarkLabel; - private String ruleClassName; - public RuleFunction(Builder builder, RuleClassType type) { + public RuleFunction(Builder builder, RuleClassType type, + ImmutableList<Pair<String, SkylarkAttr.Descriptor>> attributes, + Location definitionLocation) { super("rule", FunctionSignature.KWARGS); this.builder = builder; this.type = type; + this.attributes = attributes; + this.definitionLocation = definitionLocation; } @Override @@ -387,15 +400,10 @@ public class SkylarkRuleClassFunctions { throws EvalException, InterruptedException, ConversionException { env.checkLoadingPhase(getName(), ast.getLocation()); try { - if (ruleClassName == null || skylarkLabel == null) { + if (ruleClass == null) { throw new EvalException(ast.getLocation(), "Invalid rule class hasn't been exported by a Skylark file"); } - if (type == RuleClassType.TEST != TargetUtils.isTestRuleName(ruleClassName)) { - throw new EvalException(ast.getLocation(), "Invalid rule class name '" + ruleClassName - + "', test rule class names must end with '_test' and other rule classes must not"); - } - RuleClass ruleClass = builder.build(ruleClassName); PackageContext pkgContext = (PackageContext) env.lookup(PackageFactory.PKG_CONTEXT); return RuleFactory.createAndAddRule( pkgContext, ruleClass, (Map<String, Object>) args[0], ast, env); @@ -407,18 +415,32 @@ public class SkylarkRuleClassFunctions { /** * Export a RuleFunction from a Skylark file with a given name. */ - void export(Label skylarkLabel, String ruleClassName) { + void export(Label skylarkLabel, String ruleClassName) throws EvalException { + Preconditions.checkState(ruleClass == null && builder != null); this.skylarkLabel = skylarkLabel; - this.ruleClassName = ruleClassName; + if (type == RuleClassType.TEST != TargetUtils.isTestRuleName(ruleClassName)) { + throw new EvalException(definitionLocation, "Invalid rule class name '" + ruleClassName + + "', test rule class names must end with '_test' and other rule classes must not"); + } + for (Pair<String, SkylarkAttr.Descriptor> attribute : attributes) { + addAttribute(definitionLocation, builder, + attribute.getSecond().getAttributeBuilder().build(attribute.getFirst())); + } + this.ruleClass = builder.build(ruleClassName); + + this.builder = null; + this.attributes = null; } @VisibleForTesting - public RuleClass.Builder getBuilder() { - return builder; + public RuleClass getRuleClass() { + Preconditions.checkState(ruleClass != null && builder == null); + return ruleClass; } } - public static void exportRuleFunctionsAndAspects(Environment env, Label skylarkLabel) { + public static void exportRuleFunctionsAndAspects(Environment env, Label skylarkLabel) + throws EvalException { for (String name : env.getGlobals().getDirectVariableNames()) { try { Object value = env.lookup(name); |