aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/syntax/EvaluationContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/syntax/EvaluationContext.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/EvaluationContext.java223
1 files changed, 223 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/EvaluationContext.java b/src/main/java/com/google/devtools/build/lib/syntax/EvaluationContext.java
new file mode 100644
index 0000000000..c361bb3fca
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/syntax/EvaluationContext.java
@@ -0,0 +1,223 @@
+// 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.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.packages.CachingPackageLocator;
+import com.google.devtools.build.lib.syntax.Environment.NoSuchVariableException;
+import com.google.devtools.build.lib.vfs.Path;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Context for the evaluation of programs.
+ */
+public final class EvaluationContext {
+
+ @Nullable private EventHandler eventHandler;
+ private Environment env;
+ @Nullable private ValidationEnvironment validationEnv;
+ private boolean parsePython;
+
+ private EvaluationContext(EventHandler eventHandler, Environment env,
+ @Nullable ValidationEnvironment validationEnv, boolean parsePython) {
+ this.eventHandler = eventHandler;
+ this.env = env;
+ this.validationEnv = validationEnv;
+ this.parsePython = parsePython;
+ }
+
+ /**
+ * The fail fast handler, which throws a runtime exception whenever we encounter an error event.
+ */
+ public static final EventHandler FAIL_FAST_HANDLER = new EventHandler() {
+ @Override
+ public void handle(Event event) {
+ Preconditions.checkArgument(
+ !EventKind.ERRORS_AND_WARNINGS.contains(event.getKind()), event);
+ }
+ };
+
+ public static final EventHandler PRINT_HANDLER = new EventHandler() {
+ @Override
+ public void handle(Event event) {
+ System.out.print(event.getMessage());
+ }
+ };
+
+ public static EvaluationContext newBuildContext(EventHandler eventHandler, Environment env,
+ boolean parsePython) {
+ return new EvaluationContext(eventHandler, env, null, parsePython);
+ }
+
+ public static EvaluationContext newBuildContext(EventHandler eventHandler, Environment env) {
+ return newBuildContext(eventHandler, env, false);
+ }
+
+ public static EvaluationContext newBuildContext(EventHandler eventHandler) {
+ return newBuildContext(eventHandler, new Environment());
+ }
+
+ public static EvaluationContext newSkylarkContext(
+ Environment env, ValidationEnvironment validationEnv) {
+ return new EvaluationContext(env.getEventHandler(), env, validationEnv, false);
+ }
+
+ public static EvaluationContext newSkylarkContext(EventHandler eventHandler) {
+ return newSkylarkContext(new SkylarkEnvironment(eventHandler), new ValidationEnvironment());
+ }
+
+ public Environment getEnvironment() {
+ return env;
+ }
+
+ public EventHandler getEventHandler() {
+ return eventHandler;
+ }
+
+ public ValidationEnvironment getValidationEnvironment() {
+ return validationEnv;
+ }
+
+ /** Base context for Skylark evaluation for internal use only, while initializing builtins */
+ static final EvaluationContext SKYLARK_INITIALIZATION = newSkylarkContext(FAIL_FAST_HANDLER);
+
+ /** Mock package locator */
+ private static final class EmptyPackageLocator implements CachingPackageLocator {
+ @Override
+ public Path getBuildFileForPackage(String packageName) {
+ return null;
+ }
+ }
+
+ /** An empty package locator */
+ private static final CachingPackageLocator EMPTY_PACKAGE_LOCATOR = new EmptyPackageLocator();
+
+ /** Create a Lexer without a supporting file */
+ @VisibleForTesting
+ Lexer createLexer(String... input) {
+ return new Lexer(ParserInputSource.create(Joiner.on("\n").join(input), null),
+ eventHandler);
+ }
+
+ /** Is this a Skylark evaluation context? */
+ public boolean isSkylark() {
+ return env.isSkylarkEnabled();
+ }
+
+ /** Parse a string without a supporting file, returning statements and comments */
+ @VisibleForTesting
+ Parser.ParseResult parseFileWithComments(String... input) {
+ return isSkylark()
+ ? Parser.parseFileForSkylark(createLexer(input), eventHandler, null, validationEnv)
+ : Parser.parseFile(createLexer(input), eventHandler, EMPTY_PACKAGE_LOCATOR, parsePython);
+ }
+
+ /** Parse a string without a supporting file, returning statements only */
+ @VisibleForTesting
+ List<Statement> parseFile(String... input) {
+ return parseFileWithComments(input).statements;
+ }
+
+ /** Parse an Expression from string without a supporting file */
+ @VisibleForTesting
+ Expression parseExpression(String... input) {
+ return Parser.parseExpression(createLexer(input), eventHandler);
+ }
+
+ /** Evaluate an Expression */
+ @VisibleForTesting
+ Object evalExpression(Expression expression) throws EvalException, InterruptedException {
+ return expression.eval(env);
+ }
+
+ /** Evaluate an Expression as parsed from String-s */
+ Object evalExpression(String... input) throws EvalException, InterruptedException {
+ return evalExpression(parseExpression(input));
+ }
+
+ /** Parse a build (not Skylark) Statement from string without a supporting file */
+ @VisibleForTesting
+ Statement parseStatement(String... input) {
+ return Parser.parseStatement(createLexer(input), eventHandler);
+ }
+
+ /**
+ * Evaluate a Statement
+ * @param statement the Statement
+ * @return the value of the evaluation, if it's an Expression, or else null
+ */
+ @Nullable private Object eval(Statement statement) throws EvalException, InterruptedException {
+ if (statement instanceof ExpressionStatement) {
+ return evalExpression(((ExpressionStatement) statement).getExpression());
+ }
+ statement.exec(env);
+ return null;
+ }
+
+ /**
+ * Evaluate a list of Statement-s
+ * @return the value of the last statement if it's an Expression or else null
+ */
+ @Nullable private Object eval(List<Statement> statements)
+ throws EvalException, InterruptedException {
+ Object last = null;
+ for (Statement statement : statements) {
+ last = eval(statement);
+ }
+ return last;
+ }
+
+ /** Update a variable in the environment, in fluent style */
+ public EvaluationContext update(String varname, Object value) throws EvalException {
+ env.update(varname, value);
+ if (validationEnv != null) {
+ validationEnv.update(
+ varname, SkylarkType.typeForInference(SkylarkType.of(value.getClass())), null);
+ }
+ return this;
+ }
+
+ /** Lookup a variable in the environment */
+ public Object lookup(String varname) throws NoSuchVariableException {
+ return env.lookup(varname);
+ }
+
+ /** Print a String in this context */
+ public void print(String msg) {
+ if (msg != null) {
+ eventHandler.handle(new Event(EventKind.STDOUT, null, msg));
+ }
+ }
+
+ /** Print a String in this context */
+ public void println(String msg) {
+ if (msg != null) {
+ print(msg + "\n");
+ }
+ }
+
+ /** Evaluate a series of statements */
+ public Object eval(String... input) throws EvalException, InterruptedException {
+ return eval(parseFile(input));
+ }
+}