KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > kawa > functions > AddOp


1 // Copyright (c) 2000, 2001, 2003, 2005 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.kawa.functions;
5 import gnu.math.*;
6 import java.math.*;
7 import gnu.mapping.*;
8 import gnu.expr.*;
9 import gnu.bytecode.*;
10 import gnu.kawa.lispexpr.LangPrimType;
11
12 /**
13  * Implement the Scheme standard functions "+" and "-".
14  * @author Per Bothner
15  */

16
17 public class AddOp extends ProcedureN implements CanInline, Inlineable
18 {
19   int plusOrMinus = 1;
20
21   public AddOp(String JavaDoc name, int plusOrMinus)
22   {
23     setName(name);
24     this.plusOrMinus = plusOrMinus;
25   }
26
27   public static final AddOp $Pl = new AddOp("+", 1);
28   public static final AddOp $Mn = new AddOp("-", -1);
29
30   public static Object JavaDoc apply2(int plusOrMinus, Object JavaDoc arg1, Object JavaDoc arg2)
31   {
32     int code1 = Arithmetic.classifyValue(arg1);
33     int code2 = Arithmetic.classifyValue(arg2);
34     /*
35     if (code1 < 0 || code2 < 0)
36     throw new ClasscastException(); // FIXME
37     */

38     int code = code1 < code2 ? code2 : code1;
39     switch (code)
40       {
41       case Arithmetic.INT_CODE:
42     int i1 = Arithmetic.asInt(arg1);
43     int i2 = Arithmetic.asInt(arg2);
44     return new Integer JavaDoc(plusOrMinus > 0 ? i1 + i2 : i1 - i2);
45       case Arithmetic.LONG_CODE:
46     long l1 = Arithmetic.asLong(arg1);
47     long l2 = Arithmetic.asLong(arg2);
48     return new Long JavaDoc(plusOrMinus > 0 ? l1 + l2 : l1 - l2);
49       case Arithmetic.BIGINTEGER_CODE:
50     BigInteger bi1 = Arithmetic.asBigInteger(arg1);
51     BigInteger bi2 = Arithmetic.asBigInteger(arg2);
52     return plusOrMinus > 0 ? bi1.add(bi2) : bi1.subtract(bi2);
53       case Arithmetic.INTNUM_CODE:
54     return IntNum.add(Arithmetic.asIntNum(arg1), Arithmetic.asIntNum(arg2),
55               plusOrMinus);
56       case Arithmetic.BIGDECIMAL_CODE:
57     BigDecimal bd1 = Arithmetic.asBigDecimal(arg1);
58     BigDecimal bd2 = Arithmetic.asBigDecimal(arg2);
59     return plusOrMinus > 0 ? bd1.add(bd2) : bd1.subtract(bd2);
60       case Arithmetic.RATNUM_CODE:
61     return RatNum.add(Arithmetic.asRatNum(arg1), Arithmetic.asRatNum(arg2),
62               plusOrMinus);
63       case Arithmetic.FLOAT_CODE:
64     float f1 = Arithmetic.asFloat(arg1);
65     float f2 = Arithmetic.asFloat(arg2);
66     return new Float JavaDoc(plusOrMinus > 0 ? f1 + f2 : f1 - f2);
67       case Arithmetic.DOUBLE_CODE:
68     double d1 = Arithmetic.asDouble(arg1);
69     double d2 = Arithmetic.asDouble(arg2);
70     return new Double JavaDoc(plusOrMinus > 0 ? d1 + d2 : d1 - d2);
71       case Arithmetic.FLONUM_CODE:
72     d1 = Arithmetic.asDouble(arg1);
73     d2 = Arithmetic.asDouble(arg2);
74     return new DFloNum(plusOrMinus > 0 ? d1 + d2 : d1 - d2);
75       default:
76     Numeric num1 = Arithmetic.asNumeric(arg1);
77     Numeric num2 = Arithmetic.asNumeric(arg2);
78     return num1.add(num2, plusOrMinus);
79       }
80   }
81
82   public static Object JavaDoc $Pl(Object JavaDoc arg1, Object JavaDoc arg2)
83   {
84     return apply2(1, arg1, arg2);
85   }
86
87   public static Object JavaDoc $Mn(Object JavaDoc arg1, Object JavaDoc arg2)
88   {
89     return apply2(-1, arg1, arg2);
90   }
91
92   public static Object JavaDoc $Mn(Object JavaDoc arg1)
93   {
94     return ((Numeric) arg1).neg();
95   }
96
97   public static Object JavaDoc $Pl$V (Object JavaDoc arg1, Object JavaDoc arg2,
98                    Object JavaDoc arg3, Object JavaDoc[] rest)
99   {
100     return applyN(1, apply2(1,apply2(1, arg1, arg2), arg3), rest);
101   }
102
103   public static Object JavaDoc $Mn$V (Object JavaDoc arg1, Object JavaDoc arg2,
104                    Object JavaDoc arg3, Object JavaDoc[] rest)
105   {
106     return applyN(-1, apply2(-1,apply2(-1, arg1, arg2), arg3), rest);
107   }
108
109   public static Object JavaDoc applyN(int plusOrMinus, Object JavaDoc[] args)
110   {
111     int len = args.length;
112     if (len == 0)
113       return IntNum.zero ();
114     Object JavaDoc result = args[0];
115     if (len == 1 && plusOrMinus < 0)
116       return $Mn(result);
117     for (int i = 1; i < len; i++)
118       result = apply2(plusOrMinus, result, args[i]);
119     return result;
120   }
121
122   public static Object JavaDoc applyN(int plusOrMinus, Object JavaDoc init, Object JavaDoc[] args)
123   {
124     int len = args.length;
125     Object JavaDoc result = init;
126     for (int i = 0; i < len; i++)
127       result = apply2(plusOrMinus, result, args[i]);
128     return result;
129   }
130
131   public Object JavaDoc applyN (Object JavaDoc[] args)
132   {
133     return applyN(plusOrMinus, args);
134   }
135
136   /** Convert (PROC A B C) to (PROC (PROC A B) C) etc. */
137
138   public static Expression pairwise(Procedure proc,
139                                     Expression rproc, Expression[] args,
140                     ExpWalker walker)
141   {
142     int len = args.length;
143     Expression prev = args[0];
144     for (int i = 1; i < len; i++)
145       {
146         Expression[] args2 = new Expression[2];
147         args2[0] = prev;
148         args2[1] = args[i];
149         ApplyExp next = new ApplyExp(rproc, args2);
150         if (proc instanceof CanInline)
151           prev = ((CanInline) proc).inline(next, walker);
152         else
153           prev = next;
154       }
155     return prev;
156   }
157
158   public Expression inline (ApplyExp exp, ExpWalker walker)
159   {
160     // Inlining may yield PrimProcedure instructions of bytecode instructions
161
// which we don't know how to interpret (yet).
162
if (! walker.getCompilation().mustCompile)
163       return exp;
164     Expression folded = exp.inlineIfConstant(this, walker);
165     if (folded != exp)
166       return folded;
167     Expression[] args = exp.getArgs();
168     if (args.length > 2)
169       return pairwise(this, exp.getFunction(), args, walker);
170     if (args.length == 1 && plusOrMinus < 0)
171       {
172         Type type0 = args[0].getType();
173         if (type0 instanceof PrimType)
174           {
175             char sig0 = type0.getSignature().charAt(0);
176             Type type = null;
177             int opcode = 0;
178             if (sig0 == 'V' || sig0 == 'Z' || sig0 == 'C')
179               {
180                 // error
181
}
182             else if (sig0 == 'D')
183               {
184                 opcode = 119 /* dneg */;
185                 type = LangPrimType.doubleType;
186               }
187             else if (sig0 == 'F')
188               {
189                 opcode = 118 /* fneg */;
190                 type = LangPrimType.floatType;
191               }
192             else if (sig0 == 'J')
193               {
194                 opcode = 117 /* lneg */;
195                 type = LangPrimType.longType;
196               }
197             else
198               {
199                 opcode = 116 /* ineg */;
200                 type = LangPrimType.intType;
201               }
202             if (type != null)
203               {
204                 PrimProcedure prim
205                   = PrimProcedure.makeBuiltinUnary(opcode, type);
206                 return new ApplyExp(prim, args);
207               }
208           }
209       }
210     if (args.length == 2)
211       {
212     return primInline(plusOrMinus > 0 ? 96 /* iadd */ : 100 /* isub */,
213               exp);
214       }
215     return exp;
216   }
217
218   public static Expression primInline (int opcode, ApplyExp exp)
219   {
220     Expression[] args = exp.getArgs();
221     if (args.length == 2)
222       {
223         Type type0 = args[0].getType();
224         Type type1 = args[1].getType();
225         if (type0 instanceof PrimType && type1 instanceof PrimType)
226           {
227             char sig0 = type0.getSignature().charAt(0);
228             char sig1 = type1.getSignature().charAt(0);
229             Type type = null;
230             if (sig0 == 'V' || sig0 == 'Z' || sig0 == 'C'
231                 || sig1 == 'V' || sig1 == 'Z' || sig1 == 'C')
232               {
233                 // error
234
}
235             else if (sig0 == 'D' || sig1 == 'D')
236               {
237                 opcode += 3;
238                 type = LangPrimType.doubleType;
239               }
240             else if (sig0 == 'F' || sig1 == 'F')
241               {
242                 opcode += 2;
243                 type = LangPrimType.floatType;
244               }
245             else if (sig0 == 'J' || sig1 == 'J')
246               {
247                 opcode += 1;
248                 type = LangPrimType.longType;
249               }
250             else
251               {
252                 type = LangPrimType.intType;
253               }
254             if (type != null)
255               {
256                 PrimProcedure prim
257                   = PrimProcedure.makeBuiltinBinary(opcode, type);
258                 return new ApplyExp(prim, args);
259               }
260           }
261       }
262     return exp;
263   }
264
265   /*
266   static ClassType typeInteger = ClassType.make("java.lang.Integer");
267   static ClassType typeLong = ClassType.make("java.lang.Long");
268   */

269   static ClassType typeIntNum = ClassType.make("gnu.math.IntNum");
270   static ClassType typeDFloNum = ClassType.make("gnu.math.DFloNum");
271   static ClassType typeRealNum = ClassType.make("gnu.math.RealNum");
272   static ClassType typeNumeric = ClassType.make("gnu.math.Numeric");
273
274   public void compile (ApplyExp exp, Compilation comp, Target target)
275   {
276     Expression[] args = exp.getArgs();
277     int len = args.length;
278     if (len == 0)
279       {
280     comp.compileConstant(IntNum.zero(), target);
281     return;
282       }
283     Type type = getReturnType(args);
284     Type ttype = target.getType();
285     if (len == 1 || target instanceof IgnoreTarget)
286       {
287     // FIXME implement optimization for unary
288
ApplyExp.compile(exp, comp, target);
289     return;
290       }
291     PrimType ptype = null;
292     if (ttype instanceof PrimType)
293       {
294     char sig = type.getSignature().charAt(0);
295     if (sig == 'V' || sig == 'Z' || sig == 'C')
296      ptype = null; // error
297
else if (sig == 'D' || sig == 'F')
298       {
299         if (type.isSubtype(typeRealNum))
300           ptype = LangPrimType.doubleType;
301       }
302     else
303       {
304         if (type.isSubtype(typeIntNum))
305           ptype = sig == 'J' ? LangPrimType.longType : LangPrimType.intType;
306       }
307       }
308     if (ptype != null)
309       {
310     CodeAttr code = comp.getCode();
311     // FIXME would be nice to use iinc when appropriate!
312
// We would need to use a special LocalVariableTarget,
313
// created by SetExp when dest is a local variable.
314
// Then if len==2 && ptype==LangPrimType.intType
315
// && target instanceof LocalVariableTarget
316
// && one arg is QuoteExp && other arg is same local as target
317
// => then emit iinc.
318
args[0].compile(comp, ttype);
319     for (int i = 1; i < len; i++)
320       {
321         args[i].compile(comp, ptype);
322         if (plusOrMinus > 0)
323           code.emitAdd(ptype);
324         else
325           code.emitSub(ptype);
326       }
327     target.compileFromStack(comp, ttype);
328       }
329     else if (type.isSubtype(typeDFloNum))
330       {
331     PrimType dtype = LangPrimType.doubleType;
332     Target dtarget = new StackTarget(dtype);
333     CodeAttr code = comp.getCode();
334     args[0].compile(comp, dtarget);
335     for (int i = 1; i < len; i++)
336       {
337         args[i].compile(comp, dtarget);
338         if (plusOrMinus > 0)
339           code.emitAdd(dtype);
340         else
341           code.emitSub(dtype);
342       }
343     target.compileFromStack(comp, dtype);
344       }
345     else
346       ApplyExp.compile(exp, comp, target);
347   }
348
349   /** Classify an expression according to its numeric type.
350    * kind==0: not a number.
351    * kind==1: a non-real number
352    * kind==2: real number
353    * kind==3: floating-point
354    * kind==4: exact integer
355    */

356   public static int classify (Type type)
357   {
358     int kind = 0;
359     if (type instanceof PrimType)
360       {
361     char sig = type.getSignature().charAt(0);
362     if (sig == 'V' || sig == 'Z' || sig == 'C')
363       return 0;
364     else if (sig == 'D' || sig == 'F')
365       return 3;
366     else
367       return 4;
368       }
369     else if (type.isSubtype(typeIntNum))
370       return 4;
371     else if (type.isSubtype(typeDFloNum))
372       return 3;
373     else if (type.isSubtype(typeRealNum))
374       return 2;
375     else if (type.isSubtype(typeNumeric))
376       return 1;
377     else
378       return 0;
379   }
380
381   public Type getReturnType (Expression[] args)
382   {
383     int len = args.length;
384     if (len == 0)
385       return typeIntNum;
386     Type type = Type.pointer_type;
387     int kind0 = 0;
388     for (int i = 0; i < len; i++)
389       {
390     Expression arg = args[i];
391     int kind = classify(arg.getType());
392
393     if (kind == 0)
394       return Type.pointer_type;
395
396     if (i == 0)
397       kind0 = kind;
398
399     if (kind0 == 4 && kind == 4)
400       type = typeIntNum;
401     else if (kind0 >= 2 && kind >= 2)
402       {
403         if (kind0 == 3 || kind == 3)
404           {
405         type = typeDFloNum;
406         kind0 = 3;
407           }
408         else
409           {
410         type = typeRealNum;
411         kind0 = 2;
412           }
413       }
414     else if (kind0 >= 1 && kind >= 1)
415       {
416         type = typeNumeric;
417         kind0 = 1;
418       }
419     else
420       return Type.pointer_type;
421       }
422     return type;
423   }
424 }
425
Popular Tags