KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > mapping > Procedure


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

4 package gnu.mapping;
5
6 /**
7  * The abstract parent for all Scheme functions.
8  * @author Per Bothner
9  */

10
11 public abstract class Procedure extends PropertySet
12 {
13   private static final String JavaDoc sourceLocationKey = "source-location";
14   private static final String JavaDoc setterKey = "setter";
15
16   public void setSourceLocation (String JavaDoc file, int line)
17   {
18     setProperty(sourceLocationKey, file + ":" + line);
19   }
20
21   public String JavaDoc getSourceLocation ()
22   {
23     Object JavaDoc value = getProperty(sourceLocationKey, null);
24     return value == null ? null : value.toString();
25   }
26
27   public Procedure()
28   {
29   }
30
31   public Procedure(String JavaDoc n)
32   {
33     setName(n);
34   }
35
36   public abstract Object JavaDoc applyN (Object JavaDoc[] args) throws Throwable JavaDoc;
37
38   public abstract Object JavaDoc apply0 () throws Throwable JavaDoc;
39
40   public abstract Object JavaDoc apply1 (Object JavaDoc arg1) throws Throwable JavaDoc;
41
42   public abstract Object JavaDoc apply2 (Object JavaDoc arg1,Object JavaDoc arg2) throws Throwable JavaDoc;
43
44   public abstract Object JavaDoc apply3 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3) throws Throwable JavaDoc;
45
46   public abstract Object JavaDoc apply4(Object JavaDoc arg1,Object JavaDoc arg2,
47                 Object JavaDoc arg3,Object JavaDoc arg4) throws Throwable JavaDoc;
48
49   /** Minimum number of arguments required. */
50   public final int minArgs() { return numArgs() & 0xFFF; }
51
52   /** Maximum number of arguments allowed, or -1 for unlimited.
53    * (May also return -1 if there are keyword arguments, for implementation
54    * reasons.) */

55   public final int maxArgs() { return numArgs() >> 12; }
56
57   /** Check that the number of arguments in a call is valid.
58     * @param proc the Procedure being called
59     * @param argCount the number of arguments in the call
60     * @exception WrongArguments there are too many or too
61     * few actual arguments
62     */

63   public static void checkArgCount(Procedure proc, int argCount)
64   {
65     int num = proc.numArgs();
66     if (argCount < (num & 0xFFF)
67     || (num >= 0 && argCount > (num >> 12)))
68       throw new WrongArguments(proc, argCount);
69   }
70
71   /** Return minArgs()|(maxArgs<<12). */
72
73   /* We use a single virtual function to reduce the number of methods
74    * in the system, as well as the number of virtual method table entries.
75    * We shift by 12 so the number can normally be represented using a
76    * sipush instruction, without requiring a constant pool entry.
77    */

78   public int numArgs() { return 0xfffff000; }
79
80   /* CPS: ??
81   public void apply1(Object arg, CallContext stack, CallFrame rlink, int rpc)
82   {
83     context.value = apply1(arg);
84     context.frame = rlink;
85     context.pc = rpc;
86   }
87   */

88
89   /** Call this Procedure using the explicit-CallContext-convention.
90    * The input arguments are (by default) in stack.args;
91    * the result is written to ctx.consumer. */

92
93   public void apply (CallContext ctx) throws Throwable JavaDoc
94   {
95     apply(this, ctx);
96   }
97
98   public static void apply (Procedure proc, CallContext ctx) throws Throwable JavaDoc
99   {
100     Object JavaDoc result;
101     int count = ctx.count;
102     if (ctx.where == 0 && count != 0)
103       result = proc.applyN(ctx.values);
104     else
105       {
106     switch (count)
107       {
108       case 0:
109         result = proc.apply0();
110         break;
111       case 1:
112         result = proc.apply1(ctx.getNextArg());
113         break;
114       case 2:
115         result = proc.apply2(ctx.getNextArg(), ctx.getNextArg());
116         break;
117       case 3:
118         result = proc.apply3(ctx.getNextArg(), ctx.getNextArg(),
119                  ctx.getNextArg());
120         break;
121       case 4:
122         result = proc.apply4(ctx.getNextArg(), ctx.getNextArg(),
123                  ctx.getNextArg(), ctx.getNextArg());
124         break;
125       default:
126         result = proc.applyN(ctx.getArgs());
127         break;
128       }
129       }
130     ctx.writeValue(result);
131   }
132
133   /** Pass zero arguments.
134    * @return non-negative if the match succeeded, else negative.
135    */

