d672b4f7ef00439c5417354285327cae310b15a3
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / dom / InfixExpression.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11
12 package net.sourceforge.phpdt.core.dom;
13
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18
19 /**
20  * Infix expression AST node type.
21  * <pre>
22  * InfixExpression:
23  *    Expression InfixOperator Expression { InfixOperator Expression } 
24  * </pre>
25  * 
26  * @since 2.0
27  * @noinstantiate This class is not intended to be instantiated by clients.
28  */
29 public class InfixExpression extends Expression {
30
31         /**
32          * Infix operators (typesafe enumeration).
33          * <pre>
34          * InfixOperator:<code>
35          *    <b>*</b>  TIMES
36          *    <b>/</b>  DIVIDE
37          *    <b>%</b>  REMAINDER
38          *    <b>+</b>  PLUS
39          *    <b>-</b>  MINUS
40          *    <b>&lt;&lt;</b>  LEFT_SHIFT
41          *    <b>&gt;&gt;</b>  RIGHT_SHIFT_SIGNED
42          *    <b>&gt;&gt;&gt;</b>  RIGHT_SHIFT_UNSIGNED
43          *    <b>&lt;</b>  LESS
44          *    <b>&gt;</b>  GREATER
45          *    <b>&lt;=</b>  LESS_EQUALS
46          *    <b>&gt;=</b>  GREATER_EQUALS
47          *    <b>==</b>  EQUALS
48          *    <b>!=</b>  NOT_EQUALS
49          *    <b>^</b>  XOR
50          *    <b>&amp;</b>  AND
51          *    <b>|</b>  OR
52          *    <b>&amp;&amp;</b>  CONDITIONAL_AND
53          *    <b>||</b>  CONDITIONAL_OR</code>
54          * </pre>
55          */
56         public static class Operator {
57         
58                 /**
59                  * The token for the operator.
60                  */
61                 private String token;
62                 
63                 /**
64                  * Creates a new infix operator with the given token.
65                  * <p>
66                  * Note: this constructor is private. The only instances
67                  * ever created are the ones for the standard operators.
68                  * </p>
69                  * 
70                  * @param token the character sequence for the operator
71                  */
72                 private Operator(String token) {
73                         this.token = token;
74                 }
75                 
76                 /**
77                  * Returns the character sequence for the operator.
78                  * 
79                  * @return the character sequence for the operator
80                  */
81                 public String toString() {
82                         return token;
83                 }
84                 
85                 /** Multiplication "*" operator. */
86                 public static final Operator TIMES = new Operator("*");//$NON-NLS-1$
87                 /** Division "/" operator. */
88                 public static final Operator DIVIDE = new Operator("/");//$NON-NLS-1$
89                 /** Remainder "%" operator. */
90                 public static final Operator REMAINDER = new Operator("%");//$NON-NLS-1$
91                 /** Addition (or string concatenation) "+" operator. */
92                 public static final Operator PLUS = new Operator("+");//$NON-NLS-1$
93                 /** Subtraction "-" operator. */
94                 public static final Operator MINUS = new Operator("-");//$NON-NLS-1$
95                 /** Left shift "&lt;&lt;" operator. */
96                 public static final Operator LEFT_SHIFT = new Operator("<<");//$NON-NLS-1$
97                 /** Signed right shift "&gt;&gt;" operator. */
98                 public static final Operator RIGHT_SHIFT_SIGNED = new Operator(">>");//$NON-NLS-1$
99                 /** Unsigned right shift "&gt;&gt;&gt;" operator. */
100                 public static final Operator RIGHT_SHIFT_UNSIGNED = 
101                         new Operator(">>>");//$NON-NLS-1$
102                 /** Less than "&lt;" operator. */
103                 public static final Operator LESS = new Operator("<");//$NON-NLS-1$
104                 /** Greater than "&gt;" operator. */
105                 public static final Operator GREATER = new Operator(">");//$NON-NLS-1$
106                 /** Less than or equals "&lt;=" operator. */
107                 public static final Operator LESS_EQUALS = new Operator("<=");//$NON-NLS-1$
108                 /** Greater than or equals "&gt=;" operator. */
109                 public static final Operator GREATER_EQUALS = new Operator(">=");//$NON-NLS-1$
110                 /** Equals "==" operator. */
111                 public static final Operator EQUALS = new Operator("==");//$NON-NLS-1$
112                 /** Not equals "!=" operator. */
113                 public static final Operator NOT_EQUALS = new Operator("!=");//$NON-NLS-1$
114                 /** Exclusive OR "^" operator. */
115                 public static final Operator XOR = new Operator("^");//$NON-NLS-1$
116                 /** Inclusive OR "|" operator. */
117                 public static final Operator OR = new Operator("|");//$NON-NLS-1$
118                 /** AND "&amp;" operator. */
119                 public static final Operator AND = new Operator("&");//$NON-NLS-1$
120                 /** Conditional OR "||" operator. */
121                 public static final Operator CONDITIONAL_OR = new Operator("||");//$NON-NLS-1$
122                 /** Conditional AND "&amp;&amp;" operator. */
123                 public static final Operator CONDITIONAL_AND = new Operator("&&");//$NON-NLS-1$
124                 
125                 /**
126                  * Map from token to operator (key type: <code>String</code>;
127                  * value type: <code>Operator</code>).
128                  */
129                 private static final Map CODES;
130                 static {
131                         CODES = new HashMap(20);
132                         Operator[] ops = {
133                                         TIMES,
134                                         DIVIDE,
135                                         REMAINDER,
136                                         PLUS,
137                                         MINUS,
138                                         LEFT_SHIFT,
139                                         RIGHT_SHIFT_SIGNED,
140                                         RIGHT_SHIFT_UNSIGNED,
141                                         LESS,
142                                         GREATER,
143                                         LESS_EQUALS,
144                                         GREATER_EQUALS,
145                                         EQUALS,
146                                         NOT_EQUALS,
147                                         XOR,
148                                         OR,
149                                         AND,
150                                         CONDITIONAL_OR,
151                                         CONDITIONAL_AND,
152                                 };
153                         for (int i = 0; i < ops.length; i++) {
154                                 CODES.put(ops[i].toString(), ops[i]);
155                         }
156                 }
157
158                 /**
159                  * Returns the infix operator corresponding to the given string,
160                  * or <code>null</code> if none.
161                  * <p>
162                  * <code>toOperator</code> is the converse of <code>toString</code>:
163                  * that is, <code>Operator.toOperator(op.toString()) == op</code> for 
164                  * all operators <code>op</code>.
165                  * </p>
166                  * 
167                  * @param token the character sequence for the operator
168                  * @return the infix operator, or <code>null</code> if none
169                  */
170                 public static Operator toOperator(String token) {
171                         return (Operator) CODES.get(token);
172                 }
173                 
174         }
175         
176         /**
177          * The "leftOperand" structural property of this node type.
178          * @since 3.0
179          */
180         public static final ChildPropertyDescriptor LEFT_OPERAND_PROPERTY = 
181                 new ChildPropertyDescriptor(InfixExpression.class, "leftOperand", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
182
183         /**
184          * The "operator" structural property of this node type.
185          * @since 3.0
186          */
187         public static final SimplePropertyDescriptor OPERATOR_PROPERTY = 
188                 new SimplePropertyDescriptor(InfixExpression.class, "operator", InfixExpression.Operator.class, MANDATORY); //$NON-NLS-1$
189         
190         /**
191          * The "rightOperand" structural property of this node type.
192          * @since 3.0
193          */
194         public static final ChildPropertyDescriptor RIGHT_OPERAND_PROPERTY = 
195                 new ChildPropertyDescriptor(InfixExpression.class, "rightOperand", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
196
197         /**
198          * The "extendedOperands" structural property of this node type.
199          * @since 3.0
200          */
201         public static final ChildListPropertyDescriptor EXTENDED_OPERANDS_PROPERTY = 
202                 new ChildListPropertyDescriptor(InfixExpression.class, "extendedOperands", Expression.class, CYCLE_RISK); //$NON-NLS-1$
203
204         /**
205          * A list of property descriptors (element type: 
206          * {@link StructuralPropertyDescriptor}),
207          * or null if uninitialized.
208          */
209         private static final List PROPERTY_DESCRIPTORS;
210         
211         static {
212                 List properyList = new ArrayList(5);
213                 createPropertyList(InfixExpression.class, properyList);
214                 addProperty(LEFT_OPERAND_PROPERTY, properyList);
215                 addProperty(OPERATOR_PROPERTY, properyList);
216                 addProperty(RIGHT_OPERAND_PROPERTY, properyList);
217                 addProperty(EXTENDED_OPERANDS_PROPERTY, properyList);
218                 PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
219         }
220
221         /**
222          * Returns a list of structural property descriptors for this node type.
223          * Clients must not modify the result.
224          * 
225          * @param apiLevel the API level; one of the
226          * <code>AST.JLS*</code> constants
227
228          * @return a list of property descriptors (element type: 
229          * {@link StructuralPropertyDescriptor})
230          * @since 3.0
231          */
232         public static List propertyDescriptors(int apiLevel) {
233                 return PROPERTY_DESCRIPTORS;
234         }
235                         
236         /**
237          * The infix operator; defaults to InfixExpression.Operator.PLUS.
238          */
239         private InfixExpression.Operator operator = InfixExpression.Operator.PLUS;
240
241         /**
242          * The left operand; lazily initialized; defaults to an unspecified,
243          * but legal, simple name.
244          */
245         private Expression leftOperand = null;
246
247         /**
248          * The right operand; lazily initialized; defaults to an unspecified,
249          * but legal, simple name.
250          */
251         private Expression rightOperand = null;
252
253         /**
254          * The list of extended operand expressions (element type: 
255          * <code>Expression</code>). Lazily initialized; defaults to an empty list.
256          */
257         private ASTNode.NodeList extendedOperands = null;
258
259         /**
260          * Creates a new AST node for an infix expression owned by the given 
261          * AST. By default, the node has unspecified (but legal) operator,
262          * left and right operands, and an empty list of additional operands.
263          * 
264          * @param ast the AST that is to own this node
265          */
266         InfixExpression(AST ast) {
267                 super(ast);
268         }
269
270         /* (omit javadoc for this method)
271          * Method declared on ASTNode.
272          */
273         final List internalStructuralPropertiesForType(int apiLevel) {
274                 return propertyDescriptors(apiLevel);
275         }
276         
277         /* (omit javadoc for this method)
278          * Method declared on ASTNode.
279          */
280         final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) {
281                 if (property == OPERATOR_PROPERTY) {
282                         if (get) {
283                                 return getOperator();
284                         } else {
285                                 setOperator((Operator) value);
286                                 return null;
287                         }
288                 }
289                 // allow default implementation to flag the error
290                 return super.internalGetSetObjectProperty(property, get, value);
291         }
292
293         /* (omit javadoc for this method)
294          * Method declared on ASTNode.
295          */
296         final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
297                 if (property == LEFT_OPERAND_PROPERTY) {
298                         if (get) {
299                                 return getLeftOperand();
300                         } else {
301                                 setLeftOperand((Expression) child);
302                                 return null;
303                         }
304                 }
305                 if (property == RIGHT_OPERAND_PROPERTY) {
306                         if (get) {
307                                 return getRightOperand();
308                         } else {
309                                 setRightOperand((Expression) child);
310                                 return null;
311                         }
312                 }
313                 // allow default implementation to flag the error
314                 return super.internalGetSetChildProperty(property, get, child);
315         }
316         
317         /* (omit javadoc for this method)
318          * Method declared on ASTNode.
319          */
320         final List internalGetChildListProperty(ChildListPropertyDescriptor property) {
321                 if (property == EXTENDED_OPERANDS_PROPERTY) {
322                         return extendedOperands();
323                 }
324                 // allow default implementation to flag the error
325                 return super.internalGetChildListProperty(property);
326         }
327
328         /* (omit javadoc for this method)
329          * Method declared on ASTNode.
330          */
331         final int getNodeType0() {
332                 return INFIX_EXPRESSION;
333         }
334
335         /* (omit javadoc for this method)
336          * Method declared on ASTNode.
337          */
338         ASTNode clone0(AST target) {
339                 InfixExpression result = new InfixExpression(target);
340                 result.setSourceRange(this.getStartPosition(), this.getLength());
341                 result.setOperator(getOperator());
342                 result.setLeftOperand((Expression) getLeftOperand().clone(target));
343                 result.setRightOperand((Expression) getRightOperand().clone(target));
344                 if (this.extendedOperands != null) {
345                         // be careful not to trigger lazy creation of list
346                         result.extendedOperands().addAll(
347                                 ASTNode.copySubtrees(target, this.extendedOperands()));
348                 }
349                 return result;
350         }
351
352         /* (omit javadoc for this method)
353          * Method declared on ASTNode.
354          */
355         final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
356                 // dispatch to correct overloaded match method
357                 return matcher.match(this, other);
358         }
359
360         /* (omit javadoc for this method)
361          * Method declared on ASTNode.
362          */
363         void accept0(ASTVisitor visitor) {
364                 boolean visitChildren = visitor.visit(this);
365                 if (visitChildren) {
366                         // visit children in normal left to right reading order
367                         acceptChild(visitor, getLeftOperand());
368                         acceptChild(visitor, getRightOperand());
369                         if (this.extendedOperands != null) {
370                                 // be careful not to trigger lazy creation of list
371                                 acceptChildren(visitor, this.extendedOperands);
372                         }
373                 }
374                 visitor.endVisit(this);
375         }
376         
377         /**
378          * Returns the operator of this infix expression.
379          * 
380          * @return the infix operator
381          */ 
382         public InfixExpression.Operator getOperator() {
383                 return this.operator;
384         }
385
386         /**
387          * Sets the operator of this infix expression.
388          * 
389          * @param operator the infix operator
390          * @exception IllegalArgumentException if the argument is incorrect
391          */ 
392         public void setOperator(InfixExpression.Operator operator) {
393                 if (operator == null) {
394                         throw new IllegalArgumentException();
395                 }
396                 preValueChange(OPERATOR_PROPERTY);
397                 this.operator = operator;
398                 postValueChange(OPERATOR_PROPERTY);
399         }
400
401         /**
402          * Returns the left operand of this infix expression.
403          * 
404          * @return the left operand node
405          */ 
406         public Expression getLeftOperand() {
407                 if (this.leftOperand  == null) {
408                         // lazy init must be thread-safe for readers
409                         synchronized (this) {
410                                 if (this.leftOperand == null) {
411                                         preLazyInit();
412                                         this.leftOperand= new SimpleName(this.ast);
413                                         postLazyInit(this.leftOperand, LEFT_OPERAND_PROPERTY);
414                                 }
415                         }
416                 }
417                 return this.leftOperand;
418         }
419                 
420         /**
421          * Sets the left operand of this infix expression.
422          * 
423          * @param expression the left operand node
424          * @exception IllegalArgumentException if:
425          * <ul>
426          * <li>the node belongs to a different AST</li>
427          * <li>the node already has a parent</li>
428          * <li>a cycle in would be created</li>
429          * </ul>
430          */ 
431         public void setLeftOperand(Expression expression) {
432                 if (expression == null) {
433                         throw new IllegalArgumentException();
434                 }
435                 ASTNode oldChild = this.leftOperand;
436                 preReplaceChild(oldChild, expression, LEFT_OPERAND_PROPERTY);
437                 this.leftOperand = expression;
438                 postReplaceChild(oldChild, expression, LEFT_OPERAND_PROPERTY);
439         }
440
441         /**
442          * Returns the right operand of this infix expression.
443          * 
444          * @return the right operand node
445          */ 
446         public Expression getRightOperand() {
447                 if (this.rightOperand  == null) {
448                         // lazy init must be thread-safe for readers
449                         synchronized (this) {
450                                 if (this.rightOperand  == null) {
451                                         preLazyInit();
452                                         this.rightOperand= new SimpleName(this.ast);
453                                         postLazyInit(this.rightOperand, RIGHT_OPERAND_PROPERTY);
454                                 }
455                         }
456                 }
457                 return this.rightOperand;
458         }
459                 
460         /**
461          * Sets the right operand of this infix expression.
462          * 
463          * @param expression the right operand node
464          * @exception IllegalArgumentException if:
465          * <ul>
466          * <li>the node belongs to a different AST</li>
467          * <li>the node already has a parent</li>
468          * <li>a cycle in would be created</li>
469          * </ul>
470          */ 
471         public void setRightOperand(Expression expression) {
472                 if (expression == null) {
473                         throw new IllegalArgumentException();
474                 }
475                 ASTNode oldChild = this.rightOperand;
476                 preReplaceChild(oldChild, expression, RIGHT_OPERAND_PROPERTY);
477                 this.rightOperand = expression;
478                 postReplaceChild(oldChild, expression, RIGHT_OPERAND_PROPERTY);
479         }
480         
481         /**
482          * Returns where there are any extended operands.
483          * 
484          * @return <code>true</code> if there are one or more extended operands,
485          *    and <code>false</code> if there are no extended operands
486          */
487         public boolean hasExtendedOperands() {
488                 return 
489                         (this.extendedOperands != null) && this.extendedOperands.size() > 0;
490         }
491         
492         /**
493          * Returns the live list of extended operands.
494          * <p>
495          * The extended operands is the preferred way of representing deeply nested
496          * expressions of the form <code>L op R op R2 op R3...</code> where
497          * the same operator appears between all the operands (the most 
498          * common case being lengthy string concatenation expressions). Using
499          * the extended operands keeps the trees from getting too deep; this
500          * decreases the risk is running out of thread stack space at runtime
501          * when traversing such trees.
502          * ((a + b) + c) + d would be translated to:
503          *      leftOperand: a
504          *      rightOperand: b
505          *      extendedOperands: {c, d}
506          *      operator: +
507          * </p>
508          * 
509          * @return the live list of extended operands
510          *   (element type: <code>Expression</code>)
511          */
512         public List extendedOperands() {
513                 if (this.extendedOperands == null) {
514                         // lazily initialize
515                         this.extendedOperands = new ASTNode.NodeList(EXTENDED_OPERANDS_PROPERTY);
516                 }
517                 return this.extendedOperands;
518         }
519
520         /* (omit javadoc for this method)
521          * Method declared on ASTNode.
522          */
523         int memSize() {
524                 // treat Operator as free
525                 return BASE_NODE_SIZE + 4 * 4;
526         }
527         
528         /* (omit javadoc for this method)
529          * Method declared on ASTNode.
530          */
531         int treeSize() {
532                 return 
533                         memSize()
534                         + (this.leftOperand == null ? 0 : getLeftOperand().treeSize())
535                         + (this.rightOperand == null ? 0 : getRightOperand().treeSize())
536                         + (this.extendedOperands == null ? 0 : extendedOperands.listSize());
537         }
538 }