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
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 0bb5847..f0063d0 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 @@
* 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 @@
@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 @@
@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));
}
}