source: branches/0.17.x/abcl/src/org/armedbear/lisp/Interpreter.java

Last change on this file was 12255, checked in by ehuelsmann, 16 years ago

Rename ConditionThrowable? to ControlTransfer? and remove

try/catch blocks which don't have anything to do with
non-local transfer of control.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.6 KB
Line 
1/*
2 * Interpreter.java
3 *
4 * Copyright (C) 2002-2006 Peter Graves
5 * $Id: Interpreter.java 12255 2009-11-06 22:36:32Z ehuelsmann $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import java.io.BufferedReader;
37import java.io.File;
38import java.io.IOException;
39import java.io.InputStream;
40import java.io.InputStreamReader;
41import java.io.OutputStream;
42
43public final class Interpreter extends Lisp
44{
45    // There can only be one interpreter.
46    public static Interpreter interpreter;
47
48    private final boolean jlisp;
49    private final InputStream inputStream;
50    private final OutputStream outputStream;
51
52    private static boolean noinit = false;
53    private static boolean noinform = false;
54
55    public static synchronized Interpreter getInstance()
56    {
57        return interpreter;
58    }
59
60    // Interface.
61    public static synchronized Interpreter createInstance()
62    {
63        if (interpreter != null)
64            return null;
65        interpreter = new Interpreter();
66        _NOINFORM_.setSymbolValue(T);
67        initializeLisp();
68        return interpreter;
69    }
70
71    public static synchronized Interpreter createDefaultInstance(String[] args)
72    {
73        if (interpreter != null)
74            return null;
75        interpreter = new Interpreter();
76        try {
77            if (args != null)
78                preprocessCommandLineArguments(args);
79            if (!noinform) {
80                Stream out = getStandardOutput();
81                out._writeString(banner());
82                out._finishOutput();
83            }
84            if (noinform)
85                _NOINFORM_.setSymbolValue(T);
86            else {
87                double uptime = (System.currentTimeMillis() - Main.startTimeMillis) / 1000.0;
88                getStandardOutput()._writeString("Low-level initialization completed in " +
89                                                 uptime + " seconds.\n");
90            }
91            initializeLisp();
92            initializeTopLevel();
93            if (!noinit)
94                processInitializationFile();
95            if (args != null)
96                postprocessCommandLineArguments(args);
97        }
98        catch (Throwable t) {
99            t.printStackTrace();
100        }
101        return interpreter;
102    }
103
104    public static synchronized Interpreter createJLispInstance(
105        InputStream in,
106        OutputStream out,
107        String initialDirectory,
108        String version)
109    {
110        if (interpreter != null)
111            return null;
112        interpreter = new Interpreter(in, out, initialDirectory);
113        try {
114            Stream stdout = getStandardOutput();
115            stdout._writeLine(version);
116            stdout._writeString(banner());
117            stdout._finishOutput();
118        }
119        catch (Throwable t) {
120            t.printStackTrace();
121        }
122        initializeJLisp();
123        initializeTopLevel();
124        processInitializationFile();
125        return interpreter;
126    }
127
128    private Interpreter()
129    {
130        jlisp = false;
131        inputStream = null;
132        outputStream = null;
133    }
134
135    private Interpreter(InputStream inputStream, OutputStream outputStream,
136                        String initialDirectory)
137    {
138        jlisp = true;
139        this.inputStream = inputStream;
140        this.outputStream = outputStream;
141        resetIO(new Stream(inputStream, Symbol.CHARACTER),
142                new Stream(outputStream, Symbol.CHARACTER));
143        if (!initialDirectory.endsWith(File.separator))
144            initialDirectory = initialDirectory.concat(File.separator);
145        try {
146            Symbol.DEFAULT_PATHNAME_DEFAULTS.setSymbolValue(new Pathname(initialDirectory));
147        }
148        catch (Throwable t) {
149            Debug.trace(t);
150        }
151    }
152
153    // Interface.
154    public LispObject eval(String s)
155    {
156        return eval(new StringInputStream(s).read(true, NIL, false,
157                                                  LispThread.currentThread()));
158    }
159
160    public static synchronized void initializeLisp()
161    {
162        if (!initialized) {
163            Load.loadSystemFile("boot.lisp", false, false, false);
164            initialized = true;
165        }
166    }
167
168    public static synchronized void initializeJLisp()
169    {
170        if (!initialized) {
171            try {
172                Symbol.FEATURES.setSymbolValue(new Cons(Keyword.J,
173                                                   Symbol.FEATURES.getSymbolValue()));
174                Load.loadSystemFile("boot.lisp", false, false, false);
175                Class.forName("org.armedbear.j.LispAPI");
176                Load.loadSystemFile("j.lisp");
177            }
178            catch (Throwable t) {
179                // ### FIXME exception
180                t.printStackTrace();
181            }
182            initialized = true;
183        }
184    }
185
186    private static boolean topLevelInitialized;
187
188    private static synchronized void initializeTopLevel()
189    {
190        if (!topLevelInitialized) {
191            try {
192                // Resolve top-level-loop autoload.
193                Symbol TOP_LEVEL_LOOP = intern("TOP-LEVEL-LOOP", PACKAGE_TPL);
194                LispObject tplFun = TOP_LEVEL_LOOP.getSymbolFunction();
195                if (tplFun instanceof Autoload) {
196                    Autoload autoload = (Autoload) tplFun;
197                    autoload.load();
198                }
199            }
200            catch (Throwable t) {
201                t.printStackTrace();
202            }
203            topLevelInitialized = true;
204        }
205    }
206
207    private static synchronized void processInitializationFile()
208    {
209        try {
210            String userHome = System.getProperty("user.home");
211            File file = new File(userHome, ".abclrc");
212            if (file.isFile()) {
213                Load.load(file.getCanonicalPath());
214                return;
215            }
216        }
217        catch (Throwable t) {
218            t.printStackTrace();
219        }
220    }
221
222    // Check for --noinit; verify that arguments are supplied for --load and
223    // --eval options.
224    private static void preprocessCommandLineArguments(String[] args)
225
226    {
227        if (args != null) {
228            for (int i = 0; i < args.length; ++i) {
229                String arg = args[i];
230                if (arg.equals("--noinit")) {
231                    noinit = true;
232                } else if (arg.equals("--noinform")) {
233                    noinform = true;
234                } else if (arg.equals("--batch")) {
235                    _BATCH_MODE_.setSymbolValue(T);
236                } else if (arg.equals("--eval")) {
237                    if (i + 1 < args.length) {
238                        ++i;
239                    } else {
240                        System.err.println("No argument supplied to --eval");
241                        System.exit(1);
242                    }
243                } else if (arg.equals("--load") ||
244                           arg.equals("--load-system-file")) {
245                    if (i + 1 < args.length) {
246                        ++i;
247                    } else {
248                        System.err.println("No argument supplied to --load");
249                        System.exit(1);
250                    }
251                }
252            }
253        }
254    }
255
256    // Do the --load and --eval actions.
257    private static void postprocessCommandLineArguments(String[] args)
258
259    {
260        if (args != null) {
261            for (int i = 0; i < args.length; ++i) {
262                String arg = args[i];
263                if (arg.equals("--eval")) {
264                    if (i + 1 < args.length) {
265                        try {
266                            evaluate(args[i + 1]);
267                        }
268                        catch (UnhandledCondition c) {
269                            final String separator =
270                                System.getProperty("line.separator");
271                            FastStringBuffer sb = new FastStringBuffer();
272                            sb.append(separator);
273                            sb.append("Caught ");
274                            sb.append(c.getCondition().typeOf().writeToString());
275                            sb.append(" while processing --eval option \"" +
276                                      args[i + 1] + "\":");
277                            sb.append(separator);
278                            sb.append("  ");
279                            final LispThread thread = LispThread.currentThread();
280                            thread.bindSpecial(Symbol.PRINT_ESCAPE, NIL);
281                            sb.append(c.getCondition().writeToString());
282                            sb.append(separator);
283                            System.err.print(sb.toString());
284                            System.exit(2);
285                        }
286                        ++i;
287                    } else {
288                        // Shouldn't happen.
289                        System.err.println("No argument supplied to --eval");
290                        System.exit(1);
291                    }
292                } else if (arg.equals("--load") ||
293                           arg.equals("--load-system-file")) {
294                    if (i + 1 < args.length) {
295                        if (arg.equals("--load"))
296                            Load.load(new Pathname(args[i + 1]),
297                                      args[i + 1],
298                                      false, false, true);
299                        else
300                            Load.loadSystemFile(args[i + 1]);
301                        ++i;
302                    } else {
303                        // Shouldn't happen.
304                        System.err.println("No argument supplied to --load");
305                        System.exit(1);
306                    }
307                }
308            }
309        }
310    }
311
312    public void run()
313    {
314        final LispThread thread = LispThread.currentThread();
315        try {
316            Symbol TOP_LEVEL_LOOP = intern("TOP-LEVEL-LOOP", PACKAGE_TPL);
317            LispObject tplFun = TOP_LEVEL_LOOP.getSymbolFunction();
318            if (tplFun instanceof Function) {
319                thread.execute(tplFun);
320                return;
321            }
322            // We only arrive here if something went wrong and we weren't able
323            // to load top-level.lisp and run the normal top-level loop.
324            Stream out = getStandardOutput();
325            while (true) {
326                try {
327                    thread.resetStack();
328                    thread.lastSpecialBinding = null;
329                    out._writeString("* ");
330                    out._finishOutput();
331                    LispObject object =
332                        getStandardInput().read(false, EOF, false, thread);
333                    if (object == EOF)
334                        break;
335                    out.setCharPos(0);
336                    Symbol.MINUS.setSymbolValue(object);
337                    LispObject result = eval(object, new Environment(), thread);
338                    Debug.assertTrue(result != null);
339                    Symbol.STAR_STAR_STAR.setSymbolValue(Symbol.STAR_STAR.getSymbolValue());
340                    Symbol.STAR_STAR.setSymbolValue(Symbol.STAR.getSymbolValue());
341                    Symbol.STAR.setSymbolValue(result);
342                    Symbol.PLUS_PLUS_PLUS.setSymbolValue(Symbol.PLUS_PLUS.getSymbolValue());
343                    Symbol.PLUS_PLUS.setSymbolValue(Symbol.PLUS.getSymbolValue());
344                    Symbol.PLUS.setSymbolValue(Symbol.MINUS.getSymbolValue());
345                    out = getStandardOutput();
346                    out.freshLine();
347                    LispObject[] values = thread.getValues();
348                    Symbol.SLASH_SLASH_SLASH.setSymbolValue(Symbol.SLASH_SLASH.getSymbolValue());
349                    Symbol.SLASH_SLASH.setSymbolValue(Symbol.SLASH.getSymbolValue());
350                    if (values != null) {
351                        LispObject slash = NIL;
352                        for (int i = values.length; i-- > 0;)
353                            slash = new Cons(values[i], slash);
354                        Symbol.SLASH.setSymbolValue(slash);
355                        for (int i = 0; i < values.length; i++)
356                            out._writeLine(values[i].writeToString());
357                    } else {
358                        Symbol.SLASH.setSymbolValue(new Cons(result));
359                        out._writeLine(result.writeToString());
360                    }
361                    out._finishOutput();
362                }
363                catch (StackOverflowError e) {
364                    getStandardInput().clearInput();
365                    out._writeLine("Stack overflow");
366                }
367                catch (ControlTransfer c) {
368                    // We're on the toplevel, if this occurs,
369                    // we're toast...
370                    reportError(c, thread);
371                }
372                catch (Throwable t) {
373                    getStandardInput().clearInput();
374                    out.printStackTrace(t);
375                    thread.printBacktrace();
376                }
377            }
378        }
379        catch (Throwable t) {
380            t.printStackTrace();
381        }
382    }
383
384    private static void reportError(ControlTransfer c, LispThread thread)
385    {
386        try {
387            getStandardInput().clearInput();
388            Stream out = getStandardOutput();
389            out.freshLine();
390            Condition condition = (Condition) c.getCondition();
391            out._writeLine("Error: unhandled condition: " +
392                           condition.writeToString());
393            if (thread != null)
394                thread.printBacktrace();
395        }
396        catch (Throwable t) {
397           
398        }
399    }
400
401    private static void reportError(UnhandledCondition c, LispThread thread)
402    {
403        try {
404            getStandardInput().clearInput();
405            Stream out = getStandardOutput();
406            out.freshLine();
407            Condition condition = (Condition) c.getCondition();
408            out._writeLine("Error: unhandled condition: " +
409                           condition.writeToString());
410            if (thread != null)
411                thread.printBacktrace();
412        }
413        catch (Throwable t) {
414           
415        }
416    }
417
418    public void kill()
419    {
420        kill(0);
421    }
422
423    public void kill(int status)
424    {
425        if (jlisp) {
426            try {
427                inputStream.close();
428            }
429            catch (IOException e) {
430                Debug.trace(e);
431            }
432            try {
433                outputStream.close();
434            }
435            catch (IOException e) {
436                Debug.trace(e);
437            }
438        } else
439            System.exit(status);
440    }
441
442    public synchronized void dispose()
443    {
444        Debug.trace("Interpreter.dispose");
445        Debug.assertTrue(interpreter == this);
446        interpreter = null;
447    }
448
449    @Override
450    protected void finalize() throws Throwable
451    {
452        System.err.println("Interpreter.finalize");
453    }
454
455    public static final class UnhandledCondition extends Error
456    {
457        LispObject condition;
458
459        UnhandledCondition(LispObject condition) {
460            this.condition = condition;
461        }
462
463        public LispObject getCondition() {
464            return condition;
465        }
466    };
467
468    private static final Primitive _DEBUGGER_HOOK_FUNCTION =
469        new Primitive("%debugger-hook-function", PACKAGE_SYS, false)
470    {
471        @Override
472        public LispObject execute(LispObject first, LispObject second)
473            throws UnhandledCondition
474        {
475            final Condition condition = (Condition) first;
476            if (interpreter == null) {
477                final LispThread thread = LispThread.currentThread();
478                final SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
479                thread.bindSpecial(Symbol.PRINT_ESCAPE, NIL);
480                try {
481                    final LispObject truename =
482                        Symbol.LOAD_TRUENAME.symbolValue(thread);
483                    if (truename != NIL) {
484                        final LispObject stream =
485                            _LOAD_STREAM_.symbolValue(thread);
486                        if (stream instanceof Stream) {
487                            final int lineNumber =
488                                ((Stream)stream).getLineNumber() + 1;
489                            final int offset =
490                                ((Stream)stream).getOffset();
491                            Debug.trace("Error loading " +
492                                        truename.writeToString() +
493                                        " at line " + lineNumber +
494                                        " (offset " + offset + ")");
495                        }
496                    }
497                    Debug.trace("Encountered unhandled condition of type " +
498                                condition.typeOf().writeToString() + ':');
499                    Debug.trace("  " + condition.writeToString());
500                }
501                catch (Throwable t) {}
502                finally {
503                    thread.lastSpecialBinding = lastSpecialBinding;
504                }
505            }
506            throw new UnhandledCondition(condition);
507        }
508    };
509
510    public static final LispObject readFromString(String s)
511    {
512        try {
513            return new StringInputStream(s).read(true, NIL, false,
514                                                 LispThread.currentThread());
515        }
516        catch (Throwable t) {
517            return null;
518        }
519    }
520
521    // For j.
522    /** Runs its input string through the lisp reader and evaluates the result.
523     *
524     * @param s A string with a valid Common Lisp expression
525     * @return The result of the evaluation
526     * @exception UnhandledCondition in case the an error occurs which
527     *      should be passed to the Lisp debugger
528     */
529    public static LispObject evaluate(String s)
530    {
531        if (!initialized)
532            initializeJLisp();
533        StringInputStream stream = new StringInputStream(s);
534        final LispThread thread = LispThread.currentThread();
535        LispObject obj = stream.read(false, EOF, false, thread);
536        if (obj == EOF)
537            return error(new EndOfFile(stream));
538        final SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
539        thread.bindSpecial(Symbol.DEBUGGER_HOOK, _DEBUGGER_HOOK_FUNCTION);
540        try {
541            return eval(obj, new Environment(), thread);
542        }
543        finally {
544            thread.lastSpecialBinding = lastSpecialBinding;
545        }
546    }
547
548    private static final String build;
549
550    static {
551        String s = null;
552        InputStream in = Interpreter.class.getResourceAsStream("build");
553        if (in != null) {
554            try {
555                BufferedReader reader =
556                    new BufferedReader(new InputStreamReader(in));
557                s = reader.readLine();
558                reader.close();
559            }
560            catch (IOException e) {}
561        }
562        build = s;
563    }
564
565    private static String banner()
566    {
567        final String sep = System.getProperty("line.separator");
568        FastStringBuffer sb = new FastStringBuffer("Armed Bear Common Lisp ");
569        sb.append(Version.getVersion());
570        if (build != null) {
571            sb.append(" (built ");
572            sb.append(build);
573            sb.append(')');
574        }
575        sb.append(sep);
576        sb.append("Java ");
577        sb.append(System.getProperty("java.version"));
578        sb.append(' ');
579        sb.append(System.getProperty("java.vendor"));
580        sb.append(sep);
581        String vm = System.getProperty("java.vm.name");
582        if (vm != null) {
583            sb.append(vm);
584            sb.append(sep);
585        }
586        return sb.toString();
587    }
588}
Note: See TracBrowser for help on using the repository browser.