001: package gnu.expr;
002:
003: import java.io.*;
004: import java.util.zip.*; // import java.util.jar.*; // Java2
005: import gnu.mapping.*;
006: import gnu.bytecode.*;
007:
008: /**
009: * Class used to implement Scheme top-level environments.
010: * @author Per Bothner
011: */
012:
013: public class ModuleExp extends LambdaExp {
014: /** True if the body is too complex to evaluate,and we must compile it.
015: * This is because it contains a construct we know how to compile, but not
016: * evaluate, and it it outside a lambda (which we always compile).
017: * This can be a let scope, or primitive procedure. */
018: public boolean mustCompile;
019:
020: public static boolean debugPrintExpr = false;
021:
022: public static final int EXPORT_SPECIFIED = LambdaExp.NEXT_AVAIL_FLAG;
023: public static final int STATIC_SPECIFIED = EXPORT_SPECIFIED << 1;
024: public static final int NONSTATIC_SPECIFIED = STATIC_SPECIFIED << 1;
025: public static final int SUPERTYPE_SPECIFIED = NONSTATIC_SPECIFIED << 1;
026:
027: public String getJavaName() {
028: return name == null ? "lambda" : Compilation.mangleName(name);
029: }
030:
031: public ModuleExp() {
032: }
033:
034: public Object eval(Environment env) throws Throwable {
035: //if (thisValue != null)
036: /// return thisValue;
037: try {
038: Class clas = evalToClass();
039: Object inst = clas.newInstance();
040:
041: Procedure proc = (Procedure) inst;
042: if (proc.getName() == null)
043: proc.setName(this .name);
044: //thisValue = proc;
045: return inst;
046: } catch (InstantiationException ex) {
047: throw new RuntimeException(
048: "class not instantiable: in lambda eval");
049: } catch (IllegalAccessException ex) {
050: throw new RuntimeException(
051: "class illegal access: in lambda eval");
052: }
053: }
054:
055: /** Used to control which .zip file dumps are generated. */
056: public static String dumpZipPrefix;
057: public static int dumpZipCounter;
058:
059: ///** A cache if this has already been evaluated. */
060: //Procedure thisValue;
061:
062: public Class evalToClass() {
063: try {
064: String class_name = getJavaName();
065:
066: Compilation comp = new Compilation(this , class_name, null,
067: true);
068:
069: byte[][] classes = new byte[comp.numClasses][];
070: String[] classNames = new String[comp.numClasses];
071: for (int iClass = 0; iClass < comp.numClasses; iClass++) {
072: ClassType clas = comp.classes[iClass];
073: classNames[iClass] = clas.getName();
074: classes[iClass] = clas.writeToArray();
075: }
076: if (dumpZipPrefix != null) {
077: StringBuffer zipname = new StringBuffer(dumpZipPrefix);
078: if (dumpZipCounter >= 0)
079: zipname.append(++dumpZipCounter);
080: zipname.append(".zip");
081: java.io.FileOutputStream zfout = new java.io.FileOutputStream(
082: zipname.toString());
083: java.util.zip.ZipOutputStream zout = new java.util.zip.ZipOutputStream(
084: zfout);
085: for (int iClass = 0; iClass < comp.numClasses; iClass++) {
086: String clname = classNames[iClass]
087: .replace('.', '/')
088: + ".class";
089: java.util.zip.ZipEntry zent = new java.util.zip.ZipEntry(
090: clname);
091: zent.setSize(classes[iClass].length);
092: java.util.zip.CRC32 crc = new java.util.zip.CRC32();
093: crc.update(classes[iClass]);
094: zent.setCrc(crc.getValue());
095: zent.setMethod(java.util.zip.ZipEntry.STORED);
096: zout.putNextEntry(zent);
097: zout.write(classes[iClass]);
098: }
099: zout.close();
100: }
101:
102: /* DEBUGGING:
103: for (int iClass = 0; iClass < comp.numClasses; iClass++)
104: ClassTypeWriter.print(comp.classes[iClass], System.out, 0);
105: */
106:
107: ArrayClassLoader loader = new ArrayClassLoader(classNames,
108: classes);
109: Class clas = loader.loadClass(class_name, true);
110: /* Pass literal values to the compiled code. */
111: for (Literal init = comp.literalsChain; init != null; init = init.next) {
112: /* DEBUGGING:
113: OutPort out = OutPort.errDefault();
114: out.print("init["+init.index+"]=");
115: SFormat.print(init.value, out);
116: out.println();
117: */
118: try {
119: clas.getDeclaredField(init.field.getName()).set(
120: null, init.value);
121: } catch (java.lang.NoSuchFieldException ex) {
122: throw new Error("internal error - " + ex);
123: }
124: }
125: return clas;
126: } catch (java.io.IOException ex) {
127: ex.printStackTrace(OutPort.errDefault());
128: throw new RuntimeException("I/O error in lambda eval: "
129: + ex);
130: } catch (ClassNotFoundException ex) {
131: throw new RuntimeException("class not found in lambda eval");
132: } catch (IllegalAccessException ex) {
133: throw new RuntimeException(
134: "class illegal access: in lambda eval");
135: }
136: }
137:
138: public final Object evalModule(Environment env) throws Throwable {
139: CallContext ctx = new CallContext();
140: ctx.values = Values.noArgs;
141: evalModule(env, ctx);
142: return Values.make((gnu.lists.TreeList) ctx.vstack);
143: }
144:
145: public final void evalModule(Environment env, CallContext ctx)
146: throws Throwable {
147: Environment orig_env = Environment.getCurrent();
148: try {
149: if (env != orig_env)
150: Environment.setCurrent(env);
151:
152: if (debugPrintExpr) {
153: OutPort dout = OutPort.outDefault();
154: dout.println("[Evaluating module \"" + getName()
155: + "\" mustCompile=" + mustCompile + ':');
156: this .print(dout);
157: dout.println(']');
158: dout.flush();
159: }
160:
161: if (!mustCompile) // optimization - don't generate unneeded Class.
162: body.eval(env, ctx);
163: else {
164: ModuleBody mod = (ModuleBody) eval(env);
165: //gnu.kawa.reflect.ClassMemberConstraint.defineAll(mod, env);
166: ctx.proc = mod;
167: }
168: ctx.runUntilDone();
169: } finally {
170: if (env != orig_env)
171: Environment.setCurrent(orig_env);
172: }
173: }
174:
175: ClassType super Type;
176: ClassType[] interfaces;
177:
178: public final ClassType getSuperType() {
179: return super Type;
180: }
181:
182: public final void setSuperType(ClassType s) {
183: super Type = s;
184: }
185:
186: public final ClassType[] getInterfaces() {
187: return interfaces;
188: }
189:
190: public final void setInterfaces(ClassType[] s) {
191: interfaces = s;
192: }
193:
194: public final boolean isStatic() {
195: return (getFlag(STATIC_SPECIFIED) || (gnu.expr.Compilation.moduleStatic > 0
196: && !getFlag(SUPERTYPE_SPECIFIED) && !getFlag(NONSTATIC_SPECIFIED)));
197: }
198:
199: void allocFields(Compilation comp) {
200: for (Declaration decl = firstDecl(); decl != null; decl = decl
201: .nextDecl()) {
202: if ((decl.isSimple() && !decl.isPublic())
203: || decl.field != null)
204: continue;
205: /* NICE: remove spurious dependancy
206: if (decl.getFlag(Declaration.IS_SYNTAX)
207: && ((kawa.lang.Macro) decl.getConstantValue()).expander instanceof LambdaExp
208: && ! decl.isPrivate())
209: continue; // Handled in SetExp.
210: */
211: Expression value = decl.getValue();
212: if (value instanceof LambdaExp
213: && !(value instanceof ClassExp)) {
214: ((LambdaExp) value).allocFieldFor(comp);
215: } else {
216: if (!(value instanceof QuoteExp)
217: || !decl.getFlag(Declaration.IS_CONSTANT)
218: || comp.immediate)
219: value = null;
220: decl.makeField(comp, value);
221: }
222: }
223: }
224:
225: public void compileToFiles(String topname, String directory,
226: String prefix) throws java.io.IOException {
227: if (directory == null || directory.length() == 0)
228: directory = "";
229: else if (directory.charAt(directory.length() - 1) != File.separatorChar)
230: directory = directory + File.separatorChar;
231: String name = getName();
232: if (name != null) {
233: topname = name;
234: if (prefix == null) {
235: int index = name.lastIndexOf('.');
236: if (index >= 0)
237: prefix = name.substring(0, index + 1);
238: }
239: }
240:
241: if (debugPrintExpr) {
242: OutPort dout = OutPort.outDefault();
243: dout.println("[Compiling module-name:" + getName()
244: + " top:" + topname + " prefix=" + prefix + " :");
245: this .print(dout);
246: dout.println(']');
247: dout.flush();
248: }
249:
250: /* DEBUGGING:
251: OutPort perr = OutPort.errDefault();
252: perr.println ("[Expression to compile topname:"+topname+" prefix:"+prefix);
253: this.print (perr);
254: perr.println();
255: perr.flush();
256: */
257:
258: Compilation comp = new Compilation(this , topname, prefix, false);
259: for (int iClass = 0; iClass < comp.numClasses; iClass++) {
260: ClassType clas = comp.classes[iClass];
261: String out_name = (directory
262: + clas.getName().replace('.', File.separatorChar) + ".class");
263: String parent = new File(out_name).getParent();
264: if (parent != null)
265: new File(parent).mkdirs();
266: clas.writeToFile(out_name);
267: }
268: }
269:
270: public void compileToArchive(String fname)
271: throws java.io.IOException {
272: boolean makeJar = false;
273: if (fname.endsWith(".zip"))
274: makeJar = false;
275: else if (fname.endsWith(".jar"))
276: makeJar = true;
277: else {
278: fname = fname + ".zip";
279: makeJar = false;
280: }
281: Compilation comp = new Compilation(this ,
282: LambdaExp.fileFunctionName, null, false);
283: File zar_file = new File(fname);
284: if (zar_file.exists())
285: zar_file.delete();
286: ZipOutputStream zout;
287: /* Java2:
288: if (makeJar)
289: zout = new JarOutputStream (new FileOutputStream (zar_file));
290: else
291: */
292: {
293: zout = new ZipOutputStream(new FileOutputStream(zar_file));
294: zout.setMethod(zout.STORED); // no compression
295: }
296:
297: byte[][] classes = new byte[comp.numClasses][];
298: CRC32 zcrc = new CRC32();
299: for (int iClass = 0; iClass < comp.numClasses; iClass++) {
300: ClassType clas = comp.classes[iClass];
301: classes[iClass] = clas.writeToArray();
302: ZipEntry zent = new ZipEntry(clas.getName().replace('.',
303: '/')
304: + ".class");
305:
306: zent.setSize(classes[iClass].length);
307: zcrc.reset();
308: zcrc.update(classes[iClass], 0, classes[iClass].length);
309: zent.setCrc(zcrc.getValue());
310:
311: zout.putNextEntry(zent);
312: zout.write(classes[iClass]);
313: }
314: zout.close();
315: }
316:
317: protected Expression walk(ExpWalker walker) {
318: return walker.walkModuleExp(this );
319: }
320:
321: public void print(OutPort out) {
322: out.startLogicalBlock("(Module/", ")", 2);
323: if (name != null) {
324: out.print(name);
325: out.print('/');
326: }
327: out.print(id);
328: out.print('/');
329: out.writeSpaceFill();
330: out.startLogicalBlock("(", false, ")");
331: for (Declaration decl = firstDecl(); decl != null; decl = decl
332: .nextDecl()) {
333: out.print(decl);
334: out.writeSpaceFill();
335: }
336: out.endLogicalBlock(")");
337: out.writeSpaceLinear();
338: if (body == null)
339: out.print("<null body>");
340: else
341: body.print(out);
342: out.endLogicalBlock(")");
343: }
344: }
|