KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > kawa > lang > Lambda


1 package kawa.lang;
2 import gnu.mapping.*;
3 import gnu.expr.*;
4 import gnu.lists.*;
5 import gnu.bytecode.Type;
6 import gnu.kawa.functions.Convert;
7
8 /**
9  * The Syntax transformer that re-writes the lambda builtin.
10  * @author Per Bothner
11  */

12
13 public class Lambda extends Syntax
14 {
15   public Object JavaDoc optionalKeyword;
16   public Object JavaDoc restKeyword;
17   public Object JavaDoc keyKeyword;
18
19   public static final Keyword nameKeyword = Keyword.make("name");
20
21   public Expression defaultDefault = QuoteExp.falseExp;
22
23   public void setKeywords(Object JavaDoc optional, Object JavaDoc rest, Object JavaDoc key)
24   {
25     optionalKeyword = optional;
26     restKeyword = rest;
27     keyKeyword = key;
28   }
29
30   public Expression rewriteForm (Pair form, Translator tr)
31   {
32     Expression exp = rewrite(form.cdr, tr);
33     Translator.setLine(exp, form);
34     return exp;
35   }
36
37   public Expression rewrite (Object JavaDoc obj, Translator tr)
38   {
39     if (! (obj instanceof Pair))
40       return tr.syntaxError ("missing formals in lambda");
41     int old_errors = tr.getMessages().getErrorCount();
42     LambdaExp lexp = new LambdaExp();
43     Pair pair = (Pair) obj;
44     Translator.setLine(lexp, pair);
45     rewrite(lexp, pair.car, pair.cdr, tr, null);
46     if (tr.getMessages().getErrorCount() > old_errors)
47       return new ErrorExp("bad lambda expression");
48     return lexp;
49   }
50
51   /**
52    * Higher-level constructor, that does the re-writing.
53    * @param formals the formal parameter list (or symbol)
54    * @param body the body of the procedure
55    * @param tr the (Scheme) Translator
56    */

57   public void rewrite(LambdaExp lexp, Object JavaDoc formals, Object JavaDoc body,
58               Translator tr, TemplateScope templateScopeRest)
59   {
60     rewriteFormals(lexp, formals, tr, templateScopeRest);
61     if (body instanceof PairWithPosition)
62       lexp.setFile(((PairWithPosition) body).getFileName());
63     body = rewriteAttrs(lexp, body, tr);
64     rewriteBody(lexp, body, tr);
65   }
66
67   public void rewriteFormals(LambdaExp lexp, Object JavaDoc formals,
68               Translator tr, TemplateScope templateScopeRest)
69   {
70     if (lexp.getSymbol() == null)
71       {
72         String JavaDoc filename = lexp.getFileName();
73         int line = lexp.getLineNumber();
74         if (filename != null && line > 0)
75           lexp.setSourceLocation(filename, line);
76       }
77     /* Count formals, while checking that the syntax is OK. */
78     Object JavaDoc bindings = formals;
79     int opt_args = -1;
80     int rest_args = -1;
81     int key_args = -1;
82     Pair pair;
83     for (; ; bindings = pair.cdr)
84       {
85     if (bindings instanceof SyntaxForm)
86       {
87         SyntaxForm sf = (SyntaxForm) bindings;
88         // FIXME
89
bindings = sf.form;
90       }
91     if (! (bindings instanceof Pair))
92       break;
93     pair = (Pair) bindings;
94         // An initial pass to count the parameters.
95
Object JavaDoc pair_car = pair.car;
96     if (pair_car instanceof SyntaxForm)
97       pair_car = ((SyntaxForm) pair_car).form;
98     if (pair_car == optionalKeyword)
99       {
100         if (opt_args >= 0)
101           {
102         tr.syntaxError ("multiple "+optionalKeyword+" in parameter list");
103         return;
104           }
105         else if (rest_args >= 0 || key_args >= 0)
106           {
107         tr.syntaxError (optionalKeyword.toString()+" after " + restKeyword + " or " + keyKeyword);
108         return;
109           }
110         opt_args = 0;
111       }
112     else if (pair_car == restKeyword)
113       {
114         if (rest_args >= 0)
115           {
116         tr.syntaxError ("multiple " + restKeyword
117                                 + " in parameter list");
118         return;
119           }
120         else if (key_args >= 0)
121           {
122         tr.syntaxError (restKeyword.toString()
123                                 + " after " + keyKeyword);
124         return;
125           }
126         rest_args = 0;
127       }
128     else if (pair_car == keyKeyword)
129       {
130         if (key_args >= 0)
131           {
132         tr.syntaxError ("multiple " + keyKeyword
133                                 + " in parameter list");
134         return;
135           }
136         key_args = 0;
137       }
138         else if (tr.matches(pair.car, "::") && pair.cdr instanceof Pair)
139           pair = (Pair) pair.cdr;
140     else if (key_args >= 0)
141       key_args++;
142     else if (rest_args >= 0)
143       rest_args++;
144     else if (opt_args >= 0)
145       opt_args++;
146     else
147       lexp.min_args++;
148     bindings = pair.cdr;
149       }
150     if (bindings instanceof String JavaDoc || bindings instanceof Symbol)
151       {
152     if (opt_args >= 0 || key_args >= 0 || rest_args >= 0)
153       {
154         tr.syntaxError ("dotted rest-arg after " + optionalKeyword
155                             +", " + restKeyword + ", or " + keyKeyword);
156         return;
157       }
158     rest_args = 1;
159       }
160     else if (bindings != LList.Empty)
161       {
162     tr.syntaxError ("misformed formals in lambda");
163     return;
164       }
165     if (rest_args > 1)
166       {
167     tr.syntaxError ("multiple " + restKeyword + " parameters");
168         return;
169       }
170     if (opt_args < 0)
171       opt_args = 0;
172     if (rest_args < 0)
173       rest_args = 0;
174     if (key_args < 0)
175       key_args = 0;
176     if (rest_args > 0)
177       lexp.max_args = -1;
178     else // Is this useful?
179
lexp.max_args = lexp.min_args + opt_args + 2 * key_args;
180     if (opt_args + key_args > 0)
181       lexp.defaultArgs = new Expression[opt_args + key_args];
182     if (key_args > 0)
183       lexp.keywords = new Keyword[key_args];
184
185     bindings = formals;
186     opt_args = 0;
187     key_args = 0;
188     Object JavaDoc mode = null;
189     for (; ; bindings = pair.cdr)
190       {
191     if (bindings instanceof SyntaxForm)
192       {
193         SyntaxForm sf = (SyntaxForm) bindings;
194         bindings = sf.form;
195         // The SyntaxForm "surrounds" both the current binding (the car),
196
// as well as the cdr - i.e. the remaining bindings.
197
templateScopeRest = sf.scope;
198       }
199     TemplateScope templateScope = templateScopeRest;
200     if (! (bindings instanceof Pair))
201       break;
202     pair = (Pair) bindings;
203     Object JavaDoc pair_car = pair.car;
204     if (pair_car instanceof SyntaxForm)
205       {
206         SyntaxForm sf = (SyntaxForm) pair_car;
207         pair_car = sf.form;
208         templateScope = sf.scope;
209       }
210     if (pair_car == optionalKeyword
211         || pair_car == restKeyword || pair_car == keyKeyword)
212       {
213         mode = pair_car;
214         continue;
215       }
216     Object JavaDoc savePos = tr.pushPositionOf(pair);
217     Object JavaDoc name = null;
218     Object JavaDoc defaultValue = defaultDefault;
219     Pair typeSpecPair = null;
220         Pair p;
221     if (tr.matches(pair_car, "::"))
222       {
223         tr.syntaxError("'::' must follow parameter name");
224         return;
225       }
226     if (pair_car instanceof String JavaDoc || pair_car instanceof Symbol)
227           {
228             name = pair_car;
229             if (pair.cdr instanceof Pair
230                 && tr.matches((p = (Pair) pair.cdr).car, "::"))
231               {
232                 if (! (pair.cdr instanceof Pair))
233                   {
234                     tr.syntaxError("'::' not followed by a type specifier"
235                                    + " (for parameter '" + name + "')");
236                     return;
237                   }
238                 p = (Pair) p.cdr;
239                 typeSpecPair = p;
240                 pair = p;
241               }
242           }
243     else if (pair_car instanceof Pair)
244       {
245         p = (Pair) pair_car;
246         pair_car = p.car;
247         if (pair_car instanceof SyntaxForm)
248           {
249         SyntaxForm sf = (SyntaxForm) pair_car;
250         pair_car = sf.form;
251         templateScope = sf.scope;
252           }
253         if ((pair_car instanceof String JavaDoc
254          || pair_car instanceof Symbol)
255         && p.cdr instanceof Pair)
256           {
257         name = pair_car;
258         p = (Pair) p.cdr;
259         if (tr.matches(p.car, "::"))
260           {
261             if (! (p.cdr instanceof Pair))
262               {
263             tr.syntaxError("'::' not followed by a type specifier"
264                        + " (for parameter '" + name + "')");
265             return;
266               }
267             p = (Pair) p.cdr;
268             typeSpecPair = p;
269             if (p.cdr instanceof Pair)
270               p = (Pair) p.cdr;
271             else if (p.cdr == LList.Empty)
272               p = null;
273             else
274               {
275             tr.syntaxError("improper list in specifier for parameter '"
276                        + name + "')");
277             return;
278               }
279           }
280         if (p != null && mode != null)
281           {
282             defaultValue = p.car;
283             if (p.cdr instanceof Pair)
284               p = (Pair) p.cdr;
285             else if (p.cdr == LList.Empty)
286               p = null;
287             else
288               {
289             tr.syntaxError("improper list in specifier for parameter '"
290                        + name + "')");
291             return;
292               }
293           }
294         if (p != null)
295           {
296             if (typeSpecPair != null)
297               {
298             tr.syntaxError("duplicate type specifier for parameter '"
299                        + name + '\'');
300             return;
301               }
302             typeSpecPair = p;
303             if (p.cdr != LList.Empty)
304               {
305             tr.syntaxError("junk at end of specifier for parameter '"
306                        + name + '\''+" after type "+p.car);
307             return;
308               }
309           }
310           }
311       }
312     if (name == null)
313       {
314         tr.syntaxError ("parameter is neither name nor (name :: type) nor (name default)"+": "+pair);
315         return;
316       }
317     if (mode == optionalKeyword || mode == keyKeyword)
318       lexp.defaultArgs[opt_args++] = new LangExp(defaultValue);
319     if (mode == keyKeyword)
320       lexp.keywords[key_args++]
321         = Keyword.make(name instanceof Symbol ? ((Symbol) name).getName()
322                : name.toString());
323     Declaration decl = new Declaration(name);
324     Translator.setLine(decl, bindings);
325     if (typeSpecPair != null)
326       {
327         decl.setType(tr.exp2Type(typeSpecPair));
328         decl.setFlag(Declaration.TYPE_SPECIFIED);
329       }
330     else if (mode == restKeyword)
331       decl.setType(Compilation.scmListType);
332     decl.noteValue(null); // Does not have a known value.
333
addParam(decl, templateScope, lexp, tr);
334     tr.popPositionOf(savePos);
335       }
336     if (bindings instanceof SyntaxForm)
337       {
338     SyntaxForm sf = (SyntaxForm) bindings;
339     bindings = sf.form;
340     templateScopeRest = sf.scope;
341       }
342     if (bindings instanceof String JavaDoc || bindings instanceof Symbol)
343       {
344     Declaration decl = new Declaration(bindings);
345     decl.setType(Compilation.scmListType);
346     decl.noteValue (null); // Does not have a known value.
347
addParam(decl, templateScopeRest, lexp, tr);
348       }
349   }
350
351   private static void addParam (Declaration decl, ScopeExp templateScope,
352                 LambdaExp lexp, Translator tr)
353   {
354     if (templateScope != null)
355       decl = tr.makeRenamedAlias(decl, templateScope);
356     lexp.addDeclaration(decl);
357     if (templateScope != null)
358       decl.context = templateScope;
359   }
360
361   public Object JavaDoc rewriteAttrs(LambdaExp lexp, Object JavaDoc body, Translator tr)
362   {
363     String JavaDoc accessFlagName = null;
364     String JavaDoc allocationFlagName = null;
365     int accessFlag = 0;
366     int allocationFlag = 0;
367     SyntaxForm syntax = null;
368     for (;;)
369       {
370     while (body instanceof SyntaxForm)
371       {
372         syntax = (SyntaxForm) body;
373         body = syntax.form;
374       }
375     if (! (body instanceof Pair))
376       break;
377     Pair pair1 = (Pair) body;
378     Object JavaDoc attrName = Translator.stripSyntax(pair1.car);
379     Object JavaDoc pair1_cdr = pair1.cdr;
380     while (pair1_cdr instanceof SyntaxForm)
381       {
382         syntax = (SyntaxForm) pair1_cdr;
383         pair1_cdr = syntax.form;
384       }
385     if (! (pair1_cdr instanceof Pair))
386       break;
387     Pair pair2 = (Pair) pair1_cdr;
388
389     Object JavaDoc attrValue;
390     if (tr.matches(attrName, "::"))
391       attrName = null;
392     else if (! (attrName instanceof Keyword))
393       break;
394     if (attrName == null)
395       {
396             Expression attrExpr = tr.rewrite_car(pair2, syntax);
397             if (lexp.isClassMethod() && "*init*".equals(lexp.getName()))
398               tr.error('e', "explicit return type for '*init*' method");
399             else
400               {
401                 gnu.bytecode.Type rtype = tr.getLanguage().getTypeFor(attrExpr);
402                 if (rtype != null)
403                   lexp.setReturnType(rtype);
404               }
405       }
406     else if (attrName == kawa.standard.object.accessKeyword)
407       {
408         Expression attrExpr = tr.rewrite_car(pair2, syntax);
409         if (! (attrExpr instanceof QuoteExp)
410         || ! ((attrValue = ((QuoteExp) attrExpr).getValue()) instanceof String JavaDoc
411               || attrValue instanceof FString))
412           tr.error('e', "access: value not a constant symbol or string");
413         else if (lexp.nameDecl == null)
414           tr.error('e', "access: not allowed for anonymous function");
415         else
416           {
417         String JavaDoc value = attrValue.toString();
418         if ("private".equals(value))
419           accessFlag = Declaration.PRIVATE_ACCESS;
420         else if ("protected".equals(value))
421           accessFlag = Declaration.PROTECTED_ACCESS;
422         else if ("public".equals(value))
423           accessFlag = Declaration.PUBLIC_ACCESS;
424         else if ("package".equals(value))
425           accessFlag = Declaration.PACKAGE_ACCESS;
426         else
427           tr.error('e', "unknown access specifier");
428         if (accessFlagName != null && value != null)
429           {
430             tr.error('e', "duplicate access specifiers - "
431                  + accessFlagName + " and "
432                  + value);
433           }
434         accessFlagName = value;
435           }
436       }
437     else if (attrName == kawa.standard.object.allocationKeyword)
438       {
439         Expression attrExpr = tr.rewrite_car(pair2, syntax);
440         if (! (attrExpr instanceof QuoteExp)
441         || ! ((attrValue = ((QuoteExp) attrExpr).getValue()) instanceof String JavaDoc
442               || attrValue instanceof FString))
443           tr.error('e', "allocation: value not a constant symbol or string");
444         else if (lexp.nameDecl == null)
445           tr.error('e', "allocation: not allowed for anonymous function");
446         else
447           {
448         String JavaDoc value = attrValue.toString();
449         if ("class".equals(value) || "static".equals(value))
450           allocationFlag = Declaration.STATIC_SPECIFIED;
451         else if ("instance".equals(value))
452           allocationFlag = Declaration.NONSTATIC_SPECIFIED;
453         else
454           tr.error('e', "unknown allocation specifier");
455         if (allocationFlagName != null && value != null)
456           {
457             tr.error('e', "duplicate allocation specifiers - "
458                  + allocationFlagName + " and "
459                  + value);
460           }
461         allocationFlagName = value;
462           }
463       }
464     else if (attrName == kawa.standard.object.throwsKeyword)
465       {
466         attrValue = pair2.car;
467         int count = Translator.listLength(attrValue);
468         if (count < 0)
469           tr.error('e', "throws: not followed by a list");
470         else
471           {
472         ReferenceExp[] exps = new ReferenceExp[count];
473         SyntaxForm syntaxLocal = syntax;
474         for (int i = 0; i < count; i++)
475           {
476             while (attrValue instanceof SyntaxForm)
477               {
478             syntaxLocal = (SyntaxForm) attrValue;
479             attrValue = syntaxLocal.form;
480               }
481             Pair pair3 = (Pair) attrValue;
482             Expression throwsExpr = tr.rewrite_car(pair3, syntaxLocal);
483             if (throwsExpr instanceof ReferenceExp)
484               {
485             exps[i] = (ReferenceExp) throwsExpr;
486               }
487             else
488               {
489             Object JavaDoc savePos = tr.pushPositionOf(pair3);
490             tr.error('e', "throws not followed by a classname");
491             tr.popPositionOf(savePos);
492               }
493             attrValue = pair3.cdr;
494           }
495         lexp.setExceptions(exps);
496           }
497       }
498         else if (attrName == nameKeyword)
499           {
500             Expression attrExpr = tr.rewrite_car(pair2, syntax);
501             if (attrExpr instanceof QuoteExp)
502               lexp.setName(((QuoteExp) attrExpr).getValue().toString());
503           }
504     else
505       {
506         tr.error('w', "unknown procedure property "+attrName);
507       }
508     body = pair2.cdr;
509       }
510     accessFlag |= allocationFlag;
511     if (accessFlag != 0)
512       lexp.nameDecl.setFlag(accessFlag);
513     if (syntax != null)
514       body = syntax.fromDatumIfNeeded(body);
515     return body;
516   }
517
518   public Object JavaDoc skipAttrs(LambdaExp lexp, Object JavaDoc body, Translator tr)
519   {
520     while (body instanceof Pair)
521       {
522     Pair pair = (Pair) body;
523     if (! (pair.cdr instanceof Pair))
524       break;
525     Object JavaDoc attrName = pair.car;
526     if (tr.matches(attrName, "::"))
527       attrName = null;
528     else if (! (attrName instanceof Keyword))
529       break;
530     body = ((Pair) pair.cdr).cdr;
531       }
532     return body;
533   }
534
535   public void rewriteBody(LambdaExp lexp, Object JavaDoc body, Translator tr)
536   {
537     int numRenamedAlias = 0;
538     // We view a top-level named function as a method, in the sense that the
539
// form (this) is allowed, if the supertype is explicitly specified.
540
if (tr.curMethodLambda == null
541         && lexp.nameDecl != null
542         && tr.getModule().getFlag(ModuleExp.SUPERTYPE_SPECIFIED))
543       tr.curMethodLambda = lexp;
544     tr.pushScope(lexp);
545     Declaration prev = null;
546     int key_args = lexp.keywords == null ? 0 : lexp.keywords.length;
547     int opt_args = lexp.defaultArgs == null ? 0
548       : lexp.defaultArgs.length - key_args;
549     int arg_i = 0;
550     int opt_i = 0;
551     for (Declaration cur = lexp.firstDecl(); cur != null; cur = cur.nextDecl())
552       {
553     if (cur.isAlias())
554       {
555         Declaration param = Translator.getOriginalRef(cur).getBinding();
556         lexp.replaceFollowing(prev, param);
557         param.context = lexp;
558         tr.pushRenamedAlias(cur);
559         numRenamedAlias++;
560         cur = param;
561       }
562     prev = cur;
563
564         if (arg_i >= lexp.min_args
565             && (arg_i < lexp.min_args + opt_args
566                 || lexp.max_args >= 0
567                 || arg_i != lexp.min_args + opt_args))
568           {
569             lexp.defaultArgs[opt_i] = tr.rewrite(lexp.defaultArgs[opt_i]);
570             opt_i++;
571           }
572         arg_i++;
573
574         tr.lexical.push(cur);
575       }
576
577     if (lexp.isClassMethod()
578         && ! lexp.nameDecl.getFlag(Declaration.STATIC_SPECIFIED))
579       {
580         // We set the type of this in ClassExp.walkChildren.
581
lexp.add(null, new Declaration(ThisExp.THIS_NAME));
582       }
583
584     LambdaExp saveLambda = tr.curLambda;
585     tr.curLambda = lexp;
586     lexp.body = tr.rewrite_body (body);
587     tr.curLambda = saveLambda;
588     Expression[] exps;
589     int len;
590     if (lexp.body instanceof BeginExp
591         && (len = (exps = ((BeginExp) lexp.body).getExpressions()).length) > 1
592         && exps[0] instanceof ReferenceExp)
593       {
594     // Handle '<TYPENAME> BODY':
595
Expression rexp = exps[0];
596         len--;
597         if (len == 1)
598           lexp.body = exps[1];
599         else
600           {
601             Expression[] new_body = new Expression[len];
602             System.arraycopy(exps, 1, new_body, 0, len);
603             lexp.body = new BeginExp(new_body);
604           }
605         Convert.setCoercedReturnValue(lexp, rexp, tr.getLanguage());
606       }
607     else if (lexp.returnType != null
608              && lexp.returnType != Type.pointer_type
609              && lexp.returnType != Type.void_type)
610       {
611     Expression value = lexp.body;
612     lexp.body = Convert.makeCoercion(value, lexp.returnType);
613     lexp.body.setLine(value);
614       }
615     tr.pop(lexp);
616     lexp.countDecls();
617     tr.popRenamedAlias(numRenamedAlias);
618     lexp.countDecls();
619     if (tr.curMethodLambda == lexp)
620       tr.curMethodLambda = null;
621   }
622
623   public void print (Consumer out)
624   {
625     out.write("#<builtin lambda>");
626   }
627 }
628
Popular Tags