@Override public Environment createEnvironment(EventHandler eventHandler, Environment environment) { return Environment.builder(Mutability.create("build test")) .setGlobals(environment == null ? Environment.BUILD : environment.getGlobals()) .setEventHandler(eventHandler) .build(); }
private static Environment.Frame createConstantsGlobals() { try (Mutability mutability = Mutability.create("CONSTANTS")) { Environment env = Environment.builder(mutability).build(); Runtime.setupConstants(env); return env.getGlobals(); } }
private static Environment.Frame createSkylarkGlobals() { try (Mutability mutability = Mutability.create("SKYLARK")) { Environment env = Environment.builder(mutability).setSkylark().build(); Runtime.setupConstants(env); Runtime.setupMethodEnvironment(env, MethodLibrary.skylarkGlobalFunctions); return env.getGlobals(); } }
@Override public Environment createEnvironment(EventHandler eventHandler, Environment environment) { return Environment.builder(Mutability.create("skylark test")) .setSkylark() .setGlobals(environment == null ? Environment.SKYLARK : environment.getGlobals()) .setEventHandler(eventHandler) .build(); }
/** * Create a Rule Configured Target from the ruleContext and the ruleImplementation. The * registeredProviderTypes map indicates which keys in structs returned by skylark rules should be * interpreted as native TransitiveInfoProvider instances of type (map value). */ public static ConfiguredTarget buildRule( RuleContext ruleContext, BaseFunction ruleImplementation, Map<String, Class<? extends TransitiveInfoProvider>> registeredProviderTypes) throws InterruptedException { String expectFailure = ruleContext.attributes().get("expect_failure", Type.STRING); try (Mutability mutability = Mutability.create("configured target")) { SkylarkRuleContext skylarkRuleContext = new SkylarkRuleContext(ruleContext, Kind.RULE); Environment env = Environment.builder(mutability) .setSkylark() .setCallerLabel(ruleContext.getLabel()) .setGlobals( ruleContext .getRule() .getRuleClassObject() .getRuleDefinitionEnvironment() .getGlobals()) .setEventHandler(ruleContext.getAnalysisEnvironment().getEventHandler()) .build(); // NB: loading phase functions are not available: this is analysis already, // so we do *not* setLoadingPhase(). Object target = ruleImplementation.call( ImmutableList.<Object>of(skylarkRuleContext), ImmutableMap.<String, Object>of(), /*ast=*/ null, env); if (ruleContext.hasErrors()) { return null; } else if (!(target instanceof SkylarkClassObject) && target != Runtime.NONE && !(target instanceof Iterable)) { ruleContext.ruleError( String.format( "Rule should return a return a struct or a list, but got %s", SkylarkType.typeOf(target))); return null; } else if (!expectFailure.isEmpty()) { ruleContext.ruleError("Expected failure not found: " + expectFailure); return null; } ConfiguredTarget configuredTarget = createTarget(ruleContext, target, registeredProviderTypes); SkylarkProviderValidationUtil.checkOrphanArtifacts(ruleContext); return configuredTarget; } catch (EvalException e) { addRuleToStackTrace(e, ruleContext.getRule(), ruleImplementation); // If the error was expected, return an empty target. if (!expectFailure.isEmpty() && getMessageWithoutStackTrace(e).matches(expectFailure)) { return new com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder(ruleContext) .add(RunfilesProvider.class, RunfilesProvider.EMPTY) .build(); } ruleContext.ruleError("\n" + e.print()); return null; } }
/** * Checks that this Freezable object can be mutated from the given {@link Environment}. * * @param object a Freezable object that we check is still mutable. * @param env the {@link Environment} attempting the mutation. * @throws MutabilityException when the object was frozen already, or is from another context. */ public static void checkMutable(Freezable object, Environment env) throws MutabilityException { if (!object.mutability().isMutable()) { throw new MutabilityException("trying to mutate a frozen object"); } // Consider an {@link Environment} e1, in which is created {@link UserDefinedFunction} f1, // that closes over some variable v1 bound to list l1. If somehow, via the magic of callbacks, // f1 or l1 is passed as argument to some function f2 evaluated in {@link environment} e2 // while e1 is be mutable, e2, being a different {@link Environment}, should not be // allowed to mutate objects from e1. It's a bug, that shouldn't happen in our current code // base, so we throw an AssertionError. If in the future such situations are allowed to happen, // then we should throw a MutabilityException instead. if (!object.mutability().equals(env.mutability())) { throw new AssertionError("trying to mutate an object from a different context"); } }
private Object callCompiledFunction(Object[] arguments, FuncallExpression ast, Environment env) { compilerDebug("Calling compiled function " + getLocationPathAndLine() + " " + getName()); try { Profiler.instance() .startTask( ProfilerTask.SKYLARK_USER_COMPILED_FN, getLocationPathAndLine() + "#" + getName()); env.enterScope(this, ast, definitionGlobals); return method .get() .invoke(null, ImmutableList.builder().add(arguments).add(env).build().toArray()); } catch (IllegalAccessException e) { // this should never happen throw new RuntimeException( "Compiler created code that could not be accessed reflectively.", e); } catch (InvocationTargetException e) { compilerDebug("Error running compiled version", e.getCause()); return null; } finally { Profiler.instance().completeTask(ProfilerTask.SKYLARK_USER_COMPILED_FN); env.exitScope(); } }
/** * If the rule was created by a macro, this method sets the appropriate values for the attributes * generator_{name, function, location} and returns all attributes. * * <p>Otherwise, it returns the given attributes without any changes. */ private static AttributesAndLocation generatorAttributesForMacros( BuildLangTypedAttributeValuesMap args, @Nullable Environment env, Location location, Label label) { // Returns the original arguments if a) there is only the rule itself on the stack // trace (=> no macro) or b) the attributes have already been set by Python pre-processing. if (env == null) { return new AttributesAndLocation(args, location); } boolean hasName = args.containsAttributeNamed("generator_name"); boolean hasFunc = args.containsAttributeNamed("generator_function"); // TODO(bazel-team): resolve cases in our code where hasName && !hasFunc, or hasFunc && !hasName if (hasName || hasFunc) { return new AttributesAndLocation(args, location); } Pair<FuncallExpression, BaseFunction> topCall = env.getTopCall(); if (topCall == null || !(topCall.second instanceof UserDefinedFunction)) { return new AttributesAndLocation(args, location); } FuncallExpression generator = topCall.first; BaseFunction function = topCall.second; String name = generator.getNameArg(); ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder(); for (String attributeName : args.getAttributeNames()) { builder.put(attributeName, args.getAttributeValue(attributeName)); } builder.put("generator_name", (name == null) ? args.getAttributeValue("name") : name); builder.put("generator_function", function.getName()); if (generator.getLocation() != null) { location = generator.getLocation(); } String relativePath = maybeGetRelativeLocation(location, label); if (relativePath != null) { builder.put("generator_location", relativePath); } try { return new AttributesAndLocation( new BuildLangTypedAttributeValuesMap(builder.build()), location); } catch (IllegalArgumentException ex) { // We just fall back to the default case and swallow any messages. return new AttributesAndLocation(args, location); } }
@Override public Object call(Object[] arguments, FuncallExpression ast, Environment env) throws EvalException, InterruptedException { if (!env.mutability().isMutable()) { throw new EvalException(getLocation(), "Trying to call in frozen environment"); } if (env.getStackTrace().contains(this)) { throw new EvalException( getLocation(), String.format( "Recursion was detected when calling '%s' from '%s'", getName(), Iterables.getLast(env.getStackTrace()).getName())); } if (enableCompiler && method.isPresent()) { Object returnValue = callCompiledFunction(arguments, ast, env); if (returnValue != null) { return returnValue; } } Profiler.instance().startTask(ProfilerTask.SKYLARK_USER_FN, getName()); try { env.enterScope(this, ast, definitionGlobals); ImmutableList<String> names = signature.getSignature().getNames(); // Registering the functions's arguments as variables in the local Environment int i = 0; for (String name : names) { env.update(name, arguments[i++]); } try { for (Statement stmt : statements) { if (stmt instanceof ReturnStatement) { // Performance optimization. // Executing the statement would throw an exception, which is slow. return ((ReturnStatement) stmt).getReturnExpression().eval(env); } else { stmt.exec(env); } } } catch (ReturnStatement.ReturnException e) { return e.getValue(); } return Runtime.NONE; } finally { Profiler.instance().completeTask(ProfilerTask.SKYLARK_USER_FN); env.exitScope(); } }
@Override void exec(Environment env) throws EvalException, InterruptedException { List<Expression> defaultExpressions = signature.getDefaultValues(); ArrayList<Object> defaultValues = null; ArrayList<SkylarkType> types = null; if (defaultExpressions != null) { defaultValues = new ArrayList<>(defaultExpressions.size()); for (Expression expr : defaultExpressions) { defaultValues.add(expr.eval(env)); } } env.update( ident.getName(), new UserDefinedFunction( ident, FunctionSignature.WithValues.<Object, SkylarkType>create( signature.getSignature(), defaultValues, types), statements, (SkylarkEnvironment) env)); }
/** * Constructs an Extension by extracting the new global definitions from an Environment. Also * caches a hash code for the transitive content of the file and its dependencies. * * @param env the Environment from which to extract an Extension. */ public Extension(Environment env) { super(env); this.transitiveContentHashCode = env.getTransitiveContentHashCode(); }