Skip to content

Commit dfe164d

Browse files
committed
GROOVY-10598
1 parent 1cbd11a commit dfe164d

File tree

6 files changed

+604
-0
lines changed

6 files changed

+604
-0
lines changed

base/org.codehaus.groovy25/.checkstyle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<file-match-pattern match-pattern="groovy/ast/Parameter.java" include-pattern="false" />
3030
<file-match-pattern match-pattern="groovy/ast/expr/ClassExpression.java" include-pattern="false" />
3131
<file-match-pattern match-pattern="groovy/ast/expr/ConstantExpression.java" include-pattern="false" />
32+
<file-match-pattern match-pattern="groovy/ast/expr/DeclarationExpression.java" include-pattern="false" />
3233
<file-match-pattern match-pattern="groovy/ast/expr/EmptyExpression.java" include-pattern="false" />
3334
<file-match-pattern match-pattern="groovy/ast/expr/(Static)?MethodCallExpression.java" include-pattern="false" />
3435
<file-match-pattern match-pattern="groovy/ast/tools/(Expression|General|Generics)Utils.java" include-pattern="false" />
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.codehaus.groovy.ast.expr;
20+
21+
import org.codehaus.groovy.GroovyBugError;
22+
import org.codehaus.groovy.ast.GroovyCodeVisitor;
23+
import org.codehaus.groovy.syntax.Token;
24+
25+
import static org.apache.groovy.ast.tools.ClassNodeUtils.formatTypeName;
26+
27+
/**
28+
* Represents one or more local variables. Typically it is a single local variable
29+
* declared by name with an expression like "def foo" or with type "String foo". However,
30+
* the multiple assignment feature allows you to create two or more variables using
31+
* an expression like: <code>def (x, y) = [1, 2]</code>.
32+
* <p>
33+
* You can access the left hand side of a declaration using the
34+
* "<code>Expression getLeftExpression()</code>" method. In which case you might then
35+
* use <code>instanceof</code> and casting to perform operations specific to a
36+
* single local variable (<code>VariableExpression</code>) or for the multiple
37+
* assignment case (<code>TupleExpression</code>).
38+
* <p>
39+
* Alternatively, if <code>isMultipleAssignmentDeclaration()</code> is <code>false</code>
40+
* you can use the method "<code>VariableExpression getVariableExpression()</code>" method.
41+
* Similarly, if <code>isMultipleAssignmentDeclaration()</code> is <code>true</code>
42+
* you can use the method "<code>TupleExpression getTupleExpression()</code>" method.
43+
* Calling either of these expression getters when the "isMultipleAssignment" condition
44+
* is not appropriate is unsafe and will result in a <code>ClassCastException</code>.
45+
*/
46+
public class DeclarationExpression extends BinaryExpression {
47+
48+
/**
49+
* Creates a DeclarationExpression for VariableExpressions like "def x" or "String y = 'foo'".
50+
* @param left
51+
* the left hand side of a variable declaration
52+
* @param operation
53+
* the operation, typically an assignment operator
54+
* @param right
55+
* the right hand side of a declaration
56+
*/
57+
public DeclarationExpression(final VariableExpression left, final Token operation, final Expression right) {
58+
this((Expression) left, operation, right);
59+
}
60+
61+
/**
62+
* Creates a DeclarationExpression for Expressions like "def (x, y) = [1, 2]"
63+
* @param left
64+
* the left hand side of a declaration. Must be either a VariableExpression or
65+
* a TupleExpression with at least one element.
66+
* @param operation
67+
* the operation, typically an assignment operator
68+
* @param right
69+
* the right hand side of a declaration
70+
*/
71+
public DeclarationExpression(final Expression left, final Token operation, final Expression right) {
72+
super(left, Token.newSymbol("=", operation.getStartLine(), operation.getStartColumn()), right);
73+
check(left);
74+
}
75+
76+
private static void check(Expression left) {
77+
if (left instanceof VariableExpression) {
78+
//nothing
79+
} else if (left instanceof TupleExpression) {
80+
TupleExpression tuple = (TupleExpression) left;
81+
if (tuple.getExpressions().isEmpty()) throw new GroovyBugError("one element required for left side");
82+
} else {
83+
throw new GroovyBugError("illegal left expression for declaration: "+left);
84+
}
85+
}
86+
87+
@Override
88+
public void visit(GroovyCodeVisitor visitor) {
89+
visitor.visitDeclarationExpression(this);
90+
}
91+
92+
/**
93+
* This method returns the left hand side of the declaration cast to the VariableExpression type.
94+
* This is an unsafe method to call. In a multiple assignment statement, the left hand side will
95+
* be a TupleExpression and a ClassCastException will occur. If you invoke this method then
96+
* be sure to invoke isMultipleAssignmentDeclaration() first to check that it is safe to do so.
97+
* If that method returns true then this method is safe to call.
98+
*
99+
* @return left hand side of normal variable declarations
100+
* @throws ClassCastException if the left hand side is not a VariableExpression (and is probably a multiple assignment statement).
101+
*/
102+
public VariableExpression getVariableExpression() {
103+
return (VariableExpression) this.getLeftExpression();
104+
}
105+
106+
/**
107+
* This method returns the left hand side of the declaration cast to the TupleExpression type.
108+
* This is an unsafe method to call. In a single assignment statement, the left hand side will
109+
* be a VariableExpression and a ClassCastException will occur. If you invoke this method then
110+
* be sure to invoke isMultipleAssignmentDeclaration() first to check that it is safe to do so.
111+
* If that method returns true then this method is safe to call.
112+
* @return
113+
* left hand side of multiple assignment declarations
114+
* @throws ClassCastException
115+
* if the left hand side is not a TupleExpression (and is probably a VariableExpression).
116+
*
117+
*/
118+
public TupleExpression getTupleExpression() {
119+
return (TupleExpression) this.getLeftExpression();
120+
}
121+
122+
@Override
123+
public String getText() {
124+
StringBuilder text = new StringBuilder();
125+
126+
if (!isMultipleAssignmentDeclaration()) {
127+
VariableExpression v = getVariableExpression();
128+
if (v.isDynamicTyped()) {
129+
text.append("def");
130+
} else {
131+
text.append(formatTypeName(v.getType()));
132+
}
133+
text.append(' ').append(v.getText());
134+
} else {
135+
TupleExpression t = getTupleExpression();
136+
text.append("def (");
137+
for (Expression e : t.getExpressions()) {
138+
if (e instanceof VariableExpression) {
139+
VariableExpression v = (VariableExpression) e;
140+
if (!v.isDynamicTyped()) {
141+
text.append(formatTypeName(v.getType())).append(' ');
142+
}
143+
}
144+
text.append(e.getText()).append(", ");
145+
}
146+
text.setLength(text.length() - 2);
147+
text.append(')');
148+
}
149+
text.append(' ').append(getOperation().getText());
150+
text.append(' ').append(getRightExpression().getText());
151+
152+
return text.toString();
153+
}
154+
155+
/**
156+
* This method sets the leftExpression for this BinaryExpression. The parameter must be
157+
* either a VariableExpression or a TupleExpression with one or more elements.
158+
* @param leftExpression
159+
* either a VariableExpression or a TupleExpression with one or more elements.
160+
*/
161+
@Override
162+
public void setLeftExpression(Expression leftExpression) {
163+
check(leftExpression);
164+
super.setLeftExpression(leftExpression);
165+
}
166+
167+
@Override
168+
public void setRightExpression(Expression rightExpression) {
169+
super.setRightExpression(rightExpression);
170+
}
171+
172+
@Override
173+
public Expression transformExpression(ExpressionTransformer transformer) {
174+
Expression ret = new DeclarationExpression(transformer.transform(getLeftExpression()),
175+
getOperation(), transformer.transform(getRightExpression()));
176+
ret.setSourcePosition(this);
177+
ret.addAnnotations(getAnnotations());
178+
ret.setDeclaringClass(getDeclaringClass());
179+
ret.copyNodeMetaData(this);
180+
return ret;
181+
}
182+
183+
/**
184+
* This method tells you if this declaration is a multiple assignment declaration, which
185+
* has the form "def (x, y) = ..." in Groovy. If this method returns true, then the left
186+
* hand side is an ArgumentListExpression. Do not call "getVariableExpression()" on this
187+
* object if this method returns true, instead use "getLeftExpression()".
188+
* @return
189+
* true if this declaration is a multiple assignment declaration, which means the
190+
* left hand side is an ArgumentListExpression.
191+
*/
192+
public boolean isMultipleAssignmentDeclaration() {
193+
return getLeftExpression() instanceof TupleExpression;
194+
}
195+
}

base/org.codehaus.groovy30/.checkstyle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<file-match-pattern match-pattern="groovy/ast/Parameter.java" include-pattern="false" />
3535
<file-match-pattern match-pattern="groovy/ast/expr/ClassExpression.java" include-pattern="false" />
3636
<file-match-pattern match-pattern="groovy/ast/expr/ConstantExpression.java" include-pattern="false" />
37+
<file-match-pattern match-pattern="groovy/ast/expr/DeclarationExpression.java" include-pattern="false" />
3738
<file-match-pattern match-pattern="groovy/ast/expr/(Static)?MethodCallExpression.java" include-pattern="false" />
3839
<file-match-pattern match-pattern="groovy/ast/tools/(Expression|Generics)Utils.java" include-pattern="false" />
3940
<file-match-pattern match-pattern="groovy/ast/tools/WideningCategories.java" include-pattern="false" />

0 commit comments

Comments
 (0)