1 | /******************************************************************************* |
---|---|
2 | * Copyright (c) 2000, 2013 IBM Corporation and others. |
3 | * |
4 | * This program and the accompanying materials |
5 | * are made available under the terms of the Eclipse Public License 2.0 |
6 | * which accompanies this distribution, and is available at |
7 | * https://www.eclipse.org/legal/epl-2.0/ |
8 | * |
9 | * SPDX-License-Identifier: EPL-2.0 |
10 | * |
11 | * Contributors: |
12 | * IBM Corporation - initial API and implementation |
13 | *******************************************************************************/ |
14 | |
15 | package org.eclipse.jdt.core.dom; |
16 | |
17 | import java.util.ArrayList; |
18 | import java.util.HashMap; |
19 | import java.util.List; |
20 | import java.util.Map; |
21 | |
22 | /** |
23 | * Assignment expression AST node type. |
24 | * |
25 | * <pre> |
26 | * Assignment: |
27 | * Expression AssignmentOperator Expression |
28 | * </pre> |
29 | * |
30 | * @since 2.0 |
31 | * @noinstantiate This class is not intended to be instantiated by clients. |
32 | */ |
33 | @SuppressWarnings({"rawtypes", "unchecked"}) |
34 | public class Assignment extends Expression { |
35 | |
36 | /** |
37 | * Assignment operators (typesafe enumeration). |
38 | * <pre> |
39 | * AssignmentOperator:<code> |
40 | * <b>=</b> ASSIGN |
41 | * <b>+=</b> PLUS_ASSIGN |
42 | * <b>-=</b> MINUS_ASSIGN |
43 | * <b>*=</b> TIMES_ASSIGN |
44 | * <b>/=</b> DIVIDE_ASSIGN |
45 | * <b>&=</b> BIT_AND_ASSIGN |
46 | * <b>|=</b> BIT_OR_ASSIGN |
47 | * <b>^=</b> BIT_XOR_ASSIGN |
48 | * <b>%=</b> REMAINDER_ASSIGN |
49 | * <b><<=</b> LEFT_SHIFT_ASSIGN |
50 | * <b>>>=</b> RIGHT_SHIFT_SIGNED_ASSIGN |
51 | * <b>>>>=</b> RIGHT_SHIFT_UNSIGNED_ASSIGN</code> |
52 | * </pre> |
53 | */ |
54 | public static class Operator { |
55 | |
56 | /** |
57 | * The name of the operator |
58 | */ |
59 | private String op; |
60 | |
61 | /** |
62 | * Creates a new assignment operator with the given name. |
63 | * <p> |
64 | * Note: this constructor is private. The only instances |
65 | * ever created are the ones for the standard operators. |
66 | * </p> |
67 | * |
68 | * @param op the character sequence for the operator |
69 | */ |
70 | private Operator(String op) { |
71 | this.op = op; |
72 | } |
73 | |
74 | /** |
75 | * Returns the character sequence for the operator. |
76 | * |
77 | * @return the character sequence for the operator |
78 | */ |
79 | @Override |
80 | public String toString() { |
81 | return this.op; |
82 | } |
83 | |
84 | /** = operator. */ |
85 | public static final Operator ASSIGN = new Operator("=");//$NON-NLS-1$ |
86 | /** += operator. */ |
87 | public static final Operator PLUS_ASSIGN = new Operator("+=");//$NON-NLS-1$ |
88 | /** -= operator. */ |
89 | public static final Operator MINUS_ASSIGN = new Operator("-=");//$NON-NLS-1$ |
90 | /** *= operator. */ |
91 | public static final Operator TIMES_ASSIGN = new Operator("*=");//$NON-NLS-1$ |
92 | /** /= operator. */ |
93 | public static final Operator DIVIDE_ASSIGN = new Operator("/=");//$NON-NLS-1$ |
94 | /** &= operator. */ |
95 | public static final Operator BIT_AND_ASSIGN = new Operator("&=");//$NON-NLS-1$ |
96 | /** |= operator. */ |
97 | public static final Operator BIT_OR_ASSIGN = new Operator("|=");//$NON-NLS-1$ |
98 | /** ^= operator. */ |
99 | public static final Operator BIT_XOR_ASSIGN = new Operator("^=");//$NON-NLS-1$ |
100 | /** %= operator. */ |
101 | public static final Operator REMAINDER_ASSIGN = new Operator("%=");//$NON-NLS-1$ |
102 | /** <<== operator. */ |
103 | public static final Operator LEFT_SHIFT_ASSIGN = |
104 | new Operator("<<=");//$NON-NLS-1$ |
105 | /** >>= operator. */ |
106 | public static final Operator RIGHT_SHIFT_SIGNED_ASSIGN = |
107 | new Operator(">>=");//$NON-NLS-1$ |
108 | /** >>>= operator. */ |
109 | public static final Operator RIGHT_SHIFT_UNSIGNED_ASSIGN = |
110 | new Operator(">>>=");//$NON-NLS-1$ |
111 | |
112 | /** |
113 | * Returns the assignment operator corresponding to the given string, |
114 | * or <code>null</code> if none. |
115 | * <p> |
116 | * <code>toOperator</code> is the converse of <code>toString</code>: |
117 | * that is, <code>Operator.toOperator(op.toString()) == op</code> for all |
118 | * operators <code>op</code>. |
119 | * </p> |
120 | * |
121 | * @param token the character sequence for the operator |
122 | * @return the assignment operator, or <code>null</code> if none |
123 | */ |
124 | public static Operator toOperator(String token) { |
125 | return (Operator) CODES.get(token); |
126 | } |
127 | |
128 | /** |
129 | * Map from token to operator (key type: <code>String</code>; |
130 | * value type: <code>Operator</code>). |
131 | */ |
132 | private static final Map CODES; |
133 | static { |
134 | CODES = new HashMap(20); |
135 | Operator[] ops = { |
136 | ASSIGN, |
137 | PLUS_ASSIGN, |
138 | MINUS_ASSIGN, |
139 | TIMES_ASSIGN, |
140 | DIVIDE_ASSIGN, |
141 | BIT_AND_ASSIGN, |
142 | BIT_OR_ASSIGN, |
143 | BIT_XOR_ASSIGN, |
144 | REMAINDER_ASSIGN, |
145 | LEFT_SHIFT_ASSIGN, |
146 | RIGHT_SHIFT_SIGNED_ASSIGN, |
147 | RIGHT_SHIFT_UNSIGNED_ASSIGN |
148 | }; |
149 | for (int i = 0; i < ops.length; i++) { |
150 | CODES.put(ops[i].toString(), ops[i]); |
151 | } |
152 | } |
153 | } |
154 | |
155 | /** |
156 | * The "leftHandSide" structural property of this node type (child type: {@link Expression}). |
157 | * @since 3.0 |
158 | */ |
159 | public static final ChildPropertyDescriptor LEFT_HAND_SIDE_PROPERTY = |
160 | new ChildPropertyDescriptor(Assignment.class, "leftHandSide", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ |
161 | |
162 | /** |
163 | * The "operator" structural property of this node type (type: {@link Assignment.Operator}). |
164 | * @since 3.0 |
165 | */ |
166 | public static final SimplePropertyDescriptor OPERATOR_PROPERTY = |
167 | new SimplePropertyDescriptor(Assignment.class, "operator", Assignment.Operator.class, MANDATORY); //$NON-NLS-1$ |
168 | |
169 | /** |
170 | * The "rightHandSide" structural property of this node type (child type: {@link Expression}). |
171 | * @since 3.0 |
172 | */ |
173 | public static final ChildPropertyDescriptor RIGHT_HAND_SIDE_PROPERTY = |
174 | new ChildPropertyDescriptor(Assignment.class, "rightHandSide", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ |
175 | |
176 | /** |
177 | * A list of property descriptors (element type: |
178 | * {@link StructuralPropertyDescriptor}), |
179 | * or null if uninitialized. |
180 | */ |
181 | private static final List PROPERTY_DESCRIPTORS; |
182 | |
183 | static { |
184 | List properyList = new ArrayList(4); |
185 | createPropertyList(Assignment.class, properyList); |
186 | addProperty(LEFT_HAND_SIDE_PROPERTY, properyList); |
187 | addProperty(OPERATOR_PROPERTY, properyList); |
188 | addProperty(RIGHT_HAND_SIDE_PROPERTY, properyList); |
189 | PROPERTY_DESCRIPTORS = reapPropertyList(properyList); |
190 | } |
191 | |
192 | /** |
193 | * Returns a list of structural property descriptors for this node type. |
194 | * Clients must not modify the result. |
195 | * |
196 | * @param apiLevel the API level; one of the |
197 | * <code>AST.JLS*</code> constants |
198 | |
199 | * @return a list of property descriptors (element type: |
200 | * {@link StructuralPropertyDescriptor}) |
201 | * @since 3.0 |
202 | */ |
203 | public static List propertyDescriptors(int apiLevel) { |
204 | return PROPERTY_DESCRIPTORS; |
205 | } |
206 | |
207 | /** |
208 | * The assignment operator; defaults to Assignment.Operator.ASSIGN |
209 | */ |
210 | private Assignment.Operator assignmentOperator = Assignment.Operator.ASSIGN; |
211 | |
212 | /** |
213 | * The left hand side; lazily initialized; defaults to an unspecified, |
214 | * but legal, simple name. |
215 | */ |
216 | private Expression leftHandSide = null; |
217 | |
218 | /** |
219 | * The right hand side; lazily initialized; defaults to an unspecified, |
220 | * but legal, simple name. |
221 | */ |
222 | private Expression rightHandSide = null; |
223 | |
224 | /** |
225 | * Creates a new AST node for an assignment expression owned by the given |
226 | * AST. By default, the node has an assignment operator, and unspecified |
227 | * left and right hand sides. |
228 | * |
229 | * @param ast the AST that is to own this node |
230 | */ |
231 | Assignment(AST ast) { |
232 | super(ast); |
233 | } |
234 | |
235 | @Override |
236 | final List internalStructuralPropertiesForType(int apiLevel) { |
237 | return propertyDescriptors(apiLevel); |
238 | } |
239 | |
240 | @Override |
241 | final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { |
242 | if (property == OPERATOR_PROPERTY) { |
243 | if (get) { |
244 | return getOperator(); |
245 | } else { |
246 | setOperator((Operator) value); |
247 | return null; |
248 | } |
249 | } |
250 | // allow default implementation to flag the error |
251 | return super.internalGetSetObjectProperty(property, get, value); |
252 | } |
253 | |
254 | @Override |
255 | final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { |
256 | if (property == LEFT_HAND_SIDE_PROPERTY) { |
257 | if (get) { |
258 | return getLeftHandSide(); |
259 | } else { |
260 | setLeftHandSide((Expression) child); |
261 | return null; |
262 | } |
263 | } |
264 | if (property == RIGHT_HAND_SIDE_PROPERTY) { |
265 | if (get) { |
266 | return getRightHandSide(); |
267 | } else { |
268 | setRightHandSide((Expression) child); |
269 | return null; |
270 | } |
271 | } |
272 | // allow default implementation to flag the error |
273 | return super.internalGetSetChildProperty(property, get, child); |
274 | } |
275 | |
276 | @Override |
277 | final int getNodeType0() { |
278 | return ASSIGNMENT; |
279 | } |
280 | |
281 | @Override |
282 | ASTNode clone0(AST target) { |
283 | Assignment result = new Assignment(target); |
284 | result.setSourceRange(getStartPosition(), getLength()); |
285 | result.setOperator(getOperator()); |
286 | result.setLeftHandSide((Expression) getLeftHandSide().clone(target)); |
287 | result.setRightHandSide((Expression) getRightHandSide().clone(target)); |
288 | return result; |
289 | } |
290 | |
291 | @Override |
292 | final boolean subtreeMatch0(ASTMatcher matcher, Object other) { |
293 | // dispatch to correct overloaded match method |
294 | return matcher.match(this, other); |
295 | } |
296 | |
297 | @Override |
298 | void accept0(ASTVisitor visitor) { |
299 | boolean visitChildren = visitor.visit(this); |
300 | if (visitChildren) { |
301 | // visit children in normal left to right reading order |
302 | acceptChild(visitor, getLeftHandSide()); |
303 | acceptChild(visitor, getRightHandSide()); |
304 | } |
305 | visitor.endVisit(this); |
306 | } |
307 | |
308 | /** |
309 | * Returns the operator of this assignment expression. |
310 | * |
311 | * @return the assignment operator |
312 | */ |
313 | public Assignment.Operator getOperator() { |
314 | return this.assignmentOperator; |
315 | } |
316 | |
317 | /** |
318 | * Sets the operator of this assignment expression. |
319 | * |
320 | * @param assignmentOperator the assignment operator |
321 | * @exception IllegalArgumentException if the argument is incorrect |
322 | */ |
323 | public void setOperator(Assignment.Operator assignmentOperator) { |
324 | if (assignmentOperator == null) { |
325 | throw new IllegalArgumentException(); |
326 | } |
327 | preValueChange(OPERATOR_PROPERTY); |
328 | this.assignmentOperator = assignmentOperator; |
329 | postValueChange(OPERATOR_PROPERTY); |
330 | } |
331 | |
332 | /** |
333 | * Returns the left hand side of this assignment expression. |
334 | * |
335 | * @return the left hand side node |
336 | */ |
337 | public Expression getLeftHandSide() { |
338 | if (this.leftHandSide == null) { |
339 | // lazy init must be thread-safe for readers |
340 | synchronized (this) { |
341 | if (this.leftHandSide == null) { |
342 | preLazyInit(); |
343 | this.leftHandSide= new SimpleName(this.ast); |
344 | postLazyInit(this.leftHandSide, LEFT_HAND_SIDE_PROPERTY); |
345 | } |
346 | } |
347 | } |
348 | return this.leftHandSide; |
349 | } |
350 | |
351 | /** |
352 | * Sets the left hand side of this assignment expression. |
353 | * |
354 | * @param expression the left hand side node |
355 | * @exception IllegalArgumentException if: |
356 | * <ul> |
357 | * <li>the node belongs to a different AST</li> |
358 | * <li>the node already has a parent</li> |
359 | * <li>a cycle in would be created</li> |
360 | * </ul> |
361 | */ |
362 | public void setLeftHandSide(Expression expression) { |
363 | if (expression == null) { |
364 | throw new IllegalArgumentException(); |
365 | } |
366 | // an Assignment may occur inside a Expression - must check cycles |
367 | ASTNode oldChild = this.leftHandSide; |
368 | preReplaceChild(oldChild, expression, LEFT_HAND_SIDE_PROPERTY); |
369 | this.leftHandSide = expression; |
370 | postReplaceChild(oldChild, expression, LEFT_HAND_SIDE_PROPERTY); |
371 | } |
372 | |
373 | /** |
374 | * Returns the right hand side of this assignment expression. |
375 | * |
376 | * @return the right hand side node |
377 | */ |
378 | public Expression getRightHandSide() { |
379 | if (this.rightHandSide == null) { |
380 | // lazy init must be thread-safe for readers |
381 | synchronized (this) { |
382 | if (this.rightHandSide == null) { |
383 | preLazyInit(); |
384 | this.rightHandSide= new SimpleName(this.ast); |
385 | postLazyInit(this.rightHandSide, RIGHT_HAND_SIDE_PROPERTY); |
386 | } |
387 | } |
388 | } |
389 | return this.rightHandSide; |
390 | } |
391 | |
392 | /** |
393 | * Sets the right hand side of this assignment expression. |
394 | * |
395 | * @param expression the right hand side node |
396 | * @exception IllegalArgumentException if: |
397 | * <ul> |
398 | * <li>the node belongs to a different AST</li> |
399 | * <li>the node already has a parent</li> |
400 | * <li>a cycle in would be created</li> |
401 | * </ul> |
402 | */ |
403 | public void setRightHandSide(Expression expression) { |
404 | if (expression == null) { |
405 | throw new IllegalArgumentException(); |
406 | } |
407 | // an Assignment may occur inside a Expression - must check cycles |
408 | ASTNode oldChild = this.rightHandSide; |
409 | preReplaceChild(oldChild, expression, RIGHT_HAND_SIDE_PROPERTY); |
410 | this.rightHandSide = expression; |
411 | postReplaceChild(oldChild, expression, RIGHT_HAND_SIDE_PROPERTY); |
412 | } |
413 | |
414 | @Override |
415 | int memSize() { |
416 | // treat Code as free |
417 | return BASE_NODE_SIZE + 3 * 4; |
418 | } |
419 | |
420 | @Override |
421 | int treeSize() { |
422 | return |
423 | memSize() |
424 | + (this.leftHandSide == null ? 0 : getLeftHandSide().treeSize()) |
425 | + (this.rightHandSide == null ? 0 : getRightHandSide().treeSize()); |
426 | } |
427 | } |
428 | |
429 |
Members