aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google
diff options
context:
space:
mode:
authorGravatar Laurent Le Brun <laurentlb@google.com>2015-03-19 10:12:49 +0000
committerGravatar Han-Wen Nienhuys <hanwen@google.com>2015-03-20 14:34:30 +0000
commit024238256de1c2ffa3e75cff5900e9df21322ae7 (patch)
tree47555ca1a1d51b00d0e2234ad0f85ade2e50e452 /src/main/java/com/google
parent5ea2c89608f883ec57ca09d85954847376fe7e0b (diff)
Refactoring: Introduce a new class LValue.
This CL is just moving code from AssignmentStatement to a new class. The goal is to share code dealing with LValues. LValues can be found here: - lvalue = 2 - [for lvalue in exp] - {a: b for lvalue in exp] - for lvalue in exp: pass The LValue itself can have different forms: - a - a, b - a[0] - a, (b, c) - [a[0], (b, c)] - a[1:5] Although we may not handle everything, we need to make sure that the same things can be used in variable assignment and in for loops. -- MOS_MIGRATED_REVID=89015483
Diffstat (limited to 'src/main/java/com/google')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java51
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/LValue.java97
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java2
4 files changed, 104 insertions, 48 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
index 3e181329e3..c8aaefd704 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
@@ -1239,7 +1239,7 @@ public final class PackageFactory {
EventHandler eventHandler) {
for (Statement stmt : ast.getStatements()) {
if (stmt instanceof AssignmentStatement) {
- Expression lvalue = ((AssignmentStatement) stmt).getLValue();
+ Expression lvalue = ((AssignmentStatement) stmt).getLValue().getExpression();
if (!(lvalue instanceof Ident)) {
continue;
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java b/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java
index 0bb584701a..f0063d0325 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java
@@ -14,14 +14,12 @@
package com.google.devtools.build.lib.syntax;
-import com.google.common.base.Preconditions;
-
/**
* Syntax node for an assignment statement.
*/
public final class AssignmentStatement extends Statement {
- private final Expression lvalue;
+ private final LValue lvalue;
private final Expression expression;
@@ -29,14 +27,14 @@ public final class AssignmentStatement extends Statement {
* Constructs an assignment: "lvalue := value".
*/
AssignmentStatement(Expression lvalue, Expression expression) {
- this.lvalue = lvalue;
+ this.lvalue = new LValue(lvalue);
this.expression = expression;
}
/**
* Returns the LHS of the assignment.
*/
- public Expression getLValue() {
+ public LValue getLValue() {
return lvalue;
}
@@ -54,38 +52,7 @@ public final class AssignmentStatement extends Statement {
@Override
void exec(Environment env) throws EvalException, InterruptedException {
- if (!(lvalue instanceof Ident)) {
- throw new EvalException(getLocation(),
- "can only assign to variables, not to '" + lvalue + "'");
- }
-
- Ident ident = (Ident) lvalue;
- Object result = expression.eval(env);
- Preconditions.checkNotNull(result, "result of %s is null", expression);
-
- if (env.isSkylarkEnabled()) {
- // The variable may have been referenced successfully if a global variable
- // with the same name exists. In this case an Exception needs to be thrown.
- SkylarkEnvironment skylarkEnv = (SkylarkEnvironment) env;
- if (skylarkEnv.hasBeenReadGlobalVariable(ident.getName())) {
- throw new EvalException(getLocation(), "Variable '" + ident.getName()
- + "' is referenced before assignment."
- + "The variable is defined in the global scope.");
- }
- Class<?> variableType = skylarkEnv.getVariableType(ident.getName());
- Class<?> resultType = EvalUtils.getSkylarkType(result.getClass());
- if (variableType != null && !variableType.equals(resultType)
- && !resultType.equals(Environment.NoneType.class)
- && !variableType.equals(Environment.NoneType.class)) {
- throw new EvalException(getLocation(), String.format("Incompatible variable types, "
- + "trying to assign %s (type of %s) to variable %s which is already %s",
- EvalUtils.prettyPrintValue(result),
- EvalUtils.getDataTypeName(result),
- ident.getName(),
- EvalUtils.getDataTypeNameFromClass(variableType)));
- }
- }
- env.update(ident.getName(), result);
+ lvalue.assign(env, getLocation(), expression);
}
@Override
@@ -95,14 +62,6 @@ public final class AssignmentStatement extends Statement {
@Override
void validate(ValidationEnvironment env) throws EvalException {
- // TODO(bazel-team): Implement other validations.
- if (lvalue instanceof Ident) {
- Ident ident = (Ident) lvalue;
- SkylarkType resultType = expression.validate(env);
- env.update(ident.getName(), resultType, getLocation());
- } else {
- throw new EvalException(getLocation(),
- "can only assign to variables, not to '" + lvalue + "'");
- }
+ lvalue.validate(env, getLocation(), expression.validate(env));
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/LValue.java b/src/main/java/com/google/devtools/build/lib/syntax/LValue.java
new file mode 100644
index 0000000000..a328118a6e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/syntax/LValue.java
@@ -0,0 +1,97 @@
+// Copyright 2014 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.base.Preconditions;
+import com.google.devtools.build.lib.events.Location;
+
+import java.io.Serializable;
+
+/**
+ * Class representing an LValue.
+ * It appears in assignment, for loop and comprehensions, e.g.
+ * lvalue = 2
+ * [for lvalue in exp]
+ * for lvalue in exp: pass
+ * An LValue can be a simple variable or something more complex like a tuple.
+ */
+public class LValue implements Serializable {
+ // Currently, expr can only be an Ident, but we plan to support more.
+ private final Expression expr;
+
+ public LValue(Expression expr) {
+ this.expr = expr;
+ }
+
+ public Expression getExpression() {
+ return expr;
+ }
+
+ /**
+ * Assign a value to an LValue and update the environment.
+ */
+ public void assign(Environment env, Location loc, Expression rvalue)
+ throws EvalException, InterruptedException {
+ if (!(expr instanceof Ident)) {
+ throw new EvalException(loc,
+ "can only assign to variables, not to '" + expr + "'");
+ }
+
+ Ident ident = (Ident) expr;
+ Object result = rvalue.eval(env);
+ Preconditions.checkNotNull(result, "result of %s is null", rvalue);
+
+ if (env.isSkylarkEnabled()) {
+ // The variable may have been referenced successfully if a global variable
+ // with the same name exists. In this case an Exception needs to be thrown.
+ SkylarkEnvironment skylarkEnv = (SkylarkEnvironment) env;
+ if (skylarkEnv.hasBeenReadGlobalVariable(ident.getName())) {
+ throw new EvalException(loc, "Variable '" + ident.getName()
+ + "' is referenced before assignment."
+ + "The variable is defined in the global scope.");
+ }
+ Class<?> variableType = skylarkEnv.getVariableType(ident.getName());
+ Class<?> resultType = EvalUtils.getSkylarkType(result.getClass());
+ if (variableType != null && !variableType.equals(resultType)
+ && !resultType.equals(Environment.NoneType.class)
+ && !variableType.equals(Environment.NoneType.class)) {
+ throw new EvalException(loc, String.format("Incompatible variable types, "
+ + "trying to assign %s (type of %s) to variable %s which is already %s",
+ EvalUtils.prettyPrintValue(result),
+ EvalUtils.getDataTypeName(result),
+ ident.getName(),
+ EvalUtils.getDataTypeNameFromClass(variableType)));
+ }
+ }
+ env.update(ident.getName(), result);
+ }
+
+ void validate(ValidationEnvironment env, Location loc, SkylarkType rvalueType)
+ throws EvalException {
+ // TODO(bazel-team): Implement other validations.
+ if (expr instanceof Ident) {
+ Ident ident = (Ident) expr;
+ env.update(ident.getName(), rvalueType, loc);
+ return;
+ }
+ throw new EvalException(loc,
+ "can only assign to variables, not to '" + expr + "'");
+ }
+
+ @Override
+ public String toString() {
+ return expr.toString();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java b/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java
index 2463d25600..439a4b197e 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java
@@ -85,7 +85,7 @@ public class SyntaxTreeVisitor {
}
public void visit(AssignmentStatement node) {
- visit(node.getLValue());
+ visit(node.getLValue().getExpression());
visit(node.getExpression());
}