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 | * Prefix expression AST node type. |
24 | * |
25 | * <pre> |
26 | * PrefixExpression: |
27 | * PrefixOperator 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 PrefixExpression extends Expression { |
35 | |
36 | /** |
37 | * Prefix operators (typesafe enumeration). |
38 | * <pre> |
39 | * PrefixOperator: |
40 | * <b><code>++</code></b> <code>INCREMENT</code> |
41 | * <b><code>--</code></b> <code>DECREMENT</code> |
42 | * <b><code>+</code></b> <code>PLUS</code> |
43 | * <b><code>-</code></b> <code>MINUS</code> |
44 | * <b><code>~</code></b> <code>COMPLEMENT</code> |
45 | * <b><code>!</code></b> <code>NOT</code> |
46 | * </pre> |
47 | */ |
48 | public static class Operator { |
49 | |
50 | /** |
51 | * The token for the operator. |
52 | */ |
53 | private String token; |
54 | |
55 | /** |
56 | * Creates a new prefix operator with the given token. |
57 | * <p> |
58 | * Note: this constructor is private. The only instances |
59 | * ever created are the ones for the standard operators. |
60 | * </p> |
61 | * |
62 | * @param token the character sequence for the operator |
63 | */ |
64 | private Operator(String token) { |
65 | this.token = token; |
66 | } |
67 | |
68 | /** |
69 | * Returns the character sequence for the operator. |
70 | * |
71 | * @return the character sequence for the operator |
72 | */ |
73 | @Override |
74 | public String toString() { |
75 | return this.token; |
76 | } |
77 | |
78 | /** Prefix increment "++" operator. */ |
79 | public static final Operator INCREMENT = new Operator("++");//$NON-NLS-1$ |
80 | /** Prefix decrement "--" operator. */ |
81 | public static final Operator DECREMENT = new Operator("--");//$NON-NLS-1$ |
82 | /** Unary plus "+" operator. */ |
83 | public static final Operator PLUS = new Operator("+");//$NON-NLS-1$ |
84 | /** Unary minus "-" operator. */ |
85 | public static final Operator MINUS = new Operator("-");//$NON-NLS-1$ |
86 | /** Bitwise complement "~" operator. */ |
87 | public static final Operator COMPLEMENT = new Operator("~");//$NON-NLS-1$ |
88 | /** Logical complement "!" operator. */ |
89 | public static final Operator NOT = new Operator("!");//$NON-NLS-1$ |
90 | |
91 | /** |
92 | * Map from token to operator (key type: <code>String</code>; |
93 | * value type: <code>Operator</code>). |
94 | */ |
95 | private static final Map CODES; |
96 | static { |
97 | CODES = new HashMap(20); |
98 | Operator[] ops = { |
99 | INCREMENT, |
100 | DECREMENT, |
101 | PLUS, |
102 | MINUS, |
103 | COMPLEMENT, |
104 | NOT, |
105 | }; |
106 | for (int i = 0; i < ops.length; i++) { |
107 | CODES.put(ops[i].toString(), ops[i]); |
108 | } |
109 | } |
110 | |
111 | /** |
112 | * Returns the prefix operator corresponding to the given string, |
113 | * or <code>null</code> if none. |
114 | * <p> |
115 | * <code>toOperator</code> is the converse of <code>toString</code>: |
116 | * that is, <code>Operator.toOperator(op.toString()) == op</code> for |
117 | * all operators <code>op</code>. |
118 | * </p> |
119 | * |
120 | * @param token the character sequence for the operator |
121 | * @return the prefix operator, or <code>null</code> if none |
122 | */ |
123 | public static Operator toOperator(String token) { |
124 | return (Operator) CODES.get(token); |
125 | } |
126 | } |
127 | |
128 | /** |
129 | * The "operator" structural property of this node type (type: {@link PrefixExpression.Operator}). |
130 | * @since 3.0 |
131 | */ |
132 | public static final SimplePropertyDescriptor OPERATOR_PROPERTY = |
133 | new SimplePropertyDescriptor(PrefixExpression.class, "operator", PrefixExpression.Operator.class, MANDATORY); //$NON-NLS-1$ |
134 | |
135 | /** |
136 | * The "operand" structural property of this node type (child type: {@link Expression}). |
137 | * @since 3.0 |
138 | */ |
139 | public static final ChildPropertyDescriptor OPERAND_PROPERTY = |
140 | new ChildPropertyDescriptor(PrefixExpression.class, "operand", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ |
141 | |
142 | /** |
143 | * A list of property descriptors (element type: |
144 | * {@link StructuralPropertyDescriptor}), |
145 | * or null if uninitialized. |
146 | */ |
147 | private static final List PROPERTY_DESCRIPTORS; |
148 | |
149 | static { |
150 | List propertyList = new ArrayList(3); |
151 | createPropertyList(PrefixExpression.class, propertyList); |
152 | addProperty(OPERATOR_PROPERTY, propertyList); |
153 | addProperty(OPERAND_PROPERTY, propertyList); |
154 | PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); |
155 | } |
156 | |
157 | /** |
158 | * Returns a list of structural property descriptors for this node type. |
159 | * Clients must not modify the result. |
160 | * |
161 | * @param apiLevel the API level; one of the |
162 | * <code>AST.JLS*</code> constants |
163 | |
164 | * @return a list of property descriptors (element type: |
165 | * {@link StructuralPropertyDescriptor}) |
166 | * @since 3.0 |
167 | */ |
168 | public static List propertyDescriptors(int apiLevel) { |
169 | return PROPERTY_DESCRIPTORS; |
170 | } |
171 | |
172 | /** |
173 | * The operator; defaults to an unspecified prefix operator. |
174 | */ |
175 | private PrefixExpression.Operator operator = |
176 | PrefixExpression.Operator.PLUS; |
177 | |
178 | /** |
179 | * The operand; lazily initialized; defaults to an unspecified, |
180 | * but legal, simple name. |
181 | */ |
182 | private Expression operand = null; |
183 | |
184 | /** |
185 | * Creates a new AST node for an prefix expression owned by the given |
186 | * AST. By default, the node has unspecified (but legal) operator and |
187 | * operand. |
188 | * |
189 | * @param ast the AST that is to own this node |
190 | */ |
191 | PrefixExpression(AST ast) { |
192 | super(ast); |
193 | } |
194 | |
195 | @Override |
196 | final List internalStructuralPropertiesForType(int apiLevel) { |
197 | return propertyDescriptors(apiLevel); |
198 | } |
199 | |
200 | @Override |
201 | final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { |
202 | if (property == OPERATOR_PROPERTY) { |
203 | if (get) { |
204 | return getOperator(); |
205 | } else { |
206 | setOperator((Operator) value); |
207 | return null; |
208 | } |
209 | } |
210 | // allow default implementation to flag the error |
211 | return super.internalGetSetObjectProperty(property, get, value); |
212 | } |
213 | |
214 | @Override |
215 | final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { |
216 | if (property == OPERAND_PROPERTY) { |
217 | if (get) { |
218 | return getOperand(); |
219 | } else { |
220 | setOperand((Expression) child); |
221 | return null; |
222 | } |
223 | } |
224 | // allow default implementation to flag the error |
225 | return super.internalGetSetChildProperty(property, get, child); |
226 | } |
227 | |
228 | @Override |
229 | final int getNodeType0() { |
230 | return PREFIX_EXPRESSION; |
231 | } |
232 | |
233 | @Override |
234 | ASTNode clone0(AST target) { |
235 | PrefixExpression result = new PrefixExpression(target); |
236 | result.setSourceRange(getStartPosition(), getLength()); |
237 | result.setOperator(getOperator()); |
238 | result.setOperand((Expression) getOperand().clone(target)); |
239 | return result; |
240 | } |
241 | |
242 | @Override |
243 | final boolean subtreeMatch0(ASTMatcher matcher, Object other) { |
244 | // dispatch to correct overloaded match method |
245 | return matcher.match(this, other); |
246 | } |
247 | |
248 | @Override |
249 | void accept0(ASTVisitor visitor) { |
250 | boolean visitChildren = visitor.visit(this); |
251 | if (visitChildren) { |
252 | // visit children in normal left to right reading order |
253 | acceptChild(visitor, getOperand()); |
254 | } |
255 | visitor.endVisit(this); |
256 | } |
257 | |
258 | /** |
259 | * Returns the operator of this prefix expression. |
260 | * |
261 | * @return the operator |
262 | */ |
263 | public PrefixExpression.Operator getOperator() { |
264 | return this.operator; |
265 | } |
266 | |
267 | /** |
268 | * Sets the operator of this prefix expression. |
269 | * |
270 | * @param operator the operator |
271 | * @exception IllegalArgumentException if the argument is incorrect |
272 | */ |
273 | public void setOperator(PrefixExpression.Operator operator) { |
274 | if (operator == null) { |
275 | throw new IllegalArgumentException(); |
276 | } |
277 | preValueChange(OPERATOR_PROPERTY); |
278 | this.operator = operator; |
279 | postValueChange(OPERATOR_PROPERTY); |
280 | } |
281 | |
282 | /** |
283 | * Returns the operand of this prefix expression. |
284 | * |
285 | * @return the operand expression node |
286 | */ |
287 | public Expression getOperand() { |
288 | if (this.operand == null) { |
289 | // lazy init must be thread-safe for readers |
290 | synchronized (this) { |
291 | if (this.operand == null) { |
292 | preLazyInit(); |
293 | this.operand= new SimpleName(this.ast); |
294 | postLazyInit(this.operand, OPERAND_PROPERTY); |
295 | } |
296 | } |
297 | } |
298 | return this.operand; |
299 | } |
300 | |
301 | /** |
302 | * Sets the operand of this prefix expression. |
303 | * |
304 | * @param expression the operand expression node |
305 | * @exception IllegalArgumentException if: |
306 | * <ul> |
307 | * <li>the node belongs to a different AST</li> |
308 | * <li>the node already has a parent</li> |
309 | * <li>a cycle in would be created</li> |
310 | * </ul> |
311 | */ |
312 | public void setOperand(Expression expression) { |
313 | if (expression == null) { |
314 | throw new IllegalArgumentException(); |
315 | } |
316 | ASTNode oldChild = this.operand; |
317 | preReplaceChild(oldChild, expression, OPERAND_PROPERTY); |
318 | this.operand = expression; |
319 | postReplaceChild(oldChild, expression, OPERAND_PROPERTY); |
320 | } |
321 | |
322 | @Override |
323 | int memSize() { |
324 | // treat Operator as free |
325 | return BASE_NODE_SIZE + 2 * 4; |
326 | } |
327 | |
328 | @Override |
329 | int treeSize() { |
330 | return |
331 | memSize() |
332 | + (this.operand == null ? 0 : getOperand().treeSize()); |
333 | } |
334 | } |
335 | |
336 |
Members