aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/syntax
diff options
context:
space:
mode:
authorGravatar Francois-Rene Rideau <tunes@google.com>2015-04-10 18:31:43 +0000
committerGravatar Lukacs Berki <lberki@google.com>2015-04-13 11:46:38 +0000
commite6a46b82e8e4e402fc70848f761d5486d2316d8f (patch)
treef6220192c5cb676be7192ee25e172ddc12096217 /src/main/java/com/google/devtools/build/lib/syntax
parent3af12e60e75a8d6acc5c272c29bf562030f6f975 (diff)
Allow evaluation from String
Lift the Evaluation code from the test files AbstractParserTestCase and AbstractEvaluationTestCase into new files EvaluationContext. Remove this code's dependency on FsApparatus (and thus to InMemoryFS), by making the Lexer accept null as filename. Also remove dependency on EventCollectionApparatus; parameterized by an EventHandler. Have the SkylarkSignatureProcessor use this Evaluation for defaultValue-s. While refactoring evaluation, have SkylarkShell use it, which fixes its ValidationEnvironment issues. TODO: refactor the tests to use this new infrastructure. -- MOS_MIGRATED_REVID=90824736
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/syntax')
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Environment.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/EvaluationContext.java223
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Lexer.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Parser.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java16
5 files changed, 246 insertions, 14 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
index 456007f9ba..bd595127fc 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
@@ -135,14 +135,18 @@ public class Environment {
this.eventHandler = Preconditions.checkNotNull(eventHandler);
}
+ public EventHandler getEventHandler() {
+ return eventHandler;
+ }
+
// Sets up the global environment
private void setupGlobal() {
// In Python 2.x, True and False are global values and can be redefined by the user.
// In Python 3.x, they are keywords. We implement them as values, for the sake of
// simplicity. We define them as Boolean objects.
- env.put("False", FALSE);
- env.put("True", TRUE);
- env.put("None", NONE);
+ update("False", FALSE);
+ update("True", TRUE);
+ update("None", NONE);
}
public boolean isSkylarkEnabled() {
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));
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java b/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java
index fd68bdea09..86b8de7b1d 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java
@@ -164,7 +164,8 @@ public final class Lexer {
@Override
public PathFragment getPath() {
- return lineNumberTable.getPath(getStartOffset()).asFragment();
+ Path path = lineNumberTable.getPath(getStartOffset());
+ return path != null ? path.asFragment() : null;
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java
index e8c30c393f..75b8db8b4c 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java
@@ -212,7 +212,13 @@ class Parser {
@VisibleForTesting
public static Statement parseStatement(
Lexer lexer, EventHandler eventHandler) {
- return new Parser(lexer, eventHandler, null).parseSmallStatement();
+ Parser parser = new Parser(lexer, eventHandler, null);
+ Statement result = parser.parseSmallStatement();
+ while (parser.token.kind == TokenKind.NEWLINE) {
+ parser.nextToken();
+ }
+ parser.expect(TokenKind.EOF);
+ return result;
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
index c772038276..6d7b1dbb1f 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSignatureProcessor.java
@@ -82,15 +82,15 @@ public class SkylarkSignatureProcessor {
paramList.add(getParameter(name, starParam, enforcedTypes, doc, undocumented,
/*mandatory=*/false, /*star=*/true, /*starStar=*/false, /*defaultValue=*/null));
}
+ for (Param param : annotation.mandatoryNamedOnly()) {
+ paramList.add(getParameter(name, param, enforcedTypes, doc, undocumented,
+ /*mandatory=*/true, /*star=*/false, /*starStar=*/false, /*defaultValue=*/null));
+ }
for (Param param : annotation.optionalNamedOnly()) {
paramList.add(getParameter(name, param, enforcedTypes, doc, undocumented,
/*mandatory=*/false, /*star=*/false, /*starStar=*/false,
/*defaultValue=*/getDefaultValue(param, defaultValuesIterator)));
}
- for (Param param : annotation.mandatoryNamedOnly()) {
- paramList.add(getParameter(name, param, enforcedTypes, doc, undocumented,
- /*mandatory=*/true, /*star=*/false, /*starStar=*/false, /*defaultValue=*/null));
- }
if (annotation.extraKeywords().length > 0) {
Preconditions.checkArgument(annotation.extraKeywords().length == 1);
paramList.add(
@@ -190,13 +190,11 @@ public class SkylarkSignatureProcessor {
return Environment.NONE;
} else {
try {
- // TODO(bazel-team): when we have Evaluation, remove the throw and uncomment the return.
- throw new RuntimeException("Not Implemented Yet!");
- // return new Evaluation ().eval(param.defaultValue());
+ return EvaluationContext.SKYLARK_INITIALIZATION.evalExpression(param.defaultValue());
} catch (Exception e) {
throw new RuntimeException(String.format(
- "Exception while processing @SkylarkSignature.Param %s, default value %s: %s",
- param.name(), param.defaultValue(), e.getMessage()), e);
+ "Exception while processing @SkylarkSignature.Param %s, default value %s",
+ param.name(), param.defaultValue()), e);
}
}
}