source: branches/0.19.x/abcl/src/org/armedbear/lisp/Load.java

Last change on this file was 12553, checked in by Mark Evenson, 15 years ago

Backport r12550: Fix loading of packed FASLs which have been renamed.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 27.9 KB
Line 
1/*
2 * Load.java
3 *
4 * Copyright (C) 2002-2007 Peter Graves
5 * $Id: Load.java 12553 2010-03-17 13:22:36Z 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.IOException;
39import java.io.InputStream;
40import java.net.URL;
41
42/* This file holds ABCL's (FASL and non-FASL) loading behaviours.
43 *
44 * The loading process works like this:
45 *   The loader associates the input filename with a special variable
46 *   and starts evaluating the forms in the file.
47 *
48 *   If one of the forms is (INIT-FASL :VERSION <version>), from that
49 *   point the file is taken to be a FASL.
50 *   The FASL loader takes over and retrieves the file being loaded
51 *   from the special variable and continues loading from there.
52 *
53 */
54public final class Load
55{
56    public static final LispObject load(String filename)
57    {
58        final LispThread thread = LispThread.currentThread();
59        return load(new Pathname(filename),
60                    Symbol.LOAD_VERBOSE.symbolValue(thread) != NIL,
61                    Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
62                    true);
63    }
64 
65    /** @return Pathname of loadable file based on NAME, or null if
66     * none can be determined. */
67    private static final Pathname findLoadableFile(Pathname name) {
68        LispObject truename  = Pathname.truename(name, false);
69        if (truename instanceof Pathname) {
70            Pathname t = (Pathname)truename;
71            if (t.name != NIL
72                && t.name != null) {
73                return t;
74            }
75        }
76        if (name.type == NIL
77            && (name.name != NIL || name.name != null)) {
78            Pathname lispPathname = new Pathname(name);
79            lispPathname.type = new SimpleString("lisp");
80            lispPathname.invalidateNamestring();
81            LispObject lisp = Pathname.truename(lispPathname, false);
82            Pathname abclPathname = new Pathname(name);
83            abclPathname.type = new SimpleString("abcl");
84            abclPathname.invalidateNamestring();
85            LispObject abcl = Pathname.truename(abclPathname, false);
86            if (lisp instanceof Pathname && abcl instanceof Pathname) {
87                lispPathname = (Pathname)lisp;
88                abclPathname = (Pathname)abcl;
89                long lispLastModified = lispPathname.getLastModified();
90                long abclLastModified = abclPathname.getLastModified();
91              if (abclLastModified > lispLastModified) {
92                  return lispPathname;
93              } else {
94                  return abclPathname;
95              }
96            } else if (abcl instanceof Pathname) {
97                return (Pathname) abcl;
98            } else if (lisp instanceof Pathname) { 
99                return (Pathname) lisp;
100            }
101        }
102        if (name.isJar()) {
103            if (name.type.equals(NIL)) {
104                name.type = COMPILE_FILE_INIT_FASL_TYPE;
105                name.invalidateNamestring();
106                Pathname result = findLoadableFile(name);
107                if (result != null) {
108                    return result;
109                }
110                name.type = new SimpleString(COMPILE_FILE_TYPE);
111                name.invalidateNamestring();
112                result = findLoadableFile(name);
113                if (result != null) {
114                    return result;
115                }
116            }
117        }
118        return null;
119    }
120 
121    public static final LispObject load(Pathname pathname,
122                                        boolean verbose,
123                                        boolean print,
124                                        boolean ifDoesNotExist)
125    {
126        return load(pathname, verbose, print, ifDoesNotExist, false);
127    }
128
129    public static final LispObject load(final Pathname pathname,
130                                        boolean verbose,
131                                        boolean print,
132                                        boolean ifDoesNotExist,
133                                        boolean returnLastResult)
134
135    {
136        Pathname mergedPathname = null;
137        if (!pathname.isAbsolute() && !pathname.isJar()) {
138            Pathname pathnameDefaults
139                = coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue());
140            mergedPathname = Pathname.mergePathnames(pathname, pathnameDefaults);
141        }
142
143        Pathname truename = findLoadableFile(mergedPathname != null ? mergedPathname : pathname);
144
145        if (truename == null || truename.equals(NIL)) {
146            if (ifDoesNotExist) {
147                return error(new FileError("File not found.", pathname));
148            } else {
149                Debug.warn("Failed to load " + pathname.getNamestring());
150                return NIL;
151            }
152        }
153
154        if (Utilities.checkZipFile(truename)) {
155            String n = truename.getNamestring();
156            if (n.startsWith("jar:")) {
157                n = "jar:" + n + "!/" + truename.name.getStringValue() + "."
158                    + COMPILE_FILE_INIT_FASL_TYPE;
159            } else {
160                n = "jar:file:" + n + "!/" + truename.name.getStringValue() + "."
161                    + COMPILE_FILE_INIT_FASL_TYPE;
162            }
163            mergedPathname = new Pathname(n);
164            LispObject initTruename = Pathname.truename(mergedPathname);
165            if (initTruename == null || initTruename.equals(NIL)) {
166                // Maybe the enclosing JAR has been renamed?
167                Pathname p = new Pathname(mergedPathname);
168                p.name = Keyword.WILD;
169                p.invalidateNamestring();
170                LispObject result = Pathname.MATCH_WILD_JAR_PATHNAME.execute(p);
171
172                if      (result instanceof Cons
173                    && ((Cons)result).length() == 1
174                    && ((Cons)result).car() instanceof Pathname) {
175                    initTruename = (Pathname)result.car();
176                } else {
177                  String errorMessage
178                      = "Loadable FASL not found for "
179                      + "'" + pathname + "'"
180                      + " in "
181                      + "'" + mergedPathname + "'";
182                  if (ifDoesNotExist) {
183                      return error(new FileError(errorMessage, mergedPathname));
184                  } else {
185                      Debug.trace(errorMessage);
186                      return NIL;
187                  }
188                }
189            }
190            truename = (Pathname)initTruename;
191        }
192       
193        InputStream in = truename.getInputStream();
194        Debug.assertTrue(in != null);
195   
196        try {
197            return loadFileFromStream(pathname, truename,
198                                      new Stream(Symbol.SYSTEM_STREAM, in, Symbol.CHARACTER),
199                                      verbose, print, false, returnLastResult);
200        }
201        catch (FaslVersionMismatch e) {
202            StringBuilder sb =
203                new StringBuilder("Incorrect fasl version: ");
204            sb.append(truename);
205            return error(new SimpleError(sb.toString()));
206        }
207        finally {
208            if (in != null) {
209                try {
210                   in.close();
211                }
212                catch (IOException e) {
213                    return error(new LispError(e.getMessage()));
214                }
215            }
216        }
217    }
218
219    public static final LispObject loadSystemFile(String filename)
220
221    {
222        final LispThread thread = LispThread.currentThread();
223        return loadSystemFile(filename,
224                              Symbol.LOAD_VERBOSE.symbolValue(thread) != NIL,
225                              Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
226                              false);
227    }
228
229    public static final LispObject loadSystemFile(String filename, boolean auto)
230
231    {
232        LispThread thread = LispThread.currentThread();
233        if (auto) {
234            final SpecialBindingsMark mark = thread.markSpecialBindings();
235            thread.bindSpecial(Symbol.CURRENT_READTABLE,
236                               STANDARD_READTABLE.symbolValue(thread));
237            thread.bindSpecial(Symbol._PACKAGE_, PACKAGE_CL_USER);
238            try {
239                return loadSystemFile(filename,
240                                      _AUTOLOAD_VERBOSE_.symbolValue(thread) != NIL,
241                                      Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
242                                      auto);
243            }
244            finally {
245                thread.resetSpecialBindings(mark);
246            }
247        } else {
248            return loadSystemFile(filename,
249                                  Symbol.LOAD_VERBOSE.symbolValue(thread) != NIL,
250                                  Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
251                                  auto);
252        }
253    }
254
255    static final LispObject COMPILE_FILE_INIT_FASL_TYPE = new SimpleString("_");
256
257    public static final LispObject loadSystemFile(final String filename,
258                                                  boolean verbose,
259                                                  boolean print,
260                                                  boolean auto)
261
262    {
263        InputStream in = null;
264        Pathname pathname = null;
265        Pathname truename = null;
266        pathname = new Pathname(filename);
267        Pathname mergedPathname = Pathname.mergePathnames(pathname, Site.getLispHome());
268        truename = findLoadableFile(mergedPathname);
269        if (truename == null || truename.equals(NIL)) {
270            // Make an attempt to use the boot classpath
271            String path = pathname.asEntryPath();
272            URL url = Lisp.class.getResource(path);
273            if (url == null || url.toString().endsWith("/")) {
274                url = Lisp.class.getResource(path + ".abcl");
275                if (url == null) {
276                    url = Lisp.class.getResource(path + ".lisp");
277                }
278            }
279            if (url == null) {
280                return error(new LispError("Failed to find loadable system file "
281                                           + "'" + path + "'"
282                                           + " in boot classpath."));
283            }               
284            Pathname urlPathname = new Pathname(url);
285            truename = findLoadableFile(urlPathname);
286            if (truename == null) {
287                return error(new LispError("Failed to find loadable system file in boot classpath "
288                                           + "'" + url + "'"));
289            }
290        }
291
292        // Look for a init FASL inside a packed FASL
293        if (truename.type.writeToString().equals(COMPILE_FILE_TYPE) && Utilities.checkZipFile(truename))  {
294            Pathname init = new Pathname(truename.getNamestring());
295            init.type = COMPILE_FILE_INIT_FASL_TYPE;
296            LispObject t = Pathname.truename(init);
297            if (t instanceof Pathname) {
298                truename = (Pathname)t;
299            } else {
300                return error (new LispError("Failed to find loadable init FASL in "
301                                            + "'" + init.getNamestring() + "'"));
302            }
303        }
304
305        in = truename.getInputStream();
306
307        if (in != null) {
308            final LispThread thread = LispThread.currentThread();
309            final SpecialBindingsMark mark = thread.markSpecialBindings();
310            thread.bindSpecial(_WARN_ON_REDEFINITION_, NIL);
311            try {
312                Stream stream = new Stream(Symbol.SYSTEM_STREAM, in, Symbol.CHARACTER);
313                return loadFileFromStream(pathname, truename, stream,
314                                          verbose, print, auto);
315            } catch (FaslVersionMismatch e) {
316                StringBuilder sb =
317                    new StringBuilder("; Incorrect fasl version: ");
318                sb.append(truename);
319                System.err.println(sb.toString());
320            } finally {
321                thread.resetSpecialBindings(mark);
322                try {
323                    in.close();
324                }
325                catch (IOException e) {
326                    return error(new LispError(e.getMessage()));
327                }
328            }
329        }
330        return error(new FileError("Failed to load system file: " 
331                                   + "'" + filename + "'"
332                                   + " resolved as " 
333                                   + "'" + mergedPathname + "'" , 
334                                   truename));
335    }
336
337    // ### *fasl-version*
338    // internal symbol
339    static final Symbol _FASL_VERSION_ =
340        exportConstant("*FASL-VERSION*", PACKAGE_SYS, Fixnum.getInstance(35));
341
342    // ### *fasl-external-format*
343    // internal symbol
344    private static final Symbol _FASL_EXTERNAL_FORMAT_ =
345        internConstant("*FASL-EXTERNAL-FORMAT*", PACKAGE_SYS,
346                       new SimpleString("UTF-8"));
347
348    // ### *fasl-anonymous-package*
349    // internal symbol
350    /**
351     * This variable gets bound to a package with no name in which the
352     * reader can intern its uninterned symbols.
353     *
354     */
355    public static final Symbol _FASL_ANONYMOUS_PACKAGE_ =
356        internSpecial("*FASL-ANONYMOUS-PACKAGE*", PACKAGE_SYS, NIL);
357
358    // ### init-fasl &key version
359    private static final Primitive INIT_FASL = new init_fasl();
360    private static class init_fasl extends Primitive {
361        init_fasl() {
362            super("init-fasl", PACKAGE_SYS, true, "&key version");
363        }
364        @Override
365        public LispObject execute(LispObject first, LispObject second)
366
367        {
368            if (first == Keyword.VERSION) {
369                if (second.eql(_FASL_VERSION_.getSymbolValue())) {
370                    // OK
371                    final LispThread thread = LispThread.currentThread();
372                    thread.bindSpecial(_FASL_ANONYMOUS_PACKAGE_, NIL);
373                    thread.bindSpecial(_SOURCE_, NIL);
374                    return faslLoadStream(thread);
375                }
376            }
377            throw new FaslVersionMismatch(second);
378        }
379    }
380
381    private static final LispObject loadFileFromStream(Pathname pathname,
382                                                       Pathname truename,
383                                                       Stream in,
384                                                       boolean verbose,
385                                                       boolean print,
386                                                       boolean auto)
387        {
388        return loadFileFromStream(pathname, truename, in, verbose, print, auto, false);
389    }
390
391    // A nil TRUENAME signals a load from stream which has no possible path
392    private static final LispObject loadFileFromStream(LispObject pathname,
393                                                       LispObject truename,
394                                                       Stream in,
395                                                       boolean verbose,
396                                                       boolean print,
397                                                       boolean auto,
398                                                       boolean returnLastResult)
399
400    {
401        long start = System.currentTimeMillis();
402        final LispThread thread = LispThread.currentThread();
403        final SpecialBindingsMark mark = thread.markSpecialBindings();
404        // "LOAD binds *READTABLE* and *PACKAGE* to the values they held before
405        // loading the file."
406        thread.bindSpecialToCurrentValue(Symbol.CURRENT_READTABLE);
407        thread.bindSpecialToCurrentValue(Symbol._PACKAGE_);
408        int loadDepth = Fixnum.getValue(_LOAD_DEPTH_.symbolValue(thread));
409        thread.bindSpecial(_LOAD_DEPTH_, Fixnum.getInstance(++loadDepth));
410        // Compiler policy.
411        thread.bindSpecialToCurrentValue(_SPEED_);
412        thread.bindSpecialToCurrentValue(_SPACE_);
413        thread.bindSpecialToCurrentValue(_SAFETY_);
414        thread.bindSpecialToCurrentValue(_DEBUG_);
415        thread.bindSpecialToCurrentValue(_EXPLAIN_);
416        final String prefix = getLoadVerbosePrefix(loadDepth);
417        try {
418            thread.bindSpecial(Symbol.LOAD_PATHNAME, pathname);
419
420            // The motivation behind the following piece of complexity
421            // is the need to preserve the semantics of
422            // *LOAD-TRUENAME* as always containing the truename of
423            // the current "Lisp file".  Since an ABCL packed FASL
424            // actually has a Lisp file (aka "the init FASL") and one
425            // or more Java classes from the compiler, we endeavor to
426            // make *LOAD-TRUENAME* refer to the "overall" truename so
427            // that a (LOAD *LOAD-TRUENAME*) would be equivalent to
428            // reloading the complete current "Lisp file".  If this
429            // value diverges from the "true" truename, we set the
430            // symbol SYS::*LOAD-TRUENAME-FASL* to that divergent
431            // value.  Currently the only code that uses this value is
432            // Lisp.readFunctionBytes().
433            Pathname truePathname = null;
434            if (!truename.equals(NIL)) {
435                truePathname = new Pathname(((Pathname)truename).getNamestring());
436                String type = truePathname.type.getStringValue();
437                if (type.equals(COMPILE_FILE_TYPE)
438                    || type.equals(COMPILE_FILE_INIT_FASL_TYPE.toString())) {
439                    thread.bindSpecial(Symbol.LOAD_TRUENAME_FASL, truePathname);
440                }
441                if (truePathname.type.getStringValue()
442                    .equals(COMPILE_FILE_INIT_FASL_TYPE.getStringValue())
443                    && truePathname.isJar()) {
444                    if (truePathname.device.cdr() != NIL ) {
445                        // set truename to the enclosing JAR
446                        truePathname.host = NIL;
447                        truePathname.directory = NIL;
448                        truePathname.name = NIL;
449                        truePathname.type = NIL;
450                        truePathname.invalidateNamestring();
451                    } else {
452                        // XXX There is something fishy in the asymmetry
453                        // between the "jar:jar:http:" and "jar:jar:file:"
454                        // cases but this currently passes the tests.
455                        if (!(truePathname.device.car() instanceof AbstractString)) {
456                            truePathname = (Pathname)truePathname.device.car();
457                            truePathname.invalidateNamestring();
458                        }
459                    }
460                    thread.bindSpecial(Symbol.LOAD_TRUENAME, truePathname);
461                } else {
462                    thread.bindSpecial(Symbol.LOAD_TRUENAME, truename);
463                }
464            } else {
465                thread.bindSpecial(Symbol.LOAD_TRUENAME, truename);
466            }
467            thread.bindSpecial(_SOURCE_,
468                               pathname != null ? pathname : NIL);
469            if (verbose) {
470                Stream out = getStandardOutput();
471                out.freshLine();
472                out._writeString(prefix);
473                out._writeString(auto ? " Autoloading " : " Loading ");
474                out._writeString(!truename.equals(NIL) ? truePathname.writeToString() : "stream");
475                out._writeLine(" ...");
476                out._finishOutput();
477                LispObject result = loadStream(in, print, thread, returnLastResult);
478                long elapsed = System.currentTimeMillis() - start;
479                out.freshLine();
480                out._writeString(prefix);
481                out._writeString(auto ? " Autoloaded " : " Loaded ");
482                out._writeString(!truename.equals(NIL) ? truePathname.writeToString() : "stream");
483                out._writeString(" (");
484                out._writeString(String.valueOf(((float)elapsed)/1000));
485                out._writeLine(" seconds)");
486                out._finishOutput();
487                return result;
488            } else
489                return loadStream(in, print, thread, returnLastResult);
490        }
491        finally {
492            thread.resetSpecialBindings(mark);
493        }
494    }
495
496    public static String getLoadVerbosePrefix(int loadDepth)
497    {
498        StringBuilder sb = new StringBuilder(";");
499        for (int i = loadDepth - 1; i-- > 0;)
500            sb.append(' ');
501        return sb.toString();
502    }
503
504    private static final LispObject loadStream(Stream in, boolean print,
505                                               LispThread thread)
506        {
507        return loadStream(in, print, thread, false);
508    }
509
510    private static final LispObject loadStream(Stream in, boolean print,
511                                               LispThread thread, boolean returnLastResult)
512
513    {
514        final SpecialBindingsMark mark = thread.markSpecialBindings();
515        thread.bindSpecial(_LOAD_STREAM_, in);
516        SpecialBinding sourcePositionBinding =
517            thread.bindSpecial(_SOURCE_POSITION_, Fixnum.ZERO);
518        try {
519            final Environment env = new Environment();
520            LispObject result = NIL;
521            while (true) {
522                sourcePositionBinding.value = Fixnum.getInstance(in.getOffset());
523                LispObject obj = in.read(false, EOF, false, thread);
524                if (obj == EOF)
525                    break;
526                result = eval(obj, env, thread);
527                if (print) {
528                    Stream out =
529                        checkCharacterOutputStream(Symbol.STANDARD_OUTPUT.symbolValue(thread));
530                    out._writeLine(result.writeToString());
531                    out._finishOutput();
532                }
533            }
534            if(returnLastResult) {
535                return result;
536            } else {
537                return T;
538            }
539        }
540        finally {
541            thread.resetSpecialBindings(mark);
542        }
543    }
544
545    static final LispObject faslLoadStream(LispThread thread)
546    {
547        Stream in = (Stream) _LOAD_STREAM_.symbolValue(thread);
548        final Environment env = new Environment();
549        final SpecialBindingsMark mark = thread.markSpecialBindings();
550        LispObject result = NIL;
551        try {
552            thread.bindSpecial(_FASL_ANONYMOUS_PACKAGE_, new Package());
553            thread.bindSpecial(AUTOLOADING_CACHE,
554                               AutoloadedFunctionProxy.makePreloadingContext());
555            in.setExternalFormat(_FASL_EXTERNAL_FORMAT_.symbolValue(thread));
556            while (true) {
557                LispObject obj = in.faslRead(false, EOF, true, thread);
558                if (obj == EOF)
559                    break;
560                result = eval(obj, env, thread);
561            }
562        }
563        finally {
564            thread.resetSpecialBindings(mark);
565        }
566        return result;
567        //There's no point in using here the returnLastResult flag like in
568        //loadStream(): this function is only called from init-fasl, which is
569        //only called from load, which already has its own policy for choosing
570        //whether to return T or the last value.
571    }
572
573
574    // ### %load filespec verbose print if-does-not-exist => generalized-boolean
575    private static final Primitive _LOAD = new _load();
576    private static class _load extends Primitive {
577        _load() {
578            super("%load", PACKAGE_SYS, false,
579                  "filespec verbose print if-does-not-exist");
580        }
581        @Override
582        public LispObject execute(LispObject filespec, LispObject verbose,
583                                  LispObject print, LispObject ifDoesNotExist)
584        {
585            return load(filespec, verbose, print, ifDoesNotExist, NIL);
586        }
587    }
588
589    // ### %load-returning-last-result filespec verbose print if-does-not-exist => object
590    private static final Primitive _LOAD_RETURNING_LAST_RESULT = new _load_returning_last_result();
591    private static class _load_returning_last_result extends Primitive {
592        _load_returning_last_result() {
593            super("%load-returning-last-result", PACKAGE_SYS, false,
594                  "filespec verbose print if-does-not-exist");
595        }
596        @Override
597        public LispObject execute(LispObject filespec, LispObject verbose,
598                                  LispObject print, LispObject ifDoesNotExist)
599            {
600            return load(filespec, verbose, print, ifDoesNotExist, T);
601        }
602    }
603
604    static final LispObject load(LispObject filespec,
605                                         LispObject verbose,
606                                         LispObject print,
607                                         LispObject ifDoesNotExist,
608                                         LispObject returnLastResult)
609        {
610        if (filespec instanceof Stream) {
611            if (((Stream)filespec).isOpen()) {
612                LispObject pathname;
613                if (filespec instanceof FileStream)
614                    pathname = ((FileStream)filespec).getPathname();
615                else
616                    pathname = NIL;
617                LispObject truename;
618                if (pathname instanceof Pathname)
619                    truename = pathname;
620                else
621                    truename = NIL;
622                return loadFileFromStream(pathname,
623                                          truename,
624                                          (Stream) filespec,
625                                          verbose != NIL,
626                                          print != NIL,
627                                          false,
628                                          returnLastResult != NIL);
629            }
630            // If stream is closed, fall through...
631        }
632        Pathname pathname = coerceToPathname(filespec);
633        if (pathname instanceof LogicalPathname)
634            pathname = LogicalPathname.translateLogicalPathname((LogicalPathname)pathname);
635        return load(pathname,
636                    verbose != NIL,
637                    print != NIL,
638                    ifDoesNotExist != NIL,
639                    returnLastResult != NIL);
640    }
641
642    // ### load-system-file
643    private static final Primitive LOAD_SYSTEM_FILE = new load_system_file();
644    private static class load_system_file extends Primitive {
645        load_system_file () {
646            super("load-system-file", PACKAGE_SYS, true);
647        }
648        @Override
649        public LispObject execute(LispObject arg)
650        {
651            final LispThread thread = LispThread.currentThread();
652            return loadSystemFile(arg.getStringValue(),
653                                  Symbol.LOAD_VERBOSE.symbolValue(thread) != NIL,
654                                  Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
655                                  false);
656        }
657    }
658
659    private static class FaslVersionMismatch extends Error
660    {
661        private final LispObject version;
662
663        public FaslVersionMismatch(LispObject version)
664        {
665            this.version = version;
666        }
667
668        public LispObject getVersion()
669        {
670            return version;
671        }
672    }
673}
Note: See TracBrowser for help on using the repository browser.