001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.el;
031:
032: import com.caucho.vfs.WriteStream;
033:
034: import javax.el.ELContext;
035: import javax.el.ELException;
036: import java.io.IOException;
037: import java.math.BigDecimal;
038: import java.math.BigInteger;
039:
040: /**
041: * Represents a binary numeric operation
042: */
043: public class BinaryExpr extends Expr {
044: private int _op;
045: private Expr _left;
046: private Expr _right;
047:
048: /**
049: * Creates the binary expression.
050: *
051: * @param op the binary operation's lexical code
052: * @param left the left subexpression
053: * @param right the right subexpression
054: */
055: private BinaryExpr(int op, Expr left, Expr right) {
056: _op = op;
057: _left = left;
058: _right = right;
059: }
060:
061: public static Expr create(int op, Expr left, Expr right) {
062: switch (op) {
063: case ADD:
064: return new AddExpr(left, right);
065: case SUB:
066: return new SubExpr(left, right);
067: case MUL:
068: return new MulExpr(left, right);
069: case DIV:
070: return new DivExpr(left, right);
071: case MOD:
072: return new ModExpr(left, right);
073:
074: default:
075: throw new UnsupportedOperationException();
076: }
077: }
078:
079: /**
080: * Returns true if this is a constant expression.
081: */
082: @Override
083: public boolean isConstant() {
084: return _left.isConstant() && _right.isConstant();
085: }
086:
087: /**
088: * Evaluate the expression as an object.
089: *
090: * @param env the variable environment
091: *
092: * @return the result as an object
093: */
094: @Override
095: public Object getValue(ELContext env) throws ELException {
096: Object aObj = _left.getValue(env);
097: Object bObj = _right.getValue(env);
098:
099: if (aObj instanceof BigDecimal || bObj instanceof BigDecimal) {
100: BigDecimal a = toBigDecimal(aObj, env);
101: BigDecimal b = toBigDecimal(bObj, env);
102:
103: switch (_op) {
104: case ADD:
105: return a.add(b);
106: case SUB:
107: return a.subtract(b);
108: case MUL:
109: return a.multiply(b);
110: case DIV:
111: return a.divide(b, BigDecimal.ROUND_HALF_UP);
112: case MOD: {
113: double da = toDouble(aObj, env);
114: double db = toDouble(bObj, env);
115:
116: return new Double(da % db);
117: }
118: default:
119: throw new IllegalStateException();
120: }
121: } else if (aObj instanceof BigInteger
122: || bObj instanceof BigInteger) {
123: BigInteger a = toBigInteger(aObj, env);
124: BigInteger b = toBigInteger(bObj, env);
125:
126: switch (_op) {
127: case ADD:
128: return a.add(b);
129: case SUB:
130: return a.subtract(b);
131: case MUL:
132: return a.multiply(b);
133: case DIV: {
134: BigDecimal da = toBigDecimal(aObj, env);
135: BigDecimal db = toBigDecimal(bObj, env);
136:
137: return da.divide(db, BigDecimal.ROUND_HALF_UP);
138: }
139: case MOD: {
140: if (aObj instanceof Float || aObj instanceof Double
141: || bObj instanceof Float
142: || bObj instanceof Double) {
143: double da = toDouble(aObj, env);
144: double db = toDouble(bObj, env);
145:
146: return new Double(da % db);
147: } else
148: return a.remainder(b);
149: }
150: default:
151: throw new IllegalStateException();
152: }
153: }
154:
155: else if (isDouble(aObj) || isDouble(bObj)) {
156: double a = toDouble(aObj, env);
157: double b = toDouble(bObj, env);
158: double dValue = 0;
159:
160: switch (_op) {
161: case ADD:
162: dValue = a + b;
163: break;
164: case SUB:
165: dValue = a - b;
166: break;
167: case MUL:
168: dValue = a * b;
169: break;
170: case DIV:
171: dValue = a / b;
172: break;
173: case MOD:
174: dValue = a % b;
175: break;
176: }
177:
178: return Double.isNaN(dValue) ? new Double(0) : new Double(
179: dValue);
180: }
181:
182: if (aObj == null && bObj == null)
183: return new Integer(0);
184:
185: if (bObj instanceof Double || bObj instanceof Float) {
186: double a = toDouble(aObj, env);
187: double b = ((Number) bObj).doubleValue();
188: double dValue = 0;
189:
190: switch (_op) {
191: case ADD:
192: dValue = a + b;
193: break;
194: case SUB:
195: dValue = a - b;
196: break;
197: case MUL:
198: dValue = a * b;
199: break;
200: case DIV:
201: dValue = a / b;
202: break;
203:
204: case MOD:
205: dValue = a % b;
206: break;
207: }
208:
209: return Double.isNaN(dValue) ? new Double(0) : new Double(
210: dValue);
211: } else if (aObj instanceof Number) {
212: long a = ((Number) aObj).longValue();
213: long b = toLong(bObj, env);
214:
215: switch (_op) {
216: case ADD:
217: return new Long(a + b);
218: case SUB:
219: return new Long(a - b);
220: case MUL:
221: return new Long(a * b);
222: case DIV:
223: double dValue = (double) a / (double) b;
224:
225: return Double.isNaN(dValue) ? new Double(0)
226: : new Double(dValue);
227:
228: case MOD:
229: return new Long(a % b);
230: }
231: } else if (bObj instanceof Number) {
232: long a = toLong(aObj, env);
233: long b = ((Number) bObj).longValue();
234:
235: switch (_op) {
236: case ADD:
237: return new Long(a + b);
238: case SUB:
239: return new Long(a - b);
240: case MUL:
241: return new Long(a * b);
242: case DIV:
243: double dValue = (double) a / (double) b;
244:
245: return Double.isNaN(dValue) ? new Double(0)
246: : new Double(dValue);
247:
248: case MOD:
249: return new Long(a % b);
250: }
251: }
252:
253: if (isDoubleString(aObj) || isDoubleString(bObj)) {
254: double a = toDouble(aObj, env);
255: double b = toDouble(bObj, env);
256:
257: switch (_op) {
258: case ADD:
259: return new Double(a + b);
260: case SUB:
261: return new Double(a - b);
262: case MUL:
263: return new Double(a * b);
264: case DIV:
265: double dValue = (double) a / (double) b;
266:
267: return Double.isNaN(dValue) ? new Double(0)
268: : new Double(dValue);
269:
270: case MOD:
271: return new Double(a % b);
272: }
273: } else {
274: long a = toLong(aObj, env);
275: long b = toLong(bObj, env);
276:
277: switch (_op) {
278: case ADD:
279: return new Long(a + b);
280: case SUB:
281: return new Long(a - b);
282: case MUL:
283: return new Long(a * b);
284: case DIV:
285: double dValue = (double) a / (double) b;
286:
287: return Double.isNaN(dValue) ? new Double(0)
288: : new Double(dValue);
289:
290: case MOD:
291: return new Long(a % b);
292: }
293: }
294:
295: return null;
296: }
297:
298: /**
299: * Evaluate the expression as a long
300: *
301: * @param env the variable environment
302: *
303: * @return the result as an long
304: */
305: @Override
306: public long evalLong(ELContext env) throws ELException {
307: long a = _left.evalLong(env);
308: long b = _right.evalLong(env);
309:
310: switch (_op) {
311: case ADD:
312: return a + b;
313: case SUB:
314: return a - b;
315: case MUL:
316: return a * b;
317: case DIV:
318: return (long) ((double) a / (double) b);
319: case MOD:
320: return a % b;
321: }
322:
323: ELException e = new ELException(L.l(
324: "error evaluating add {0} and {1}", String.valueOf(a),
325: String.valueOf(b)));
326:
327: error(e, env);
328:
329: return 0;
330: }
331:
332: /**
333: * Evaluate the expression as a double
334: *
335: * @param env the variable environment
336: *
337: * @return the result as an double
338: */
339: @Override
340: public double evalDouble(ELContext env) throws ELException {
341: double a = _left.evalDouble(env);
342: double b = _right.evalDouble(env);
343:
344: switch (_op) {
345: case ADD:
346: return a + b;
347: case SUB:
348: return a - b;
349: case MUL:
350: return a * b;
351: case DIV:
352: return a / b;
353: case MOD:
354: return a % b;
355: }
356:
357: ELException e = new ELException(L.l(
358: "error evaluating add {0} and {1}", String.valueOf(a),
359: String.valueOf(b)));
360:
361: error(e, env);
362:
363: return 0;
364: }
365:
366: /**
367: * Prints the Java code to recreate an LongLiteral.
368: *
369: * @param os the output stream to the *.java file
370: */
371: @Override
372: public void printCreate(WriteStream os) throws IOException {
373: os.print("new com.caucho.el.BinaryExpr(");
374: os.print(_op + ", ");
375: _left.printCreate(os);
376: os.print(", ");
377: _right.printCreate(os);
378: os.print(")");
379: }
380:
381: /**
382: * Returns true for equal strings.
383: */
384: public boolean equals(Object o) {
385: if (!(o instanceof BinaryExpr))
386: return false;
387:
388: BinaryExpr expr = (BinaryExpr) o;
389:
390: return (_op == expr._op && _left.equals(expr._left) && _right
391: .equals(expr._right));
392: }
393:
394: /**
395: * Returns a readable representation of the expr.
396: */
397: public String toString() {
398: String op;
399:
400: switch (_op) {
401: case ADD:
402: op = " + ";
403: break;
404: case SUB:
405: op = " - ";
406: break;
407: case MUL:
408: op = " * ";
409: break;
410: case DIV:
411: op = " / ";
412: break;
413: case MOD:
414: op = " % ";
415: break;
416: default:
417: op = " unknown(" + _op + ") ";
418: break;
419: }
420:
421: return "(" + _left + op + _right + ")";
422: }
423: }
|