KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > expr > LambdaExp


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

4 package gnu.expr;
5 import gnu.bytecode.*;
6 import gnu.mapping.*;
7 import gnu.lists.LList;
8 import java.util.Vector JavaDoc;
9
10 /**
11  * Class used to implement Scheme lambda expressions.
12  * @author Per Bothner
13  */

14
15 public class LambdaExp extends ScopeExp
16 {
17   public Expression body;
18   /** Minumnum number of parameters.
19    * Does not count implicit isThisParameter(). */

20   public int min_args;
21   /** Maximum number of actual arguments; -1 if variable. */
22   public int max_args;
23
24   /** Set of visible top-level LambdaExps that need apply methods. */
25   Vector JavaDoc applyMethods;
26
27   // public int plainArgs;
28
Variable argsArray;
29   // First argument that goes into argsArray.
30
private Declaration firstArgsArrayArg;
31
32   public Keyword[] keywords;
33   public Expression[] defaultArgs;
34
35   /** A list of Declarations, chained using Declaration's nextCapturedVar.
36     * All the Declarations are allocated in the current heapFrame. */

37   Declaration capturedVars;
38
39   public void capture (Declaration decl)
40   {
41     if (decl.isSimple())
42       {
43         if (capturedVars == null
44             && ! decl.isStatic()
45             && ! (this instanceof ModuleExp || this instanceof ClassExp))
46           {
47             heapFrame = new gnu.bytecode.Variable("heapFrame");
48           }
49         decl.setSimple(false);
50         if (! decl.isPublic())
51           {
52             decl.nextCapturedVar = capturedVars;
53             capturedVars = decl;
54           }
55       }
56   }
57
58   /** A local variable that points to the heap-allocated part of the frame.
59    * Each captured variable is a field in the heapFrame. A procedure has
60    * a heapFrame iff if has a parameter or local variable that is
61    * referenced ("captured") by a non-inline inferior procedure.
62    * (I.e there is a least one non-inline procedure that encloses the
63    * reference but not the definition.) Note that an inline procedure may
64    * have a heapFrame if it encloses a non-inline procedure. This is
65    * necessary because we represent loops as tail-recursive inline procedures.
66    */

67   Variable heapFrame;
68
69   public LambdaExp firstChild;
70   public LambdaExp nextSibling;
71
72   /** A magic value to indicate there is no unique return continuation. */
73   final static ApplyExp unknownContinuation = new ApplyExp ((Expression) null, null);
74
75   /** The unique caller that calls this lambda.
76       The value is null, if no callers have been seen.
77       A value of unknownContinuation means there are multiple call sites.
78       Tail-recursive calls do not count as multiple call sites. (With a
79       little more analysis, we could also allow multiple non-self tail-calls
80       as long as they all are ultimately called from the same place.)
81       This is used to see if we can inline the function at its unique
82       call site. */

83   public ApplyExp returnContinuation;
84
85   /** Expressions that name classes that may be thrown. */
86   ReferenceExp[] throwsSpecification;
87
88   public void setExceptions(ReferenceExp[] exceptions)
89   {
90     throwsSpecification = exceptions;
91   }
92
93   /** If non-null, a Declaration whose value is (only) this LambdaExp. */
94   public Declaration nameDecl;
95
96   /** If non-null, this is a Field that is used for implementing lexical closures.
97    * If getName() is "closureEnv", it is our parent's heapFrame,
98    * which is an instance of one of our siblings.
99    * (Otherwise, we use "this" as the implicit "closureEnv" field.) */

100   public Field closureEnvField;
101
102   /** Field in heapFrame.getType() that contains the static link.
103    * It is used by child functions to get to outer environments.
104    * Its value is this function's closureEnv value. */

105   public Field staticLinkField;
106
107   /** A variable that points to the closure environment passed in.
108    * It can be any one of:
109    * null, if no closure environment is needed;
110    * this, if this object is its parent's heapFrame;
111    * a local variable initialized from this.closureEnv;
112    * a parameter (only if !getCanRead()); or
113    * a copy of our caller's closureEnv or heapFrame (only if getInlineOnly()).
114    * See declareClosureEnv and closureEnvField. */

115   Variable closureEnv;
116
117   static final int INLINE_ONLY = 1;
118   static final int CAN_READ = 2;
119   static final int CAN_CALL = 4;
120   static final int IMPORTS_LEX_VARS = 8;
121   static final int NEEDS_STATIC_LINK = 16;
122   /* Used (future) by FindTailCalls. */
123   static final int CANNOT_INLINE = 32;
124   static final int CLASS_METHOD = 64;
125   static final int METHODS_COMPILED = 128;
126   public static final int NO_FIELD = 256;
127   /** True if any parameter default expression captures a parameter. */
128   static final int DEFAULT_CAPTURES_ARG = 512;
129   public static final int SEQUENCE_RESULT = 1024;
130   public static final int OVERLOADABLE_FIELD = 2048;
131   protected static final int NEXT_AVAIL_FLAG = 4096;
132
133   /** True iff this lambda is only "called" inline. */
134   public final boolean getInlineOnly() { return (flags & INLINE_ONLY) != 0; }
135   public final void setInlineOnly(boolean inlineOnly)
136   { setFlag(inlineOnly, INLINE_ONLY); }
137
138   public final boolean getNeedsClosureEnv ()
139   { return (flags & (NEEDS_STATIC_LINK|IMPORTS_LEX_VARS)) != 0; }
140
141   /** True if a child lambda uses lexical variables from outside.
142       Hence, a child heapFrame needs a staticLink to outer frames. */

143   public final boolean getNeedsStaticLink ()
144   { return (flags & NEEDS_STATIC_LINK) != 0; }
145
146   public final void setNeedsStaticLink(boolean needsStaticLink)
147   {
148     if (needsStaticLink) flags |= NEEDS_STATIC_LINK;
149     else flags &= ~NEEDS_STATIC_LINK;
150   }
151
152   /** True iff this lambda "captures" (uses) lexical variables from outside. */
153   public final boolean getImportsLexVars ()
154   { return (flags & IMPORTS_LEX_VARS) != 0; }
155
156   public final void setImportsLexVars(boolean importsLexVars)
157   {
158     if (importsLexVars) flags |= IMPORTS_LEX_VARS;
159     else flags &= ~IMPORTS_LEX_VARS;
160   }
161
162   public final void setImportsLexVars()
163   {
164     int old = flags;
165     flags |= IMPORTS_LEX_VARS;
166
167     // If this needs an environment (closure), then its callers do too.
168
if ((old & IMPORTS_LEX_VARS) == 0 && nameDecl != null)
169       setCallersNeedStaticLink();
170   }
171
172   public final void setNeedsStaticLink()
173   {
174     int old = flags;
175     flags |= NEEDS_STATIC_LINK;
176
177     // If this needs an environment (closure), then its callers do too.
178
if ((old & NEEDS_STATIC_LINK) == 0 && nameDecl != null)
179       setCallersNeedStaticLink();
180   }
181
182   void setCallersNeedStaticLink()
183   {
184     LambdaExp outer = outerLambda();
185     for (ApplyExp app = nameDecl.firstCall; app != null; app = app.nextCall)
186       {
187         LambdaExp caller = app.context;
188         for (; caller != outer && !(caller instanceof ModuleExp); caller = caller.outerLambda())
189           caller.setNeedsStaticLink();
190       }
191   }
192
193   public final boolean getCanRead()
194   { return (flags & CAN_READ) != 0; }
195   public final void setCanRead(boolean read)
196   {
197     if (read) flags |= CAN_READ;
198     else flags &= ~CAN_READ;
199   }
200
201   public final boolean getCanCall()
202   { return (flags & CAN_CALL) != 0; }
203   public final void setCanCall(boolean called)
204   {
205     if (called) flags |= CAN_CALL;
206     else flags &= ~CAN_CALL;
207   }
208
209   /** True if this is a method in an ClassExp. */
210   public final boolean isClassMethod()
211   { return (flags & CLASS_METHOD) != 0; }
212
213   public final void setClassMethod(boolean isMethod)
214   {
215     if (isMethod) flags |= CLASS_METHOD;
216     else flags &= ~CLASS_METHOD;
217   }
218
219   /** True iff this is the dummy top-level function of a module body. */
220   public final boolean isModuleBody () { return this instanceof ModuleExp; }
221
222   /** True if a class is generated for this procedure. */
223   public final boolean isClassGenerated ()
224   {
225     return isModuleBody() || this instanceof ClassExp;
226   }
227
228   /** Specify the calling convention used for this function.
229    * @return One of the CALL_WITH_xxx values in Compilation. */

230   public int getCallConvention ()
231   {
232     if (isModuleBody())
233       return ((Compilation.defaultCallConvention
234           >= Compilation.CALL_WITH_CONSUMER)
235           ? Compilation.defaultCallConvention
236           : Compilation.CALL_WITH_CONSUMER);
237     if (isClassMethod())
238       return Compilation.CALL_WITH_RETURN;
239     return ((Compilation.defaultCallConvention
240          != Compilation.CALL_WITH_UNSPECIFIED)
241         ? Compilation.defaultCallConvention
242         : Compilation.CALL_WITH_RETURN);
243   }
244
245   public final boolean isHandlingTailCalls ()
246   {
247     return isModuleBody()
248       || (Compilation.defaultCallConvention >= Compilation.CALL_WITH_TAILCALLS
249       && ! isClassMethod());
250   }
251
252   public final boolean variable_args () { return max_args < 0; }
253
254   ClassType type = Compilation.typeProcedure;
255
256   /** Return the ClassType of the Procedure this is being compiled into. */
257   protected ClassType getCompiledClassType(Compilation comp)
258   {
259     if (type == Compilation.typeProcedure)
260       throw new Error JavaDoc("internal error: getCompiledClassType");
261     return type;
262   }
263
264   public Type getType()
265   {
266     return type;
267   }
268
269   public void setType (ClassType type)
270   {
271     this.type = type;
272   }
273
274   /** Number of argument variable actually passed by the caller.
275    * For functions that accept more than 4 argument, or take a variable number,
276    * this is 1, since in that all arguments are passed in a single array. */

277   public int incomingArgs ()
278   {
279     // The max_args > 0 is a hack to handle LambdaProcedure, which
280
// currently always uses a single array argument.
281
return min_args == max_args && max_args <= 4 && max_args > 0 ? max_args : 1;
282   }
283
284   /** If non-zero, the selector field of the ModuleMethod for this. */
285   int selectorValue;
286
287   int getSelectorValue(Compilation comp)
288   {
289     int s = selectorValue;
290     if (s == 0)
291       {
292     s = comp.maxSelectorValue;
293     comp.maxSelectorValue = s + primMethods.length;
294     selectorValue = ++s;
295       }
296     return s;
297   }
298
299   /** Methods used to implement this functions.
300    * primMethods[0] is used if the argument count is min_args;
301    * primMethods[1] is used if the argument count is min_args+1;
302    * primMethods[primMethods.length-1] is used otherwise.
303    */

304   Method[] primMethods;
305
306   /** Select the method used given an argument count. */
307   public final Method getMethod(int argCount)
308   {
309     if (primMethods == null || (max_args >= 0 && argCount > max_args))
310       return null;
311     int index = argCount - min_args;
312     if (index < 0)
313       return null; // Too few arguments.
314
int length = primMethods.length;
315     return primMethods[index < length ? index : length - 1];
316   }
317
318   /** Get the method that contains the actual body of the procedure.
319    * (The other methods are just stubs that call that method.) */

320   public final Method getMainMethod()
321   {
322     Method[] methods = primMethods;
323     return methods == null ? null : methods[methods.length-1];
324   }
325
326   /** Return the parameter type of the "keyword/rest" parameters. */
327   public final Type restArgType()
328   {
329     if (min_args == max_args)
330       return null;
331     if (primMethods == null)
332       throw new Error JavaDoc("internal error - restArgType");
333     Method[] methods = primMethods;
334     if (max_args >= 0 && methods.length > max_args - min_args)
335       return null;
336     Method method = methods[methods.length-1];
337     Type[] types = method.getParameterTypes();
338     int ilast = types.length-1;
339     if (method.getName().endsWith("$X"))
340       ilast--;
341     return types[ilast];
342   }
343
344   public LambdaExp outerLambda ()
345   {
346     return outer == null ? null : outer.currentLambda ();
347   }
348
349   /** Return the closest outer non-inlined LambdaExp. */
350
351   public LambdaExp outerLambdaNotInline ()
352   {
353     for (ScopeExp exp = this; (exp = exp.outer) != null; )
354       {
355     if (exp instanceof LambdaExp)
356       {
357         LambdaExp result = (LambdaExp) exp;
358         if (! result.getInlineOnly())
359           return result;
360       }
361       }
362     return null;
363   }
364
365   /** True if given LambdaExp is inlined in this function, perhaps indirectly.
366    * Is false if this is not inline-only or if getCaller() is not inlined is
367    * outer. Usually the same as (this.outerLambdaNotInline()==outer),
368    * except in the case that outer.getInlineOnly(). */

369   boolean inlinedIn (LambdaExp outer)
370   {
371     if (! getInlineOnly())
372       return false;
373     for (ScopeExp exp = getCaller(); exp != null; exp = exp.outer)
374       {
375     if (exp instanceof LambdaExp)
376       {
377         
378         LambdaExp result = (LambdaExp) exp;
379         if (result == outer)
380           return true;
381         if (! result.getInlineOnly())
382           return false;
383       }
384       }
385     return false;
386   }
387
388   /** For an INLINE_ONLY function, return the function it gets inlined in. */
389   public LambdaExp getCaller ()
390   {
391     return returnContinuation.context;
392   }
393
394   Variable thisVariable;
395
396   public Variable declareThis(ClassType clas)
397   {
398     if (thisVariable == null)
399       {
400         thisVariable = new Variable("this");
401     getVarScope().addVariableAfter(null, thisVariable);
402     thisVariable.setParameter (true);
403       }
404     if (thisVariable.getType() == null)
405       thisVariable.setType(clas);
406     if (decls != null && decls.isThisParameter())
407       decls.var = thisVariable;
408     return thisVariable;
409   }
410
411   public Variable declareClosureEnv()
412   {
413     if (closureEnv == null && getNeedsClosureEnv())
414       {
415     LambdaExp parent = outerLambda();
416     if (parent instanceof ClassExp)
417       parent = parent.outerLambda();
418     Variable parentFrame = parent.heapFrame != null ? parent.heapFrame
419       : parent.closureEnv;
420     if (isClassMethod())
421       closureEnv = declareThis(type);
422     else if (parent.heapFrame == null && ! parent.getNeedsStaticLink()
423          && ! (parent instanceof ModuleExp))
424       closureEnv = null;
425     else if (! isClassGenerated() && ! getInlineOnly())
426       {
427         Method primMethod = getMainMethod();
428         if (! primMethod.getStaticFlag())
429           closureEnv = declareThis(primMethod.getDeclaringClass());
430         else
431           {
432         Type envType = primMethod.getParameterTypes()[0];
433         closureEnv = new Variable("closureEnv", envType);
434         getVarScope().addVariableAfter(null, closureEnv);
435         closureEnv.setParameter(true);
436           }
437       }
438     else if (inlinedIn(parent))
439       closureEnv = parentFrame;
440     else
441       {
442         closureEnv = new Variable("closureEnv", parentFrame.getType());
443         getVarScope().addVariable(closureEnv);
444       }
445       }
446     return closureEnv;
447   }
448
449   public LambdaExp ()
450   {
451   }
452
453   public LambdaExp(int args)
454   {
455     min_args = args;
456     max_args = args;
457   }
458
459
460   public LambdaExp (Expression body)
461   {
462     this.body = body;
463   }
464
465   /** Generate code to load heapFrame on the JVM stack. */
466   public void loadHeapFrame (Compilation comp)
467   {
468     LambdaExp curLambda = comp.curLambda;
469     while (curLambda != this && curLambda.getInlineOnly())
470       curLambda = curLambda.getCaller();
471
472     gnu.bytecode.CodeAttr code = comp.getCode();
473     if (curLambda.heapFrame != null && this == curLambda)
474       {
475         code.emitLoad(curLambda.heapFrame);
476         return;
477       }
478     ClassType curType;
479     if (curLambda.closureEnv != null)
480       {
481         code.emitLoad(curLambda.closureEnv);
482         curType = (ClassType) curLambda.closureEnv.getType();
483       }
484     else
485       {
486         code.emitPushThis();
487         curType = comp.curClass;
488       }
489     while (curLambda != this)
490       {
491         Field link = curLambda.staticLinkField;
492         if (link != null && link.getDeclaringClass() == curType)
493           {
494             code.emitGetField(link);
495             curType = (ClassType) link.getType();
496           }
497         curLambda = curLambda.outerLambda();
498       }
499   }
500
501   /** Get the i'the formal parameter. */
502   Declaration getArg (int i)
503   {
504     for (Declaration var = firstDecl(); ; var = var.nextDecl ())
505       {
506     if (var == null)
507       throw new Error JavaDoc ("internal error - getArg");
508         if (i == 0)
509           return var;
510         --i;
511       }
512   }
513
514   public void compileEnd (Compilation comp)
515   {
516     gnu.bytecode.CodeAttr code = comp.getCode();
517     if (! getInlineOnly())
518       {
519     if (comp.method.reachableHere()
520         && (Compilation.defaultCallConvention < Compilation.CALL_WITH_TAILCALLS
521         || isModuleBody() || isClassMethod() || isHandlingTailCalls()))
522       code.emitReturn();
523     popScope(code); // Undoes enterScope in allocParameters
524
if (! Compilation.fewerClasses) // FIXME
525
code.popScope(); // Undoes pushScope in method.initCode.
526
}
527
528     if (heapFrame != null)
529       comp.generateConstructor((ClassType) heapFrame.getType(), this);
530     
531     generateApplyMethods(comp);
532   }
533
534   public void generateApplyMethods(Compilation comp)
535   {
536     comp.generateMatchMethods(this);
537     if (Compilation.defaultCallConvention >= Compilation.CALL_WITH_CONSUMER)
538       comp.generateApplyMethodsWithContext(this);
539     else
540       comp.generateApplyMethodsWithoutContext(this);
541   }
542
543   Field allocFieldFor (Compilation comp)
544   {
545     if (nameDecl != null && nameDecl.field != null)
546       return nameDecl.field;
547     ClassType frameType = getOwningLambda().getHeapFrameType();
548     String JavaDoc name = getName();
549     String JavaDoc fname
550       = name == null ? "lambda" : Compilation.mangleNameIfNeeded(name);
551     int fflags = Access.FINAL;
552     if (nameDecl != null && nameDecl.context instanceof ModuleExp)
553       {
554     boolean external_access = nameDecl.needsExternalAccess();
555     if (external_access)
556       fname = Declaration.PRIVATE_PREFIX + fname;
557     if (nameDecl.getFlag(Declaration.STATIC_SPECIFIED))
558           {
559             fflags |= Access.STATIC;
560             // If there is no moduleInstanceVar, then the field gets
561
// initialized in <init>, not <clinit>,
562
// which is bad for a "static final" field.
563
if (! ((ModuleExp) nameDecl.context).isStatic())
564               fflags &= ~Access.FINAL;
565           }
566     if (! nameDecl.isPrivate() || external_access)
567       fflags |= Access.PUBLIC;
568         if ((flags & OVERLOADABLE_FIELD) != 0)
569           {
570             String JavaDoc fname0 = fname;
571             int suffix = min_args == max_args ? min_args : 1;
572             do { fname = fname0 + '$' + suffix++; }
573             while (frameType.getDeclaredField(fname) != null);
574           }
575       }
576     else
577       {
578     fname = fname + "$Fn" + ++comp.localFieldIndex;
579     if (! getNeedsClosureEnv())
580       fflags = (fflags | Access.STATIC) & ~Access.FINAL;
581       }
582     Type rtype = Compilation.typeModuleMethod;
583     Field field = frameType.addField (fname, rtype, fflags);
584     if (nameDecl != null)
585       nameDecl.field = field;
586     return field;
587   }
588
589   final void addApplyMethod (Compilation comp)
590   {
591     LambdaExp owner = this;
592     // Similar to getOwningLambda(), but we can't add apply methods
593
// to a ClassExp - at least not unless it extends ModuleBody.
594
for (;;)
595       {
596         owner = owner.outerLambda();
597     if (owner instanceof ModuleExp
598         || owner.heapFrame != null)
599           break;
600       }
601     ClassType frameType = owner.getHeapFrameType();
602     if (! (frameType.getSuperclass().isSubtype(Compilation.typeModuleBody)))
603       owner = comp.getModule();
604     if (owner.applyMethods == null)
605       owner.applyMethods = new Vector JavaDoc();
606     owner.applyMethods.addElement(this);
607   }
608
609   public Field compileSetField (Compilation comp)
610   {
611     if (comp.usingCPStyle())
612       compile(comp, Type.pointer_type);
613     else
614       {
615     compileAsMethod(comp);
616     addApplyMethod(comp);
617       }
618
619     return (new ProcInitializer(this, comp)).field;
620   }
621
622   public void compile (Compilation comp, Target target)
623   {
624     if (target instanceof IgnoreTarget
625     && (getInlineOnly() || ! getCanRead()))
626       return;
627     Type rtype;
628     CodeAttr code = comp.getCode();
629
630     if (comp.usingCPStyle())
631       {
632     // Label func_start = new Label(code);
633
Label func_end = new Label(code);
634     LambdaExp saveLambda = comp.curLambda;
635     comp.curLambda = this;
636     type = saveLambda.type;
637     closureEnv = saveLambda.closureEnv;
638         /*
639     if (comp.usingCPStyle())
640       {
641         heapFrame = comp.thisDecl;
642         for (Declaration var = firstDecl();
643          var != null; var = var.nextDecl())
644           var.assignField(comp);
645       }
646         */

647     gnu.bytecode.SwitchState fswitch = comp.fswitch;
648     int pc = comp.fswitch.getMaxValue() + 1;
649     code.emitGoto(func_end);
650     Type[] stackTypes = code.saveStackTypeState(true);
651
652     fswitch.addCase(pc, code);
653         /*
654     code.emitPushThis();
655     code.emitGetField(comp.argsCallContextField);
656     code.emitStore(comp.argsArray);
657         */

658     allocParameters(comp);
659     enterFunction(comp);
660
661     compileBody(comp);
662     compileEnd(comp);
663     comp.curLambda = saveLambda;
664     func_end.define(code);
665     code.restoreStackTypeState(stackTypes);
666     ClassType ctype = comp.curClass;
667     rtype = ctype;
668     /*
669     code.emitNew(ctype);
670     code.emitDup(ctype);
671     code.emitInvokeSpecial(ctype.constructor);
672     code.emitDup(ctype);
673     code.emitPushInt(pc);
674     code.emitPutField(comp.saved_pcCallFrameField);
675     if (isHandlingTailCalls())
676       {
677         // Set name field.
678         if (name != null)
679           {
680         code.emitDup(ctype);
681         code.emitPushString(name);
682         code.emitInvokeVirtual(comp.setNameMethod);
683           }
684         // Set numArgs field.
685         code.emitDup(ctype);
686         code.emitPushInt(min_args | (max_args << 12));
687         code.emitPutField(comp.numArgsCallFrameField);
688         // Set static link field to this CallFrame.
689         code.emitDup(ctype);
690         code.emitPushThis();
691         code.emitPutField(comp.callerCallFrameField);
692       }
693     */

694       }
695     else
696       { LambdaExp outer = outerLambda();
697     rtype = Compilation.typeModuleMethod;
698     if ((flags & NO_FIELD) != 0
699         || (comp.immediate && outer instanceof ModuleExp))
700       {
701         compileAsMethod(comp);
702         addApplyMethod(comp);
703         ProcInitializer.emitLoadModuleMethod(this, comp);
704       }
705     else
706       {
707         Field field = compileSetField(comp);
708         if (field.getStaticFlag())
709           code.emitGetStatic(field);
710         else
711           {
712         LambdaExp parent = comp.curLambda;
713         Variable frame
714           = parent.heapFrame != null ? parent.heapFrame
715           : parent.closureEnv;
716         code.emitLoad(frame);
717         code.emitGetField(field);
718           }
719       }
720       }
721     target.compileFromStack(comp, rtype);
722   }
723
724   public ClassType getHeapFrameType()
725   {
726     if (this instanceof ModuleExp || this instanceof ClassExp)
727       return (ClassType) getType();
728     else
729       return (ClassType) heapFrame.getType();
730   }
731
732
733   public LambdaExp getOwningLambda()
734   {
735     ScopeExp exp = outer;
736     for (;; exp = exp.outer)
737       {
738     if (exp == null)
739       return null;
740     if (exp instanceof ModuleExp
741         || (exp instanceof ClassExp && getNeedsClosureEnv())
742         || (exp instanceof LambdaExp
743         && ((LambdaExp) exp).heapFrame != null))
744       return (LambdaExp) exp;
745       }
746   }
747
748   void addMethodFor (Compilation comp, ObjectType closureEnvType)
749   {
750     ScopeExp sc = this;
751     while (sc != null && ! (sc instanceof ClassExp))
752       sc = sc.outer;
753     ClassType ctype;
754     // If this is nested inside a Class, then create the method in that
755
// class - in case it references a private field/method.
756
if (sc != null)
757       ctype = ((ClassExp) sc).instanceType;
758     else
759       ctype = getOwningLambda().getHeapFrameType();
760     addMethodFor(ctype, comp, closureEnvType);
761   }
762
763   void addMethodFor (ClassType ctype, Compilation comp, ObjectType closureEnvType)
764   {
765     // generate_unique_name (new_class, child.getName());
766
String JavaDoc name = getName();
767     LambdaExp outer = outerLambda();
768
769     int key_args = keywords == null ? 0 : keywords.length;
770     int opt_args = defaultArgs == null ? 0 : defaultArgs.length - key_args;
771     int numStubs =
772       ((flags & DEFAULT_CAPTURES_ARG) != 0) ? 0 : opt_args;
773     boolean varArgs = max_args < 0 || min_args + numStubs < max_args;
774     primMethods = new Method[numStubs + 1];
775
776     boolean isStatic;
777     // 'I' if initMethod ($finit$); 'C' if clinitMethod (<clinit>).
778
char isInitMethod = '\0';
779     if (nameDecl != null
780     && nameDecl.getFlag(Declaration.NONSTATIC_SPECIFIED))
781       isStatic = false;
782     else if (nameDecl != null
783          && nameDecl.getFlag(Declaration.STATIC_SPECIFIED))
784       isStatic = true;
785     else if (isClassMethod())
786       {
787     if (outer instanceof ClassExp)
788       {
789         ClassExp cl = (ClassExp) outer;
790         isStatic = cl.isMakingClassPair() && closureEnvType != null;
791         if (this == cl.initMethod)
792           isInitMethod = 'I';
793         else if (this == cl.clinitMethod)
794           {
795         isInitMethod = 'C';
796         isStatic = true;
797           }
798       }
799     else
800       isStatic = false;
801       }
802     else if (thisVariable != null || closureEnvType == ctype)
803       isStatic = false;
804     else if (nameDecl != null && nameDecl.context instanceof ModuleExp)
805       {
806     ModuleExp mexp = (ModuleExp) nameDecl.context;
807     isStatic = mexp.getSuperType() == null && mexp.getInterfaces() == null;
808       }
809     else
810       isStatic = true;
811
812     StringBuffer JavaDoc nameBuf = new StringBuffer JavaDoc(60);
813     int mflags = isStatic ? Access.STATIC : 0;
814     if (nameDecl != null)
815       {
816     if (nameDecl.needsExternalAccess())
817       mflags |= Access.PUBLIC;
818     else
819           {
820             short defaultFlag = nameDecl.isPrivate() ? 0 : Access.PUBLIC;
821             if (isClassMethod())
822               defaultFlag = nameDecl.getAccessFlags(defaultFlag);
823             mflags |= defaultFlag;
824           }
825       }
826     if (! (outer.isModuleBody() || outer instanceof ClassExp)
827     || name == null)
828       {
829     nameBuf.append("lambda");
830     nameBuf.append(+(++comp.method_counter));
831       }
832     if (isInitMethod == 'C')
833       nameBuf.append("<clinit>");
834     else if (getSymbol() != null)
835       nameBuf.append(Compilation.mangleName(name));
836     if (getFlag(SEQUENCE_RESULT))
837       nameBuf.append("$C");
838     boolean withContext
839       = (getCallConvention() >= Compilation.CALL_WITH_CONSUMER
840      && isInitMethod == '\0');
841     if (isInitMethod != '\0')
842       {
843     if (isStatic)
844       { // if cl.isMakingClassPair() - i.e. defining a non-simple class:
845
// In this case the $finit$ method needs to be explicitly called
846
// by sub-class constructors. See Compilation.callInitMethods.
847
mflags = (mflags & ~Access.PROTECTED+Access.PRIVATE)+Access.PUBLIC;
848       }
849     else
850       { // if ! cl.isMakingClassPair() - i.e. defining a simple class:
851
// Make it private to prevent inherited $finit$ from overriding
852
// the current one - and thus preventing its execution.
853
mflags = (mflags & ~Access.PUBLIC+Access.PROTECTED)+Access.PRIVATE;
854       }
855       }
856     if (ctype.isInterface())
857       mflags |= Access.ABSTRACT;
858     if (! isStatic)
859       declareThis(ctype);
860
861     Type rtype
862       = (getFlag(SEQUENCE_RESULT)
863      || getCallConvention () >= Compilation.CALL_WITH_CONSUMER)
864       ? Type.void_type
865       : getReturnType().getImplementationType();
866     int extraArg = (closureEnvType != null && closureEnvType != ctype) ? 1 : 0;
867
868     int ctxArg = 0;
869     if (getCallConvention () >= Compilation.CALL_WITH_CONSUMER
870     && isInitMethod == '\0')
871       ctxArg = 1;
872
873     int nameBaseLength = nameBuf.length();
874     for (int i = 0; i <= numStubs; i++)
875       {
876     nameBuf.setLength(nameBaseLength);
877     int plainArgs = min_args + i;
878     int numArgs = plainArgs;
879     if (i == numStubs && varArgs)
880       numArgs++;
881     Type[] atypes = new Type[extraArg + numArgs + ctxArg];
882     if (extraArg > 0)
883       atypes[0] = closureEnvType;
884     Declaration var = firstDecl();
885         if (var != null && var.isThisParameter())
886           var = var.nextDecl();
887     for (int itype = 0; itype < plainArgs; var = var.nextDecl())
888       atypes[extraArg + itype++] = var.getType().getImplementationType();
889     if (ctxArg != 0)
890       atypes[atypes.length-1] = Compilation.typeCallContext;
891     if (plainArgs < numArgs)
892       {
893         nameBuf.append("$V");
894         name = nameBuf.toString();
895         Type lastType = var.getType();
896         String JavaDoc lastTypeName = lastType.getName();
897         if (key_args > 0 || numStubs < opt_args
898         || ! ("gnu.lists.LList".equals(lastTypeName)
899               || "java.lang.Object[]".equals(lastTypeName)))
900           {
901         lastType = Compilation.objArrayType;
902         argsArray = new Variable("argsArray",
903                      Compilation.objArrayType);
904         argsArray.setParameter(true);
905           }
906         firstArgsArrayArg = var;
907         atypes[atypes.length-(withContext ? 2 : 1)] = lastType;
908       }
909     if (withContext)
910       nameBuf.append("$X");
911
912     boolean classSpecified
913       = (outer instanceof ClassExp
914          || (outer instanceof ModuleExp
915          && (((ModuleExp) outer)
916              .getFlag(ModuleExp.SUPERTYPE_SPECIFIED))));
917     name = nameBuf.toString();
918     {
919       // Rename the method if an existing method has the same
920
// name and type in this class.
921
// Additionally, if the base class or interfaces were not explicitly
922
// specified, then search super-classes for conflicting methods
923
// (such as "run" or "apply").
924
int renameCount = 0;
925       int len = nameBuf.length();
926     retry:
927       for (;;)
928         {
929           for (ClassType t = ctype; t != null; t = t.getSuperclass ())
930         {
931           if (t.getDeclaredMethod(name, atypes) != null)
932             {
933               nameBuf.setLength(len);
934               nameBuf.append('$');
935               nameBuf.append(++renameCount);
936               name = nameBuf.toString();
937               continue retry;
938             }
939           if (classSpecified)
940             // Do not search in super-classes
941
break;
942         }
943           break;
944         }
945     }
946     Method method = ctype.addMethod(name, atypes, rtype, mflags);
947     primMethods[i] = method;
948
949     if (throwsSpecification != null && throwsSpecification.length > 0)
950       {
951         int n = throwsSpecification.length;
952         ClassType[] exceptions = new ClassType[n];
953         for (int j = 0; j < n; j++)
954           {
955         ClassType exception = null;
956         Declaration decl = throwsSpecification[j].getBinding();
957         if (decl != null)
958           {
959             Expression declValue = decl.getValue();
960             if (declValue instanceof ClassExp)
961               exception
962             = ((ClassExp) declValue).getCompiledClassType(comp);
963             else
964               comp.error('e', "throws specification "+decl.getName()
965                  + " has non-class lexical binding");
966           }
967         if (exception == null)
968           {
969             String JavaDoc exName = throwsSpecification[j].getName();
970             int nlen = exName.length();
971             if (nlen > 2
972             && exName.charAt(0) == '<'
973             && exName.charAt(nlen-1) == '>')
974               exName = exName.substring(1, nlen-1);
975             exception = ClassType.make(exName);
976           }
977         exceptions[j] = exception;
978           }
979         ExceptionsAttr attr = new ExceptionsAttr(method);
980         attr.setExceptions(exceptions);
981       }
982       }
983   }
984
985   // Can we merge this with allocParameters?
986
public void allocChildClasses (Compilation comp)
987   {
988     Method main = getMainMethod();
989     
990     Declaration decl = firstDecl();
991     for (;;)
992       {
993         if (decl == firstArgsArrayArg && argsArray != null)
994           {
995             getVarScope().addVariable(argsArray);
996           }
997         if (! getInlineOnly()
998             && getCallConvention() >= Compilation.CALL_WITH_CONSUMER
999             && (firstArgsArrayArg == null ? decl == null
1000                : argsArray != null ? decl == firstArgsArrayArg
1001                : decl == firstArgsArrayArg.nextDecl()))
1002          {
1003            Variable var =
1004              getVarScope().addVariable(null,
1005                                        Compilation.typeCallContext,
1006                                        "$ctx");
1007            var.setParameter(true);
1008          }
1009        if (decl == null)
1010          break;
1011        Variable var = decl.var;
1012        // i is the register to use for the current parameter
1013
if (var != null
1014            || (getInlineOnly() && decl.ignorable()))
1015          ;
1016        else if (decl.isSimple () && ! decl.isIndirectBinding())
1017          {
1018            // For a simple parameter not captured by an inferior lambda,
1019
// just allocate it in the incoming register.
1020
var = decl.allocateVariable(null);
1021            //var.allocateLocal(code);
1022
}
1023        else
1024          {
1025            // This variable was captured by an inner lambda.
1026
// Its home location is in the heapFrame.
1027
// Later, we copy it from its incoming register
1028
// to its home location heapFrame. Here we just create and
1029
// assign a Variable for the incoming (register) value.
1030
String JavaDoc vname
1031              = Compilation.mangleName(decl.getName()).intern();
1032            Type vtype = decl.getType().getImplementationType();
1033            var = decl.var = getVarScope().addVariable(null, vtype, vname);
1034            //getVarScope().addVariableAfter(var, decl);
1035
var.setParameter (true);
1036            //var.allocateLocal(code);
1037
}
1038        decl = decl.nextDecl();
1039      }
1040
1041    declareClosureEnv();
1042
1043    allocFrame(comp);
1044
1045    allocChildMethods(comp);
1046  }
1047
1048  void allocChildMethods (Compilation comp)
1049  {
1050    for (LambdaExp child = firstChild; child != null;
1051     child = child.nextSibling)
1052      {
1053    if (! child.isClassGenerated() && ! child.getInlineOnly())
1054      {
1055        ObjectType closureEnvType;
1056        if (! child.getNeedsClosureEnv())
1057          closureEnvType = null;
1058        else if (this instanceof ClassExp || this instanceof ModuleExp)
1059          closureEnvType = getCompiledClassType(comp);
1060            else
1061              {
1062                LambdaExp owner = this;
1063                while (owner.heapFrame == null)
1064          owner = owner.outerLambda();
1065                closureEnvType = (ClassType) owner.heapFrame.getType();
1066              }
1067        child.addMethodFor(comp, closureEnvType);
1068      }
1069      }
1070  }
1071
1072  public void allocFrame (Compilation comp)
1073  {
1074    if (heapFrame != null)
1075      {
1076    ClassType frameType;
1077    if (this instanceof ModuleExp || this instanceof ClassExp)
1078      frameType = getCompiledClassType(comp);
1079    else
1080      {
1081        frameType = new ClassType(comp.generateClassName("frame"));
1082        frameType.setSuper(comp.getModuleType());
1083        comp.addClass(frameType);
1084      }
1085    heapFrame.setType(frameType);
1086      }
1087  }
1088
1089  void allocParameters (Compilation comp)
1090  {
1091    CodeAttr code = comp.getCode();
1092
1093    int i = 0;
1094    int j = 0;
1095
1096    code.locals.enterScope(getVarScope());
1097    int line = getLineNumber();
1098    if (line > 0)
1099      code.putLineNumber(getFileName(), line);
1100
1101    for (Declaration decl = firstDecl(); decl != null; )
1102      {
1103    // If the only reason we are using an argsArray is because there
1104
// are more than 4 arguments, copy the arguments in local register.
1105
// Then forget about the args array. We do this first, before
1106
// the label that tail-recursion branches back to.
1107
// This way, a self-tail-call knows where to leave the argumnents.
1108
if (argsArray != null && min_args == max_args
1109        && primMethods == null
1110        && getCallConvention() < Compilation.CALL_WITH_CONSUMER)
1111      {
1112        code.emitLoad(argsArray);
1113        code.emitPushInt(j);
1114        code.emitArrayLoad(Type.pointer_type);
1115        decl.getType().emitCoerceFromObject(code);
1116        code.emitStore(decl.getVariable());
1117      }
1118    j++;
1119    i++;
1120    decl = decl.nextDecl();
1121      }
1122    if (heapFrame != null)
1123      heapFrame.allocateLocal(code);
1124  }
1125
1126  static Method searchForKeywordMethod3;
1127  static Method searchForKeywordMethod4;
1128
1129  /** Rembembers stuff to do in <init> of this class. */
1130  Initializer initChain;
1131
1132  void enterFunction (Compilation comp)
1133  {
1134    CodeAttr code = comp.getCode();
1135
1136    // Tail-calls loop back to here!
1137
getVarScope().setStartPC(code);
1138
1139    if (closureEnv != null && ! closureEnv.isParameter()
1140    && ! comp.usingCPStyle())
1141      {
1142    if (! getInlineOnly())
1143      {
1144        code.emitPushThis();
1145        Field field = closureEnvField;
1146        if (field == null)
1147          field = outerLambda().closureEnvField;
1148        code.emitGetField(field);
1149        code.emitStore(closureEnv);
1150      }
1151    else if (! inlinedIn(outerLambda()))
1152      {
1153        outerLambda().loadHeapFrame(comp);
1154        code.emitStore(closureEnv);
1155      }
1156      }
1157    if (! comp.usingCPStyle())
1158      {
1159    ClassType frameType = heapFrame == null
1160          ? currentModule().getCompiledClassType(comp)
1161          : (ClassType) heapFrame.getType();
1162    for (Declaration decl = capturedVars; decl != null;
1163         decl = decl.nextCapturedVar)
1164      {
1165        if (decl.field != null)
1166          continue;
1167            decl.makeField(frameType, comp, null);
1168      }
1169      }
1170    if (heapFrame != null && ! comp.usingCPStyle())
1171      {
1172    ClassType frameType = (ClassType) heapFrame.getType();
1173    if (closureEnv != null && ! (this instanceof ModuleExp))
1174      staticLinkField = frameType.addField("staticLink",
1175                           closureEnv.getType());
1176        if (! (this instanceof ModuleExp) && ! (this instanceof ClassExp))
1177          {
1178        code.emitNew(frameType);
1179        code.emitDup(frameType);
1180        Method constructor = Compilation.getConstructor(frameType, this);
1181        code.emitInvokeSpecial(constructor);
1182
1183            if (staticLinkField != null)
1184              {
1185                code.emitDup(heapFrame.getType());
1186                code.emitLoad(closureEnv);
1187                code.emitPutField(staticLinkField);
1188              }
1189            code.emitStore(heapFrame);
1190          }
1191      }
1192
1193    Variable argsArray = this.argsArray;
1194    if (min_args == max_args && ! Compilation.fewerClasses
1195    && primMethods == null
1196    && getCallConvention () < Compilation.CALL_WITH_CONSUMER)
1197      argsArray = null;
1198
1199    // For each non-artificial parameter, copy it from its incoming
1200
// location (a local variable register, or the argsArray) into
1201
// its home location, if they are different.
1202
int i = 0;
1203    int opt_i = 0;
1204    int key_i = 0;
1205    int key_args = keywords == null ? 0 : keywords.length;
1206    int opt_args = defaultArgs == null ? 0
1207      : defaultArgs.length - key_args;
1208    if (this instanceof ModuleExp)
1209      return;
1210    // If plainArgs>=0, it is the number of arguments *not* in argsArray.
1211
int plainArgs = -1;
1212    int defaultStart = 0;
1213    Method mainMethod = getMainMethod();
1214    Variable callContextSave = comp.callContextVar;
1215
1216    for (Declaration param = firstDecl(); param != null; param = param.nextDecl())
1217      {
1218        comp.callContextVar
1219          = (getCallConvention() < Compilation.CALL_WITH_CONSUMER ? null
1220             : getVarScope().lookup("$ctx"));
1221    if (param == firstArgsArrayArg && argsArray != null)
1222      {
1223        if (primMethods != null)
1224          {
1225        plainArgs = i;
1226        defaultStart = plainArgs - min_args;
1227          }
1228        else
1229          {
1230        plainArgs = 0;
1231        defaultStart = 0;
1232          }
1233      }
1234    if (plainArgs >= 0 || ! param.isSimple()
1235        || param.isIndirectBinding())
1236      {
1237        Type paramType = param.getType();
1238        Type stackType
1239          = (mainMethod == null || plainArgs >= 0 ? Type.pointer_type
1240         : paramType);
1241        // If the parameter is captured by an inferior lambda,
1242
// then the incoming parameter needs to be copied into its
1243
// slot in the heapFrame. Thus we emit an aaload instruction.
1244
// Unfortunately, it expects the new value *last*,
1245
// so first push the heapFrame array and the array index.
1246
if (!param.isSimple ())
1247          param.loadOwningObject(null, comp);
1248        // This part of the code pushes the incoming argument.
1249
if (plainArgs < 0)
1250          {
1251        // Simple case: Use Incoming register.
1252
code.emitLoad(param.getVariable());
1253          }
1254            else if (i < min_args)
1255          { // This is a required parameter, in argsArray[i].
1256
code.emitLoad(argsArray);
1257        code.emitPushInt(i);
1258        code.emitArrayLoad(Type.pointer_type);
1259          }
1260            else if (i < min_args + opt_args)
1261          { // An optional parameter
1262
code.emitPushInt(i - plainArgs);
1263                code.emitLoad(argsArray);
1264        code.emitArrayLength();
1265        code.emitIfIntLt();
1266                code.emitLoad(argsArray);
1267        code.emitPushInt(i - plainArgs);
1268        code.emitArrayLoad(Type.pointer_type);
1269        code.emitElse();
1270        defaultArgs[defaultStart + opt_i++].compile(comp, paramType);
1271        code.emitFi();
1272          }
1273        else if (max_args < 0 && i == min_args + opt_args)
1274          {
1275        // This is the "rest" parameter (i.e. following a "."):
1276
// Convert argsArray[i .. ] to a list.
1277
code.emitLoad(argsArray);
1278        code.emitPushInt(i - plainArgs);
1279        code.emitInvokeStatic(Compilation.makeListMethod);
1280        stackType = Compilation.scmListType;
1281              }
1282        else
1283          { // Keyword argument.
1284
code.emitLoad(argsArray);
1285        code.emitPushInt(min_args + opt_args - plainArgs);
1286        comp.compileConstant(keywords[key_i++]);
1287        Expression defaultArg = defaultArgs[defaultStart + opt_i++];
1288        // We can generate better code if the defaultArg expression
1289
// has no side effects. For simplicity and safety, we just
1290
// special case literals, which handles most cases.
1291
if (defaultArg instanceof QuoteExp)
1292          {
1293            if (searchForKeywordMethod4 == null)
1294              {
1295            Type[] argts = new Type[4];
1296            argts[0] = Compilation.objArrayType;
1297            argts[1] = Type.int_type;
1298            argts[2] = Type.pointer_type;
1299            argts[3] = Type.pointer_type;
1300            searchForKeywordMethod4
1301              = Compilation.scmKeywordType.addMethod
1302              ("searchForKeyword", argts,
1303               Type.pointer_type, Access.PUBLIC|Access.STATIC);
1304              }
1305            defaultArg.compile(comp, paramType);
1306            code.emitInvokeStatic(searchForKeywordMethod4);
1307          }
1308        else
1309          {
1310            if (searchForKeywordMethod3 == null)
1311              {
1312            Type[] argts = new Type[3];
1313            argts[0] = Compilation.objArrayType;
1314            argts[1] = Type.int_type;
1315            argts[2] = Type.pointer_type;
1316            searchForKeywordMethod3
1317              = Compilation.scmKeywordType.addMethod
1318              ("searchForKeyword", argts,
1319               Type.pointer_type, Access.PUBLIC|Access.STATIC);
1320              }
1321            code.emitInvokeStatic(searchForKeywordMethod3);
1322            code.emitDup(1);
1323            comp.compileConstant(Special.dfault);
1324            code.emitIfEq();
1325            code.emitPop(1);
1326            defaultArg.compile(comp, paramType);
1327            code.emitFi();
1328          }
1329          }
1330        // Now finish copying the incoming argument into its
1331
// home location.
1332
if (paramType != stackType)
1333          CheckedTarget.emitCheckedCoerce(comp, this, i+1, paramType);
1334        if (param.isIndirectBinding())
1335              param.pushIndirectBinding(comp);
1336        if (param.isSimple())
1337          code.emitStore(param.getVariable());
1338            else
1339          code.emitPutField(param.field);
1340      }
1341    i++;
1342      }
1343    comp.callContextVar = callContextSave;
1344  }
1345
1346  void compileChildMethods (Compilation comp)
1347  {
1348    for (LambdaExp child = firstChild; child != null; )
1349      {
1350    if (! child.getCanRead() && ! child.getInlineOnly())
1351      {
1352        child.compileAsMethod(comp);
1353      }
1354    child = child.nextSibling;
1355      }
1356  }
1357
1358  void compileAsMethod (Compilation comp)
1359  {
1360    if ((flags & METHODS_COMPILED) != 0)
1361      return;
1362    flags |= METHODS_COMPILED;
1363    Method save_method = comp.method;
1364    LambdaExp save_lambda = comp.curLambda;
1365    comp.curLambda = this;
1366
1367    Method method = primMethods[0];
1368    boolean isStatic = method.getStaticFlag();
1369    int numStubs = primMethods.length - 1;
1370    Type restArgType = restArgType();
1371
1372    int[] saveDeclFlags = null;
1373    if (numStubs > 0)
1374      {
1375    saveDeclFlags = new int[min_args + numStubs];
1376    int k = 0;
1377    for (Declaration decl = firstDecl();
1378         k < min_args + numStubs; decl = decl.nextDecl())
1379      saveDeclFlags[k++] = decl.flags;
1380      }
1381
1382    boolean ctxArg = getCallConvention () >= Compilation.CALL_WITH_CONSUMER;
1383
1384    for (int i = 0; i <= numStubs; i++)
1385      {
1386    comp.method = primMethods[i];
1387    if (i < numStubs)
1388      {
1389        CodeAttr code = comp.method.startCode();
1390        int toCall = i + 1;
1391        while (toCall < numStubs
1392           && defaultArgs[toCall] instanceof QuoteExp)
1393          toCall++;
1394        boolean varArgs = toCall == numStubs && restArgType != null;
1395        Declaration decl;
1396            Variable callContextSave = comp.callContextVar;
1397        Variable var = code.getArg(0);
1398        if (! isStatic)
1399          {
1400        code.emitPushThis();
1401        if (getNeedsClosureEnv())
1402          closureEnv = var;
1403        var = code.getArg(1);
1404          }
1405        decl = firstDecl();
1406        for (int j = 0; j < min_args + i; j++, decl = decl.nextDecl())
1407          {
1408        decl.flags |= Declaration.IS_SIMPLE;
1409        decl.var = var;
1410        code.emitLoad(var);
1411        var = var.nextVar();
1412          }
1413        comp.callContextVar = ctxArg ? var : null;
1414        for (int j = i; j < toCall; j++, decl = decl.nextDecl())
1415          {
1416        Target paramTarget = StackTarget.getInstance(decl.getType());
1417        defaultArgs[j].compile(comp, paramTarget);
1418          }
1419        if (varArgs)
1420          {
1421        Expression arg;
1422        String JavaDoc lastTypeName = restArgType.getName();
1423        if ("gnu.lists.LList".equals(lastTypeName))
1424          arg = new QuoteExp(gnu.lists.LList.Empty);
1425        else if ("java.lang.Object[]".equals(lastTypeName))
1426          arg = new QuoteExp(Values.noArgs);
1427        else // FIXME
1428
throw new Error JavaDoc("unimplemented #!rest type "+lastTypeName);
1429        arg.compile(comp, restArgType);
1430          }
1431        if (ctxArg)
1432          code.emitLoad(var);
1433        if (isStatic)
1434          code.emitInvokeStatic(primMethods[toCall]);
1435        else
1436          code.emitInvokeVirtual(primMethods[toCall]);
1437        code.emitReturn();
1438        closureEnv = null;
1439            comp.callContextVar = callContextSave;
1440      }
1441    else
1442      {
1443        if (saveDeclFlags != null)
1444          {
1445        int k = 0;
1446        for (Declaration decl = firstDecl();
1447             k < min_args + numStubs; decl = decl.nextDecl())
1448          {
1449            decl.flags = saveDeclFlags[k++];
1450            decl.var = null;
1451          }
1452          }
1453        comp.method.initCode();
1454        allocChildClasses(comp);
1455        allocParameters(comp);
1456        enterFunction(comp);
1457
1458        compileBody(comp);
1459        compileEnd(comp);
1460      }
1461      }
1462
1463    compileChildMethods(comp);
1464    comp.method = save_method;
1465    comp.curLambda = save_lambda;
1466  }
1467
1468  public void compileBody (Compilation comp)
1469  {
1470    Target target;
1471    Variable callContextSave = comp.callContextVar;
1472    comp.callContextVar = null;
1473    if (getCallConvention() >= Compilation.CALL_WITH_CONSUMER)
1474      {
1475    Variable var = getVarScope().lookup("$ctx");
1476    if (var != null && var.getType() == Compilation.typeCallContext)
1477          comp.callContextVar = var;
1478        target = ConsumerTarget.makeContextTarget(comp);
1479      }
1480    else
1481      target = Target.pushValue(getReturnType());
1482    body.compileWithPosition(comp, target,
1483                 body.getLineNumber() > 0 ? body : this);
1484    comp.callContextVar = callContextSave;
1485  }
1486
1487  /** A cache if this has already been evaluated. */
1488  Procedure thisValue;
1489
1490  protected Expression walk (ExpWalker walker)
1491  {
1492    return walker.walkLambdaExp(this);
1493  }
1494
1495  protected void walkChildren(ExpWalker walker)
1496  {
1497    walkChildrenOnly(walker);
1498    walkProperties(walker);
1499  }
1500
1501  protected final void walkChildrenOnly(ExpWalker walker)
1502  {
1503    LambdaExp save = walker.currentLambda;
1504    walker.currentLambda = this;
1505    try
1506      {
1507    walker.walkDefaultArgs(this);
1508    if (walker.exitValue == null && body != null)
1509      body = walker.walk(body);
1510      }
1511    finally
1512      {
1513    walker.currentLambda = save;
1514      }
1515  }
1516
1517  protected final void walkProperties(ExpWalker walker)
1518  {
1519    if (properties != null)
1520      {
1521    int len = properties.length;
1522    for (int i = 1; i < len; i += 2)
1523      {
1524        Object JavaDoc val = properties[i];
1525        if (val instanceof Expression)
1526          {
1527        properties[i] = walker.walk((Expression) properties[i]);
1528          }
1529      }
1530      }
1531  }
1532
1533  protected boolean mustCompile ()
1534  {
1535    if (keywords != null && keywords.length > 0)
1536      return true;
1537    if (defaultArgs != null)
1538      {
1539        for (int i = defaultArgs.length; --i >= 0; )
1540          {
1541            Expression def = defaultArgs[i];
1542            // Non-constant default arguments require care with scoping.
1543
if (def != null && ! (def instanceof QuoteExp))
1544              return true;
1545          }
1546      }
1547    return false;
1548  }
1549
1550  public void apply (CallContext ctx) throws Throwable JavaDoc
1551  {
1552    // It would be better to call setIndexes at compile-time, but that
1553
// doesn't work if we're called as a syntax expander at rewrite time.
1554
// Better, if this is a top-level eval, to create a "compile-time" module,
1555
// but I haven't figured out how to do that. FIXME.
1556
setIndexes();
1557    ctx.writeValue(new Closure(this, ctx));
1558  }
1559
1560  public Expression inline (ApplyExp exp, InlineCalls walker, Declaration decl)
1561  {
1562    int args_length = exp.args.length;
1563    String JavaDoc msg = WrongArguments.checkArgCount(getName(),
1564                                              min_args, max_args, args_length);
1565    if (msg != null)
1566      return walker.noteError(msg);
1567    int conv = getCallConvention();
1568    Compilation comp = walker.getCompilation();
1569    Method method;
1570    if (comp.inlineOk(this) && isClassMethod()
1571        && (conv <= Compilation.CALL_WITH_CONSUMER
1572            || (conv == Compilation.CALL_WITH_TAILCALLS))
1573        && (method = getMethod(args_length)) != null)
1574      {
1575        // This is an optimization to expand a call to a method in the
1576
// same ClassExp. The result is a call to a PrimProcedure instead.
1577
// This isn't just an optimization, since the re-write is
1578
// needed to ensure that if we're in an inner lambda that the
1579
// $this$ declaration is captured in a closure.
1580
PrimProcedure mproc = new PrimProcedure(method, this);
1581        Expression[] margs;
1582        if (mproc.getStaticFlag())
1583          margs = exp.args;
1584        else
1585          {
1586            LambdaExp curLambda = walker.getCurrentLambda();
1587            for (;;)
1588              {
1589                if (curLambda == null)
1590                  return walker.noteError("internal error: missing "+this);
1591                if (curLambda.outer == outer) // I.e. same class.
1592
break;
1593                curLambda = curLambda.outerLambda();
1594              }
1595            Declaration d = curLambda.firstDecl();
1596            if (d==null || ! d.isThisParameter())
1597              return walker.noteError("calling non-static method "
1598                                      +getName()+" from static method "
1599                                      +curLambda.getName());
1600            int nargs = exp.getArgCount();
1601            margs = new Expression[1 + nargs];
1602            System.arraycopy(exp.getArgs(), 0, margs, 1, nargs);
1603            margs[0] = new ThisExp(d);
1604          }
1605        ApplyExp nexp = new ApplyExp(mproc, margs);
1606        return nexp.setLine(exp);
1607      }
1608    return exp;
1609  }
1610
1611  public void print (OutPort out)
1612  {
1613    out.startLogicalBlock("(Lambda/", ")", 2);
1614    Object JavaDoc sym = getSymbol();
1615    if (sym != null)
1616      {
1617    out.print(sym);
1618    out.print('/');
1619      }
1620    out.print(id);
1621    out.print('/');
1622    out.print("fl:"); out.print(Integer.toHexString(flags));
1623    out.writeSpaceFill();
1624    printLineColumn(out);
1625    out.startLogicalBlock("(", false, ")");
1626    Special prevMode = null;
1627    int i = 0;
1628    int opt_i = 0;
1629    int key_args = keywords == null ? 0 : keywords.length;
1630    int opt_args = defaultArgs == null ? 0 : defaultArgs.length - key_args;
1631    Declaration decl = firstDecl();
1632    if (decl != null && decl.isThisParameter())
1633      i = -1;
1634    for (; decl != null; decl = decl.nextDecl())
1635      {
1636    Special mode;
1637    if (i < min_args)
1638      mode = null;
1639    else if (i < min_args + opt_args)
1640      mode = Special.optional;
1641    else if (max_args < 0 && i == min_args + opt_args)
1642      mode = Special.rest;
1643    else
1644      mode = Special.key;
1645    if (decl != firstDecl())
1646       out.writeSpaceFill();
1647    if (mode != prevMode)
1648      {
1649        out.print(mode);
1650        out.writeSpaceFill();
1651      }
1652    Expression defaultArg = null;
1653    if (mode == Special.optional || mode == Special.key)
1654      defaultArg = defaultArgs[opt_i++];
1655    if (defaultArg != null)
1656      out.print('(');
1657    decl.printInfo(out);
1658    if (defaultArg != null && defaultArg != QuoteExp.falseExp)
1659      {
1660        out.print(' ');
1661        defaultArg.print(out);
1662        out.print(')');
1663      }
1664    i++;
1665    prevMode = mode;
1666      }
1667    out.endLogicalBlock(")");
1668    out.writeSpaceLinear();
1669    if (body == null)
1670      out.print("<null body>");
1671    else
1672      body.print(out);
1673    out.endLogicalBlock(")");
1674  }
1675
1676  protected final String JavaDoc getExpClassName()
1677  {
1678    String JavaDoc cname = getClass().getName();
1679    int index = cname.lastIndexOf('.');
1680    if (index >= 0)
1681      cname = cname.substring(index+1);
1682    return cname;
1683  }
1684
1685  public String JavaDoc toString()
1686  {
1687    String JavaDoc str = getExpClassName()+':'+getSymbol()+'/'+id+'/';
1688
1689    int l = getLineNumber();
1690    if (l <= 0 && body != null)
1691      l = body.getLineNumber();
1692    if (l > 0)
1693      str = str + "l:" + l;
1694
1695    return str;
1696  }
1697
1698  /** If non-null, a sequence of (key, value)-pairs.
1699   * These will be used to call setProperty at run-time. */

1700  Object JavaDoc[] properties;
1701
1702  public Object JavaDoc getProperty(Object JavaDoc key, Object JavaDoc defaultValue)
1703  {
1704    if (properties != null)
1705      {
1706    for (int i = properties.length; (i -= 2) >= 0; )
1707      {
1708        if (properties[i] == key)
1709          return properties[i + 1];
1710      }
1711      }
1712    return defaultValue;
1713  }
1714
1715  public synchronized void setProperty(Object JavaDoc key, Object JavaDoc value)
1716  {
1717    properties = PropertySet.setProperty(properties, key, value);
1718  }
1719
1720  /** If non-null, the type of values returned by this function.
1721   * If null, the return type has not been set or calculated yet. */

1722  public Type returnType;
1723
1724  /** The return type of this function, i.e the type of its returned values. */
1725  public final Type getReturnType()
1726  {
1727    if (returnType == null)
1728      {
1729    returnType = Type.pointer_type; // To guards against cycles.
1730
// body may not be set if define scan'd but not yet rewrit'ten.
1731
if (body != null)
1732      returnType = body.getType();
1733      }
1734    return returnType;
1735  }
1736
1737  /* Set the return type of this function. */
1738  public final void setReturnType (Type returnType)
1739  {
1740    this.returnType = returnType;
1741  }
1742}
1743
1744class Closure extends MethodProc
1745{
1746  Object JavaDoc[][] evalFrames;
1747  LambdaExp lambda;
1748
1749  public int numArgs() { return lambda.min_args | (lambda.max_args << 12); }
1750
1751  public Closure (LambdaExp lexp, CallContext ctx)
1752  {
1753    this.lambda = lexp;
1754
1755    Object JavaDoc[][] oldFrames = ctx.evalFrames;
1756    if (oldFrames != null)
1757      {
1758        int n = oldFrames.length;
1759        while (n > 0 && oldFrames[n-1] == null)
1760          n--;
1761
1762        evalFrames = new Object JavaDoc[n][];
1763        System.arraycopy(oldFrames, 0, evalFrames, 0, n);
1764      }
1765    setSymbol(lambda.getSymbol());
1766  }
1767
1768  public int match0 (CallContext ctx)
1769  {
1770    return matchN(new Object JavaDoc[] { }, ctx);
1771  }
1772
1773  public int match1 (Object JavaDoc arg1, CallContext ctx)
1774  {
1775    return matchN(new Object JavaDoc[] { arg1 }, ctx);
1776  }
1777
1778  public int match2 (Object JavaDoc arg1, Object JavaDoc arg2, CallContext ctx)
1779  {
1780    return matchN(new Object JavaDoc[] { arg1, arg2 }, ctx);
1781  }
1782
1783  public int match3 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3, CallContext ctx)
1784  {
1785    return matchN(new Object JavaDoc[] { arg1, arg2, arg3 }, ctx);
1786  }
1787
1788  public int match4 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3, Object JavaDoc arg4,
1789                     CallContext ctx)
1790  {
1791    return matchN(new Object JavaDoc[] { arg1, arg2, arg3, arg4 }, ctx);
1792  }
1793
1794  public int matchN (Object JavaDoc[] args, CallContext ctx)
1795  {
1796    int num = numArgs();
1797    int nargs = args.length;
1798    int min = num & 0xFFF;
1799    if (nargs < min)
1800      return MethodProc.NO_MATCH_TOO_FEW_ARGS|min;
1801    int max = num >> 12;
1802    if (nargs > max && max >= 0)
1803      return MethodProc.NO_MATCH_TOO_MANY_ARGS|max;
1804
1805    Object JavaDoc[] evalFrame = new Object JavaDoc[lambda.frameSize];
1806    int key_args = lambda.keywords == null ? 0 : lambda.keywords.length;
1807    int opt_args = lambda.defaultArgs == null ? 0
1808      : lambda.defaultArgs.length - key_args;
1809    int i = 0;
1810    int opt_i = 0;
1811    int min_args = lambda.min_args;
1812    for (Declaration decl = lambda.firstDecl(); decl != null;
1813         decl = decl.nextDecl())
1814      {
1815        Object JavaDoc value;
1816    if (i < min_args)
1817      value = args[i++];
1818    else if (i < min_args + opt_args)
1819          {
1820            if (i < nargs)
1821              value = args[i++];
1822            else
1823              value = ((QuoteExp) lambda.defaultArgs[opt_i++]).getValue();
1824          }
1825    else if (lambda.max_args < 0 && i == min_args + opt_args)
1826          {
1827            if (decl.type instanceof ArrayType)
1828              {
1829                int rem = nargs - i;
1830                Type elementType = ((ArrayType) decl.type).getComponentType();
1831                if (elementType == Type.pointer_type)
1832                  {
1833                    Object JavaDoc[] rest = new Object JavaDoc[rem];
1834                    System.arraycopy(args, i, rest, 0, rem);
1835                    value = rest;
1836                  }
1837                else
1838                  {
1839                    Class JavaDoc elementClass = elementType.getReflectClass();
1840                    value
1841                      = java.lang.reflect.Array.newInstance(elementClass, rem);
1842                    for (int j = 0; j < rem; j++)
1843                      {
1844                        Object JavaDoc el;
1845                        try
1846                          {
1847                            el = elementType.coerceFromObject(args[i+j]);
1848                          }
1849                        catch (ClassCastException JavaDoc ex)
1850                          {
1851                            return NO_MATCH_BAD_TYPE|(i+j);
1852                          }
1853                        java.lang.reflect.Array.set(value, j, el);
1854                      }
1855                  }
1856              }
1857            else
1858              value = LList.makeList(args, i);
1859          }
1860        else // Should never happen
1861
return MethodProc.NO_MATCH_TOO_MANY_ARGS|max;
1862        if (decl.type != null)
1863          {
1864            try
1865              {
1866                value = decl.type.coerceFromObject(value);
1867              }
1868            catch (ClassCastException JavaDoc ex)
1869              {
1870                return NO_MATCH_BAD_TYPE|i;
1871              }
1872          }
1873        if (decl.isIndirectBinding())
1874          {
1875            gnu.mapping.Location loc = decl.makeIndirectLocationFor();
1876            loc.set(value);
1877            value = loc;
1878          }
1879        evalFrame[decl.evalIndex] = value;
1880      }
1881    ctx.values = evalFrame;
1882    ctx.where = 0;
1883    ctx.next = 0;
1884    ctx.proc = this;
1885    return 0; // FIXME
1886
}
1887
1888  public void apply (CallContext ctx) throws Throwable JavaDoc
1889  {
1890    int level = ScopeExp.nesting(lambda);
1891    Object JavaDoc[] evalFrame = ctx.values;
1892    Object JavaDoc[][] saveFrames = ctx.evalFrames;
1893
1894    int numFrames = evalFrames == null ? 0 : evalFrames.length;
1895    if (level >= numFrames)
1896      numFrames = level;
1897    numFrames += 10;
1898    Object JavaDoc[][] newFrames = new Object JavaDoc[numFrames][];
1899    if (evalFrames != null)
1900      System.arraycopy(evalFrames, 0, newFrames, 0, evalFrames.length);
1901    newFrames[level] = evalFrame;
1902    ctx.evalFrames = newFrames;
1903
1904    try
1905      {
1906        lambda.body.apply(ctx);
1907      }
1908    finally
1909      {
1910        ctx.evalFrames = saveFrames;
1911      }
1912  }
1913
1914  public Object JavaDoc getProperty(Object JavaDoc key, Object JavaDoc defaultValue)
1915  {
1916    Object JavaDoc value = super.getProperty(key, defaultValue);
1917    if (value == null)
1918      value = lambda.getProperty(key, defaultValue);
1919    return value;
1920  }
1921}
1922
Popular Tags