KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > expr > Compilation


1 // Copyright (c) 1999, 2000-2005, 2006 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 java.util.*;
8 import java.io.*;
9 import kawa.Shell;
10 import gnu.text.*;
11 import java.util.zip.*;
12 import java.util.Stack JavaDoc;
13
14 /** State for a single expression or module.
15  * For each top-level thing (expression or file) we compile or evaluate
16  * we create a new Compilation.
17  */

18
19 public class Compilation implements SourceLocator
20 {
21   /** True if the form is too complex to evaluate,and we must compile it.
22    * This is because it contains a construct we know how to compile, but not
23    * evaluate, and it it outside a function (which we always compile).
24    * This can be a let scope, or primitive procedure. */

25   public boolean mustCompile;
26
27   /** Used by LambdaExp.getSelectorValue if need to allocate new selector. */
28   int maxSelectorValue;
29
30   public ClassType curClass;
31   public ClassType mainClass;
32   /** Generated class that extends ModuleBody. Normally same as mainClass. */
33   public ClassType moduleClass;
34
35   public LambdaExp curLambda;
36   public ModuleExp mainLambda;
37   public Variable thisDecl;
38
39   /** Contains "$instance" if the module is static; otherwise null. */
40   Variable moduleInstanceVar;
41
42   /** A code, one of the following constants, indicating how far along
43    * we are in the parsing/compilation process.
44    * These codes are even integers for completed stages and odd integers
45    * for begun but not completed stages. */

46   private int state;
47   /** Returns a code indicating how far along
48    * we are in the parsing/compilation process. */

49   public int getState () { return state; }
50   public void setState (int state) { this.state = state; }
51   /** State code for initial pre-parse looking for module name. */
52   public static final int PROLOG_PARSING = 1;
53   /** We have determined the module name and class, but not finished parsing. */
54   public static final int PROLOG_PARSED = 2;
55   /** State code indicating the entire module has been parsed. */
56   public static final int BODY_PARSED = 4;
57   /** State code for lexical bindings having been resolved. */
58   public static final int RESOLVED = 6;
59   /** State code when various inlining and optimization passes are done. */
60   public static final int WALKED = 8;
61   /** State code that various compile-only data has been determined. */
62   public static final int COMPILE_SETUP = 10;
63   /** State code indicating the bytecode has been generated. */
64   public static final int COMPILED = 12;
65   /** State code indicating that bytecode has been written to its target. */
66   public static final int CLASS_WRITTEN = 14;
67   public static final int ERROR_SEEN = 100;
68
69   public ModuleInfo minfo;
70   public Lexer lexer;
71
72   boolean pedantic;
73   public boolean isPedantic() { return pedantic; }
74
75   /** Used to access the "main" instance.
76    * This is used for two different purposes, which may be confusing:
77    * <ul>
78    * <li>
79    * If we're compiling a static module, then {@code moduleInstanceMainField}
80    * is a field in {@code mainClass} named {@code "$instance"} that
81    * points to the single instance of the module.</li>
82    * <li>
83    * If {@code moduleClass!=mainClass} (typically because we've specified
84    * {@code module-extends}) <em>and</em> the module is non-static then
85    * {@code moduleInstanceMainField} is a field in {@code moduleClass}
86    * named {@code "$main"} that points back to {@code mainClass}.</li></ul>
87    */

88   Field moduleInstanceMainField;
89
90   public java.util.Stack JavaDoc pendingImports;
91
92   public void pushPendingImport (ModuleInfo info, ScopeExp defs)
93   {
94     if (pendingImports == null)
95       pendingImports = new java.util.Stack JavaDoc();
96     pendingImports.push(info);
97     pendingImports.push(defs);
98     Expression posExp = new ReferenceExp((Object JavaDoc) null);
99     posExp.setLine(this);
100     pendingImports.push(posExp);
101   }
102
103   /** If true, minimize the number of classes generated.
104    * Do this even if it makes things a little slower. */

105   public static boolean fewerClasses;
106
107   /** If true, print out expressions after parsing and before optimizations. */
108   public static boolean debugPrintExpr = false;
109
110   /** If true, print out final expressions after optimizations etc. */
111   public static boolean debugPrintFinalExpr;
112
113   public static Options options = new Options();
114   public Options currentOptions = new Options(options);
115   static {
116     options.add("warn-undefined-variable", Options.BOOLEAN_OPTION,
117         "warn if no compiler-visible binding for a variable");
118     options.add("warn-invoke-unknown-method", Options.BOOLEAN_OPTION,
119         "warn if invoke calls an unknown method");
120     options.add("warn-as-error", Options.BOOLEAN_OPTION,
121         "Make all warnings into errors");
122   }
123
124   /** Get a named boolean option. */
125   public final boolean getBooleanOption (String JavaDoc key, boolean defaultValue)
126   {
127     return currentOptions.getBoolean(key, defaultValue);
128   }
129
130   /** Get a named boolean option. */
131   public final boolean getBooleanOption (String JavaDoc key)
132   {
133     return currentOptions.getBoolean(key);
134   }
135
136   /** The default calling convention.
137    * One of the following CALL_WITHG_xxx values. */

138   public static int defaultCallConvention;
139   public static final int CALL_WITH_UNSPECIFIED = 0;
140   /** Plain calling convention, using regular Java parameters and returns. */
141   public static final int CALL_WITH_RETURN = 1;
142   /** Function results are written to the current CallContext's Consumer. */
143   public static final int CALL_WITH_CONSUMER = 2;
144   /** Like CALL_WITH_CONSUMER, but handle full on-stack-growing tail-calls. */
145   public static final int CALL_WITH_TAILCALLS = 3;
146   /** Support for full continuations. Not implemented. */
147   public static final int CALL_WITH_CONTINUATIONS = 4;
148
149   public boolean usingCPStyle()
150   { return defaultCallConvention == CALL_WITH_CONTINUATIONS; }
151   public boolean usingTailCalls()
152   { return defaultCallConvention >= CALL_WITH_TAILCALLS; }
153
154   /** If moduleStatic > 0, (module-static #t) is implied by default.
155    * If moduleStatic == 2, <clinit> calls run.
156    * If moduleStatic < 0, (module-static #f) is implied by default. */

157   public static int moduleStatic = 0;
158
159   ClassType[] classes;
160   int numClasses;
161
162   /** When immediate, the ClassLoader we will load the compiled
163    * classes from. */

164   ArrayClassLoader loader;
165
166   /** True if the compiled result will be immediately loaded. */
167   public boolean immediate;
168
169   /** The current method. */
170   public Method method;
171
172   Method clinitMethod;
173
174   public final CodeAttr getCode() { return method.getCode(); }
175
176   int method_counter;
177
178   /* When multiple procedures are compiled into a single method,
179      we use a switch to jump to the correct part of the method. */

180   SwitchState fswitch;
181
182   Field fswitchIndex;
183
184   // Various standard classes
185
static public ClassType typeObject = Type.pointer_type;
186   static public ClassType scmBooleanType = ClassType.make("java.lang.Boolean");
187   static public ClassType typeString = ClassType.make("java.lang.String");
188   static public ClassType javaStringType = typeString;
189   static public ClassType scmKeywordType = ClassType.make("gnu.expr.Keyword");
190   static public ClassType scmSequenceType = ClassType.make("gnu.lists.Sequence");
191   static public ClassType javaIntegerType = ClassType.make("java.lang.Integer");
192   static public ClassType scmListType = ClassType.make("gnu.lists.LList");
193   static public ClassType typePair = ClassType.make("gnu.lists.Pair");
194   static public ClassType scmPairType = typePair;
195   public static final ArrayType objArrayType = ArrayType.make(typeObject);
196   static public ClassType scmNamedType = ClassType.make("gnu.mapping.Named");
197   static public ClassType typeRunnable = ClassType.make("java.lang.Runnable");
198   public static ClassType typeType = ClassType.make("gnu.bytecode.Type");
199   public static ClassType typeObjectType
200     = ClassType.make("gnu.bytecode.ObjectType", typeType);
201   public static ClassType typeClass = Type.java_lang_Class_type;
202   static public ClassType typeClassType = ClassType.make("gnu.bytecode.ClassType", typeObjectType);
203   static public ClassType typeProcedure
204     = ClassType.make("gnu.mapping.Procedure");
205   static public ClassType typeLanguage
206     = ClassType.make("gnu.expr.Language");
207   static public ClassType typeEnvironment
208     = ClassType.make("gnu.mapping.Environment");
209   static public ClassType typeLocation
210     = ClassType.make("gnu.mapping.Location");
211   static public ClassType typeSymbol
212     = ClassType.make("gnu.mapping.Symbol");
213   static public final Method getSymbolValueMethod
214     = typeLanguage.getDeclaredMethod("getSymbolValue", 1);
215   static public final Method getSymbolProcedureMethod
216     = typeLanguage.getDeclaredMethod("getSymbolProcedure", 1);
217   static public final Method getLocationMethod
218     = typeLocation.addMethod("get", Type.typeArray0,
219                 Type.pointer_type, Access.PUBLIC);
220   static public final Method getProcedureBindingMethod
221     = typeSymbol.addMethod("getProcedure", Type.typeArray0,
222                 typeProcedure, Access.PUBLIC);
223   static public final Field trueConstant
224     = scmBooleanType.getDeclaredField("TRUE");
225   static public final Field falseConstant
226     = scmBooleanType.getDeclaredField("FALSE");
227
228   static final Method setNameMethod
229     = typeProcedure.getDeclaredMethod("setName", 1);
230   static Method makeListMethod;
231   
232   public static final Type[] int1Args = { Type.int_type };
233   public static final Type[] string1Arg = { javaStringType };
234   public static final Type[] sym1Arg = string1Arg;
235
236   static public final Method getLocation1EnvironmentMethod
237   = typeEnvironment.getDeclaredMethod("getLocation", 1);
238   static public final Method getLocation2EnvironmentMethod;
239   static {
240     Type[] args = { typeSymbol, Type.pointer_type };
241     getLocation2EnvironmentMethod
242       = typeEnvironment.addMethod("getLocation", args,
243                   typeLocation, Access.PUBLIC|Access.FINAL);
244   }
245
246   static {
247     Type[] makeListArgs = { objArrayType, Type.int_type };
248     makeListMethod = scmListType.addMethod ("makeList",
249                          makeListArgs, scmListType,
250                          Access.PUBLIC|Access.STATIC);
251   }
252
253   public static Method getCurrentEnvironmentMethod
254     = typeEnvironment.addMethod("getCurrent", Type.typeArray0,
255                 typeEnvironment,Access.PUBLIC|Access.STATIC);
256
257   public static Type[] apply0args = Type.typeArray0;
258   public static Type[] apply1args = { typeObject };
259   public static Type[] apply2args = { typeObject, typeObject };
260   public static Type[] applyNargs = { objArrayType };
261
262   static Method checkArgCountMethod;
263
264   public static Method apply0method = typeProcedure.addMethod
265   ("apply0", apply0args, typeObject, Access.PUBLIC|Access.FINAL);
266
267   public static Method apply1method;
268   public static Method apply2method;
269   public static Method apply3method;
270   public static Method apply4method;
271   public static Method applyNmethod;
272
273   static
274   {
275     apply1method = typeProcedure.addMethod ("apply1", apply1args,
276                         typeObject, Access.PUBLIC);
277     apply2method = typeProcedure.addMethod ("apply2", apply2args,
278                         typeObject, Access.PUBLIC);
279     Type[] apply3args = { typeObject, typeObject, typeObject };
280     apply3method = typeProcedure.addMethod ("apply3", apply3args,
281                         typeObject, Access.PUBLIC);
282     Type[] apply4args = { typeObject , typeObject, typeObject, typeObject};
283     apply4method = typeProcedure.addMethod ("apply4", apply4args,
284                         typeObject, Access.PUBLIC);
285     applyNmethod = typeProcedure.addMethod ("applyN", applyNargs,
286                         typeObject, Access.PUBLIC);
287     Type[] args = new Type[2];
288     args[0] = typeProcedure;
289     args[1] = Type.int_type;
290     checkArgCountMethod
291       = typeProcedure.addMethod("checkArgCount", args, Type.void_type,
292                    Access.PUBLIC|Access.STATIC);
293   }
294
295   public static Method[] applymethods = {
296     apply0method, apply1method, apply2method, apply3method,
297     apply4method, applyNmethod };
298
299   public static ClassType typeProcedure0
300     = ClassType.make("gnu.mapping.Procedure0", typeProcedure);
301   public static ClassType typeProcedure1
302     = ClassType.make("gnu.mapping.Procedure1", typeProcedure);
303   public static ClassType typeProcedure2
304     = ClassType.make("gnu.mapping.Procedure2", typeProcedure);
305   public static ClassType typeProcedure3
306     = ClassType.make("gnu.mapping.Procedure3", typeProcedure);
307   public static ClassType typeProcedure4
308     = ClassType.make("gnu.mapping.Procedure4", typeProcedure);
309   public static ClassType typeProcedureN
310     = ClassType.make("gnu.mapping.ProcedureN", typeProcedure);
311   public static ClassType typeModuleBody
312     = ClassType.make("gnu.expr.ModuleBody", typeProcedure0);
313   public static ClassType typeModuleWithContext
314     = ClassType.make("gnu.expr.ModuleWithContext", typeModuleBody);
315   public static ClassType typeApplet = ClassType.make("java.applet.Applet");
316   public static ClassType typeServlet = ClassType.make("gnu.kawa.servlet.KawaServlet");
317
318   /* Classes, fields, and methods used wgen usingCPStyle". */
319   public static ClassType typeCallContext
320     = ClassType.make("gnu.mapping.CallContext");
321   public static final ClassType typeConsumer
322     = ClassType.make("gnu.lists.Consumer");
323   public static Method getCallContextInstanceMethod
324     = typeCallContext.getDeclaredMethod("getInstance", 0);
325   public static ClassType typeValues
326     = ClassType.make("gnu.mapping.Values");
327   public static Field noArgsField
328     = typeValues.getDeclaredField("noArgs");
329   public static Field pcCallContextField
330     = typeCallContext.getDeclaredField("pc");
331   public static ClassType typeMethodProc
332   = ClassType.make("gnu.mapping.MethodProc", typeProcedureN);
333   public static ClassType typeModuleMethod
334   = ClassType.make("gnu.expr.ModuleMethod", typeMethodProc);
335   // public static Field numArgsCallFrameField = typeCallFrame.getDeclaredField("numArgs");
336
public static Field argsCallContextField
337     = typeCallContext.getDeclaredField("values");
338   public static Field procCallContextField
339     = typeCallContext.getDeclaredField("proc");
340   private static Type[] applyCpsArgs = { typeCallContext};
341   public static Method applyCpsMethod
342     = typeProcedure.addMethod("apply", applyCpsArgs, Type.void_type,
343                  Access.PUBLIC);
344
345   public static ClassType[] typeProcedureArray = {
346     typeProcedure0, typeProcedure1, typeProcedure2, typeProcedure3,
347     typeProcedure4 };
348
349   /** Rembembers stuff to do in <clinit> of main class. */
350   Initializer clinitChain;
351
352   public static boolean generateMainDefault = false;
353   /** True if we should generate a main(String[]) method. */
354   public boolean generateMain = generateMainDefault;
355
356   LitTable litTable;
357
358   public static boolean generateAppletDefault = false;
359   /** True if we should generate an Applet. */
360   public boolean generateApplet = generateAppletDefault;
361
362   public static boolean generateServletDefault = false;
363   /** True if we should generate an Servlet. */
364   public boolean generateServlet = generateServletDefault;
365
366   public final ClassType getModuleType()
367   {
368     return (defaultCallConvention >= Compilation.CALL_WITH_CONSUMER
369         ? typeModuleWithContext
370         : typeModuleBody);
371   }
372
373   /** Emit code to "evaluate" a compile-time constant.
374    * This is the normal external interface.
375    * @param value the value to be compiled
376    */

377   public void compileConstant (Object JavaDoc value)
378   {
379     gnu.bytecode.CodeAttr code = getCode();
380     if (value == null)
381       code.emitPushNull();
382     else if (value instanceof String JavaDoc && ! immediate)
383       code.emitPushString((String JavaDoc) value);
384     else
385       code.emitGetStatic(compileConstantToField(value));
386   }
387
388   public Field compileConstantToField (Object JavaDoc value)
389   {
390     Literal literal = litTable.findLiteral(value);
391     if (literal.field == null)
392       literal.assign(litTable);
393     return literal.field;
394   }
395
396   public static boolean inlineOk = true;
397
398   public boolean inlineOk (Expression proc)
399   {
400     if (proc instanceof LambdaExp)
401       {
402     // The compiler gets confused if we turn off inlining for nested
403
// procedures - and they can't be rebound anyway.
404
if (! (((LambdaExp) proc).currentLambda() instanceof ModuleExp))
405       return true;
406       }
407     return inlineOk;
408   }
409
410   public boolean inlineOk (Procedure proc)
411   {
412     return inlineOk;
413   }
414
415   public void compileConstant (Object JavaDoc value, Target target)
416   {
417     if (target instanceof IgnoreTarget)
418       return;
419     if (value instanceof Values)
420       {
421     Object JavaDoc[] values = ((Values) value).getValues();
422         int len = values.length;
423         if (target instanceof ConsumerTarget)
424           {
425             for (int i = 0; i < len; i++)
426               {
427                 compileConstant(values[i], target);
428               }
429             return;
430           }
431         else if (target instanceof SeriesTarget)
432           {
433             SeriesTarget starget = (SeriesTarget) target;
434             Label saveDone = starget.done;
435             if (len > 0)
436               {
437                 starget.done = null;
438                 for (int i = 0; i < len; i++)
439                   {
440                     if (i+1 == len)
441                       starget.done = saveDone;
442                     compileConstant(values[i], target);
443                   }
444               }
445             else if (saveDone != null && getCode().reachableHere())
446               getCode().emitGoto(saveDone);
447             return;
448           }
449       }
450     if (target instanceof ConditionalTarget)
451       {
452     ConditionalTarget ctarg = (ConditionalTarget) target;
453     getCode().emitGoto(getLanguage().isTrue(value) ? ctarg.ifTrue
454                : ctarg.ifFalse);
455     return;
456       }
457     if (target instanceof StackTarget)
458       {
459     Type type = ((StackTarget) target).getType();
460     if (type instanceof PrimType)
461       {
462         try
463           {
464         String JavaDoc signature = type.getSignature();
465         CodeAttr code = getCode();
466         char sig1 = (signature == null || signature.length() != 1) ? ' '
467           : signature.charAt(0);
468         if (value instanceof Number JavaDoc)
469           {
470             Number JavaDoc num = (Number JavaDoc) value;
471             switch (sig1)
472               {
473               case 'I':
474             code.emitPushInt(num.intValue());
475             return;
476               case 'S':
477             code.emitPushInt(num.shortValue());
478             return;
479               case 'B':
480             code.emitPushInt(num.byteValue());
481             return;
482               case 'J':
483             code.emitPushLong(num.longValue());
484             return;
485               case 'F':
486             code.emitPushFloat(num.floatValue());
487             return;
488               case 'D':
489             code.emitPushDouble(num.doubleValue());
490             return;
491               }
492           }
493         if (sig1 == 'C')
494           {
495             code.emitPushInt((int) ((PrimType) type).charValue(value));
496             return;
497           }
498         if (sig1 == 'Z')
499           {
500             boolean val = PrimType.booleanValue(value);
501             code.emitPushInt(val ? 1 : 0);
502             return;
503           }
504           }
505         catch (ClassCastException JavaDoc ex)
506           {
507         // should print an ERROR.
508
}
509       }
510         try
511           {
512             value = type.coerceFromObject(value);
513           }
514         catch (Exception JavaDoc ex)
515           {
516         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
517         if (value == Values.empty)
518           sbuf.append("cannot convert void to ");
519         else
520           {
521         sbuf.append("cannot convert literal (of type ");
522                 sbuf.append(value.getClass().getName());
523         sbuf.append(") to ");
524           }
525         sbuf.append(type.getName());
526             error('w', sbuf.toString());
527          }
528       }
529     compileConstant(value);
530     target.compileFromStack(this,
531                             value == null ? target.getType()
532                             : Type.make(value.getClass()));
533   }
534
535
536   private void dumpInitializers (Initializer inits)
537   {
538     for (Initializer init = Initializer.reverse(inits);
539          init != null; init = init.next)
540       init.emit(this);
541   }
542
543   /** Search this Compilation for a ClassType with a given name.
544    * @param name the name of the class desired
545    * @return the matching ClassType, or null if none is found */

546   public ClassType findNamedClass (String JavaDoc name)
547   {
548     for (int i = 0; i < numClasses; i++)
549       {
550     if (name.equals (classes[i].getName ()))
551       return classes[i];
552       }
553     return null;
554   }
555
556   public static String JavaDoc classPrefixDefault = "";
557   /** If non-null: a prefix for generateClassName to prepend to names. */
558   public String JavaDoc classPrefix = classPrefixDefault;
559
560   /** Recusive helper function to reverse order of words in hostname. */
561   private static void putURLWords(String JavaDoc name, StringBuffer JavaDoc sbuf)
562   {
563     int dot = name.indexOf('.');
564     if (dot > 0)
565       {
566     putURLWords(name.substring(dot+1), sbuf);
567     sbuf.append('.');
568     name = name.substring(0, dot);
569       }
570     sbuf.append(name);
571   }
572
573   /** Map a URI to a package/class name.
574    * Similar to the JAXB mangling, and that in the Java language spec.
575    */

576   public static String JavaDoc mangleURI (String JavaDoc name)
577   {
578     boolean hasSlash = name.indexOf('/') >= 0;
579     int len = name.length();
580     if (len > 6 && name.startsWith("class:"))
581       return name.substring(6);
582     // Remove "http:" or "urn:".
583
if (len > 5 && name.charAt(4) == ':'
584     && name.substring(0, 4).equalsIgnoreCase("http"))
585       {
586     name = name.substring(5);
587     len -= 5;
588     hasSlash = true;
589       }
590     else if (len > 4 && name.charAt(3) == ':'
591          && name.substring(0, 3).equalsIgnoreCase("uri"))
592       {
593     name = name.substring(4);
594     len -= 4;
595       }
596     int start = 0;
597     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
598     for (;;)
599       {
600     int slash = name.indexOf('/', start);
601     int end = slash < 0 ? len : slash;
602     boolean first = sbuf.length() == 0;
603     if (first && hasSlash)
604       {
605         // Remove initial "www.".
606
String JavaDoc host = name.substring(start, end);
607         if (end - start > 4 && host.startsWith("www."))
608           host = host.substring(4);
609         // Reverse order of words in "host" part.
610
putURLWords(host, sbuf);
611       }
612     else if (start != end)
613       {
614         if (! first)
615           sbuf.append('.');
616         if (end == len)
617           {
618         int dot = name.lastIndexOf('.', len);
619         if (dot > start + 1 && ! first)
620           {
621             // Remove file extension:
622
int extLen = len - dot;
623             if (extLen <= 4
624             || (extLen == 5 && name.endsWith("html")))
625               {
626             len -= extLen;
627             end = len;
628             name = name.substring(0, len);
629               }
630           }
631           }
632         sbuf.append(name.substring(start, end));
633       }
634     if (slash < 0)
635       break;
636     start = slash + 1;
637       }
638     return sbuf.toString();
639   }
640
641   public static String JavaDoc mangleName (String JavaDoc name)
642   {
643     return mangleName(name, -1);
644   }
645
646   public static String JavaDoc mangleNameIfNeeded (String JavaDoc name)
647   {
648     if (isValidJavaName(name))
649       return name;
650     else
651       return mangleName(name, 0);
652   }
653
654   public static boolean isValidJavaName(String JavaDoc name)
655   {
656     int len = name.length();
657     if (len == 0 || ! Character.isJavaIdentifierStart(name.charAt(0)))
658       return false;
659     for (int i = len; --i > 0; )
660       if (! Character.isJavaIdentifierPart(name.charAt(i)))
661     return false;
662     return true;
663   }
664
665   /** Convert a string to a safe Java identifier.
666    * @param reversible if we should use an invertible mapping.
667    */

668   public static String JavaDoc mangleName (String JavaDoc name, boolean reversible)
669   {
670     return mangleName(name, reversible ? 1 : -1);
671   }
672
673   /** Convert a string to a safe Java identifier.
674    * @param kind -1 - non-reversible;
675    * 0: reversible, except that '$' is not mapped;
676    * 1: reversible
677    */

678   public static String JavaDoc mangleName (String JavaDoc name, int kind)
679   {
680     boolean reversible = kind >= 0;
681     int len = name.length ();
682     if (len == 6 && name.equals("*init*")) // Constructor methods.
683
return "<init>";
684     StringBuffer JavaDoc mangled = new StringBuffer JavaDoc (len);
685     boolean upcaseNext = false;
686     for (int i = 0; i < len; i++)
687       {
688     char ch = name.charAt(i);
689     if (upcaseNext)
690       {
691         ch = Character.toTitleCase(ch);
692         upcaseNext = false;
693       }
694     if (Character.isDigit(ch))
695       {
696         if (i == 0)
697           mangled.append("$N");
698         mangled.append(ch);
699       }
700     else if (Character.isLetter(ch) || ch == '_')
701       mangled.append(ch);
702     else if (ch == '$')
703       mangled.append(kind > 1 ? "$$" : "$");
704     else
705       {
706         switch (ch)
707           {
708           case '+': mangled.append("$Pl"); break;
709           case '-':
710         if (reversible)
711           mangled.append("$Mn");
712         else
713           {
714             char next = i + 1 < len ? name.charAt(i+1) : '\0';
715             if (next == '>')
716               {
717             mangled.append("$To$");
718             i++;
719               }
720             else if (! Character.isLowerCase(next))
721               mangled.append("$Mn");
722           }
723         break;
724           case '*': mangled.append("$St"); break;
725           case '/': mangled.append("$Sl"); break;
726           case '=': mangled.append("$Eq"); break;
727           case '<': mangled.append("$Ls"); break;
728           case '>': mangled.append("$Gr"); break;
729           case '@': mangled.append("$At"); break;
730           case '~': mangled.append("$Tl"); break;
731           case '%': mangled.append("$Pc"); break;
732           case '.': mangled.append("$Dt"); break;
733           case ',': mangled.append("$Cm"); break;
734           case '(': mangled.append("$LP"); break;
735           case ')': mangled.append("$RP"); break;
736           case '[': mangled.append("$LB"); break;
737           case ']': mangled.append("$RB"); break;
738           case '{': mangled.append("$LC"); break;
739           case '}': mangled.append("$RC"); break;
740           case '\'': mangled.append("$Sq"); break;
741           case '"': mangled.append("$Dq"); break;
742           case '&': mangled.append("$Am"); break;
743           case '#': mangled.append("$Nm"); break;
744           case '?':
745         char first = mangled.length() > 0 ? mangled.charAt(0) : '\0';
746         if (! reversible
747             && i + 1 == len && Character.isLowerCase(first))
748           {
749             mangled.setCharAt(0, Character.toTitleCase(first));
750             mangled.insert(0, "is");
751           }
752         else
753           mangled.append("$Qu");
754         break;
755           case '!': mangled.append("$Ex"); break;
756           case ':': mangled.append("$Cl"); break;
757           case ';': mangled.append("$SC"); break;
758           case '^': mangled.append("$Up"); break;
759           case '|': mangled.append("$VB"); break;
760           default:
761         mangled.append('$');
762         mangled.append(Character.forDigit ((ch >> 12) & 15, 16));
763         mangled.append(Character.forDigit ((ch >> 8) & 15, 16));
764         mangled.append(Character.forDigit ((ch >> 4) & 15, 16));
765         mangled.append(Character.forDigit ((ch ) & 15, 16));
766           }
767         if (! reversible)
768           upcaseNext = true;
769       }
770       }
771     String JavaDoc mname = mangled.toString ();
772     return mname.equals(name) ? name : mname;
773   }
774
775   /** Demangle a three-character mangling starting with '$'.
776    * UNFINISHED!
777    */

778   public static char demangle2(char char1, char char2)
779   {
780     switch (char1 << 16 | char2)
781       {
782       case 'A' << 16 | 'm': return '&';
783       case 'A' << 16 | 't': return '@';
784       case 'C' << 16 | 'l': return ':';
785       case 'C' << 16 | 'm': return ',';
786       case 'D' << 16 | 'q': return '\"';
787       case 'D' << 16 | 't': return '.';
788       case 'E' << 16 | 'q': return '=';
789       case 'E' << 16 | 'x': return '!';
790       case 'G' << 16 | 'r': return '>';
791       case 'L' << 16 | 'B': return '[';
792       case 'L' << 16 | 'C': return '{';
793       case 'L' << 16 | 'P': return '(';
794       case 'L' << 16 | 's': return '<';
795       case 'M' << 16 | 'c': return '%';
796       case 'M' << 16 | 'n': return '-';
797       case 'N' << 16 | 'm': return '#';
798       case 'P' << 16 | 'c': return '%';
799       case 'P' << 16 | 'l': return '+';
800       case 'Q' << 16 | 'u': return '?';
801       case 'R' << 16 | 'B': return ']';
802       case 'R' << 16 | 'C': return '}';
803       case 'R' << 16 | 'P': return ')';
804       case 'S' << 16 | 'C': return ';';
805       case 'S' << 16 | 'l': return '/';
806       case 'S' << 16 | 'q': return '\\';
807       case 'S' << 16 | 't': return '*';
808       case 'T' << 16 | 'l': return '~';
809       case 'U' << 16 | 'p': return '^';
810       case 'V' << 16 | 'B': return '|';
811       }
812     return (char) (-1);
813   }
814
815   public static String JavaDoc demangleName(String JavaDoc name)
816   {
817     return demangleName(name, false);
818   }
819
820   public static String JavaDoc demangleName(String JavaDoc name, boolean reversible)
821   {
822     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
823     int len = name.length();
824     boolean mangled = false;
825     boolean predicate = false;
826     boolean downCaseNext = false;
827     for (int i = 0; i < len; i++)
828       {
829     char ch = name.charAt(i);
830     if (downCaseNext && ! reversible)
831       {
832         ch = Character.toLowerCase(ch);
833         downCaseNext = false;
834       }
835     char d;
836     if (!reversible
837         && ch == 'i' && i == 0 && len > 2 && name.charAt(i+1) == 's'
838         && ! Character.isLowerCase(d = name.charAt(i+2)))
839       {
840         mangled = true;
841         predicate = true;
842         i++;
843         if (Character.isUpperCase(d) || Character.isTitleCase(d))
844           {
845         sbuf.append(Character.toLowerCase(d));
846         i++;
847         continue;
848           }
849         continue;
850       }
851     else if (ch == '$' && i + 2 < len)
852       {
853         char c1 = name.charAt(i+1);
854         char c2 = name.charAt(i+2);
855         d = Compilation.demangle2(c1, c2);
856         if (d != (char)(-1))
857           {
858         sbuf.append(d);
859         i += 2;
860         mangled = true;
861         downCaseNext = true;
862         continue;
863           }
864         else if (c1 == 'T' && c2 == 'o' && i + 3 < len
865              && name.charAt(i+3) == '$')
866           {
867         sbuf.append("->");
868         i += 3;
869         mangled = true;
870         downCaseNext = true;
871         continue;
872           }
873       }
874     else if (! reversible && i > 1
875          && (Character.isUpperCase(ch) || Character.isTitleCase(ch))
876          && (Character.isLowerCase(name.charAt(i-1))))
877       {
878         sbuf.append('-');
879         mangled = true;
880         ch = Character.toLowerCase(ch);
881       }
882     sbuf.append(ch);
883       }
884     if (predicate)
885       sbuf.append('?');
886     return mangled ? sbuf.toString() : name;
887   }
888
889   /** Generate an unused class name.
890    * @param hint the requested name (or prefix)
891    * @return a unique class name.
892    */

893   public String JavaDoc generateClassName (String JavaDoc hint)
894   {
895     hint = mangleName(hint, true);
896     if (mainClass != null)
897       hint = mainClass.getName() + '$' + hint;
898     else if (classPrefix != null)
899       hint = classPrefix + hint;
900     if (findNamedClass (hint) == null)
901       return hint;
902     for (int i = 0; ; i++)
903       {
904     String JavaDoc new_hint = hint + i;
905     if (findNamedClass (new_hint) == null)
906       return new_hint;
907       }
908   }
909
910   public Compilation (boolean immediate, SourceMessages messages)
911   {
912     this(messages);
913     this.immediate = immediate;
914   }
915
916   public Compilation (SourceMessages messages)
917   {
918     this.messages = messages;
919     lexical = new NameLookup(getLanguage());
920   }
921
922   public Compilation (Language language, SourceMessages messages)
923   {
924     this(language, messages, new NameLookup(language));
925   }
926
927   public Compilation (Language language, SourceMessages messages,
928               NameLookup lexical)
929   {
930     this.language = language;
931     this.messages = messages;
932     this.lexical = lexical;
933   }
934
935   /** Shared processing for both compiling/eval. */
936   public void walkModule (ModuleExp mexp)
937   {
938     if (debugPrintExpr)
939       {
940     OutPort dout = OutPort.errDefault();
941     dout.println("[Module:" + mexp.getName());
942     mexp.print(dout);
943     dout.println(']');
944     dout.flush();
945       }
946
947     InlineCalls.inlineCalls(mexp, this);
948     PushApply.pushApply(mexp);
949     ChainLambdas.chainLambdas(mexp, this);
950     FindTailCalls.findTailCalls(mexp, this);
951   }
952
953   public void outputClass (String JavaDoc directory) throws IOException
954   {
955     char dirSep = File.separatorChar;
956     for (int iClass = 0; iClass < numClasses; iClass++)
957       {
958     ClassType clas = classes[iClass];
959     String JavaDoc out_name
960       = (directory + clas.getName().replace('.', dirSep)
961          + ".class");
962     String JavaDoc parent = new File(out_name).getParent();
963     if (parent != null)
964       new File(parent).mkdirs();
965     clas.writeToFile(out_name);
966
967         clas.cleanupAfterCompilation();
968       }
969
970     minfo.comp = null;
971     mainLambda.body = null;
972     mainLambda = null;
973     litTable = null;
974   }
975
976   public void compileToArchive (ModuleExp mexp, String JavaDoc fname)
977     throws java.io.IOException JavaDoc
978   {
979     boolean makeJar = false;
980     if (fname.endsWith(".zip"))
981       makeJar = false;
982     else if (fname.endsWith(".jar"))
983       makeJar = true;
984     else
985       {
986     fname = fname + ".zip";
987     makeJar = false;
988       }
989
990     process(COMPILED);
991
992     File zar_file = new File (fname);
993     if (zar_file.exists ())
994       zar_file.delete ();
995     ZipOutputStream zout;
996     /* #ifdef JAVA2 */
997     if (makeJar)
998       zout = new java.util.jar.JarOutputStream JavaDoc(new FileOutputStream(zar_file));
999     else
1000    /* #endif */
1001      {
1002    zout = new ZipOutputStream (new FileOutputStream (zar_file));
1003    zout.setMethod(ZipOutputStream.STORED); // no compression
1004
}
1005
1006    byte[][] classBytes = new byte[numClasses][];
1007    CRC32 zcrc = new CRC32();
1008    for (int iClass = 0; iClass < numClasses; iClass++)
1009      {
1010    ClassType clas = classes[iClass];
1011    classBytes[iClass] = clas.writeToArray ();
1012    ZipEntry zent = new ZipEntry(clas.getName ().replace ('.', '/')
1013                     + ".class");
1014
1015    zent.setSize(classBytes[iClass].length);
1016    zcrc.reset();
1017    zcrc.update(classBytes[iClass], 0, classBytes[iClass].length);
1018    zent.setCrc(zcrc.getValue());
1019
1020    zout.putNextEntry (zent);
1021    zout.write (classBytes[iClass]);
1022      }
1023    zout.close ();
1024  }
1025
1026  // FIXME - make this settable, as it does make .class files bigger.
1027
public static boolean emitSourceDebugExtAttr = true;
1028
1029  private void registerClass (ClassType new_class)
1030  {
1031    if (classes == null)
1032      classes = new ClassType[20];
1033    else if (numClasses >= classes.length)
1034      {
1035    ClassType[] new_classes = new ClassType[2 * classes.length];
1036    System.arraycopy (classes, 0, new_classes, 0, numClasses);
1037    classes = new_classes;
1038      }
1039    new_class.access_flags |= new_class.isInterface() ? Access.PUBLIC
1040      : Access.PUBLIC|Access.SUPER;
1041    if (new_class == mainClass && numClasses > 0)
1042      {
1043        // Ensure mainClass is written first when writing an archive.
1044
new_class = classes[0];
1045        classes[0] = mainClass;
1046      }
1047    classes[numClasses++] = new_class;
1048  }
1049
1050  public void addClass (ClassType new_class)
1051  {
1052    if (mainLambda.filename != null)
1053      {
1054    if (emitSourceDebugExtAttr)
1055      new_class.setStratum(getLanguage().getName());
1056    new_class.setSourceFile(mainLambda.filename);
1057      }
1058    registerClass(new_class);
1059    /* #ifdef JAVA5 */
1060    // new_class.setClassfileVersionJava5();
1061
/* #endif */
1062  }
1063
1064  public void addMainClass (ModuleExp module)
1065  {
1066    mustCompile = true;
1067
1068    mainClass = module.classFor(this);
1069
1070    ClassType type = mainClass;
1071    ClassType[] interfaces = module.getInterfaces();
1072    if (interfaces != null)
1073      type.setInterfaces(interfaces);
1074    ClassType sup = module.getSuperType();
1075    if (sup == null)
1076      {
1077        if (generateApplet)
1078      sup = typeApplet;
1079    else if (generateServlet)
1080      sup = typeServlet;
1081    else
1082      sup = getModuleType();
1083      }
1084    if (! generateServlet)
1085      type.addInterface(typeRunnable);
1086    type.setSuper(sup);
1087
1088    module.type = type;
1089    addClass(type);
1090    getConstructor(mainClass, module);
1091  }
1092
1093  public final Method getConstructor (LambdaExp lexp)
1094  {
1095    return getConstructor(lexp.getHeapFrameType(), lexp);
1096  }
1097
1098  public static final Method getConstructor (ClassType clas, LambdaExp lexp)
1099  {
1100    Method meth = clas.getDeclaredMethod("<init>", 0);
1101    if (meth != null)
1102      return meth;
1103    Type[] args;
1104    if (lexp instanceof ClassExp && lexp.staticLinkField != null)
1105      {
1106    args = new Type[1];
1107    args[0] = lexp.staticLinkField.getType();
1108      }
1109    else
1110      args = apply0args;
1111    return clas.addMethod("<init>", Access.PUBLIC, args, Type.void_type);
1112  }
1113
1114  public final void generateConstructor (LambdaExp lexp)
1115  {
1116    generateConstructor (lexp.getHeapFrameType(), lexp);
1117  }
1118
1119  public final void generateConstructor (ClassType clas, LambdaExp lexp)
1120  {
1121    Method save_method = method;
1122    Variable callContextSave = callContextVar;
1123    callContextVar = null;
1124    ClassType save_class = curClass;
1125    curClass = clas;
1126    Method constructor_method = getConstructor(clas, lexp);
1127    clas.constructor = constructor_method;
1128    method = constructor_method;
1129    CodeAttr code = constructor_method.startCode();
1130
1131    if (lexp instanceof ClassExp && lexp.staticLinkField != null)
1132      {
1133    code.emitPushThis();
1134    code.emitLoad(code.getCurrentScope().getVariable(1));
1135    code.emitPutField(lexp.staticLinkField);
1136      }
1137    Method superConstructor
1138      = clas.getSuperclass().addMethod("<init>", Access.PUBLIC,
1139                       apply0args, Type.void_type);
1140    code.emitPushThis();
1141    code.emitInvokeSpecial(superConstructor);
1142
1143    if (curClass == mainClass
1144        // Optimization: No pointing in calling register if we aren't
1145
// compiling a named module.
1146
&& minfo != null && minfo.sourcePath != null)
1147      {
1148    code.emitPushThis();
1149    code.emitInvokeStatic(ClassType.make("gnu.expr.ModuleInfo")
1150                              .getDeclaredMethod("register", 1));
1151      }
1152
1153    if (lexp.initChain != null)
1154      {
1155    // Create dummy lambda, for its closureEnv. This may be needed
1156
// if init.value contains a reference that uses our heap frame.
1157
LambdaExp save = curLambda;
1158    curLambda = new LambdaExp();
1159    curLambda.closureEnv = code.getArg(0);
1160    curLambda.outer = save;
1161        Initializer init;
1162    while ((init = lexp.initChain) != null)
1163      {
1164        lexp.initChain = null;
1165        dumpInitializers(init);
1166      }
1167    curLambda = save;
1168      }
1169
1170    if (lexp instanceof ClassExp)
1171      {
1172    ClassExp cexp = (ClassExp) lexp;
1173    callInitMethods(cexp.getCompiledClassType(this), new Vector(10));
1174      }
1175
1176    code.emitReturn();
1177    method = save_method;
1178    curClass = save_class;
1179    callContextVar = callContextSave;
1180  }
1181
1182  /** In an <init> for a generated ClassExp, emit $finit$ calls.
1183   * This recursively traverses superclasses, and also calls their $finit$.
1184   * @param clas Class to search for $finit$, and to search supertypes.
1185   * @param seen array of seen classes, to avoid duplicate $finit$ calls.
1186   */

1187  void callInitMethods (ClassType clas, Vector seen)
1188  {
1189    if (clas == null)
1190      return;
1191
1192    String JavaDoc name = clas.getName();
1193    if ("java.lang.Object".equals(name))
1194      return;
1195    // Check for duplicates.
1196
for (int i = seen.size(); --i >= 0; )
1197      if (((ClassType) seen.elementAt(i)).getName() == name)
1198    return;
1199    seen.addElement(clas);
1200
1201    // Recusive call to emit $finit$ of super-types. However, don't do that
1202
// for clas.getSuperclass(), because our <init> will automatically call
1203
// the super-class's <init>, which will call its $finit$.
1204
ClassType[] interfaces = clas.getInterfaces();
1205    if (interfaces != null)
1206      {
1207    int n = interfaces.length;
1208    for (int i = 0; i < n; i++)
1209      callInitMethods(interfaces[i], seen);
1210      }
1211
1212    int clEnvArgs = 1;
1213    if (clas instanceof PairClassType)
1214      clas = ((PairClassType) clas).instanceType;
1215    else if (clas.isInterface())
1216      {
1217    try
1218      {
1219        clas = ((ClassType)
1220            Type.make(Class.forName(clas.getName() + "$class")));
1221      }
1222    catch (Throwable JavaDoc ex)
1223      {
1224        return;
1225      }
1226      }
1227    else
1228      clEnvArgs = 0;
1229    Method meth = clas.getDeclaredMethod("$finit$", clEnvArgs);
1230    if (meth != null)
1231      {
1232    CodeAttr code = getCode();
1233    code.emitPushThis();
1234    code.emitInvoke(meth);
1235      }
1236  }
1237
1238  public void generateMatchMethods(LambdaExp lexp)
1239  {
1240    int numApplyMethods
1241      = lexp.applyMethods == null ? 0 : lexp.applyMethods.size();
1242    if (numApplyMethods == 0)
1243      return;
1244    Method save_method = method;
1245    ClassType save_class = curClass;
1246    ClassType procType = typeModuleMethod;
1247    curClass = lexp.getHeapFrameType();
1248    if (! (curClass.getSuperclass().isSubtype(typeModuleBody)))
1249      curClass = moduleClass;
1250    CodeAttr code = null;
1251    for (int i = 0; i <= 5; i++)
1252      {
1253    boolean needThisMatch = false;
1254    SwitchState aswitch = null;
1255    String JavaDoc mname = null;
1256    Type[] matchArgs = null;
1257    for (int j = numApplyMethods; --j >= 0; )
1258      {
1259        LambdaExp source = (LambdaExp) lexp.applyMethods.elementAt(j);
1260        // Select the subset of source.primMethods[*] that are suitable
1261
// for the current apply method.
1262
Method[] primMethods = source.primMethods;
1263        int numMethods = primMethods.length;
1264        boolean varArgs = source.max_args < 0
1265          || source.max_args >= source.min_args + numMethods;
1266        int methodIndex;
1267        if (i < 5) // Handling match0 .. match4
1268
{
1269        methodIndex = i - source.min_args;
1270        if (methodIndex < 0 || methodIndex >= numMethods
1271            || (methodIndex == numMethods - 1 && varArgs))
1272          continue;
1273        numMethods = 1;
1274        varArgs = false;
1275          }
1276        else // Handling matchN
1277
{
1278        methodIndex = 5 - source.min_args;
1279        if (methodIndex > 0 && numMethods <= methodIndex && ! varArgs)
1280          continue;
1281        methodIndex = numMethods-1;
1282          }
1283        if (! needThisMatch)
1284          {
1285        // First LambdaExp we seen suitable for this i.
1286
if (i < 5)
1287          {
1288            mname = "match"+i;
1289            matchArgs = new Type[i + 2];
1290            for (int k = i; k >= 0; k--)
1291              matchArgs[k+1] = typeObject;
1292            matchArgs[i+1] = typeCallContext;
1293          }
1294        else
1295          {
1296            mname = "matchN";
1297            matchArgs = new Type[3];
1298            matchArgs[1] = objArrayType;
1299            matchArgs[2] = typeCallContext;
1300          }
1301        matchArgs[0] = procType;
1302        method = curClass.addMethod (mname, matchArgs, Type.int_type,
1303                         Access.PUBLIC);
1304        code = method.startCode();
1305
1306        code.emitLoad(code.getArg(1)); // method
1307
code.emitGetField(procType.getField("selector"));
1308        aswitch = new SwitchState(code);
1309
1310        needThisMatch = true;
1311          }
1312
1313        aswitch.addCase(source.getSelectorValue(this), code);
1314
1315        int line = source.getLineNumber();
1316        if (line > 0)
1317          code.putLineNumber(source.getFileName(), line);
1318
1319        Variable ctxVar = code.getArg(i == 5 ? 3 : i+2);
1320
1321        if (i < 5)
1322          {
1323        Declaration var = source.firstDecl();
1324        for (int k = 1; k <= i; k++)
1325          {
1326            code.emitLoad(ctxVar);
1327            code.emitLoad(code.getArg(k+1));
1328            Type ptype = var.getType();
1329            if (ptype != Type.pointer_type)
1330              {
1331            if (ptype instanceof TypeValue)
1332              {
1333                Label trueLabel = new Label(code),
1334                  falseLabel = new Label(code);
1335                ConditionalTarget ctarget =
1336                  new ConditionalTarget(trueLabel, falseLabel,
1337                            getLanguage());
1338                code.emitDup();
1339                ((TypeValue) ptype).emitIsInstance(null, this,
1340                                   ctarget);
1341                falseLabel.define(code);
1342                code.emitPushInt(MethodProc.NO_MATCH_BAD_TYPE|k);
1343                code.emitReturn();
1344                trueLabel.define(code);
1345              }
1346            else if (ptype instanceof ClassType
1347                && ptype != Type.pointer_type
1348                && ptype != Type.tostring_type) // FIXME
1349
{
1350                code.emitDup();
1351                ptype.emitIsInstance(code);
1352                code.emitIfIntEqZero();
1353                code.emitPushInt(MethodProc.NO_MATCH_BAD_TYPE|k);
1354                code.emitReturn();
1355                code.emitFi();
1356              }
1357              }
1358            code.emitPutField(typeCallContext.getField("value"+k));
1359            var = var.nextDecl();
1360          }
1361          }
1362        else
1363          {
1364        // FIXME - need to check
1365
code.emitLoad(ctxVar);
1366        code.emitLoad(code.getArg(2));
1367        code.emitPutField(typeCallContext.getField("values"));
1368          }
1369        code.emitLoad(ctxVar);
1370        if (defaultCallConvention < Compilation.CALL_WITH_CONSUMER)
1371          code.emitLoad(code.getArg(1)); // proc
1372
else
1373          code.emitLoad(code.getArg(0)); // this (module)
1374
code.emitPutField(procCallContextField);
1375        code.emitLoad(ctxVar);
1376        if (defaultCallConvention >= CALL_WITH_CONSUMER)
1377          code.emitPushInt(source.getSelectorValue(this)+methodIndex);
1378        else
1379          code.emitPushInt(i);
1380        code.emitPutField(pcCallContextField);
1381        code.emitPushInt(0);
1382        code.emitReturn();
1383          }
1384    if (needThisMatch)
1385      {
1386        aswitch.addDefault(code);
1387        int nargs = i > 4 ? 2 : i + 1;
1388        nargs++;
1389        for (int k = 0; k <= nargs; k++)
1390          code.emitLoad(code.getArg(k));
1391        Method defMethod = (typeModuleBody
1392                .getDeclaredMethod(mname, matchArgs.length));
1393        code.emitInvokeSpecial(defMethod);
1394        code.emitReturn();
1395        aswitch.finish(code);
1396      }
1397      }
1398    method = save_method;
1399    curClass = save_class;
1400  }
1401
1402  /** Generate ModuleBody's <tt>apply(CallContext)</tt> method
1403   * Use the <tt>applyMethods</tt> vector, which contains methods that
1404   * implement the (public, readable) methods of the current module. */

1405  public void generateApplyMethodsWithContext(LambdaExp lexp)
1406  {
1407    int numApplyMethods
1408      = lexp.applyMethods == null ? 0 : lexp.applyMethods.size();
1409    if (numApplyMethods == 0)
1410      return;
1411    ClassType save_class = curClass;
1412    curClass = lexp.getHeapFrameType();
1413    if (! (curClass.getSuperclass().isSubtype(typeModuleWithContext)))
1414      curClass = moduleClass;
1415    ClassType procType = typeModuleMethod;
1416    Method save_method = method;
1417    CodeAttr code = null;
1418    Type[] applyArgs = { typeCallContext };
1419
1420    // First LambdaExp we seen suitable for this i.
1421
method = curClass.addMethod ("apply", applyArgs,
1422                 (Type) Type.void_type,
1423                 Access.PUBLIC);
1424    code = method.startCode();
1425    Variable ctxVar = code.getArg(1);
1426
1427    code.emitLoad(ctxVar);
1428    code.emitGetField(pcCallContextField);
1429    SwitchState aswitch = new SwitchState(code);
1430
1431    for (int j = 0; j < numApplyMethods; ++j)
1432      {
1433    LambdaExp source = (LambdaExp) lexp.applyMethods.elementAt(j);
1434    Method[] primMethods = source.primMethods;
1435    int numMethods = primMethods.length;
1436
1437    for (int i = 0; i < numMethods; i++)
1438      {
1439        // Select the subset of source.primMethods[*] that are suitable
1440
// for the current apply method.
1441
boolean varArgs
1442          = (i == numMethods - 1
1443         && (source.max_args < 0
1444             || source.max_args >= source.min_args + numMethods));
1445        int methodIndex = i;
1446
1447        aswitch.addCase(source.getSelectorValue(this) + i, code);
1448
1449        int line = source.getLineNumber();
1450        if (line > 0)
1451          code.putLineNumber(source.getFileName(), line);
1452
1453        Method primMethod = primMethods[methodIndex];
1454        Type[] primArgTypes = primMethod.getParameterTypes();
1455        int singleArgs = source.min_args+methodIndex;
1456        Variable counter = null;
1457        int pendingIfEnds = 0;
1458
1459        if (i > 4 && numMethods > 1) // FIXME
1460
{
1461        counter = code.addLocal(Type.int_type);
1462        code.emitLoad(ctxVar);
1463        code.emitGetField(typeCallContext.getDeclaredField("count"));
1464        if (source.min_args != 0)
1465          {
1466            code.emitPushInt(source.min_args);
1467            code.emitSub(Type.int_type);
1468          }
1469        code.emitStore(counter);
1470          }
1471
1472        int needsThis = primMethod.getStaticFlag() ? 0 : 1;
1473            int explicitFrameArg
1474              = singleArgs + (varArgs ? 2 : 1) < primArgTypes.length ? 1 : 0;
1475        if (needsThis + explicitFrameArg > 0)
1476          {
1477        code.emitPushThis();
1478        if (curClass == moduleClass && mainClass != moduleClass)
1479          code.emitGetField(moduleInstanceMainField);
1480          }
1481
1482        Declaration var = source.firstDecl();
1483        for (int k = 0; k < singleArgs; k++)
1484          {
1485        if (counter != null && k >= source.min_args)
1486          {
1487            code.emitLoad(counter);
1488            code.emitIfIntLEqZero();
1489            code.emitLoad(ctxVar);
1490            code.emitInvoke(primMethods[k - source.min_args]);
1491            code.emitElse();
1492            pendingIfEnds++;
1493            code.emitInc(counter, (short) (-1));
1494          }
1495
1496        code.emitLoad(ctxVar);
1497        if (k <= 4 && ! varArgs && source.max_args <= 4)
1498          code.emitGetField(typeCallContext
1499                    .getDeclaredField("value"+(k+1)));
1500        else
1501          {
1502            code.emitGetField(typeCallContext
1503                      .getDeclaredField("values"));
1504            code.emitPushInt(k);
1505            code.emitArrayLoad(Type.pointer_type);
1506          }
1507        Type ptype = var.getType();
1508        if (ptype != Type.pointer_type)
1509          CheckedTarget.emitCheckedCoerce(this, source,
1510                          k+1, ptype);
1511        var = var.nextDecl();
1512          }
1513
1514        if (varArgs)
1515          {
1516        Type lastArgType = primArgTypes[explicitFrameArg+singleArgs];
1517        if (lastArgType instanceof ArrayType)
1518          {
1519            Type elType
1520              = ((ArrayType) lastArgType).getComponentType();
1521            boolean mustConvert
1522              = ! "java.lang.Object".equals(elType.getName());
1523            if (mustConvert)
1524              new Error JavaDoc("not implemented mustConvert restarg");
1525            code.emitLoad(ctxVar);
1526            code.emitPushInt(singleArgs);
1527            code.emitInvokeVirtual(typeCallContext.getDeclaredMethod("getRestArgsArray", 1));
1528          }
1529        else if ("gnu.lists.LList".equals
1530             (lastArgType.getName()))
1531          {
1532            code.emitLoad(ctxVar);
1533            code.emitPushInt(singleArgs);
1534            code.emitInvokeVirtual(typeCallContext.getDeclaredMethod("getRestArgsList", 1));
1535          }
1536        else if (lastArgType == typeCallContext)
1537          code.emitLoad(ctxVar);
1538        else
1539          throw new RuntimeException JavaDoc("unsupported #!rest type:"+lastArgType);
1540              }
1541        code.emitLoad(ctxVar); // get $ctx
1542
code.emitInvoke(primMethod);
1543        while (--pendingIfEnds >= 0)
1544          code.emitFi();
1545        if (defaultCallConvention < Compilation.CALL_WITH_CONSUMER)
1546          Target.pushObject.compileFromStack(this,
1547                         source.getReturnType());
1548        code.emitReturn();
1549          }
1550      }
1551    aswitch.addDefault(code);
1552    Method errMethod = typeModuleMethod.getDeclaredMethod("applyError", 0);
1553    code.emitInvokeStatic(errMethod);
1554    code.emitReturn();
1555    aswitch.finish(code);
1556    method = save_method;
1557    curClass = save_class;
1558  }
1559
1560  /** Generate ModuleBody's <tt>apply0</tt>...<tt>applyN</tt> methods.
1561   * Use the <tt>applyMethods</tt> vector, which contains methods that
1562   * implement the (public, readable) methods of the current module.
1563   */

1564  public void generateApplyMethodsWithoutContext(LambdaExp lexp)
1565  {
1566    int numApplyMethods
1567      = lexp.applyMethods == null ? 0 : lexp.applyMethods.size();
1568    if (numApplyMethods == 0)
1569      return;
1570    ClassType save_class = curClass;
1571    curClass = lexp.getHeapFrameType();
1572    ClassType procType = typeModuleMethod;
1573    if (! (curClass.getSuperclass().isSubtype(typeModuleBody)))
1574      curClass = moduleClass;
1575    Method save_method = method;
1576    CodeAttr code = null;
1577    for (int i = defaultCallConvention >= Compilation.CALL_WITH_CONSUMER
1578       ? 5 : 0;
1579     i < 6; i++)
1580      {
1581    // If i < 5, generate the method named ("apply"+i);
1582
// else generate "applyN".
1583
boolean needThisApply = false;
1584    SwitchState aswitch = null;
1585    String JavaDoc mname = null;
1586    Type[] applyArgs = null;
1587
1588    for (int j = numApplyMethods; --j >= 0; )
1589      {
1590        LambdaExp source = (LambdaExp) lexp.applyMethods.elementAt(j);
1591        // Select the subset of source.primMethods[*] that are suitable
1592
// for the current apply method.
1593
Method[] primMethods = source.primMethods;
1594        int numMethods = primMethods.length;
1595        boolean varArgs = source.max_args < 0
1596          || source.max_args >= source.min_args + numMethods;
1597        int methodIndex;
1598        boolean skipThisProc = false;
1599        if (i < 5) // Handling apply0 .. apply4
1600
{
1601        methodIndex = i - source.min_args;
1602        if (methodIndex < 0 || methodIndex >= numMethods
1603            || (methodIndex == numMethods - 1 && varArgs))
1604          skipThisProc = true;
1605        numMethods = 1;
1606        varArgs = false;
1607          }
1608        else // Handling applyN
1609
{
1610        methodIndex = 5 - source.min_args;
1611        if (methodIndex > 0 && numMethods <= methodIndex && ! varArgs)
1612          skipThisProc = true;
1613        methodIndex = numMethods-1;
1614          }
1615        if (skipThisProc)
1616          continue;
1617        if (! needThisApply)
1618          {
1619        // First LambdaExp we seen suitable for this i.
1620
if (i < 5)
1621          {
1622            mname = "apply"+i;
1623            applyArgs = new Type[i + 1];
1624            for (int k = i; k > 0; k--)
1625              applyArgs[k] = typeObject;
1626          }
1627        else
1628          {
1629            mname = "applyN";
1630            applyArgs = new Type[2];
1631            applyArgs[1] = objArrayType;
1632          }
1633        applyArgs[0] = procType;
1634        method = curClass.addMethod (mname, applyArgs,
1635                         defaultCallConvention >= Compilation.CALL_WITH_CONSUMER ? (Type) Type.void_type : (Type) Type.pointer_type,
1636                         Access.PUBLIC);
1637        code = method.startCode();
1638
1639        code.emitLoad(code.getArg(1)); // method
1640
code.emitGetField(procType.getField("selector"));
1641        aswitch = new SwitchState(code);
1642
1643        needThisApply = true;
1644          }
1645
1646        aswitch.addCase(source.getSelectorValue(this), code);
1647
1648        int line = source.getLineNumber();
1649        if (line > 0)
1650          code.putLineNumber(source.getFileName(), line);
1651
1652        Method primMethod = primMethods[methodIndex];
1653        Type[] primArgTypes = primMethod.getParameterTypes();
1654        int singleArgs = source.min_args+methodIndex;
1655        Variable counter = null;
1656        int pendingIfEnds = 0;
1657
1658        if (i > 4 && numMethods > 1)
1659          {
1660        counter = code.addLocal(Type.int_type);
1661        code.emitLoad(code.getArg(2));
1662        code.emitArrayLength();
1663        if (source.min_args != 0)
1664          {
1665            code.emitPushInt(source.min_args);
1666            code.emitSub(Type.int_type);
1667          }
1668        code.emitStore(counter);
1669          }
1670
1671        int needsThis = primMethod.getStaticFlag() ? 0 : 1;
1672            int explicitFrameArg
1673              = singleArgs + (varArgs ? 1 : 0) < primArgTypes.length ? 1 : 0;
1674        if (needsThis + explicitFrameArg > 0)
1675          {
1676        code.emitPushThis();
1677        if (curClass == moduleClass && mainClass != moduleClass)
1678          code.emitGetField(moduleInstanceMainField);
1679          }
1680
1681        Declaration var = source.firstDecl();
1682        for (int k = 0; k < singleArgs; k++)
1683          {
1684        if (counter != null && k >= source.min_args)
1685          {
1686            code.emitLoad(counter);
1687            code.emitIfIntLEqZero();
1688            code.emitInvoke(primMethods[k - source.min_args]);
1689            code.emitElse();
1690            pendingIfEnds++;
1691            code.emitInc(counter, (short) (-1));
1692          }
1693
1694        Variable pvar = null;
1695        if (i <= 4) // apply'i method
1696
{
1697            pvar = code.getArg(k + 2);
1698            code.emitLoad(pvar);
1699          }
1700        else // applyN method
1701
{
1702            // Load Object[]args value:
1703
code.emitLoad(code.getArg(2));
1704            code.emitPushInt(k);
1705            code.emitArrayLoad(Type.pointer_type);
1706          }
1707        Type ptype = var.getType();
1708        if (ptype != Type.pointer_type)
1709          CheckedTarget.emitCheckedCoerce(this, source,
1710                          k+1, ptype, pvar);
1711        var = var.nextDecl();
1712          }
1713
1714        if (varArgs)
1715          {
1716        Type lastArgType = primArgTypes[explicitFrameArg+singleArgs];
1717        if (lastArgType instanceof ArrayType)
1718          {
1719            Type elType
1720              = ((ArrayType) lastArgType).getComponentType();
1721            boolean mustConvert
1722              = ! "java.lang.Object".equals(elType.getName());
1723            if (singleArgs == 0 && ! mustConvert)
1724              code.emitLoad(code.getArg(2)); // load args array.
1725
else
1726              {
1727            code.pushScope();
1728            if (counter == null)
1729              {
1730                counter = code.addLocal(Type.int_type);
1731                code.emitLoad(code.getArg(2));
1732                code.emitArrayLength();
1733                if (singleArgs != 0)
1734                  {
1735                code.emitPushInt(singleArgs);
1736                code.emitSub(Type.int_type);
1737                  }
1738                code.emitStore(counter);
1739              }
1740            code.emitLoad(counter);
1741            code.emitNewArray(elType);
1742            Label testLabel = new Label(code);
1743            code.emitGoto(testLabel);
1744            Label loopTopLabel = new Label(code);
1745            loopTopLabel.define(code);
1746
1747            code.emitDup(1); // new array
1748
code.emitLoad(counter);
1749            code.emitLoad(code.getArg(2));
1750            code.emitLoad(counter);
1751            if (singleArgs != 0)
1752              {
1753                code.emitPushInt(singleArgs);
1754                code.emitAdd(Type.int_type);
1755              }
1756            code.emitArrayLoad(Type.pointer_type);
1757            if (mustConvert)
1758              {
1759                CheckedTarget.emitCheckedCoerce
1760                  (this, source, source.getName(),
1761                   0, elType, null);
1762              }
1763            code.emitArrayStore(elType);
1764            testLabel.define(code);
1765            code.emitInc(counter, (short) (-1));
1766            code.emitLoad(counter);
1767            code.emitGotoIfIntGeZero(loopTopLabel);
1768            code.popScope();
1769              }
1770          }
1771        else if ("gnu.lists.LList".equals
1772             (lastArgType.getName()))
1773          {
1774            code.emitLoad(code.getArg(2)); // load args array.
1775
code.emitPushInt(singleArgs);
1776            code.emitInvokeStatic(Compilation.makeListMethod);
1777          }
1778        else if (lastArgType == typeCallContext)
1779          code.emitLoad(code.getArg(2));
1780        else
1781          throw new RuntimeException JavaDoc("unsupported #!rest type:"+lastArgType);
1782              }
1783        code.emitInvoke(primMethod);
1784        while (--pendingIfEnds >= 0)
1785          code.emitFi();
1786        if (defaultCallConvention < Compilation.CALL_WITH_CONSUMER)
1787          Target.pushObject.compileFromStack(this,
1788                         source.getReturnType());
1789        code.emitReturn();
1790          }
1791    if (needThisApply)
1792      {
1793        aswitch.addDefault(code);
1794        if (defaultCallConvention >= Compilation.CALL_WITH_CONSUMER)
1795          {
1796        Method errMethod
1797          = typeModuleMethod.getDeclaredMethod("applyError", 0);
1798        code.emitInvokeStatic(errMethod);
1799          }
1800        else
1801          {
1802        int nargs = i > 4 ? 2 : i + 1;
1803        nargs++;
1804        for (int k = 0; k < nargs; k++)
1805          code.emitLoad(code.getArg(k));
1806        code.emitInvokeSpecial(typeModuleBody.getDeclaredMethod(mname, applyArgs));
1807          }
1808        code.emitReturn();
1809        aswitch.finish(code);
1810      }
1811      }
1812    method = save_method;
1813    curClass = save_class;
1814  }
1815
1816  private Method startClassInit ()
1817  {
1818    method = curClass.addMethod ("<clinit>", apply0args, Type.void_type,
1819                 Access.PUBLIC|Access.STATIC);
1820
1821    CodeAttr code = method.startCode();
1822
1823    if (generateMain || generateApplet || generateServlet)
1824      {
1825    ClassType languageType
1826      = (ClassType) Type.make(getLanguage().getClass());
1827    Method registerMethod
1828      = languageType.getDeclaredMethod("registerEnvironment", 0);
1829    if (registerMethod != null)
1830      code.emitInvokeStatic(registerMethod);
1831      }
1832    return method;
1833  }
1834
1835  /** Parse/walk/compile this module as needed and requested.
1836   * This method does not process any dependent modules (expect indirectly,
1837   * such as may be done by a require form).
1838   * @param wantedState the desired value of getState().
1839   */

1840  public void process (int wantedState)
1841  {
1842    Compilation saveCompilation = Compilation.getCurrent();
1843    try
1844      {
1845        Compilation.setCurrent(this);
1846        ModuleExp mexp = getModule();
1847        if (wantedState >= BODY_PARSED && getState() < BODY_PARSED-1)
1848          {
1849            setState(BODY_PARSED-1);
1850            language.parse(this, 0);
1851            lexer.close();
1852            lexer = null;
1853            setState(messages.seenErrors() ? ERROR_SEEN : BODY_PARSED);
1854            if (pendingImports != null)
1855              return;
1856          }
1857        if (wantedState >= RESOLVED && getState() < RESOLVED)
1858          {
1859            addMainClass(mexp);
1860            language.resolve(this);
1861            setState(messages.seenErrors() ? ERROR_SEEN : RESOLVED);
1862          }
1863        if (wantedState >= WALKED && getState() < WALKED)
1864          {
1865            walkModule(mexp);
1866            setState(messages.seenErrors() ? ERROR_SEEN : WALKED);
1867          }
1868        if (wantedState >= COMPILE_SETUP && getState() < COMPILE_SETUP)
1869          {
1870            litTable = new LitTable(this);
1871            mexp.setCanRead(true);
1872            FindCapturedVars.findCapturedVars(mexp, this);
1873            mexp.allocFields(this);
1874            mexp.allocChildMethods(this);
1875            setState(messages.seenErrors() ? ERROR_SEEN : COMPILE_SETUP);
1876          }
1877        if (wantedState >= COMPILED && getState() < COMPILED)
1878          {
1879            generateBytecode();
1880            setState(messages.seenErrors() ? ERROR_SEEN : COMPILED);
1881          }
1882        if (wantedState >= CLASS_WRITTEN && getState() < CLASS_WRITTEN)
1883          {
1884            ModuleManager manager = ModuleManager.getInstance();
1885            outputClass(manager.getCompilationDirectory());
1886            setState(CLASS_WRITTEN);
1887          }
1888      }
1889    catch (gnu.text.SyntaxException ex)
1890      {
1891        setState(ERROR_SEEN);
1892        if (ex.getMessages() != getMessages())
1893          throw new RuntimeException JavaDoc ("confussing syntax error: "+ex);
1894        // otherwise ignore it - it's already been recorded in messages.
1895
}
1896    catch (java.io.IOException JavaDoc ex)
1897      {
1898        ex.printStackTrace();
1899        error('f', "caught "+ex);
1900        setState(ERROR_SEEN);
1901      }
1902    finally
1903      {
1904        Compilation.setCurrent(saveCompilation);
1905      }
1906  }
1907
1908  /** The guts of compiling a module to one or more classes.
1909   * Assumes walkModule has been done.
1910   */

1911  void generateBytecode ()
1912  {
1913    ModuleExp module = getModule();
1914    if (debugPrintFinalExpr)
1915      {
1916    OutPort dout = OutPort.errDefault();
1917    dout.println ("[Compiling final "+module.getName()
1918                     + " to " + mainClass.getName() + ":");
1919    module.print(dout);
1920    dout.println(']');
1921    dout.flush();
1922      }
1923
1924    ClassType neededSuper = getModuleType();
1925    if (mainClass.getSuperclass().isSubtype(neededSuper))
1926      moduleClass = mainClass;
1927    else
1928      {
1929    moduleClass = new ClassType(generateClassName("frame"));
1930    moduleClass.setSuper(neededSuper);
1931    addClass(moduleClass);
1932    generateConstructor(moduleClass, module);
1933      }
1934
1935    curClass = module.type;
1936    int arg_count;
1937    LambdaExp saveLambda = curLambda;
1938    curLambda = module;
1939    Type[] arg_types;
1940    if (module.isHandlingTailCalls())
1941      {
1942    arg_count = 1;
1943    arg_types = new Type[1];
1944    arg_types[0] = typeCallContext;
1945      }
1946    else if (module.min_args != module.max_args || module.min_args > 4
1947    || (fewerClasses && curClass == mainClass))
1948      {
1949    arg_count = 1;
1950    arg_types = new Type[1];
1951    arg_types[0] = new ArrayType (typeObject);
1952      }
1953    else
1954      {
1955    arg_count = module.min_args;
1956    arg_types = new Type[arg_count];
1957    for (int i = arg_count; --i >= 0; )
1958      arg_types[i] = typeObject;
1959      }
1960
1961    CodeAttr code;
1962    Variable heapFrame = module.heapFrame;
1963    boolean staticModule = module.isStatic();
1964    Method apply_method;
1965    
1966    apply_method = curClass.addMethod ("run", arg_types, Type.void_type,
1967                       Access.PUBLIC+Access.FINAL);
1968    method = apply_method;
1969    // For each parameter, assign it to its proper slot.
1970
// If a parameter !isSimple(), we cannot assign it to a local slot,
1971
// so instead create an artificial Variable for the incoming argument.
1972
// Below, we assign the value to the slot.
1973
method.initCode();
1974    code = getCode();
1975    // if (usingCPStyle()) code.addParamLocals();
1976

1977    thisDecl = method.getStaticFlag() ? null : module.declareThis(module.type);
1978    module.closureEnv = module.thisVariable;
1979    module.heapFrame = module.isStatic() ? null : module.thisVariable;
1980    module.allocChildClasses(this);
1981
1982    if (module.isHandlingTailCalls() || usingCPStyle())
1983      {
1984    callContextVar = new Variable ("$ctx", typeCallContext);
1985    module.getVarScope().addVariableAfter(thisDecl, callContextVar);
1986    callContextVar.setParameter(true);
1987      }
1988
1989    int line = module.getLineNumber();
1990    if (line > 0)
1991      code.putLineNumber(module.getFileName(), line);
1992
1993    module.allocParameters(this);
1994    module.enterFunction(this);
1995    if (usingCPStyle())
1996      {
1997    loadCallContext();
1998        code.emitGetField(pcCallContextField);
1999        fswitch = new SwitchState(code);
2000    Label l = new Label(code);
2001    l.define(code);
2002    fswitch.addCase(0, l, code);
2003      }
2004
2005    module.compileBody(this);
2006    module.compileChildMethods(this);
2007
2008    Label startLiterals = null;
2009    Label afterLiterals = null;
2010    Method initMethod = null;
2011
2012    if (curClass == mainClass)
2013      {
2014    Method save_method = method;
2015        Variable callContextSave = callContextVar;
2016        callContextVar = null;
2017
2018    initMethod = startClassInit();
2019        clinitMethod = initMethod;
2020    code = getCode();
2021
2022        startLiterals = new Label(code);
2023        afterLiterals = new Label(code);
2024        code.fixupChain(afterLiterals, startLiterals);
2025      
2026    if (staticModule)
2027      {
2028        generateConstructor (module);
2029
2030        code.emitNew(moduleClass);
2031        code.emitDup(moduleClass);
2032        code.emitInvokeSpecial(moduleClass.constructor);
2033        moduleInstanceMainField
2034          = moduleClass.addField("$instance", mainClass,
2035                     Access.STATIC|Access.PUBLIC|Access.FINAL);
2036        code.emitPutStatic(moduleInstanceMainField);
2037      }
2038        Initializer init;
2039        while ((init = clinitChain) != null)
2040          {
2041            clinitChain = null;
2042            dumpInitializers(init);
2043          }
2044
2045    if (! immediate && module.staticInitRun())
2046      {
2047        code.emitGetStatic(moduleInstanceMainField);
2048        code.emitInvokeInterface(typeRunnable.getDeclaredMethod("run", 0));
2049      }
2050    code.emitReturn();
2051
2052    if (moduleClass != mainClass
2053        && ! staticModule && ! generateMain && ! immediate)
2054      {
2055        // Compare the run methods in ModuleBody.
2056
method = curClass.addMethod("run", Access.PUBLIC,
2057                    Type.typeArray0, Type.void_type);
2058        code = method.startCode();
2059        Variable ctxVar = code.addLocal(typeCallContext);
2060        Variable saveVar = code.addLocal(typeConsumer);
2061        Variable exceptionVar = code.addLocal(Type.throwable_type);
2062        // ctx = CallContext.getInstance();
2063
code.emitInvokeStatic(getCallContextInstanceMethod);
2064        code.emitStore(ctxVar);
2065        Field consumerFld = typeCallContext.getDeclaredField("consumer");
2066        // save = ctx.consumer;
2067
code.emitLoad(ctxVar);
2068        code.emitGetField(consumerFld);
2069        code.emitStore(saveVar);
2070        // ctx.consumer = VoidConsumer.instance:
2071
code.emitLoad(ctxVar);
2072        code.emitGetStatic(ClassType.make("gnu.lists.VoidConsumer")
2073                   .getDeclaredField("instance"));
2074        code.emitPutField(consumerFld);
2075        // try {
2076
code.emitTryStart(false, Type.void_type);
2077        // this.apply(ctx):
2078
code.emitPushThis();
2079        code.emitLoad(ctxVar);
2080        code.emitInvokeVirtual(save_method);
2081        // exception = null
2082
code.emitPushNull();
2083        code.emitStore(exceptionVar);
2084        // } catch (Throwable th) { exception = th; }
2085
code.emitTryEnd();
2086        code.emitCatchStart(exceptionVar);
2087        code.emitCatchEnd();
2088        code.emitTryCatchEnd();
2089        // MooduleBody.runCleanup(ctx, ex, save);
2090
code.emitLoad(ctxVar);
2091        code.emitLoad(exceptionVar);
2092        code.emitLoad(saveVar);
2093        code.emitInvokeStatic(typeModuleBody
2094                  .getDeclaredMethod("runCleanup", 3));
2095        code.emitReturn();
2096      }
2097
2098    method = save_method;
2099        callContextVar = callContextSave;
2100      }
2101
2102    module.compileEnd(this);
2103
2104    curLambda = saveLambda;
2105
2106    if (Compilation.fewerClasses) // FIXME
2107
method.popScope(); // Undoes pushScope in method.initCode.
2108

2109    module.heapFrame = heapFrame; // Restore heapFrame.
2110
if (usingCPStyle() || (fewerClasses && curClass == mainClass))
2111      {
2112    code = getCode();
2113    fswitch.finish(code);
2114      }
2115
2116    if (startLiterals != null || callContextVar != null)
2117      {
2118    method = initMethod;
2119    code = getCode();
2120
2121    Label endLiterals = new Label(code);
2122    code.fixupChain(startLiterals, endLiterals);
2123
2124        if (callContextVarForInit != null)
2125          {
2126            code.emitInvokeStatic(getCallContextInstanceMethod);
2127            code.emitStore(callContextVarForInit);
2128          }
2129
2130    try
2131      {
2132            if (immediate)
2133              {
2134                code.emitPushInt(registerForImmediateLiterals(this));
2135                code.emitInvokeStatic(ClassType.make("gnu.expr.Compilation")
2136                                      .getDeclaredMethod("setupLiterals", 1));
2137              }
2138            else
2139              litTable.emit();
2140      }
2141    catch (Throwable JavaDoc ex)
2142      {
2143        error('e', "Literals: Internal error:" + ex);
2144      }
2145    code.fixupChain(endLiterals, afterLiterals);
2146      }
2147
2148    if (generateMain && curClass == mainClass)
2149      {
2150    Type[] args = { new ArrayType(javaStringType) };
2151    method = curClass.addMethod("main", Access.PUBLIC|Access.STATIC,
2152                    args, Type.void_type);
2153                    
2154    code = method.startCode();
2155
2156    if (Shell.defaultFormatName != null)
2157      {
2158        code.emitPushString(Shell.defaultFormatName);
2159        code.emitInvokeStatic(ClassType.make("kawa.Shell")
2160                  .getDeclaredMethod("setDefaultFormat", 1));
2161      }
2162    code.emitLoad(code.getArg(0));
2163    code.emitInvokeStatic(typeModuleBody.getDeclaredMethod("processArgs", 1));
2164    if (moduleInstanceMainField != null)
2165      code.emitGetStatic(moduleInstanceMainField);
2166    else
2167      {
2168        code.emitNew(curClass);
2169        code.emitDup(curClass);
2170        code.emitInvokeSpecial(curClass.constructor);
2171      }
2172    code.emitInvokeVirtual(typeModuleBody.getDeclaredMethod("runAsMain", 0));
2173    code.emitReturn();
2174      }
2175
2176    String JavaDoc uri;
2177    if (minfo != null && (uri = minfo.getNamespaceUri()) != null)
2178      {
2179        // Need to generate a ModuleSet for this class, so XQuery can find
2180
// this module and other modules in the same namespace.
2181
ModuleManager manager = ModuleManager.getInstance();
2182        String JavaDoc mainPrefix = mainClass.getName();
2183        int dot = mainPrefix.lastIndexOf('.');
2184        if (dot < 0)
2185          {
2186            mainPrefix = "";
2187          }
2188        else
2189          {
2190            String JavaDoc mainPackage = mainPrefix.substring(0, dot);
2191            try
2192              {
2193                manager.loadPackageInfo(mainPackage);
2194              }
2195            catch (ClassNotFoundException JavaDoc ex)
2196              {
2197                // Do nothing.
2198
}
2199            catch (Throwable JavaDoc ex)
2200              {
2201                error('e', "error loading map for "+mainPackage+" - "+ex);
2202              }
2203            mainPrefix = mainPrefix.substring(0, dot+1);
2204          }
2205        ClassType mapClass = new ClassType(mainPrefix + ModuleSet.MODULES_MAP);
2206        ClassType typeModuleSet = ClassType.make("gnu.expr.ModuleSet");
2207        mapClass.setSuper(typeModuleSet);
2208        registerClass(mapClass);
2209
2210        method = mapClass.addMethod("<init>", Access.PUBLIC,
2211                                apply0args, Type.void_type);
2212        Method superConstructor
2213          = typeModuleSet.addMethod("<init>", Access.PUBLIC,
2214                                    apply0args, Type.void_type);
2215        code = method.startCode();
2216        code.emitPushThis();
2217        code.emitInvokeSpecial(superConstructor);
2218        code.emitReturn();
2219
2220        ClassType typeModuleManager = ClassType.make("gnu.expr.ModuleManager");
2221        Type[] margs = { typeModuleManager };
2222        method = mapClass.addMethod("register", margs, Type.void_type,
2223                                    Access.PUBLIC);
2224        code = method.startCode();
2225        Method reg = typeModuleManager.getDeclaredMethod("register", 3);
2226
2227        for (ModuleInfo mi = manager.firstModule();
2228             mi != null; mi = mi.nextModule())
2229          {
2230            String JavaDoc miClassName = mi.className;
2231            if (miClassName == null
2232                || ! miClassName.startsWith(mainPrefix))
2233              continue;
2234            String JavaDoc moduleSource = mi.sourcePath;
2235            String JavaDoc moduleUri = mi.getNamespaceUri();
2236            code.emitLoad(code.getArg(1));
2237            compileConstant(miClassName);
2238            if (! URI_utils.isAbsolute(moduleSource))
2239              try
2240                {
2241                  // If the source path was relative, emit it as relative.
2242
// But make it relative to the compilation directory,
2243
// to allows sources to be moved along with binaries.
2244
char sep = File.separatorChar;
2245                  String JavaDoc path = manager.getCompilationDirectory();
2246                  path = path + mainPrefix.replace('.', sep);
2247                  path = URI_utils.toURL(path).toString();
2248                  int plen = path.length();
2249                  if (plen > 0 && path.charAt(plen-1) != sep)
2250                    path = path + sep;
2251                  moduleSource = URI_utils.relativize(mi.sourceAbsPath, path).toString();
2252                }
2253              catch (Throwable JavaDoc ex)
2254                {
2255                  throw new WrappedException("exception while fixing up '"
2256                                             +moduleSource+'\'',
2257                                             ex);
2258                }
2259            compileConstant(moduleSource);
2260            compileConstant(moduleUri);
2261            code.emitInvokeVirtual(reg);
2262          }
2263        code.emitReturn();
2264      }
2265  }
2266
2267  int localFieldIndex;
2268  public Field allocLocalField (Type type, String JavaDoc name)
2269  {
2270    if (name == null)
2271      name = "tmp_"+(++localFieldIndex);
2272    Field field = curClass.addField(name, type, 0);
2273    return field;
2274  }
2275
2276  /** If non-null, contains the value of the current CallContext. */
2277  Variable callContextVar;
2278  Variable callContextVarForInit;
2279
2280  /** Generate code to push the current CallContext on the JVM stack. */
2281  public final void loadCallContext()
2282  {
2283    CodeAttr code = getCode();
2284    if (callContextVar != null && ! callContextVar.dead())
2285      code.emitLoad(callContextVar);
2286    // We're cautious about re-using a previously extracted CallContext,
2287
// because it's tricky to manage the variables safely.
2288
// A possible solution is to inject a Variable into the current scope,
2289
// and making sure each separate straight-line block has its own scope.
2290
// (If the current scope is in the same "basic block" as an outer scope,
2291
// we can use that instead.) FIXME
2292
else if (method == clinitMethod)
2293      {
2294        // The variable is initialized just after literals.
2295
callContextVar = new Variable("$ctx", typeCallContext);
2296        // To make sure it doesn't clash with variables that have already
2297
// allocated and freed for previous initialzier.
2298
callContextVar.reserveLocal(code.getMaxLocals(), code);
2299        code.emitLoad(callContextVar);
2300        callContextVarForInit = callContextVar;
2301      }
2302    else
2303      {
2304        code.emitInvokeStatic(getCallContextInstanceMethod);
2305        code.emitDup();
2306        callContextVar = new Variable("$ctx", typeCallContext);
2307        code.getCurrentScope().addVariable(code, callContextVar);
2308        code.emitStore(callContextVar);
2309      }
2310  }
2311
2312  public void freeLocalField (Field field)
2313  {
2314    // FIXME
2315
}
2316
2317  /** This may not make sense, except for Lisp-like languages.
2318   * For those, 'input' an s-expression from the reader. */

2319  public Expression parse (Object JavaDoc input)
2320  {
2321    throw new Error JavaDoc("unimeplemented parse");
2322  }
2323
2324  protected Language language;
2325  public Language getLanguage() { return language; }
2326
2327  public LambdaExp currentLambda () { return current_scope.currentLambda (); }
2328
2329  public final ModuleExp getModule() { return mainLambda; }
2330  public void setModule(ModuleExp mexp) { mainLambda = mexp; }
2331
2332  public boolean isStatic() { return mainLambda.isStatic(); }
2333
2334  /** The same as getModule, until we allow nested modules. */
2335  public ModuleExp currentModule() { return current_scope.currentModule(); }
2336
2337  /** Note that we have seen a construct that must be compiled, not evaluated.
2338   * If we are not inside a lambda (which is always compiled), but
2339   * only inside the outer-most ModuleExp, note that it must be compiled.
2340   */

2341  public void mustCompileHere ()
2342  {
2343    mustCompile = true;
2344  }
2345
2346  public ScopeExp currentScope() { return current_scope; }
2347
2348  /** Set <code>currentScope()</code>.
2349   * Also update the <code>nesting</code> object.
2350   */

2351  public void setCurrentScope (ScopeExp scope)
2352  {
2353    int scope_nesting = ScopeExp.nesting(scope);
2354    int current_nesting = ScopeExp.nesting(current_scope);
2355    while (current_nesting > scope_nesting)
2356      {
2357    pop(current_scope);
2358    current_nesting--;
2359      }
2360    ScopeExp sc = scope;
2361    while (scope_nesting > current_nesting)
2362      {
2363    sc = sc.outer;
2364    scope_nesting--;
2365      }
2366    while (sc != current_scope)
2367      {
2368    pop(current_scope);
2369    sc = sc.outer;
2370      }
2371    pushChain(scope, sc);
2372  }
2373
2374  void pushChain (ScopeExp scope, ScopeExp limit)
2375  {
2376    if (scope != limit)
2377      {
2378    pushChain(scope.outer, limit);
2379        pushScope(scope);
2380        lexical.push(scope);
2381      }
2382  }
2383
2384  public ModuleExp pushNewModule (Lexer lexer)
2385  {
2386    this.lexer = lexer;
2387    return pushNewModule(lexer.getName());
2388  }
2389
2390  public ModuleExp pushNewModule (String JavaDoc filename)
2391  {
2392    ModuleExp module = new ModuleExp();
2393    if (filename != null)
2394      module.setFile(filename);
2395    if (Compilation.generateAppletDefault)
2396      module.setFlag(ModuleExp.SUPERTYPE_SPECIFIED);
2397    if (immediate)
2398      {
2399        module.setFlag(ModuleExp.IMMEDIATE);
2400        new ModuleInfo().setCompilation(this);
2401      }
2402    mainLambda = module;
2403    push(module);
2404    return module;
2405  }
2406
2407  public void push (ScopeExp scope)
2408  {
2409    pushScope(scope);
2410    lexical.push(scope);
2411  }
2412
2413  public final void pushScope (ScopeExp scope)
2414  {
2415    if (! mustCompile
2416        // We set mustCompile if we see a LambdaExp - not because we must
2417
// but because it is usually desirable.
2418
&& (scope.mustCompile()
2419            || (scope instanceof LambdaExp && ! (scope instanceof ModuleExp))))
2420      mustCompileHere();
2421    scope.outer = current_scope;
2422    current_scope = scope;
2423  }
2424
2425  public void pop (ScopeExp scope)
2426  {
2427    lexical.pop(scope);
2428    current_scope = scope.outer;
2429  }
2430
2431  public final void pop ()
2432  {
2433    pop(current_scope);
2434  }
2435
2436  public void push (Declaration decl)
2437  {
2438    lexical.push(decl);
2439  }
2440
2441  public Declaration lookup(Object JavaDoc name, int namespace)
2442  {
2443    return lexical.lookup(name, namespace);
2444  }
2445
2446  /** Called for classes referenced in bytecode.
2447   * Since this only does something when immediate, we only care about
2448   * classes referenced in the bytecode when immediate.
2449   * It is used to ensure that we can inherit from classes defines when in
2450   * immediate mode (in Scheme using define-class or similar).
2451   */

2452  public void usedClass (Type type)
2453  {
2454    while (type instanceof ArrayType)
2455      type = ((ArrayType) type).getComponentType();
2456    if (! immediate || ! (type instanceof ClassType))
2457      return;
2458    ClassType clas = (ClassType) type;
2459    if (loader != null && clas.isExisting())
2460      {
2461    loader.addClass(clas.getReflectClass());
2462      }
2463  }
2464
2465  public SourceMessages getMessages() { return messages; }
2466  public void setMessages (SourceMessages messages)
2467  { this.messages = messages; }
2468 
2469  public void error(char severity, String JavaDoc message, SourceLocator location)
2470  {
2471    String JavaDoc file = location.getFileName();
2472    int line = location.getLineNumber();
2473    int column = location.getColumnNumber();
2474    if (file == null || line <= 0)
2475      {
2476        file = getFileName();
2477        line = getLineNumber();
2478        column = getColumnNumber();
2479      }
2480
2481    if (severity == 'w' && getBooleanOption("warn-as-error", false))
2482      severity = 'e';
2483    messages.error(severity, file, line, column, message);
2484  }
2485
2486  public void error(char severity, String JavaDoc message)
2487  {
2488    if (severity == 'w' && getBooleanOption("warn-as-error", false))
2489      severity = 'e';
2490    
2491    messages.error(severity, this, message);
2492  }
2493
2494  public void error(char severity, Declaration decl, String JavaDoc msg1, String JavaDoc msg2)
2495  {
2496    error(severity, msg1 + decl.getName() + msg2, null, decl);
2497  }
2498
2499  public void error(char severity, String JavaDoc message,
2500                    String JavaDoc code, Declaration decl)
2501  {
2502    if (severity == 'w' && getBooleanOption("warn-as-error", false))
2503      severity = 'e';
2504    
2505    String JavaDoc filename = getFileName();
2506    int line = getLineNumber();
2507    int column = getColumnNumber();
2508    int decl_line = decl.getLineNumber();
2509    if (decl_line > 0)
2510      {
2511    filename = decl.getFileName();
2512    line = decl_line;
2513    column = decl.getColumnNumber();
2514      }
2515    messages.error(severity, filename, line, column, message, code);
2516  }
2517
2518  /**
2519   * Handle syntax errors (at rewrite time).
2520   * @param message an error message to print out
2521   * @return an ErrorExp
2522   */

2523  public Expression syntaxError (String JavaDoc message)
2524  {
2525    error('e', message);
2526    return new ErrorExp (message);
2527  }
2528
2529  public final int getLineNumber() { return messages.getLineNumber(); }
2530  public final int getColumnNumber() { return messages.getColumnNumber(); }
2531  public final String JavaDoc getFileName() { return messages.getFileName(); }
2532  public String JavaDoc getPublicId() { return messages.getPublicId(); }
2533  public String JavaDoc getSystemId() { return messages.getSystemId(); }
2534  public boolean isStableSourceLocation() { return false; }
2535
2536  public void setFile(String JavaDoc filename) { messages.setFile(filename); }
2537  public void setLine(int line) { messages.setLine(line); }
2538  public void setColumn(int column) { messages.setColumn(column); }
2539  public final void setLine(Expression position)
2540  { messages.setLocation(position); }
2541  public final void setLocation (SourceLocator position)
2542  { messages.setLocation(position); }
2543
2544  public void setLine(String JavaDoc filename, int line, int column)
2545  {
2546    messages.setLine(filename, line, column);
2547  }
2548
2549  /** A help vector for building expressions. */
2550  public Stack JavaDoc exprStack;
2551
2552  public void letStart ()
2553  {
2554    pushScope(new LetExp(null));
2555  }
2556
2557  public Declaration letVariable (Object JavaDoc name, Type type, Expression init)
2558  {
2559    LetExp let = (LetExp) current_scope;
2560    Declaration decl = let.addDeclaration(name, type);
2561    decl.noteValue(init);
2562    return decl;
2563  }
2564
2565  public void letEnter ()
2566  {
2567    LetExp let = (LetExp) current_scope;
2568    int ndecls = let.countDecls();
2569    Expression[] inits = new Expression[ndecls];
2570    int i = 0;
2571    for (Declaration decl = let.firstDecl();
2572     decl != null;
2573     decl = decl.nextDecl())
2574      inits[i++] = decl.getValue();
2575    let.inits = inits;
2576    lexical.push(let);
2577  }
2578
2579  public LetExp letDone (Expression body)
2580  {
2581    LetExp let = (LetExp) current_scope;
2582    let.body = body;
2583    pop(let);
2584    return let;
2585  }
2586
2587  private void checkLoop()
2588  {
2589    if (((LambdaExp) current_scope).getName() != "%do%loop")
2590      throw new Error JavaDoc("internal error - bad loop state");
2591  }
2592
2593  /** Start a new loop.
2594   * (We could make this implied by the first loopVaribale call ???) */

2595  public void loopStart()
2596  {
2597    LambdaExp loopLambda = new LambdaExp();
2598    Expression[] inits = { loopLambda };
2599    LetExp let = new LetExp(inits);
2600    String JavaDoc fname = "%do%loop";
2601    Declaration fdecl = let.addDeclaration(fname);
2602    fdecl.noteValue(loopLambda);
2603    loopLambda.setName(fname);
2604    let.outer = current_scope;
2605    loopLambda.outer = let;
2606    current_scope = loopLambda;
2607  }
2608
2609  public Declaration loopVariable(Object JavaDoc name, Type type, Expression init)
2610  {
2611    checkLoop();
2612    LambdaExp loopLambda = (LambdaExp) current_scope;
2613    Declaration decl = loopLambda.addDeclaration(name, type);
2614    if (exprStack == null)
2615      exprStack = new Stack JavaDoc();
2616    exprStack.push(init);
2617    loopLambda.min_args++;
2618    return decl;
2619  }
2620
2621  /** Done handling loop variables, and pushes them into the lexical scope.
2622   * Ready to parse the loop condition. */

2623  public void loopEnter ()
2624  {
2625    checkLoop();
2626    LambdaExp loopLambda = (LambdaExp) current_scope;
2627    int ninits = loopLambda.min_args;
2628    loopLambda.max_args = ninits;
2629    Expression[] inits = new Expression[ninits];
2630    for (int i = ninits; --i >= 0; )
2631      inits[i] = (Expression) exprStack.pop();
2632    LetExp let = (LetExp) loopLambda.outer;
2633    Declaration fdecl = let.firstDecl(); // The decls for loopLambda.
2634
let.setBody(new ApplyExp(new ReferenceExp(fdecl), inits));
2635    lexical.push(loopLambda);
2636  }
2637  public void loopCond(Expression cond)
2638  {
2639    checkLoop();
2640    exprStack.push(cond);
2641  }
2642  public void loopBody(Expression body)
2643  {
2644    LambdaExp loopLambda = (LambdaExp) current_scope;
2645    loopLambda.body = body;
2646  }
2647  public Expression loopRepeat(Expression[] exps)
2648  {
2649    LambdaExp loopLambda = (LambdaExp) current_scope;
2650    ScopeExp let = loopLambda.outer;
2651    Declaration fdecl = let.firstDecl(); // The decls for loopLambda.
2652
Expression cond = (Expression) exprStack.pop();
2653    Expression recurse = new ApplyExp(new ReferenceExp(fdecl), exps);
2654    loopLambda.body = new IfExp(cond,
2655                new BeginExp(loopLambda.body, recurse),
2656                QuoteExp.voidExp);
2657    lexical.pop(loopLambda);
2658    current_scope = let.outer;
2659    return let;
2660  }
2661
2662  public Expression loopRepeat ()
2663  {
2664    return loopRepeat(Expression.noExpressions);
2665  }
2666
2667  public Expression loopRepeat (Expression exp)
2668  {
2669    Expression[] args = { exp };
2670    return loopRepeat(args);
2671  }
2672
2673  /** If non-null, a helper method generated by getForNameHelper. */
2674  Method forNameHelper;
2675
2676  public void loadClassRef (ClassType clas)
2677  {
2678    // Try an optimization
2679
if (clas == mainClass && mainLambda.isStatic()
2680        // moduleInstanceMainField may not have been set yet.
2681
&& moduleInstanceMainField != null)
2682      {
2683        CodeAttr code = getCode();
2684        code.emitGetStatic(moduleInstanceMainField);
2685        code.emitInvokeVirtual(Type.pointer_type.getDeclaredMethod("getClass", 0));
2686      }
2687    else
2688      loadClassRef(clas.getName());
2689  }
2690
2691  /** Generate code to load a named Class without initializing it.
2692   */

2693  public void loadClassRef (String JavaDoc className)
2694  {
2695    CodeAttr code = getCode();
2696    if (curClass.getClassfileMajorVersion() >= 49) // Java5 feature
2697
code.emitPushClass(className);
2698    else
2699      {
2700        code.emitPushString(className);
2701        code.emitInvokeStatic(getForNameHelper());
2702      }
2703  }
2704
2705  /** Generate a method to find a named Class without initializing it.
2706   * Generate a static helper method "class$" like javac generates for
2707   * 'CLASS.class', but does not initialize CLASS. Also, we don't bother
2708   * catching exceptions, since the JVM doesn't require us to. I.e. generates:
2709   * public static class $(String name)
2710   * { return Class.forName(name, false,
2711   * Class.forName(THISCLASSNAME).getClassLoader()); }
2712   * Note that we want the result to use the same ClassLoader as the caller,
2713   * which is why we generate a static helper method.
2714   */

2715  public Method getForNameHelper ()
2716  {
2717    if (forNameHelper == null)
2718      {
2719    /* #ifdef JAVA2 */
2720    Method save_method = method;
2721    method = curClass.addMethod("class$", Access.PUBLIC|Access.STATIC,
2722                    string1Arg, typeClass);
2723    forNameHelper = method;
2724    CodeAttr code = method.startCode();
2725    code.emitLoad(code.getArg(0));
2726    code.emitPushInt(0);
2727    code.emitPushString(mainClass.getName());
2728    code.emitInvokeStatic(typeClass.getDeclaredMethod("forName", 1));
2729    code.emitInvokeVirtual(typeClass.getDeclaredMethod("getClassLoader", 0));
2730    code.emitInvokeStatic(typeClass.getDeclaredMethod("forName", 3));
2731    code.emitReturn();
2732    method = save_method;
2733    /* #else */
2734    // forNameHelper = typeClass.getDeclaredMethod("forName", 1);
2735
/* #endif */
2736      }
2737    return forNameHelper;
2738  }
2739
2740  public Object JavaDoc resolve(Object JavaDoc name, boolean function)
2741  {
2742    Environment env = Environment.getCurrent();
2743    Symbol symbol;
2744    if (name instanceof String JavaDoc)
2745      symbol = env.defaultNamespace().lookup((String JavaDoc) name);
2746    else
2747      symbol = (Symbol) name;
2748    if (symbol == null)
2749      return null;
2750    if (function && getLanguage().hasSeparateFunctionNamespace())
2751      return env.getFunction(symbol, null);
2752    return env.get(symbol, null);
2753  }
2754
2755  /** A key we can pass from the compiler to identity a Compilation. */
2756  private int keyUninitialized;
2757  /** Chain of immediate Compilation whose setupLiterals hasn't been called. */
2758  private static Compilation chainUninitialized;
2759  /** Next in chain headed by chainUninitialized. */
2760  private Compilation nextUninitialized;
2761
2762  /** Call-back from compiled code to initialize literals in immediate mode.
2763   * In non-immediate mode (i.e. generating class files) the compiler emits
2764   * code to "re-construct" literal values. However, in immediate mode
2765   * that would be wasteful, plus we would get values that are similar (equals)
2766   * to but not necessarily identical (eq) to the compile-time literal.
2767   * So we need to pass the literal values to the compiled code, by using
2768   * reflectiion to initialize various static fields. This method does that.
2769   * It is called from start of the the generated static initializer, which
2770   * helps makes things more consistent between immediate and non-immediate
2771   * mode.
2772   */

2773  public static void setupLiterals (int key)
2774  {
2775    Compilation comp = Compilation.findForImmediateLiterals(key);
2776    try
2777      {
2778        Class JavaDoc clas = comp.loader.loadClass(comp.mainClass.getName(), true);
2779
2780    /* Pass literal values to the compiled code. */
2781    for (Literal init = comp.litTable.literalsChain; init != null;
2782         init = init.next)
2783      {
2784        /* DEBUGGING:
2785        OutPort out = OutPort.errDefault();
2786        out.print("init["+init.index+"]=");
2787        out.print(init.value);
2788        out.println();
2789        */

2790            clas.getDeclaredField(init.field.getName())
2791              .set(null, init.value);
2792      }
2793      }
2794    catch (Throwable JavaDoc ex)
2795      {
2796        throw new WrappedException("internal error", ex);
2797      }
2798  }
2799
2800  public static synchronized int
2801  registerForImmediateLiterals (Compilation comp)
2802  {
2803    int i = 0;
2804    for (Compilation c = chainUninitialized; c != null; c = c.nextUninitialized)
2805      {
2806        if (i <= c.keyUninitialized)
2807          i = c.keyUninitialized + 1;
2808      }
2809    comp.keyUninitialized = i;
2810    comp.nextUninitialized = chainUninitialized;
2811    chainUninitialized = comp;
2812    return i;
2813  }
2814
2815  public static synchronized Compilation findForImmediateLiterals (int key)
2816  {
2817    Compilation prev = null;
2818    for (Compilation comp = chainUninitialized; ; )
2819      {
2820        Compilation next = comp.nextUninitialized;
2821        if (comp.keyUninitialized == key)
2822          {
2823            if (prev == null)
2824              chainUninitialized = next;
2825            else
2826              prev.nextUninitialized = next;
2827            return comp;
2828          }
2829        prev = comp;
2830        comp = next;
2831      }
2832  }
2833
2834  /** Current lexical scope - map name to Declaration. */
2835  public NameLookup lexical;
2836
2837  protected ScopeExp current_scope;
2838
2839  protected SourceMessages messages;
2840
2841  private static final ThreadLocation current =
2842    new ThreadLocation("current-compilation");
2843
2844  public static Compilation getCurrent ()
2845  {
2846    return (Compilation) current.get();
2847  }
2848
2849  public static void setCurrent (Compilation comp)
2850  {
2851    current.set(comp);
2852  }
2853
2854  public String JavaDoc toString ()
2855  {
2856    return "<compilation "+mainLambda+">";
2857  }
2858}
2859
Popular Tags