KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > expr > ModuleExp


1 package gnu.expr;
2 import gnu.mapping.*;
3 import gnu.bytecode.*;
4 import gnu.mapping.Location; // As opposed to gnu.bytecode.Location
5
import gnu.text.*;
6 import java.io.*;
7 import gnu.kawa.reflect.StaticFieldLocation;
8 import java.net.URL JavaDoc;
9
10 /**
11  * Class used to implement Scheme top-level environments.
12  * @author Per Bothner
13  */

14
15 public class ModuleExp extends LambdaExp
16                implements Externalizable
17 {
18   public static final int EXPORT_SPECIFIED = LambdaExp.NEXT_AVAIL_FLAG;
19   public static final int STATIC_SPECIFIED = EXPORT_SPECIFIED << 1;
20   public static final int NONSTATIC_SPECIFIED = STATIC_SPECIFIED << 1;
21   public static final int SUPERTYPE_SPECIFIED = NONSTATIC_SPECIFIED << 1;
22   public static final int STATIC_RUN_SPECIFIED = SUPERTYPE_SPECIFIED << 1;
23   public static final int LAZY_DECLARATIONS = STATIC_RUN_SPECIFIED << 1;
24   public static final int IMMEDIATE = LAZY_DECLARATIONS << 1;
25
26   public String JavaDoc getJavaName ()
27   {
28     String JavaDoc name = getName();
29     return name == null ? "lambda" : Compilation.mangleName(name, 0);
30   }
31
32   public ModuleExp ()
33   {
34   }
35
36   /** Used to control which .zip file dumps are generated. */
37   public static String JavaDoc dumpZipPrefix;
38
39   static int lastZipCounter;
40
41   /** Numeric identifier for this interactive "command".
42    * Incremented by Shell.run, and used to set the module name,
43    * and maybe the name of the --debug-dump-zip output file.
44    * We increment and use this counter purely to ease debugging.
45    * (Since each module gets its own ClassLoader, they don't
46    * need to be named differently, and it doesn't matter
47    * if there is a race condition on the counter.) */

48   public static int interactiveCounter;
49
50   public static Class JavaDoc evalToClass (Compilation comp, URL JavaDoc url)
51   {
52     ModuleExp mexp = comp.getModule();
53     SourceMessages messages = comp.getMessages();
54     try
55       {
56     ArrayClassLoader loader = new ArrayClassLoader ();
57         if (url == null)
58           {
59             CallContext ctx = CallContext.getInstance();
60             String JavaDoc base = ctx.getBaseUri();
61             url = URI_utils.toURL(base);
62           }
63         loader.setResourceContext(url);
64     comp.loader = loader;
65
66         comp.minfo.loadByStages(Compilation.COMPILED);
67
68     if (messages.seenErrors())
69       return null;
70
71     java.util.zip.ZipOutputStream JavaDoc zout = null;
72     if (dumpZipPrefix != null)
73       {
74         StringBuffer JavaDoc zipname = new StringBuffer JavaDoc(dumpZipPrefix);
75             
76             lastZipCounter++;
77         if (interactiveCounter > lastZipCounter)
78           lastZipCounter = interactiveCounter;
79             zipname.append(lastZipCounter);
80         zipname.append(".zip");
81         java.io.FileOutputStream JavaDoc zfout
82           = new java.io.FileOutputStream JavaDoc(zipname.toString());
83         zout = new java.util.zip.ZipOutputStream JavaDoc(zfout);
84       }
85
86     for (int iClass = 0; iClass < comp.numClasses; iClass++)
87       {
88         ClassType clas = comp.classes[iClass];
89         String JavaDoc className = clas.getName ();
90         byte[] classBytes = clas.writeToArray ();
91         loader.addClass(className, classBytes);
92             // This reduces memory leaks if we do lots of evalToClass.
93
clas.cleanupAfterCompilation();
94
95         if (zout != null)
96           {
97         String JavaDoc clname = className.replace ('.', '/') + ".class";
98         java.util.zip.ZipEntry JavaDoc zent
99           = new java.util.zip.ZipEntry JavaDoc (clname);
100         zent.setSize(classBytes.length);
101         java.util.zip.CRC32 JavaDoc crc = new java.util.zip.CRC32 JavaDoc();
102         crc.update(classBytes);
103         zent.setCrc(crc.getValue());
104         zent.setMethod(java.util.zip.ZipEntry.STORED);
105         zout.putNextEntry(zent);
106         zout.write(classBytes);
107           }
108       }
109     if (zout != null)
110       {
111         zout.close ();
112       }
113
114     /* DEBUGGING:
115     for (int iClass = 0; iClass < comp.numClasses; iClass++)
116       ClassTypeWriter.print(comp.classes[iClass], System.out, 0);
117     */

118
119         Class JavaDoc clas = null;
120     for (int iClass = 0; iClass < comp.numClasses; iClass++)
121       {
122         ClassType ctype = comp.classes[iClass];
123             Class JavaDoc cclass = loader.loadClass(ctype.getName(), false);
124             ctype.setReflectClass(cclass);
125             ctype.setExisting(true);
126             if (iClass == 0)
127               clas = cclass;
128           }
129
130         ModuleInfo minfo = comp.minfo;
131         minfo.moduleClass = clas;
132         int ndeps = minfo.numDependencies;
133
134         for (int idep = 0; idep < ndeps; idep++)
135           {
136             ModuleInfo dep = minfo.dependencies[idep];
137             if (dep.moduleClass == null)
138               dep.moduleClass = evalToClass(dep.comp, null);
139             comp.loader.addClass(dep.moduleClass);
140           }
141
142         return clas;
143       }
144     catch (java.io.IOException JavaDoc ex)
145       {
146     throw new WrappedException("I/O error in lambda eval", ex);
147       }
148     catch (ClassNotFoundException JavaDoc ex)
149       {
150     throw new WrappedException("class not found in lambda eval", ex);
151       }
152     catch (Throwable JavaDoc ex)
153       {
154     comp.error('f', "internal compile error - caught "+ex);
155     throw WrappedException.wrapIfNeeded(ex);
156       }
157   }
158
159   /** Flag to force compilation, even when not required. */
160   public static boolean alwaysCompile = false;
161
162   public final static boolean evalModule (Environment env, CallContext ctx,
163                                        Compilation comp, URL JavaDoc url,
164                                        OutPort msg)
165     throws Throwable JavaDoc
166   {
167     comp.getLanguage().resolve(comp);
168     ModuleExp mexp = comp.getModule();
169     Environment orig_env = Environment.getCurrent();
170     Compilation orig_comp = Compilation.getCurrent();
171     SourceMessages messages = comp.getMessages();
172     ClassLoader JavaDoc savedLoader = null;
173     Thread JavaDoc thread = null; // Non-null if we need to restore context ClassLoader.
174
try
175       {
176     if (env != orig_env)
177       Environment.setCurrent(env);
178         if (comp != orig_comp)
179           Compilation.setCurrent(comp);
180
181         if (alwaysCompile || comp.mustCompile)
182           comp.addMainClass(mexp);
183
184         comp.walkModule(mexp);
185         comp.setState(Compilation.WALKED);
186
187         if (msg != null ? messages.checkErrors(msg, 20) : messages.seenErrors())
188           return false;
189
190     if (! alwaysCompile && ! comp.mustCompile)
191       { // optimization - don't generate unneeded Class.
192
if (Compilation.debugPrintFinalExpr)
193           {
194         msg.println ("[Evaluating final module \""+mexp.getName()+"\":");
195         mexp.print(msg);
196         msg.println(']');
197         msg.flush();
198           }
199         mexp.body.apply(ctx);
200       }
201     else
202       {
203             if (comp.mainClass == null)
204               comp.addMainClass(mexp);
205
206         try
207           {
208         Class JavaDoc clas = evalToClass(comp, url);
209         if (clas == null)
210           return false;
211                 try
212                   {
213                     thread = Thread.currentThread();
214                     savedLoader = thread.getContextClassLoader();
215                     thread.setContextClassLoader(clas.getClassLoader());
216                   }
217                 catch (Throwable JavaDoc ex)
218                   {
219                     thread = null;
220                   }
221
222                 Object JavaDoc inst;
223                 try
224                   {
225                     inst = clas.getDeclaredField("$instance").get(null);
226                   }
227                 catch (NoSuchFieldException JavaDoc ex)
228                   {
229                     inst = clas.newInstance();
230                   }
231
232         // Import declarations defined in module into the Environment.
233
for (Declaration decl = mexp.firstDecl();
234              decl != null; decl = decl.nextDecl())
235           {
236             Object JavaDoc dname = decl.getSymbol();
237             if (decl.isPrivate() || dname == null)
238               continue;
239             Field fld = decl.field;
240             Symbol sym = dname instanceof Symbol ? (Symbol) dname
241               : Symbol.make("", dname.toString().intern());
242             Object JavaDoc property = comp.getLanguage()
243               .getEnvPropertyFor(decl);
244             // Would it be better to check if fld is FINAL?
245
// If it is, gets its value; otherwise create
246
// a FieldLocation to access it? FIXME.
247
Expression dvalue = decl.getValue();
248             if (decl.getFlag(Declaration.PROCEDURE|Declaration.IS_CONSTANT|Declaration.INDIRECT_BINDING)
249                         && ! (dvalue instanceof ReferenceExp
250                               && ((ReferenceExp) dvalue).getBinding().needsContext()))
251               {
252             Object JavaDoc value;
253             if (dvalue instanceof QuoteExp
254                 && dvalue != QuoteExp.undefined_exp)
255               value = ((QuoteExp) dvalue).getValue();
256             else
257                           value = decl.field.getReflectField().get(null);
258             if (decl.isIndirectBinding())
259               env.addLocation(sym, property, (Location) value);
260             else
261               env.define(sym, property, value);
262             // if IS_CONSTANT ... make Location constant. FIXME.
263
}
264             else
265               {
266                         StaticFieldLocation loc
267                           = new StaticFieldLocation(fld.getDeclaringClass(),
268                                                     fld.getName());
269             loc.setDeclaration(decl);
270             env.addLocation(sym, property, loc);
271               }
272           }
273                 if (msg != null ? messages.checkErrors(msg, 20)
274                     : messages.seenErrors())
275                   return false;
276                 if (inst instanceof ModuleBody)
277                   ((ModuleBody) inst).run(ctx);
278           }
279         catch (IllegalAccessException JavaDoc ex)
280           {
281         throw new RuntimeException JavaDoc("class illegal access: in lambda eval");
282           }
283       }
284     ctx.runUntilDone();
285       }
286     finally
287       {
288     if (env != orig_env)
289       Environment.setCurrent(orig_env);
290     if (comp != orig_comp)
291       Compilation.setCurrent(orig_comp);
292         if (thread != null)
293           thread.setContextClassLoader(savedLoader);
294       }
295     return true;
296   }
297
298   ClassType superType;
299   ClassType[] interfaces;
300
301   ModuleInfo info;
302
303   public final ClassType getSuperType() { return superType; }
304   public final void setSuperType(ClassType s) { superType = s; }
305   public final ClassType[] getInterfaces() { return interfaces; }
306   public final void setInterfaces(ClassType[] s) { interfaces = s; }
307
308   public final boolean isStatic ()
309   {
310     // In immediate mode there is no point in a non-static module:
311
// a static module is simpler and more efficient.
312
return (getFlag(STATIC_SPECIFIED)
313         || ((gnu.expr.Compilation.moduleStatic > 0
314                  || getFlag(IMMEDIATE))
315         && ! getFlag(SUPERTYPE_SPECIFIED)
316         && ! getFlag(NONSTATIC_SPECIFIED)));
317   }
318
319   /** True if module body (i.e. run) is called by class initializer. */
320   public boolean staticInitRun ()
321   {
322     return (isStatic()
323             && (getFlag(STATIC_RUN_SPECIFIED)
324                 || Compilation.moduleStatic == 2));
325   }
326
327   public void allocChildClasses (Compilation comp)
328   {
329     declareClosureEnv();
330     if (! comp.usingCPStyle())
331       return;
332     allocFrame(comp);
333   }
334
335   void allocFields (Compilation comp)
336   {
337     // We want the create the loc$XXX Symbol fields for unknowns first,
338
// because it is possible some later Declaration's initializer may depend
339
// on it. Normally this is not an issue, as initializer are usually
340
// run as part of the "body" of the module, which is executed later.
341
// However, constant initializers are an exception - they are
342
// executed at init time.
343
for (Declaration decl = firstDecl();
344          decl != null; decl = decl.nextDecl())
345       {
346     if ((decl.isSimple() && ! decl.isPublic()) || decl.field != null)
347       continue;
348     if (decl.getFlag(Declaration.IS_UNKNOWN)
349             // We might have an unrefered unknown if the reference gets
350
// optimized away. For example references to <CLASSNAME>.
351
&& decl.getFlag(Declaration.CAN_READ|Declaration.CAN_CALL))
352       decl.makeField(comp, null);
353       }
354     for (Declaration decl = firstDecl();
355          decl != null; decl = decl.nextDecl())
356       {
357     if (decl.field != null)
358       continue;
359     Expression value = decl.getValue();
360     if (((decl.isSimple() && ! decl.isPublic()))
361             // Kludge - needed for macros - see Savannah bug #13601.
362
&& ! decl.isNamespaceDecl()
363             && ! (decl.getFlag(Declaration.IS_CONSTANT)
364                   && decl.getFlag(Declaration.CAN_READ|Declaration.CAN_CALL))
365         && ! (value instanceof ClassExp))
366       continue;
367     if (decl.getFlag(Declaration.IS_UNKNOWN))
368       continue;
369         if (value instanceof ModuleExp) // if decl set by a module-name command.
370
continue;
371     if (value instanceof LambdaExp && ! (value instanceof ClassExp))
372       {
373         ((LambdaExp) value).allocFieldFor(comp);
374       }
375     else
376       {
377             if (! (decl.getFlag(Declaration.IS_CONSTANT) || decl.isAlias())
378         || value == QuoteExp.undefined_exp)
379           value = null;
380         decl.makeField(comp, value);
381       }
382       }
383   }
384
385   protected Expression walk (ExpWalker walker)
386   {
387     return walker.walkModuleExp(this);
388   }
389
390   public void print (OutPort out)
391   {
392     out.startLogicalBlock("(Module/", ")", 2);
393     Object JavaDoc sym = getSymbol();
394     if (sym != null)
395       {
396     out.print(sym);
397     out.print('/');
398       }
399     out.print(id);
400     out.print('/');
401     out.writeSpaceFill();
402     out.startLogicalBlock("(", false, ")");
403     Declaration decl = firstDecl();
404     if (decl != null)
405       {
406     out.print("Declarations:");
407     for (; decl != null; decl = decl.nextDecl())
408       {
409         out.writeSpaceFill();
410         decl.printInfo(out);
411       }
412       }
413     out.endLogicalBlock(")");
414     out.writeSpaceLinear();
415     if (body == null)
416       out.print("<null body>");
417     else
418       body.print (out);
419     out.endLogicalBlock(")");
420   }
421
422   public Declaration firstDecl ()
423   {
424     synchronized (this)
425       {
426     if (getFlag(LAZY_DECLARATIONS))
427           info.setupModuleExp();
428       }
429     return decls;
430   }
431
432   /** Return the class this module.
433    * If not set yet, sets it now, based on the source file name.
434    */

435   public ClassType classFor (Compilation comp)
436   {
437     if (type != null && type != Compilation.typeProcedure)
438       return (ClassType) type;
439     String JavaDoc fileName = getFileName();
440     File file = null;
441     String JavaDoc mname = getName();
442     if (mname != null)
443       fileName = mname;
444     else if (fileName == null)
445       {
446         fileName = getName();
447         if (fileName == null)
448           fileName = "$unnamed_input_file$";
449       }
450     else if (filename.equals("-") || filename.equals("<stdin>"))
451       {
452         fileName = getName();
453         if (fileName == null)
454           fileName = "$stdin$";
455       }
456     else
457       {
458         file = new File(fileName);
459         fileName = file.getName();
460         int dotIndex = fileName.lastIndexOf('.');
461         if (dotIndex > 0)
462           fileName = fileName.substring (0, dotIndex);
463       }
464     String JavaDoc parent;
465     String JavaDoc className;
466     if (getName() == null)
467       setName(fileName);
468     fileName = Compilation.mangleNameIfNeeded(fileName);
469     if (comp.classPrefix.length() == 0
470         && file != null
471         && ! file.isAbsolute()
472         && (parent = file.getParent()) != null
473         && parent.length() > 0 // Probably redundant.
474
&& parent.indexOf("..") < 0)
475       {
476         parent = parent.replaceAll(System.getProperty("file.separator"), "/");
477         if (parent.startsWith("./"))
478           parent = parent.substring(2);
479         className = parent.equals(".") ? fileName
480           : Compilation.mangleURI(parent) + "." + fileName;
481       }
482     else
483       className = comp.classPrefix + fileName;
484     ClassType clas = new ClassType(className);
485     setType(clas);
486     if (comp.mainLambda == this)
487       {
488         if (comp.mainClass == null)
489           comp.mainClass = clas;
490         else if (! className.equals(comp.mainClass.getName()))
491           comp.error('e', "inconsistent main class name: "+className
492                      +" - old name: "+comp.mainClass.getName());
493       }
494     return clas;
495   }
496
497   public void writeExternal(ObjectOutput out) throws IOException
498   {
499     String JavaDoc name = null;
500     if (type != null && type != Compilation.typeProcedure
501     && ! type.isExisting())
502       // The class is (presumably) one we're currently generating.
503
// At run-time it may be loaded by a non-system ClassLoader.
504
// Thus compiling the class literal needs to use loadClassRef.
505
out.writeObject(type);
506     else
507       {
508     if (name == null)
509       name = getName();
510     if (name == null)
511       name = getFileName();
512     out.writeObject(name);
513       }
514   }
515
516   public void readExternal(ObjectInput in)
517     throws IOException, ClassNotFoundException JavaDoc
518   {
519     Object JavaDoc name = in.readObject();
520     if (name instanceof ClassType)
521       {
522     type = (ClassType) name;
523     setName(type.getName());
524       }
525     else
526       setName((String JavaDoc) name);
527     flags |= LAZY_DECLARATIONS;
528   }
529 }
530
Popular Tags