136   public int match0 (CallContext ctx)
137   {
138     int num = numArgs();
139     int min = num & 0xFFF;
140     if (min > 0)
141       return MethodProc.NO_MATCH_TOO_FEW_ARGS|min;
142     if (num < 0)
143       return matchN(ProcedureN.noArgs, ctx);
144     ctx.count = 0;
145     ctx.where = 0;
146     ctx.next = 0;
147     ctx.proc = this;
148     return 0;
149   }
150
151   /** Pass one argument.
152    * @return non-negative if the match succeeded, else negative.
153    */

154   public int match1 (Object JavaDoc arg1, CallContext ctx)
155   {
156     int num = numArgs();
157     int min = num & 0xFFF;
158     if (min > 1)
159       return MethodProc.NO_MATCH_TOO_FEW_ARGS|min;
160     if (num >= 0)
161       {
162         int max = num >> 12;
163     if (max < 1)
164           return MethodProc.NO_MATCH_TOO_MANY_ARGS|max;
165     ctx.value1 = arg1;
166     ctx.count = 1;
167     ctx.where = CallContext.ARG_IN_VALUE1;
168     ctx.next = 0;
169     ctx.proc = this;
170     return 0;
171       }
172     Object JavaDoc[] args = { arg1 };
173     return matchN(args, ctx);
174   }
175
176   /** Pass two arguments.
177    * @return non-negative if the match succeeded, else negative.
178    */

179   public int match2 (Object JavaDoc arg1, Object JavaDoc arg2, CallContext ctx)
180   {
181     int num = numArgs();
182     int min = num & 0xFFF;
183     if (min > 2)
184       return MethodProc.NO_MATCH_TOO_FEW_ARGS|min;
185     if (num >= 0)
186       {
187         int max = num >> 12;
188     if (max < 2)
189           return MethodProc.NO_MATCH_TOO_MANY_ARGS|max;
190     ctx.value1 = arg1;
191     ctx.value2 = arg2;
192     ctx.count = 2;
193     ctx.where = CallContext.ARG_IN_VALUE1
194       |(CallContext.ARG_IN_VALUE2<<4);
195     ctx.next = 0;
196     ctx.proc = this;
197     return 0;
198       }
199     Object JavaDoc[] args = { arg1, arg2 };
200     return matchN(args, ctx);
201   }
202
203   /** Pass three arguments.
204    * @return non-negative if the match succeeded, else negative.
205    */

206   public int match3 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3, CallContext ctx)
207   {
208     int num = numArgs();
209     int min = num & 0xFFF;
210     if (min > 3)
211       return MethodProc.NO_MATCH_TOO_FEW_ARGS|min;
212     if (num >= 0)
213       {
214         int max = num >> 12;
215     if (max < 3)
216           return MethodProc.NO_MATCH_TOO_MANY_ARGS|max;
217     ctx.value1 = arg1;
218     ctx.value2 = arg2;
219     ctx.value3 = arg3;
220     ctx.count = 3;
221     ctx.where = CallContext.ARG_IN_VALUE1
222       |(CallContext.ARG_IN_VALUE2<<4)
223       |(CallContext.ARG_IN_VALUE3<<8);
224     ctx.next = 0;
225     ctx.proc = this;
226     return 0;
227       }
228     Object JavaDoc[] args = { arg1, arg2, arg3 };
229     return matchN(args, ctx);
230   }
231
232   /** Pass four arguments.
233    * @return non-negative if the match succeeded, else negative.
234    */

