001: package jsint;
002:
003: /**
004: * This class provides methods for those scalar operations which cannot
005: * be obtained using reflection on the standard Java libraries.
006: * @author Timothy J. Hickey, Copyright 2000, tim@cs.brandeis.edu, <a href="license.txt">license</a>
007: * subsequently modified by Jscheme project members
008: * licensed under zlib licence (see license.txt)
009: */
010:
011: public class Op {
012:
013: public static final int ADD = 0, // +
014: SUB = 1, // -
015: MUL = 2, // *
016: DIV = 3, // /
017: MOD = 4, // %
018: AND = 5, // A&B
019: OR = 6, // A|B
020: XOR = 7, // A^B
021: IMP = 8, // (-A)|B, so A IMP #F == ~A
022: LSH = 9, // <<
023: RSH = 10, // >>
024: RSHZ = 11, // >>>
025: EQ = 12, // =
026: LT = 13, // <
027: GT = 14, // >
028: LE = 15, // <=
029: GE = 16, // >=
030: NE = 17, // !=
031: COMPLEMENT = 18, // ~
032: NEGATE = 19, // -
033: SGN = 20, //
034: MODULO = 21 // R4RS modulo
035: ;
036:
037: public static Number add(Object a, Object b) {
038: return genericBinaryOp(Op.ADD, a, b);
039: }
040:
041: public static Number sub(Object a, Object b) {
042: return genericBinaryOp(Op.SUB, a, b);
043: }
044:
045: public static Number mul(Object a, Object b) {
046: return genericBinaryOp(Op.MUL, a, b);
047: }
048:
049: public static Number div(Object a, Object b) {
050: return genericBinaryOp(Op.DIV, a, b);
051: }
052:
053: public static Number mod(Object a, Object b) {
054: return genericBinaryOp(Op.MOD, a, b);
055: }
056:
057: public static Number modulo(Object a, Object b) {
058: return genericBinaryOp(Op.MODULO, a, b);
059: }
060:
061: public static Number negate(Object a) {
062: return genericUnaryOp(Op.NEGATE, a);
063: }
064:
065: public static Number complement(Object a) {
066: return genericUnaryOp(Op.COMPLEMENT, a);
067: }
068:
069: public static Number sgn(Object a) {
070: return genericUnaryOp(Op.SGN, a);
071: }
072:
073: public static Number leftShift(Object a, Object b) {
074: return genericBinaryOp(Op.LSH, a, b);
075: }
076:
077: public static Number rightShift(Object a, Object b) {
078: return genericBinaryOp(Op.RSH, a, b);
079: }
080:
081: public static Number rightShiftZ(Object a, Object b) {
082: return genericBinaryOp(Op.RSHZ, a, b);
083: }
084:
085: public static boolean eq(Object a, Object b) {
086: return genericBinaryComp(Op.EQ, a, b);
087: }
088:
089: public static boolean lt(Object a, Object b) {
090: return genericBinaryComp(Op.LT, a, b);
091: }
092:
093: public static boolean gt(Object a, Object b) {
094: return genericBinaryComp(Op.GT, a, b);
095: }
096:
097: public static boolean le(Object a, Object b) {
098: return genericBinaryComp(Op.LE, a, b);
099: }
100:
101: public static boolean ge(Object a, Object b) {
102: return genericBinaryComp(Op.GE, a, b);
103: }
104:
105: public static boolean ne(Object a, Object b) {
106: return genericBinaryComp(Op.NE, a, b);
107: }
108:
109: public static Number and(Object a, Object b) {
110: return genericBinaryOp(Op.AND, a, b);
111: }
112:
113: public static Number xor(Object a, Object b) {
114: return genericBinaryOp(Op.XOR, a, b);
115: }
116:
117: public static Number or(Object a, Object b) {
118: return genericBinaryOp(Op.OR, a, b);
119: }
120:
121: public static Number imp(Object a, Object b) {
122: return genericBinaryOp(Op.IMP, a, b);
123: }
124:
125: public static Number genericBinaryMultiOp(int op, Number acc,
126: Pair args) {
127: while (args != Pair.EMPTY) {
128: acc = genericBinaryOp(op, acc, args.first);
129: args = (Pair) (args.rest);
130: }
131: return acc;
132: }
133:
134: private static Number genericBinaryOp(int op, Object a, Object b) {
135: Class c = lubNumericClass(a.getClass(), b.getClass());
136: if (c == Integer.class)
137: return binaryOpInteger(op, (Integer) coerceNumber(a,
138: Integer.class), (Integer) coerceNumber(b,
139: Integer.class));
140: else if (c == Long.class)
141: return binaryOpLong(op, (Long) coerceNumber(a, Long.class),
142: (Long) coerceNumber(b, Long.class));
143: else if (c == Float.class)
144: return binaryOpFloat(op, (Float) coerceNumber(a,
145: Float.class), (Float) coerceNumber(b, Float.class));
146: else if (c == Double.class)
147: return binaryOpDouble(op, (Double) coerceNumber(a,
148: Double.class), (Double) coerceNumber(b,
149: Double.class));
150: else
151: return wrongTypeError(a, b);
152: }
153:
154: private static boolean genericBinaryComp(int op, Object a, Object b) {
155: Class c = lubNumericClass(a.getClass(), b.getClass());
156: if (c == Integer.class)
157: return binaryCompInteger(op, (Integer) coerceNumber(a,
158: Integer.class), (Integer) coerceNumber(b,
159: Integer.class));
160: else if (c == Long.class)
161: return binaryCompLong(op,
162: (Long) coerceNumber(a, Long.class),
163: (Long) coerceNumber(b, Long.class));
164: else if (c == Float.class)
165: return binaryCompFloat(op, (Float) coerceNumber(a,
166: Float.class), (Float) coerceNumber(b, Float.class));
167: else if (c == Double.class)
168: return binaryCompDouble(op, (Double) coerceNumber(a,
169: Double.class), (Double) coerceNumber(b,
170: Double.class));
171: else {
172: wrongTypeError(a, b);
173: return false;
174: }
175: }
176:
177: private static Number genericUnaryOp(int op, Object a) {
178: Class c = lubNumericClass(a.getClass(), Integer.class);
179: if (c == Integer.class)
180: return unaryOpInteger(op, (Integer) coerceNumber(a,
181: Integer.class));
182: else if (c == Long.class)
183: return unaryOpLong(op, (Long) coerceNumber(a, Long.class));
184: else if (c == Float.class)
185: return unaryOpFloat(op,
186: (Float) coerceNumber(a, Float.class));
187: else if (c == Double.class)
188: return unaryOpDouble(op, (Double) coerceNumber(a,
189: Double.class));
190: else
191: return wrongTypeError(a);
192: }
193:
194: /**
195: KRA 29SEP01: Previous version always constructed a new number.
196: Evaluating (time (+ 1 1) 1000) consed 184 bytes per addition.
197: <p> Now we get:
198: <pre>
199: (+ 1 1) 120
200: (+ 1.0 1.0) 136
201: (+ 1.0 1) 152
202: */
203: private static Number coerceNumber(Object a, Class c) {
204: if (a instanceof Number) {
205: if (a.getClass() == c)
206: return (Number) a;
207: else if (c == Integer.class)
208: return U.toNum(((Number) a).intValue());
209: else if (c == Double.class)
210: return U.toNum(((Number) a).doubleValue());
211: // else if (c==Long.class) return U.toNum(((Number)a).longValue());
212: else if (c == Long.class)
213: return new Long(((Number) a).longValue());
214: else if (c == Float.class)
215: return new Float(((Number) a).floatValue());
216: else
217: return ((Number) E.error("Bad coersion " + a + " to "
218: + c));
219: }
220: if (a instanceof Character)
221: return coerceNumber(new Integer((int) ((Character) a)
222: .charValue()), c);
223: else
224: return ((Number) E.error("Bad coersion " + a + " to " + c));
225: }
226:
227: public static Character numberToChar(Number a) {
228: return new Character((char) a.shortValue());
229: }
230:
231: public static Number charToNumber(Character a) {
232: return new Integer((int) a.charValue());
233: }
234:
235: public static Class lubNumericClass(Class a, Class b) {
236: if ((a == Byte.class) || (a == Short.class)
237: || (a == Character.class))
238: a = Integer.class;
239: if ((b == Byte.class) || (b == Short.class)
240: || (b == Character.class))
241: b = Integer.class;
242: if (a == b)
243: return b; // KRA 30DEC03: 7% improvement in (+ 1 1).
244: if (a == Integer.class) {
245: if (b == Integer.class)
246: return Integer.class;
247: else if (b == Long.class)
248: return Long.class;
249: else if (b == Float.class)
250: return Float.class;
251: else
252: return Double.class;
253: } else if (a == Long.class) {
254: if (b == Integer.class)
255: return Long.class;
256: else if (b == Long.class)
257: return Long.class;
258: else if (b == Float.class)
259: return Float.class;
260: else
261: return Double.class;
262: } else if (a == Float.class) {
263: if (b == Integer.class)
264: return Float.class;
265: else if (b == Long.class)
266: return Float.class;
267: else if (b == Float.class)
268: return Float.class;
269: else
270: return Double.class;
271: } else
272: return Double.class;
273: }
274:
275: private static Integer unaryOpInteger(int op, Integer a) {
276: int a1 = a.intValue(), c = 0;
277: switch (op) {
278: case COMPLEMENT:
279: c = ~a1;
280: break;
281: case NEGATE:
282: c = -a1;
283: break;
284: case SGN:
285: if (a1 > 0)
286: c = 1;
287: else
288: c = -1;
289: break;
290: default:
291: unknownOpError("unaryOp", op);
292: break;
293: }
294: return new Integer(c);
295: }
296:
297: private static Long unaryOpLong(int op, Long a) {
298: long a1 = a.longValue(), c = 0;
299: switch (op) {
300: case COMPLEMENT:
301: c = ~a1;
302: break;
303: case NEGATE:
304: c = -a1;
305: break;
306: case SGN:
307: if (a1 > 0)
308: c = 1;
309: else
310: c = -1;
311: break;
312: default:
313: unknownOpError("unaryOp", op);
314: break;
315: }
316: return new Long(c);
317: }
318:
319: private static Float unaryOpFloat(int op, Float a) {
320: float a1 = a.floatValue(), c = 0.0F;
321: switch (op) {
322: case NEGATE:
323: c = -a1;
324: break;
325: case SGN:
326: if (a1 > 0)
327: c = 1;
328: else
329: c = -1;
330: break;
331: default:
332: unknownOpError("unaryOp", op);
333: break;
334: }
335: return new Float(c);
336: }
337:
338: private static Double unaryOpDouble(int op, Double a) {
339: double a1 = a.doubleValue(), c = 0.0;
340: switch (op) {
341: case NEGATE:
342: c = -a1;
343: break;
344: case SGN:
345: if (a1 > 0)
346: c = 1;
347: else
348: c = -1;
349: break;
350: default:
351: unknownOpError("unaryOp", op);
352: break;
353: }
354: return new Double(c);
355: }
356:
357: private static Integer binaryOpInteger(int op, Integer a, Integer b) {
358: int a1 = a.intValue(), b1 = b.intValue(), c = 0;
359: switch (op) {
360: case ADD:
361: c = a1 + b1;
362: break;
363: case SUB:
364: c = a1 - b1;
365: break;
366: case MUL:
367: c = a1 * b1;
368: break;
369: case DIV:
370: c = a1 / b1;
371: break;
372: case MOD:
373: c = a1 % b1;
374: break;
375: case MODULO:
376: c = a1 % b1;
377: c = (((c == 0) || ((c > 0) == (b1 > 0))) ? c : c + b1);
378: break;
379: case AND:
380: c = a1 & b1;
381: break;
382: case XOR:
383: c = a1 ^ b1;
384: break;
385: case OR:
386: c = a1 | b1;
387: break;
388: case IMP:
389: c = (~a1) | b1;
390: break;
391: case LSH:
392: c = (a1 << b1);
393: break;
394: case RSH:
395: c = (a1 >> b1);
396: break;
397: case RSHZ:
398: c = (a1 >>> b1);
399: break;
400: default:
401: unknownOpError("binaryOp", op);
402: break;
403: }
404: return U.toNum(c);
405: }
406:
407: private static Long binaryOpLong(int op, Long a, Long b) {
408: long a1 = a.longValue(), b1 = b.longValue(), c = 0L;
409: switch (op) {
410: case ADD:
411: c = a1 + b1;
412: break;
413: case SUB:
414: c = a1 - b1;
415: break;
416: case MUL:
417: c = a1 * b1;
418: break;
419: case DIV:
420: c = a1 / b1;
421: break;
422: case MOD:
423: c = a1 % b1;
424: break;
425: case MODULO:
426: c = a1 % b1;
427: c = (((c == 0) || ((c > 0) == (b1 > 0))) ? c : (c + b1));
428: break;
429: case AND:
430: c = a1 & b1;
431: break;
432: case XOR:
433: c = a1 ^ b1;
434: break;
435: case OR:
436: c = a1 | b1;
437: break;
438: case IMP:
439: c = (~a1) | b1;
440: break;
441: case LSH:
442: c = (a1 << b1);
443: break;
444: case RSH:
445: c = (a1 >> b1);
446: break;
447: case RSHZ:
448: c = (a1 >>> b1);
449: break;
450: default:
451: unknownOpError("binaryOp", op);
452: break;
453: }
454: return new Long(c);
455: }
456:
457: private static Float binaryOpFloat(int op, Float a, Float b) {
458: float a1 = a.floatValue(), b1 = b.floatValue(), c = 0.0F;
459: switch (op) {
460: case ADD:
461: c = a1 + b1;
462: break;
463: case SUB:
464: c = a1 - b1;
465: break;
466: case MUL:
467: c = a1 * b1;
468: break;
469: case DIV:
470: c = a1 / b1;
471: break;
472: case MOD:
473: c = a1 - b1 * Math.round(a1 / b1);
474: break;
475:
476: default:
477: unknownOpError("binaryOp", op);
478: break;
479: }
480: return new Float(c);
481: }
482:
483: private static Double binaryOpDouble(int op, Double a, Double b) {
484: double a1 = a.doubleValue(), b1 = b.doubleValue(), c = 0.0;
485: switch (op) {
486: case ADD:
487: c = a1 + b1;
488: break;
489: case SUB:
490: c = a1 - b1;
491: break;
492: case MUL:
493: c = a1 * b1;
494: break;
495: case DIV:
496: c = a1 / b1;
497: break;
498: case MOD:
499: c = a1 - b1 * Math.round(a1 / b1);
500: break;
501: default:
502: unknownOpError("binaryOp", op);
503: break;
504: }
505: return new Double(c);
506: }
507:
508: // binary comparisons
509: private static boolean binaryCompInteger(int op, Integer a,
510: Integer b) {
511: int a1 = a.intValue(), b1 = b.intValue();
512: boolean c = false;
513: switch (op) {
514: case EQ:
515: c = (a1 == b1);
516: break;
517: case LT:
518: c = (a1 < b1);
519: break;
520: case GT:
521: c = (a1 > b1);
522: break;
523: case LE:
524: c = (a1 <= b1);
525: break;
526: case GE:
527: c = (a1 >= b1);
528: break;
529: case NE:
530: c = (a1 != b1);
531: break;
532: default:
533: unknownOpError("binaryComp", op);
534: break;
535: }
536: return c;
537: }
538:
539: private static boolean binaryCompLong(int op, Long a, Long b) {
540: long a1 = a.longValue(), b1 = b.longValue();
541: boolean c = false;
542: switch (op) {
543: case EQ:
544: c = (a1 == b1);
545: break;
546: case LT:
547: c = (a1 < b1);
548: break;
549: case GT:
550: c = (a1 > b1);
551: break;
552: case LE:
553: c = (a1 <= b1);
554: break;
555: case GE:
556: c = (a1 >= b1);
557: break;
558: case NE:
559: c = (a1 != b1);
560: break;
561: default:
562: unknownOpError("binaryComp", op);
563: break;
564: }
565: return c;
566: }
567:
568: private static boolean binaryCompFloat(int op, Float a, Float b) {
569: float a1 = a.floatValue(), b1 = b.floatValue();
570: boolean c = false;
571: switch (op) {
572: case EQ:
573: c = (a1 == b1);
574: break;
575: case LT:
576: c = (a1 < b1);
577: break;
578: case GT:
579: c = (a1 > b1);
580: break;
581: case LE:
582: c = (a1 <= b1);
583: break;
584: case GE:
585: c = (a1 >= b1);
586: break;
587: case NE:
588: c = (a1 != b1);
589: break;
590: default:
591: unknownOpError("binaryComp", op);
592: break;
593: }
594: return c;
595: }
596:
597: private static boolean binaryCompDouble(int op, Double a, Double b) {
598: double a1 = a.doubleValue(), b1 = b.doubleValue();
599: boolean c = false;
600: switch (op) {
601: case EQ:
602: c = (a1 == b1);
603: break;
604: case LT:
605: c = (a1 < b1);
606: break;
607: case GT:
608: c = (a1 > b1);
609: break;
610: case LE:
611: c = (a1 <= b1);
612: break;
613: case GE:
614: c = (a1 >= b1);
615: break;
616: case NE:
617: c = (a1 != b1);
618: break;
619: default:
620: unknownOpError("binaryComp", op);
621: break;
622: }
623: return c;
624: }
625:
626: public static boolean eqv(Object a, Object b) {
627: if ((a instanceof Number) && (b instanceof Number))
628: return (eq((Number) a, (Number) b));
629: else if ((a == null) || (b == null))
630: return (a == b);
631: else
632: return (a.equals(b));
633: }
634:
635: public static boolean sameObject(Object a, Object b) {
636: return (a == b);
637: }
638:
639: private static Number wrongTypeError(Object a, Object b) {
640: return ((Number) E.error("binaryOp -- wrong types"
641: + a.getClass() + " " + b.getClass()));
642: }
643:
644: private static Number wrongTypeError(Object a) {
645: return ((Number) E
646: .error("unaryOp -- wrong type" + a.getClass()));
647: }
648:
649: private static Object unknownOpError(String name, int op) {
650: return E.error("Error in " + name
651: + " -- unknown operator number: " + op);
652: }
653:
654: public static Number addMulti(Pair x) {
655: return U.isPair(x) ? genericBinaryMultiOp(Op.ADD,
656: toNumber(x.first), (Pair) x.rest) : U.toNum(0);
657: }
658:
659: public static Number mulMulti(Pair x) {
660: return U.isPair(x) ? genericBinaryMultiOp(Op.MUL,
661: toNumber(x.first), (Pair) x.rest) : U.toNum(1);
662: }
663:
664: public static Number toNumber(Object x) {
665: return x instanceof Number ? (Number) x
666: : x instanceof Character ? new Integer(
667: (int) ((Character) x).charValue())
668: : ((Number) E.error(x
669: + " can't be converted to a Number"));
670: }
671: }
|