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

Last change on this file was 12749, checked in by Mark Evenson, 14 years ago

Undo previous commmit.

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