View Javadoc
1   /*
2    * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package jdk.nashorn.internal.ir;
27  
28  import jdk.nashorn.internal.codegen.types.Type;
29  import jdk.nashorn.internal.ir.annotations.Immutable;
30  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
31  import jdk.nashorn.internal.parser.TokenType;
32  
33  /**
34   * BinaryNode nodes represent two operand operations.
35   */
36  @Immutable
37  public final class BinaryNode extends Expression implements Assignment<Expression> {
38      /** Left hand side argument. */
39      private final Expression lhs;
40  
41      private final Expression rhs;
42  
43      /**
44       * Constructor
45       *
46       * @param token  token
47       * @param lhs    left hand side
48       * @param rhs    right hand side
49       */
50      public BinaryNode(final long token, final Expression lhs, final Expression rhs) {
51          super(token, lhs.getStart(), rhs.getFinish());
52          this.lhs   = lhs;
53          this.rhs   = rhs;
54      }
55  
56      private BinaryNode(final BinaryNode binaryNode, final Expression lhs, final Expression rhs) {
57          super(binaryNode);
58          this.lhs = lhs;
59          this.rhs = rhs;
60      }
61  
62      @Override
63      public boolean isComparison() {
64          switch (tokenType()) {
65          case EQ:
66          case EQ_STRICT:
67          case NE:
68          case NE_STRICT:
69          case LE:
70          case LT:
71          case GE:
72          case GT:
73              return true;
74          default:
75              return false;
76          }
77      }
78  
79      /**
80       * Return the widest possible type for this operation. This is used for compile time
81       * static type inference
82       *
83       * @return Type
84       */
85      @Override
86      public Type getWidestOperationType() {
87          switch (tokenType()) {
88          case SHR:
89          case ASSIGN_SHR:
90              return Type.LONG;
91          case ASSIGN_SAR:
92          case ASSIGN_SHL:
93          case BIT_AND:
94          case BIT_OR:
95          case BIT_XOR:
96          case ASSIGN_BIT_AND:
97          case ASSIGN_BIT_OR:
98          case ASSIGN_BIT_XOR:
99          case SAR:
100         case SHL:
101             return Type.INT;
102         case DIV:
103         case MOD:
104         case MUL:
105         case SUB:
106         case ASSIGN_DIV:
107         case ASSIGN_MOD:
108         case ASSIGN_MUL:
109         case ASSIGN_SUB:
110             return Type.NUMBER;
111         default:
112             return Type.OBJECT;
113         }
114     }
115 
116     /**
117      * Check if this node is an assigment
118      *
119      * @return true if this node assigns a value
120      */
121     @Override
122     public boolean isAssignment() {
123         switch (tokenType()) {
124         case ASSIGN:
125         case ASSIGN_ADD:
126         case ASSIGN_BIT_AND:
127         case ASSIGN_BIT_OR:
128         case ASSIGN_BIT_XOR:
129         case ASSIGN_DIV:
130         case ASSIGN_MOD:
131         case ASSIGN_MUL:
132         case ASSIGN_SAR:
133         case ASSIGN_SHL:
134         case ASSIGN_SHR:
135         case ASSIGN_SUB:
136            return true;
137         default:
138            return false;
139         }
140     }
141 
142     @Override
143     public boolean isSelfModifying() {
144         return isAssignment() && tokenType() != TokenType.ASSIGN;
145     }
146 
147     @Override
148     public Expression getAssignmentDest() {
149         return isAssignment() ? lhs() : null;
150     }
151 
152     @Override
153     public BinaryNode setAssignmentDest(Expression n) {
154         return setLHS(n);
155     }
156 
157     @Override
158     public Expression getAssignmentSource() {
159         return rhs();
160     }
161 
162     /**
163      * Assist in IR navigation.
164      * @param visitor IR navigating visitor.
165      */
166     @Override
167     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
168         if (visitor.enterBinaryNode(this)) {
169             return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor)));
170         }
171 
172         return this;
173     }
174 
175     @Override
176     public boolean isLocal() {
177         switch (tokenType()) {
178         case SAR:
179         case SHL:
180         case SHR:
181         case BIT_AND:
182         case BIT_OR:
183         case BIT_XOR:
184         case ADD:
185         case DIV:
186         case MOD:
187         case MUL:
188         case SUB:
189             return lhs.isLocal() && lhs.getType().isJSPrimitive()
190                 && rhs.isLocal() && rhs.getType().isJSPrimitive();
191         case ASSIGN_ADD:
192         case ASSIGN_BIT_AND:
193         case ASSIGN_BIT_OR:
194         case ASSIGN_BIT_XOR:
195         case ASSIGN_DIV:
196         case ASSIGN_MOD:
197         case ASSIGN_MUL:
198         case ASSIGN_SAR:
199         case ASSIGN_SHL:
200         case ASSIGN_SHR:
201         case ASSIGN_SUB:
202             return lhs instanceof IdentNode && lhs.isLocal() && lhs.getType().isJSPrimitive()
203                     && rhs.isLocal() && rhs.getType().isJSPrimitive();
204         case ASSIGN:
205             return lhs instanceof IdentNode && lhs.isLocal() && rhs.isLocal();
206         default:
207             return false;
208         }
209     }
210 
211     @Override
212     public void toString(final StringBuilder sb) {
213         final TokenType type = tokenType();
214 
215         final boolean lhsParen = type.needsParens(lhs().tokenType(), true);
216         final boolean rhsParen = type.needsParens(rhs().tokenType(), false);
217 
218         if (lhsParen) {
219             sb.append('(');
220         }
221 
222         lhs().toString(sb);
223 
224         if (lhsParen) {
225             sb.append(')');
226         }
227 
228         sb.append(' ');
229 
230         switch (type) {
231         case COMMALEFT:
232             sb.append(",<");
233             break;
234         case COMMARIGHT:
235             sb.append(",>");
236             break;
237         case INCPREFIX:
238         case DECPREFIX:
239             sb.append("++");
240             break;
241         default:
242             sb.append(type.getName());
243             break;
244         }
245 
246         sb.append(' ');
247 
248         if (rhsParen) {
249             sb.append('(');
250         }
251         rhs().toString(sb);
252         if (rhsParen) {
253             sb.append(')');
254         }
255     }
256 
257     /**
258      * Get the left hand side expression for this node
259      * @return the left hand side expression
260      */
261     public Expression lhs() {
262         return lhs;
263     }
264 
265     /**
266      * Get the right hand side expression for this node
267      * @return the left hand side expression
268      */
269     public Expression rhs() {
270         return rhs;
271     }
272 
273     /**
274      * Set the left hand side expression for this node
275      * @param lhs new left hand side expression
276      * @return a node equivalent to this one except for the requested change.
277      */
278     public BinaryNode setLHS(final Expression lhs) {
279         if (this.lhs == lhs) {
280             return this;
281         }
282         return new BinaryNode(this, lhs, rhs);
283     }
284 
285     /**
286      * Set the right hand side expression for this node
287      * @param rhs new left hand side expression
288      * @return a node equivalent to this one except for the requested change.
289      */
290     public BinaryNode setRHS(final Expression rhs) {
291         if (this.rhs == rhs) {
292             return this;
293         }
294         return new BinaryNode(this, lhs, rhs);
295     }
296 
297 }