235   public int match4 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3, Object JavaDoc arg4,
236              CallContext ctx)
237   {
238     int num = numArgs();
239     int min = num & 0xFFF;
240     if (min > 4)
241       return MethodProc.NO_MATCH_TOO_FEW_ARGS|min;
242     if (num >= 0)
243       {
244         int max = num >> 12;
245     if (max < 4)
246           return MethodProc.NO_MATCH_TOO_MANY_ARGS|max;
247     ctx.value1 = arg1;
248     ctx.value2 = arg2;
249     ctx.value3 = arg3;
250     ctx.value4 = arg4;
251     ctx.count = 4;
252     ctx.where = (CallContext.ARG_IN_VALUE1
253              |(CallContext.ARG_IN_VALUE2<<4)
254              |(CallContext.ARG_IN_VALUE3<<8)
255              |(CallContext.ARG_IN_VALUE4<<12));
256     ctx.next = 0;
257     ctx.proc = this;
258     return 0;
259       }
260     Object JavaDoc[] args = { arg1, arg2, arg3, arg4 };
261     return matchN(args, ctx);
262   }
263
264   public int matchN (Object JavaDoc[] args, CallContext ctx)
265   {
266     int num = numArgs();
267     int min = num & 0xFFF;
268     if (args.length < min)
269       return MethodProc.NO_MATCH_TOO_FEW_ARGS|min;
270     if (num >= 0)
271       {
272     switch (args.length)
273       {
274       case 0:
275         return match0(ctx);
276       case 1:
277         return match1(args[0], ctx);
278       case 2:
279         return match2(args[0], args[1], ctx);
280       case 3:
281         return match3(args[0], args[1], args[2], ctx);
282       case 4:
283         return match4(args[0], args[1], args[2], args[3], ctx);
284       default:
285         int max = num >> 12;
286         if (args.length > max)
287           return MethodProc.NO_MATCH_TOO_MANY_ARGS|max;
288       }
289       }
290     ctx.values = args;
291     ctx.count = args.length;
292     ctx.where = 0;
293     ctx.next = 0;
294     ctx.proc = this;
295     return 0;
296   }
297
298   /** Does match0, plus throws exception on argument mismatch. */
299   public void check0 (CallContext ctx)
300   {
301     int code = match0(ctx);
302     if (code != 0)
303       {
304     throw MethodProc.matchFailAsException(code, this, ProcedureN.noArgs);
305       }
306   }
307
308   /** Does match1, plus throws exception on argument mismatch. */
309   public void check1 (Object JavaDoc arg1, CallContext ctx)
310   {
311     int code = match1(arg1, ctx);
312     if (code != 0)
313       {
314     Object JavaDoc[] args = { arg1 };
315     throw MethodProc.matchFailAsException(code, this, args);
316       }
317   }
318
319   /** Does match, plus throws exception on argument mismatch. */
320   public void check2 (Object JavaDoc arg1, Object JavaDoc arg2, CallContext ctx)
321   {
322     int code = match2(arg1, arg2, ctx);
323     if (code != 0)
324       {
325     Object JavaDoc[] args = { arg1, arg2 };
326     throw MethodProc.matchFailAsException(code, this, args);
327       }
328   }
329  
330   /** Does match3, plus throws exception on argument mismatch. */
331   public void check3 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3, CallContext ctx)
332   {
333     int code = match3(arg1, arg2, arg3, ctx);
334     if (code != 0)
335       {
336     Object JavaDoc[] args = { arg1, arg2, arg3 };
337     throw MethodProc.matchFailAsException(code, this, args);
338       }
339   }
340
341   /** Does match4, plus throws exception on argument mismatch. */
342   public void check4 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3, Object JavaDoc arg4,
343               CallContext ctx)
344   {
345     int code = match4(arg1, arg2, arg3, arg4, ctx);
346     if (code != 0)
347       {
348     Object JavaDoc[] args = { arg1, arg2, arg3, arg4 };
349     throw MethodProc.matchFailAsException(code, this, args);
350       }
351   }
352
353   /** Does matchN, plus throws exception on argument mismatch. */
354   public void checkN (Object JavaDoc[] args, CallContext ctx)
355   {
356     int code = matchN(args, ctx);
357     if (code != 0)
358       {
359     throw MethodProc.matchFailAsException(code, this, args);
360       }
361   }
362
363   public Procedure getSetter()
364   {
365     if (! (this instanceof HasSetter))
366       {
367     Object JavaDoc setter = getProperty(setterKey, null);
368     if (setter instanceof Procedure)
369       return (Procedure) setter;
370     throw new RuntimeException JavaDoc("procedure '"+getName()+ "' has no setter");
371       }
372     int num_args = numArgs();
373     if (num_args == 0x0000)
374       return new Setter0(this);
375     if (num_args == 0x1001)
376       return new Setter1(this);
377     return new Setter(this);
378   }
379
380   public void setSetter (Procedure setter)
381   {
382     if (this instanceof HasSetter)
383       throw new RuntimeException JavaDoc("procedure '"+getName()+
384                  "' has builtin setter - cannot be modified");
385     setProperty(Procedure.setterKey, setter);
386   }
387
388   /** If HasSetter, the Procedure is called in the LHS of an assignment. */
389   public void set0(Object JavaDoc result) throws Throwable JavaDoc
390   {
391     getSetter().apply1(result);
392   }
393
394   public void set1(Object JavaDoc arg1, Object JavaDoc value) throws Throwable JavaDoc
395   {
396     getSetter().apply2(arg1, value);
397   }
398
399   public void setN (Object JavaDoc[] args) throws Throwable JavaDoc
400   {
401     getSetter().applyN(args);
402   }
403
404   public String JavaDoc toString ()
405   {
406     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
407     sbuf.append ("#<procedure ");
408     String JavaDoc n = getName();
409     if (n == null)
410       n = getSourceLocation();
411     if (n == null)
412       n = getClass().getName();
413     sbuf.append(n);
414     sbuf.append('>');
415     return sbuf.toString();
416   }
417 }
418
Popular Tags