001: /*
002: * Copyright (C) 2004 TiongHiang Lee
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: * Email: thlee@onemindsoft.org
019: */
020:
021: package org.onemind.jxp;
022:
023: import org.onemind.commons.java.lang.Null;
024:
025: /**
026: * The evaluator implements several arithmetic operations on objects
027: * @author TiongHiang Lee (thlee@onemindsoft.org)
028: *
029: */
030: public final class Evaluator {
031:
032: /** the precision of parameters * */
033: private static final short INT_PRECISION = 0, FLOAT_PRECISION = 1,
034: LONG_PRECISION = 2, DOUBLE_PRECISION = 3;
035:
036: /**
037: * Constructor
038: */
039: private Evaluator() {
040: }
041:
042: /**
043: * Plus operation
044: * @param a1 the first arg
045: * @param a2 the second arg
046: * @return the result
047: */
048: public static Object plus(Object a1, Object a2) {
049: if (a1 instanceof String || a1 instanceof Character) {
050: return a1.toString() + a2;
051: } else if (a2 instanceof String || a2 instanceof Character) {
052: return a1 + a2.toString();
053: }
054: Number n1 = toNumber(a1), n2 = toNumber(a2);
055: switch (getPrecision(n1, n2)) {
056: case INT_PRECISION:
057: return new Integer(n1.intValue() + n2.intValue());
058: case LONG_PRECISION:
059: return new Long(n1.longValue() + n2.longValue());
060: case FLOAT_PRECISION:
061: return new Float(n1.floatValue() + n2.floatValue());
062: case DOUBLE_PRECISION:
063: return new Double(n1.doubleValue() + n2.doubleValue());
064: default:
065: throw new InternalError("Internal error");
066: }
067: }
068:
069: /**
070: * Get the higest precision among the two number
071: * @param n1 the first number
072: * @param n2 the second numbe r
073: * @return the highest precision
074: */
075: private static short getPrecision(Number n1, Number n2) {
076: if (n1 instanceof Double || n2 instanceof Double) {
077: return DOUBLE_PRECISION;
078: } else if (n1 instanceof Float || n2 instanceof Float) {
079: return FLOAT_PRECISION;
080: } else if (n1 instanceof Long || n2 instanceof Long) {
081: return LONG_PRECISION;
082: } else { //if (n1 instanceof Integer || n2 instanceof Integer) {
083: return INT_PRECISION;
084: }
085: }
086:
087: /**
088: * Cast the object to a number
089: * @param o the object
090: * @return a number object
091: */
092: private static Number toNumber(Object o) {
093: if (o instanceof Number) {
094: return (Number) o;
095: } else {
096: throw new IllegalArgumentException(o + " is not a number");
097: }
098: }
099:
100: /**
101: * Minus operation
102: * @param a1 the first arg
103: * @param a2 the second arg
104: * @return the result
105: */
106: public static Object minus(Object a1, Object a2) {
107: Number n1 = toNumber(a1), n2 = toNumber(a2);
108: switch (getPrecision(n1, n2)) {
109: case INT_PRECISION:
110: return new Integer(n1.intValue() - n2.intValue());
111: case LONG_PRECISION:
112: return new Long(n1.longValue() - n2.longValue());
113: case FLOAT_PRECISION:
114: return new Float(n1.floatValue() - n2.floatValue());
115: case DOUBLE_PRECISION:
116: return new Double(n1.doubleValue() - n2.doubleValue());
117: default:
118: throw new InternalError("Internal error");
119: }
120: }
121:
122: /**
123: * Multiply operation
124: * @param a1 the first arg
125: * @param a2 the second arg
126: * @return the result
127: */
128: public static Object multiply(Object a1, Object a2) {
129: Number n1 = toNumber(a1), n2 = toNumber(a2);
130: switch (getPrecision(n1, n2)) {
131: case INT_PRECISION:
132: return new Integer(n1.intValue() * n2.intValue());
133: case LONG_PRECISION:
134: return new Long(n1.longValue() * n2.longValue());
135: case FLOAT_PRECISION:
136: return new Float(n1.floatValue() * n2.floatValue());
137: case DOUBLE_PRECISION:
138: return new Double(n1.doubleValue() * n2.doubleValue());
139: default:
140: throw new InternalError("Internal error");
141: }
142: }
143:
144: /**
145: * Divide operation
146: * @param a1 the first arg
147: * @param a2 the second arg
148: * @return the result
149: */
150: public static Object divide(Object a1, Object a2) {
151: Number n1 = toNumber(a1), n2 = toNumber(a2);
152: switch (getPrecision(n1, n2)) {
153: case INT_PRECISION:
154: return new Integer(n1.intValue() / n2.intValue());
155: case LONG_PRECISION:
156: return new Long(n1.longValue() / n2.longValue());
157: case FLOAT_PRECISION:
158: return new Float(n1.floatValue() / n2.floatValue());
159: case DOUBLE_PRECISION:
160: return new Double(n1.doubleValue() / n2.doubleValue());
161: default:
162: throw new InternalError("Internal error");
163: }
164: }
165:
166: /**
167: * Remainder operation
168: * @param a1 the first arg
169: * @param a2 the second arg
170: * @return the result
171: */
172: public static Object remainder(Object a1, Object a2) {
173: Number n1 = toNumber(a1), n2 = toNumber(a2);
174: switch (getPrecision(n1, n2)) {
175: case INT_PRECISION:
176: return new Integer(n1.intValue() % n2.intValue());
177: case LONG_PRECISION:
178: return new Long(n1.longValue() % n2.longValue());
179: case FLOAT_PRECISION:
180: return new Float(n1.floatValue() % n2.floatValue());
181: case DOUBLE_PRECISION:
182: return new Double(n1.doubleValue() % n2.doubleValue());
183: default:
184: throw new InternalError("Internal error");
185: }
186: }
187:
188: /**
189: * Negation operation
190: * @param a1 the first arg
191: * @return the result
192: */
193: public static Object negate(Object a1) {
194: Number n1 = toNumber(a1);
195: switch (getPrecision(n1, n1)) {
196: case INT_PRECISION:
197: return new Integer(-n1.intValue());
198: case LONG_PRECISION:
199: return new Long(-n1.longValue());
200: case FLOAT_PRECISION:
201: return new Float(-n1.floatValue());
202: case DOUBLE_PRECISION:
203: return new Double(-n1.doubleValue());
204: default:
205: throw new InternalError("Internal error");
206: }
207: }
208:
209: /**
210: * Equality operation
211: * @param a1 the first arg
212: * @param a2 the second arg
213: * @return the result
214: */
215: public static Boolean eq(Object a1, Object a2) {
216: if (a1 instanceof Number && a2 instanceof Number) {
217: return Boolean.valueOf(a1.equals(a2));
218: } else if (a1 instanceof Boolean && a2 instanceof Boolean) {
219: return Boolean.valueOf(a1.equals(a2));
220: } else if ((a1 == null || a1 == Null.instance)
221: && (a2 == null || a2 == Null.instance)) {
222: return Boolean.TRUE;
223: } else if (a1 instanceof Character && a2 instanceof Character) {
224: return Boolean.valueOf(a1.equals(a2));
225: } else {
226: return Boolean.valueOf(a1 == a2);
227: }
228: }
229:
230: /**
231: * Inequality operation
232: * @param a1 the first arg
233: * @param a2 the second arg
234: * @return the result
235: */
236: public static Boolean ne(Object a1, Object a2) {
237: if (a1 instanceof Number && a2 instanceof Number) {
238: return Boolean.valueOf(!a1.equals(a2));
239: } else if (a1 instanceof Boolean && a2 instanceof Boolean) {
240: return Boolean.valueOf(!a1.equals(a2));
241: } else if ((a1 == null || a1 == Null.instance)
242: && (a2 == null || a2 == Null.instance)) {
243: return Boolean.FALSE;
244: } else {
245: return Boolean.valueOf(a1 != a2);
246: }
247: }
248:
249: /**
250: * Less than operation
251: * @param a1 the first arg
252: * @param a2 the second arg
253: * @return the result
254: */
255: public static Boolean lt(Object a1, Object a2) {
256: Number n1 = toNumber(a1), n2 = toNumber(a2);
257: switch (getPrecision(n1, n2)) {
258: case INT_PRECISION:
259: return Boolean.valueOf(n1.intValue() < n2.intValue());
260: case LONG_PRECISION:
261: return Boolean.valueOf(n1.longValue() < n2.longValue());
262: case FLOAT_PRECISION:
263: return Boolean.valueOf(n1.floatValue() < n2.floatValue());
264: case DOUBLE_PRECISION:
265: return Boolean.valueOf(n1.doubleValue() < n2.doubleValue());
266: default:
267: throw new InternalError("Internal error");
268: }
269: }
270:
271: /**
272: * Less than or equal operation
273: * @param a1 the first arg
274: * @param a2 the second arg
275: * @return the result
276: */
277: public static Boolean le(Object a1, Object a2) {
278: Number n1 = toNumber(a1), n2 = toNumber(a2);
279: switch (getPrecision(n1, n2)) {
280: case INT_PRECISION:
281: return Boolean.valueOf(n1.intValue() <= n2.intValue());
282: case LONG_PRECISION:
283: return Boolean.valueOf(n1.longValue() <= n2.longValue());
284: case FLOAT_PRECISION:
285: return Boolean.valueOf(n1.floatValue() <= n2.floatValue());
286: case DOUBLE_PRECISION:
287: return Boolean
288: .valueOf(n1.doubleValue() <= n2.doubleValue());
289: default:
290: throw new InternalError("Internal error");
291: }
292: }
293:
294: /**
295: * Greater than operation
296: * @param a1 the first arg
297: * @param a2 the second arg
298: * @return the result
299: */
300: public static Boolean gt(Object a1, Object a2) {
301: Number n1 = toNumber(a1), n2 = toNumber(a2);
302: switch (getPrecision(n1, n2)) {
303: case INT_PRECISION:
304: return Boolean.valueOf(n1.intValue() > n2.intValue());
305: case LONG_PRECISION:
306: return Boolean.valueOf(n1.longValue() > n2.longValue());
307: case FLOAT_PRECISION:
308: return Boolean.valueOf(n1.floatValue() > n2.floatValue());
309: case DOUBLE_PRECISION:
310: return Boolean.valueOf(n1.doubleValue() > n2.doubleValue());
311: default:
312: throw new InternalError("Internal error");
313: }
314: }
315:
316: /**
317: * Greater than or equal operation
318: * @param a1 the first arg
319: * @param a2 the second arg
320: * @return the result
321: */
322: public static Boolean ge(Object a1, Object a2) {
323: Number n1 = toNumber(a1), n2 = toNumber(a2);
324: switch (getPrecision(n1, n2)) {
325: case INT_PRECISION:
326: return Boolean.valueOf(n1.intValue() >= n2.intValue());
327: case LONG_PRECISION:
328: return Boolean.valueOf(n1.longValue() >= n2.longValue());
329: case FLOAT_PRECISION:
330: return Boolean.valueOf(n1.floatValue() >= n2.floatValue());
331: case DOUBLE_PRECISION:
332: return Boolean
333: .valueOf(n1.doubleValue() >= n2.doubleValue());
334: default:
335: throw new InternalError("Internal error");
336: }
337: }
338:
339: /**
340: * Cast the given object to boolean type
341: * @param o the object
342: * @return boolean type
343: */
344: public static Boolean toBoolean(Object o) {
345: if (o instanceof Boolean) {
346: return (Boolean) o;
347: } else {
348: throw new IllegalArgumentException(o + " is not boolean");
349: }
350: }
351:
352: /**
353: * Bitwise complement operation
354: * @param o the object
355: * @return the result
356: */
357: public static Object bitwiseComplement(Object o) {
358: Number n1 = toNumber(o);
359: switch (getPrecision(n1, n1)) {
360: case INT_PRECISION:
361: return new Integer(~n1.intValue());
362: case LONG_PRECISION:
363: return new Long(~n1.longValue());
364: default:
365: throw new IllegalArgumentException(
366: "Cannot apply bitwise complement operation on float/double value");
367: }
368: }
369:
370: /**
371: * Left-shift operation
372: * @param a1 the first arg
373: * @param a2 the second arg
374: * @return the result
375: */
376: public static Object leftShift(Object a1, Object a2) {
377: Number n1 = toNumber(a1), n2 = toNumber(a2);
378: switch (getPrecision(n1, n1)) {
379: case INT_PRECISION:
380: return new Integer(n1.intValue() << n2.intValue());
381: case LONG_PRECISION:
382: return new Long(n1.longValue() << n2.intValue());
383: default:
384: throw new IllegalArgumentException(
385: "Cannot apply << operator on float/double value");
386: }
387: }
388:
389: /**
390: * right-signed-shift operation
391: * @param a1 the first arg
392: * @param a2 the second arg
393: * @return the result
394: */
395: public static Object rightSignedShift(Object a1, Object a2) {
396: Number n1 = toNumber(a1), n2 = toNumber(a2);
397: switch (getPrecision(n1, n1)) {
398: case INT_PRECISION:
399: return new Integer(n1.intValue() >> n2.intValue());
400: case LONG_PRECISION:
401: return new Long(n1.longValue() >> n2.intValue());
402: default:
403: throw new IllegalArgumentException(
404: "Cannot apply >> operator on float/double value");
405: }
406: }
407:
408: /**
409: * Right-unsigned-shift operation
410: * @param a1 the first arg
411: * @param a2 the second arg
412: * @return the result
413: */
414: public static Object rightUnsignedShift(Object a1, Object a2) {
415: Number n1 = toNumber(a1), n2 = toNumber(a2);
416: switch (getPrecision(n1, n1)) {
417: case INT_PRECISION:
418: return new Integer(n1.intValue() >>> n2.intValue());
419: case LONG_PRECISION:
420: return new Long(n1.longValue() >>> n2.intValue());
421: default:
422: throw new IllegalArgumentException(
423: "Cannot apply >>> operator on float/double value");
424: }
425: }
426:
427: /**
428: * Bitwise-and operation
429: * @param a1 the first arg
430: * @param a2 the second arg
431: * @return the result
432: */
433: public static Object bitwiseAnd(Object a1, Object a2) {
434: Number n1 = toNumber(a1), n2 = toNumber(a2);
435: switch (getPrecision(n1, n1)) {
436: case INT_PRECISION:
437: return new Integer(n1.intValue() & n2.intValue());
438: case LONG_PRECISION:
439: return new Long(n1.longValue() & n2.intValue());
440: default:
441: throw new IllegalArgumentException(
442: "Cannot apply & operator on float/double value");
443: }
444: }
445:
446: /**
447: * Bitwise-or operation
448: * @param a1 the first arg
449: * @param a2 the second arg
450: * @return the result
451: */
452: public static Object bitwiseOr(Object a1, Object a2) {
453: Number n1 = toNumber(a1), n2 = toNumber(a2);
454: switch (getPrecision(n1, n1)) {
455: case INT_PRECISION:
456: return new Integer(n1.intValue() | n2.intValue());
457: case LONG_PRECISION:
458: return new Long(n1.longValue() | n2.intValue());
459: default:
460: throw new IllegalArgumentException(
461: "Cannot apply | operator on float/double value");
462: }
463: }
464:
465: /**
466: * Bitwise-XOR operation
467: * @param a1 the first arg
468: * @param a2 the second arg
469: * @return the result
470: */
471: public static Object bitwiseXOr(Object a1, Object a2) {
472: Number n1 = toNumber(a1), n2 = toNumber(a2);
473: switch (getPrecision(n1, n1)) {
474: case INT_PRECISION:
475: return new Integer(n1.intValue() ^ n2.intValue());
476: case LONG_PRECISION:
477: return new Long(n1.longValue() ^ n2.intValue());
478: default:
479: throw new IllegalArgumentException(
480: "Cannot apply ^ operator on float/double value");
481: }
482: }
483: }
|