001: /*
002: * Interpreter.java
003: *
004: * Copyright (C) 2002-2004 Peter Graves
005: * $Id: Interpreter.java,v 1.73 2004/09/15 17:52:50 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.lisp;
023:
024: import java.io.BufferedReader;
025: import java.io.File;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.InputStreamReader;
029: import java.io.OutputStream;
030: import java.lang.reflect.Method;
031:
032: public final class Interpreter extends Lisp {
033: // There can only be one interpreter.
034: public static Interpreter interpreter;
035:
036: private static int commandNumber;
037:
038: private final boolean jlisp;
039: private final InputStream inputStream;
040: private final OutputStream outputStream;
041:
042: public static synchronized Interpreter getInstance() {
043: return interpreter;
044: }
045:
046: public static synchronized Interpreter createInstance() {
047: if (interpreter != null)
048: return null;
049: return interpreter = new Interpreter();
050: }
051:
052: public static synchronized Interpreter createInstance(
053: InputStream in, OutputStream out, String initialDirectory) {
054: if (interpreter != null)
055: return null;
056: return interpreter = new Interpreter(in, out, initialDirectory);
057: }
058:
059: private final Environment environment = new Environment();
060:
061: private Interpreter() {
062: jlisp = false;
063: inputStream = null;
064: outputStream = null;
065: }
066:
067: private Interpreter(InputStream inputStream,
068: OutputStream outputStream, String initialDirectory) {
069: jlisp = true;
070: this .inputStream = inputStream;
071: this .outputStream = outputStream;
072: resetIO(new Stream(inputStream, Symbol.CHARACTER), new Stream(
073: outputStream, Symbol.CHARACTER));
074: if (!initialDirectory.endsWith(File.separator))
075: initialDirectory = initialDirectory.concat(File.separator);
076: try {
077: _DEFAULT_PATHNAME_DEFAULTS_.setSymbolValue(new Pathname(
078: initialDirectory));
079: } catch (Throwable t) {
080: Debug.trace(t);
081: }
082: }
083:
084: public static synchronized void initializeLisp(boolean jlisp) {
085: if (!initialized) {
086: try {
087: if (jlisp) {
088: _FEATURES_.setSymbolValue(new Cons(Keyword.J,
089: _FEATURES_.getSymbolValue()));
090: }
091: Load.loadSystemFile("boot.lisp", false, false, false);
092: if (jlisp) {
093: Class.forName("org.armedbear.j.LispAPI");
094: Load.loadSystemFile("j.lisp");
095: }
096: } catch (ConditionThrowable c) {
097: reportError(c, LispThread.currentThread());
098: } catch (Throwable t) {
099: t.printStackTrace();
100: }
101: initialized = true;
102: }
103: }
104:
105: private static boolean topLevelInitialized;
106:
107: private static synchronized void initializeTopLevel() {
108: if (!topLevelInitialized) {
109: try {
110: // Resolve top-level-loop autoload.
111: Symbol TOP_LEVEL_LOOP = intern("TOP-LEVEL-LOOP",
112: PACKAGE_TPL);
113: LispObject tplFun = TOP_LEVEL_LOOP.getSymbolFunction();
114: if (tplFun instanceof Autoload) {
115: Autoload autoload = (Autoload) tplFun;
116: autoload.load();
117: }
118: do {
119: String userHome = System.getProperty("user.home");
120: File file = new File(userHome, ".abclrc");
121: if (file.isFile()) {
122: Load.load(file.getCanonicalPath());
123: break;
124: }
125: if (Utilities.isPlatformWindows()) {
126: file = new File("C:\\.abclrc");
127: if (file.isFile()) {
128: Load.load(file.getCanonicalPath());
129: break;
130: }
131: }
132: file = new File(userHome, ".ablrc");
133: if (file.isFile()) {
134: String message = "Warning: use of .ablrc is deprecated; use .abclrc instead.";
135: getStandardOutput()._writeLine(message);
136: Load.load(file.getCanonicalPath());
137: break;
138: }
139: file = new File(userHome, ".ablisprc");
140: if (file.isFile()) {
141: String message = "Warning: use of .ablisprc is deprecated; use .abclrc instead.";
142: getStandardOutput()._writeLine(message);
143: Load.load(file.getCanonicalPath());
144: break;
145: }
146: } while (false);
147: } catch (Throwable t) {
148: t.printStackTrace();
149: }
150: topLevelInitialized = true;
151: }
152: }
153:
154: private void processCommandLineArguments(String[] args) {
155: if (args.length > 0) {
156: for (int i = 0; i < args.length; ++i) {
157: String arg = args[i];
158: if (arg.equals("--eval")) {
159: if (i + 1 < args.length) {
160: LispObject result = null;
161: try {
162: result = evaluate(args[i + 1]);
163: } catch (ConditionThrowable c) {
164: System.err.println("Caught condition: "
165: + c.getCondition().toString()
166: + " while evaluating: "
167: + args[i + 1]);
168: System.exit(2);
169: }
170: ++i;
171: } else {
172: System.err
173: .println("No argument supplied to --eval");
174: System.exit(1);
175: }
176: } else if (arg.equals("--load")
177: || arg.equals("--load-system-file")) {
178: if (i + 1 < args.length) {
179: try {
180: if (arg.equals("--load"))
181: Load.load(args[i + 1], false, false,
182: true);
183: else
184: Load.loadSystemFile(args[i + 1]);
185: } catch (ConditionThrowable c) {
186: System.err.println("Caught condition: "
187: + c.getCondition().toString()
188: + " while loading: " + args[i + 1]);
189: System.exit(2);
190: }
191: ++i;
192: } else {
193: System.err
194: .println("No argument supplied to --load");
195: System.exit(1);
196: }
197: }
198: }
199: }
200: }
201:
202: public void run(String[] args) {
203: LispThread thread = null;
204: try {
205: thread = LispThread.currentThread();
206: } catch (Throwable t) {
207: return;
208: }
209: commandNumber = 0;
210: try {
211: Stream out = getStandardOutput();
212: out._writeString(banner());
213: out._finishOutput();
214: if (Utilities.isPlatformUnix()) {
215: try {
216: System.loadLibrary("abcl");
217: Class c = Class
218: .forName("org.armedbear.lisp.ControlC");
219: Method m = c.getMethod("initialize", null);
220: m.invoke(null, null);
221: out._writeString("Control-C handler installed.\n");
222: } catch (Throwable t) {
223: }
224: }
225: if (!jlisp) {
226: double uptime = (System.currentTimeMillis() - Main.startTimeMillis) / 1000.0;
227: System.out
228: .println("Low-level initialization completed in "
229: + uptime + " seconds.");
230: }
231: initializeLisp(jlisp);
232: initializeTopLevel();
233: if (args != null)
234: processCommandLineArguments(args);
235: Symbol TOP_LEVEL_LOOP = intern("TOP-LEVEL-LOOP",
236: PACKAGE_TPL);
237: LispObject tplFun = TOP_LEVEL_LOOP.getSymbolFunction();
238: if (tplFun instanceof Function) {
239: funcall0(tplFun, thread);
240: return;
241: }
242: while (true) {
243: try {
244: thread.resetStack();
245: thread.setDynamicEnvironment(null);
246: ++commandNumber;
247: out._writeString(prompt());
248: out._finishOutput();
249: LispObject object = getStandardInput().read(false,
250: EOF, false); // Top level read.
251: if (object == EOF)
252: break;
253: out.setCharPos(0);
254: Symbol.MINUS.setSymbolValue(object);
255: LispObject result = eval(object, environment,
256: thread);
257: Debug.assertTrue(result != null);
258: Symbol.STAR_STAR_STAR
259: .setSymbolValue(Symbol.STAR_STAR
260: .getSymbolValue());
261: Symbol.STAR_STAR.setSymbolValue(Symbol.STAR
262: .getSymbolValue());
263: Symbol.STAR.setSymbolValue(result);
264: Symbol.PLUS_PLUS_PLUS
265: .setSymbolValue(Symbol.PLUS_PLUS
266: .getSymbolValue());
267: Symbol.PLUS_PLUS.setSymbolValue(Symbol.PLUS
268: .getSymbolValue());
269: Symbol.PLUS.setSymbolValue(Symbol.MINUS
270: .getSymbolValue());
271: out = getStandardOutput();
272: out.freshLine();
273: LispObject[] values = thread.getValues();
274: Symbol.SLASH_SLASH_SLASH
275: .setSymbolValue(Symbol.SLASH_SLASH
276: .getSymbolValue());
277: Symbol.SLASH_SLASH.setSymbolValue(Symbol.SLASH
278: .getSymbolValue());
279: if (values != null) {
280: LispObject slash = NIL;
281: for (int i = values.length; i-- > 0;)
282: slash = new Cons(values[i], slash);
283: Symbol.SLASH.setSymbolValue(slash);
284: for (int i = 0; i < values.length; i++)
285: out._writeLine(values[i].writeToString());
286: } else {
287: Symbol.SLASH.setSymbolValue(new Cons(result));
288: out._writeLine(result.writeToString());
289: }
290: out._finishOutput();
291: } catch (StackOverflowError e) {
292: getStandardInput().clearInput();
293: out._writeLine("Stack overflow");
294: } catch (ConditionThrowable c) {
295: reportError(c, thread);
296: } catch (Throwable t) {
297: getStandardInput().clearInput();
298: out.printStackTrace(t);
299: thread.backtrace();
300: }
301: }
302: } catch (Throwable t) {
303: t.printStackTrace();
304: }
305: }
306:
307: private static void reportError(ConditionThrowable c,
308: LispThread thread) {
309: try {
310: getStandardInput().clearInput();
311: Stream out = getStandardOutput();
312: out.freshLine();
313: Condition condition = (Condition) c.getCondition();
314: out._writeLine("Error: unhandled condition: "
315: + condition.getConditionReport());
316: if (thread != null)
317: thread.backtrace();
318: } catch (Throwable t) {
319: ;
320: }
321: }
322:
323: public void kill() {
324: if (jlisp) {
325: try {
326: inputStream.close();
327: } catch (IOException e) {
328: Debug.trace(e);
329: }
330: try {
331: outputStream.close();
332: } catch (IOException e) {
333: Debug.trace(e);
334: }
335: } else
336: System.exit(0);
337: }
338:
339: public synchronized void dispose() {
340: Debug.trace("Interpreter.dispose");
341: Debug.assertTrue(interpreter == this );
342: interpreter = null;
343: }
344:
345: protected void finalize() throws Throwable {
346: System.err.println("Interpreter.finalize");
347: }
348:
349: private static final Primitive2 _DEBUGGER_HOOK_FUNCTION = new Primitive2(
350: "%debugger-hook-function", PACKAGE_SYS, false) {
351: public LispObject execute(LispObject first, LispObject second)
352: throws ConditionThrowable {
353: throw new ConditionThrowable((Condition) first);
354: }
355: };
356:
357: // Used only by org.armedbear.j.Editor.executeCommand().
358: public static LispObject evaluate(String s)
359: throws ConditionThrowable {
360: if (!initialized)
361: initializeLisp(true);
362: StringInputStream stream = new StringInputStream(s);
363: LispObject obj = stream.read(false, EOF, false);
364: if (obj == EOF)
365: return signal(new EndOfFile(stream));
366: final LispThread thread = LispThread.currentThread();
367: final Environment oldDynEnv = thread.getDynamicEnvironment();
368: thread.bindSpecial(_DEBUGGER_HOOK_, _DEBUGGER_HOOK_FUNCTION);
369: try {
370: return eval(obj, new Environment(), thread);
371: } finally {
372: thread.setDynamicEnvironment(oldDynEnv);
373: }
374: }
375:
376: private static final String build;
377:
378: static {
379: String s = null;
380: InputStream in = Interpreter.class.getResourceAsStream("build");
381: if (in != null) {
382: try {
383: BufferedReader reader = new BufferedReader(
384: new InputStreamReader(in));
385: s = reader.readLine();
386: reader.close();
387: } catch (IOException e) {
388: }
389: }
390: build = s;
391: }
392:
393: private static String banner() {
394: final String sep = System.getProperty("line.separator");
395: StringBuffer sb = new StringBuffer("Armed Bear Common Lisp ");
396: sb.append(Version.getVersion());
397: if (build != null) {
398: sb.append(" (built ");
399: sb.append(build);
400: sb.append(')');
401: }
402: sb.append(sep);
403: sb.append("Java ");
404: sb.append(System.getProperty("java.version"));
405: sb.append(' ');
406: sb.append(System.getProperty("java.vendor"));
407: sb.append(sep);
408: String vm = System.getProperty("java.vm.name");
409: if (vm != null) {
410: sb.append(vm);
411: sb.append(sep);
412: }
413: return sb.toString();
414: }
415:
416: private static String prompt() {
417: Package pkg = (Package) _PACKAGE_.getSymbolValue();
418: String pkgName = pkg.getNickname();
419: if (pkgName == null)
420: pkgName = pkg.getName();
421: StringBuffer sb = new StringBuffer();
422: sb.append(pkgName);
423: sb.append('(');
424: sb.append(commandNumber);
425: sb.append(")> ");
426: return sb.toString();
427: }
428: }
|