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

Last change on this file was 13149, checked in by astalla, 15 years ago

Keep sys::make-fasl-class-loader API compatible to avoid changing the FASL version number.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.8 KB
Line 
1/*
2 * Load.java
3 *
4 * Copyright (C) 2002-2007 Peter Graves
5 * $Id: Load.java 13149 2011-01-14 21:12:30Z astalla $
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 abclPathname;  // fasl file is newer
93              } else {
94                  return lispPathname;
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            n = Pathname.uriEncode(n);
157            if (n.startsWith("jar:")) {
158                n = "jar:" + n + "!/" + truename.name.getStringValue() + "."
159                    + COMPILE_FILE_INIT_FASL_TYPE;
160            } else {
161                n = "jar:file:" + n + "!/" + truename.name.getStringValue() + "."
162                    + COMPILE_FILE_INIT_FASL_TYPE;
163            }
164            mergedPathname = new Pathname(n);
165            LispObject initTruename = Pathname.truename(mergedPathname);
166            if (initTruename == null || initTruename.equals(NIL)) {
167                // Maybe the enclosing JAR has been renamed?
168                Pathname p = new Pathname(mergedPathname);
169                p.name = Keyword.WILD;
170                p.invalidateNamestring();
171                LispObject result = Pathname.MATCH_WILD_JAR_PATHNAME.execute(p);
172
173                if      (result instanceof Cons
174                    && ((Cons)result).length() == 1
175                    && ((Cons)result).car() instanceof Pathname) {
176                    initTruename = (Pathname)result.car();
177                } else {
178                  String errorMessage
179                      = "Loadable FASL not found for "
180                      + "'" + pathname + "'"
181                      + " in "
182                      + "'" + mergedPathname + "'";
183                  if (ifDoesNotExist) {
184                      return error(new FileError(errorMessage, mergedPathname));
185                  } else {
186                      Debug.trace(errorMessage);
187                      return NIL;
188                  }
189                }
190            }
191            truename = (Pathname)initTruename;
192        }
193       
194        InputStream in = truename.getInputStream();
195        Debug.assertTrue(in != null);
196   
197        try {
198            return loadFileFromStream(pathname, truename,
199                                      new Stream(Symbol.SYSTEM_STREAM, in, Symbol.CHARACTER),
200                                      verbose, print, false, returnLastResult);
201        }
202        finally {
203            if (in != null) {
204                try {
205                   in.close();
206                }
207                catch (IOException e) {
208                    return error(new LispError(e.getMessage()));
209                }
210            }
211        }
212    }
213
214    public static final LispObject loadSystemFile(String filename, boolean auto)
215
216    {
217        LispThread thread = LispThread.currentThread();
218        if (auto) {
219            final SpecialBindingsMark mark = thread.markSpecialBindings();
220            thread.bindSpecial(Symbol.CURRENT_READTABLE,
221                               STANDARD_READTABLE.symbolValue(thread));
222            thread.bindSpecial(Symbol._PACKAGE_, PACKAGE_CL_USER);
223            try {
224                return loadSystemFile(filename,
225                                      _AUTOLOAD_VERBOSE_.symbolValue(thread) != NIL,
226                                      Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
227                                      auto);
228            }
229            finally {
230                thread.resetSpecialBindings(mark);
231            }
232        } else {
233            return loadSystemFile(filename,
234                                  Symbol.LOAD_VERBOSE.symbolValue(thread) != NIL,
235                                  Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
236                                  auto);
237        }
238    }
239
240    private static final Symbol FASL_LOADER = PACKAGE_SYS.intern("*FASL-LOADER*");
241    static final LispObject COMPILE_FILE_INIT_FASL_TYPE = new SimpleString("_");
242
243    public static final LispObject loadSystemFile(final String filename,
244                                                  boolean verbose,
245                                                  boolean print,
246                                                  boolean auto)
247
248    {
249        InputStream in = null;
250        Pathname pathname = null;
251        Pathname truename = null;
252        pathname = new Pathname(filename);
253        LispObject bootPath = Site.getLispHome();
254        Pathname mergedPathname;
255        if (bootPath instanceof Pathname) {
256            mergedPathname = Pathname.mergePathnames(pathname, (Pathname)bootPath);
257        } else {
258            mergedPathname = pathname;
259        }
260        URL url = null;
261        truename = findLoadableFile(mergedPathname);
262        if (truename == null || truename.equals(NIL) || bootPath.equals(NIL)) {
263            // Make an attempt to use the boot classpath
264            String path = pathname.asEntryPath();
265            url = Lisp.class.getResource(path);
266            if (url == null || url.toString().endsWith("/")) {
267                url = Lisp.class.getResource(path.replace('-', '_') + ".abcl");
268                if (url == null) {
269                    url = Lisp.class.getResource(path + ".lisp");
270                }
271            }
272            if (url == null) {
273                return error(new LispError("Failed to find loadable system file "
274                                           + "'" + path + "'"
275                                           + " in boot classpath."));
276            }               
277            if (!bootPath.equals(NIL)) {
278                Pathname urlPathname = new Pathname(url);
279                truename = findLoadableFile(urlPathname);
280                if (truename == null) {
281                    return error(new LispError("Failed to find loadable system file in boot classpath "
282                                               + "'" + url + "'"));
283                }
284            } else {
285                truename = null; // We can't represent the FASL in a Pathname (q.v. OSGi)
286            }
287        }
288
289        // Look for a init FASL inside a packed FASL
290        if (truename != null
291            && truename.type.writeToString().equals(COMPILE_FILE_TYPE) && Utilities.checkZipFile(truename))  {
292            Pathname init = new Pathname(truename.getNamestring());
293            init.type = COMPILE_FILE_INIT_FASL_TYPE;
294            LispObject t = Pathname.truename(init);
295            if (t instanceof Pathname) {
296                truename = (Pathname)t;
297            } else {
298                return error (new LispError("Failed to find loadable init FASL in "
299                                            + "'" + init.getNamestring() + "'"));
300            }
301        }
302
303        if (truename != null) {
304            in = truename.getInputStream();
305        } else { 
306            try {
307                Debug.assertTrue(url != null);
308                in = url.openStream();
309            } catch (IOException e) {
310                error(new FileError("Failed to load system file: " 
311                                    + "'" + filename + "'"
312                                    + " from URL: " 
313                                    + "'" + url + "'"));
314            } 
315        }
316
317        if (in != null) {
318            final LispThread thread = LispThread.currentThread();
319            final SpecialBindingsMark mark = thread.markSpecialBindings();
320            thread.bindSpecial(_WARN_ON_REDEFINITION_, NIL);
321      thread.bindSpecial(FASL_LOADER, NIL);
322            try {
323                Stream stream = new Stream(Symbol.SYSTEM_STREAM, in, Symbol.CHARACTER);
324                return loadFileFromStream(pathname, truename, stream,
325                                          verbose, print, auto);
326            } finally {
327                thread.resetSpecialBindings(mark);
328                try {
329                    in.close();
330                }
331                catch (IOException e) {
332                    return error(new LispError(e.getMessage()));
333                }
334            }
335        }
336        return error(new FileError("Failed to load system file: " 
337                                   + "'" + filename + "'"
338                                   + " resolved as " 
339                                   + "'" + mergedPathname + "'" , 
340                                   truename));
341    }
342
343    // ### *fasl-version*
344    // internal symbol
345
346    /* TODO when bumping the version for any reason, remember to:
347     *  - remove the overload taking 3 args in
348     *    FaslClassLoader.MAKE_FASL_CLASS_LOADER
349     *  - remove the extra args (1 and 3, both NIL) passed to
350     *    make-fasl-class-loader in compile-file.lisp
351     *  - delete this comment :)
352     */
353    static final Symbol _FASL_VERSION_ =
354        exportConstant("*FASL-VERSION*", PACKAGE_SYS, Fixnum.getInstance(37));
355
356    // ### *fasl-external-format*
357    // internal symbol
358    private static final Symbol _FASL_EXTERNAL_FORMAT_ =
359        internConstant("*FASL-EXTERNAL-FORMAT*", PACKAGE_SYS,
360                       new SimpleString("UTF-8"));
361
362    // ### *fasl-uninterned-symbols*
363    // internal symbol
364    /**
365     * This variable gets bound to NIL upon loading a FASL, but
366     * gets set to a vector of symbols as one of the first actions
367     * by the FASL itself.
368     *
369     */
370    public static final Symbol _FASL_UNINTERNED_SYMBOLS_ =
371        internSpecial("*FASL-UNINTERNED-SYMBOLS*", PACKAGE_SYS, NIL);
372
373    // Function to access the uninterned symbols "array"
374    public final static LispObject getUninternedSymbol(int n) {
375        LispThread thread = LispThread.currentThread();
376        LispObject uninternedSymbols =
377            Load._FASL_UNINTERNED_SYMBOLS_.symbolValue(thread);
378
379        if (! (uninternedSymbols instanceof Cons)) // it must be a vector
380            return uninternedSymbols.AREF(n);
381
382        // During normal loading, we won't get to this bit, however,
383        // with eval-when processing, we may need to fall back to
384        // *FASL-UNINTERNED-SYMBOLS* being an alist structure
385        LispObject label = LispInteger.getInstance(n);
386        while (uninternedSymbols != NIL)
387            {
388                LispObject item = uninternedSymbols.car();
389                if (label.eql(item.cdr()))
390                  return item.car();
391
392                uninternedSymbols = uninternedSymbols.cdr();
393            }
394        return error(new LispError("No entry for uninterned symbol."));
395    }
396
397
398    // ### init-fasl &key version
399    private static final Primitive INIT_FASL = new init_fasl();
400    private static class init_fasl extends Primitive {
401        init_fasl() {
402            super("init-fasl", PACKAGE_SYS, true, "&key version");
403        }
404        @Override
405        public LispObject execute(LispObject first, LispObject second)
406
407        {
408            final LispThread thread = LispThread.currentThread();
409            if (first == Keyword.VERSION) {
410                if (second.eql(_FASL_VERSION_.getSymbolValue())) {
411                    // OK
412                    thread.bindSpecial(_FASL_UNINTERNED_SYMBOLS_, NIL);
413                    thread.bindSpecial(_SOURCE_, NIL);
414                    return faslLoadStream(thread);
415                }
416            }
417            return
418                error(new SimpleError("FASL version mismatch; found '"
419                        + second.writeToString() + "' but expected '"
420                        + _FASL_VERSION_.getSymbolValue().writeToString()
421                        + "' in "
422                        + Symbol.LOAD_PATHNAME.symbolValue(thread).writeToString()));
423        }
424    }
425
426    private static final LispObject loadFileFromStream(Pathname pathname,
427                                                       Pathname truename,
428                                                       Stream in,
429                                                       boolean verbose,
430                                                       boolean print,
431                                                       boolean auto)
432        {
433            return loadFileFromStream(pathname == null ? NIL : pathname,
434                                      truename == null ? NIL : truename,
435                                      in, verbose, print, auto, false);
436    }
437
438    private static Symbol[] savedSpecials =
439        new Symbol[] { // CLHS Specified
440                       Symbol.CURRENT_READTABLE, Symbol._PACKAGE_,
441                       // Compiler policy
442                       _SPEED_, _SPACE_, _SAFETY_, _DEBUG_, _EXPLAIN_ };
443
444    // A nil TRUENAME signals a load from stream which has no possible path
445    private static final LispObject loadFileFromStream(LispObject pathname,
446                                                       LispObject truename,
447                                                       Stream in,
448                                                       boolean verbose,
449                                                       boolean print,
450                                                       boolean auto,
451                                                       boolean returnLastResult)
452
453    {
454        long start = System.currentTimeMillis();
455        final LispThread thread = LispThread.currentThread();
456        final SpecialBindingsMark mark = thread.markSpecialBindings();
457
458        for (Symbol special : savedSpecials)
459            thread.bindSpecialToCurrentValue(special);
460
461        int loadDepth = Fixnum.getValue(_LOAD_DEPTH_.symbolValue(thread));
462        thread.bindSpecial(_LOAD_DEPTH_, Fixnum.getInstance(++loadDepth));
463        final String prefix = getLoadVerbosePrefix(loadDepth);
464        try {
465            thread.bindSpecial(Symbol.LOAD_PATHNAME, pathname);
466
467            // The motivation behind the following piece of complexity
468            // is the need to preserve the semantics of
469            // *LOAD-TRUENAME* as always containing the truename of
470            // the current "Lisp file".  Since an ABCL packed FASL
471            // actually has a Lisp file (aka "the init FASL") and one
472            // or more Java classes from the compiler, we endeavor to
473            // make *LOAD-TRUENAME* refer to the "overall" truename so
474            // that a (LOAD *LOAD-TRUENAME*) would be equivalent to
475            // reloading the complete current "Lisp file".  If this
476            // value diverges from the "true" truename, we set the
477            // symbol SYS::*LOAD-TRUENAME-FASL* to that divergent
478            // value.  Currently the only code that uses this value is
479            // Lisp.readFunctionBytes().
480            Pathname truePathname = null;
481            if (!truename.equals(NIL)) {
482                truePathname = new Pathname(((Pathname)truename).getNamestring());
483                String type = truePathname.type.getStringValue();
484                if (type.equals(COMPILE_FILE_TYPE)
485                    || type.equals(COMPILE_FILE_INIT_FASL_TYPE.toString())) {
486                    Pathname truenameFasl = new Pathname(truePathname);
487                    thread.bindSpecial(Symbol.LOAD_TRUENAME_FASL, truenameFasl);
488                }
489                if (truePathname.type.getStringValue()
490                    .equals(COMPILE_FILE_INIT_FASL_TYPE.getStringValue())
491                    && truePathname.isJar()) {
492                    if (truePathname.device.cdr() != NIL ) {
493                        // We set *LOAD-TRUENAME* to the argument that
494                        // a user would pass to LOAD.
495                        Pathname enclosingJar = (Pathname)truePathname.device.cdr().car();
496                        truePathname.device = new Cons(truePathname.device.car(), NIL);
497                        truePathname.host = NIL;
498                        truePathname.directory = enclosingJar.directory;
499                        if (truePathname.directory.car().equals(Keyword.RELATIVE)) {
500                            truePathname.directory.setCar(Keyword.ABSOLUTE);
501                        }
502                        truePathname.name = enclosingJar.name;
503                        truePathname.type = enclosingJar.type;
504                        truePathname.invalidateNamestring();
505                    } else {
506                        // XXX There is something fishy in the asymmetry
507                        // between the "jar:jar:http:" and "jar:jar:file:"
508                        // cases but this currently passes the tests.
509                        if (!(truePathname.device.car() instanceof AbstractString)) {
510                            truePathname = (Pathname)truePathname.device.car();
511                            truePathname.invalidateNamestring();
512                        }
513                    }
514                    thread.bindSpecial(Symbol.LOAD_TRUENAME, truePathname);
515                } else {
516                    thread.bindSpecial(Symbol.LOAD_TRUENAME, truename);
517                }
518            } else {
519                thread.bindSpecial(Symbol.LOAD_TRUENAME, truename);
520            }
521            thread.bindSpecial(_SOURCE_,
522                               pathname != null ? pathname : NIL);
523            if (verbose) {
524                Stream out = getStandardOutput();
525                out.freshLine();
526                out._writeString(prefix);
527                out._writeString(auto ? " Autoloading " : " Loading ");
528                out._writeString(!truename.equals(NIL) ? truePathname.writeToString() : "stream");
529                out._writeLine(" ...");
530                out._finishOutput();
531                LispObject result = loadStream(in, print, thread, returnLastResult);
532                long elapsed = System.currentTimeMillis() - start;
533                out.freshLine();
534                out._writeString(prefix);
535                out._writeString(auto ? " Autoloaded " : " Loaded ");
536                out._writeString(!truename.equals(NIL) ? truePathname.writeToString() : "stream");
537                out._writeString(" (");
538                out._writeString(String.valueOf(((float)elapsed)/1000));
539                out._writeLine(" seconds)");
540                out._finishOutput();
541                return result;
542            } else
543                return loadStream(in, print, thread, returnLastResult);
544        }
545        finally {
546            thread.resetSpecialBindings(mark);
547        }
548    }
549
550    public static String getLoadVerbosePrefix(int loadDepth)
551    {
552        StringBuilder sb = new StringBuilder(";");
553        for (int i = loadDepth - 1; i-- > 0;)
554            sb.append(' ');
555        return sb.toString();
556    }
557
558    private static final LispObject loadStream(Stream in, boolean print,
559                                               LispThread thread, boolean returnLastResult)
560
561    {
562        final SpecialBindingsMark mark = thread.markSpecialBindings();
563        thread.bindSpecial(_LOAD_STREAM_, in);
564        SpecialBinding sourcePositionBinding =
565            thread.bindSpecial(_SOURCE_POSITION_, Fixnum.ZERO);
566        try {
567            final Environment env = new Environment();
568            LispObject result = NIL;
569            while (true) {
570                sourcePositionBinding.value = Fixnum.getInstance(in.getOffset());
571                LispObject obj = in.read(false, EOF, false,
572                                         thread, Stream.currentReadtable);
573                if (obj == EOF)
574                    break;
575    result = eval(obj, env, thread);
576                if (print) {
577                    Stream out =
578                        checkCharacterOutputStream(Symbol.STANDARD_OUTPUT.symbolValue(thread));
579                    out._writeLine(result.writeToString());
580                    out._finishOutput();
581                }
582            }
583            if(returnLastResult) {
584                return result;
585            } else {
586                return T;
587            }
588        }
589        finally {
590            thread.resetSpecialBindings(mark);
591        }
592    }
593
594    static final LispObject faslLoadStream(LispThread thread)
595    {
596        Stream in = (Stream) _LOAD_STREAM_.symbolValue(thread);
597        final Environment env = new Environment();
598        final SpecialBindingsMark mark = thread.markSpecialBindings();
599        LispObject result = NIL;
600        try {
601            thread.bindSpecial(AUTOLOADING_CACHE,
602                               AutoloadedFunctionProxy.makePreloadingContext());
603            in.setExternalFormat(_FASL_EXTERNAL_FORMAT_.symbolValue(thread));
604            while (true) {
605                LispObject obj = in.read(false, EOF, true, thread, Stream.faslReadtable);
606                if (obj == EOF)
607                    break;
608                result = eval(obj, env, thread);
609            }
610        }
611        finally {
612            thread.resetSpecialBindings(mark);
613        }
614        return result;
615        //There's no point in using here the returnLastResult flag like in
616        //loadStream(): this function is only called from init-fasl, which is
617        //only called from load, which already has its own policy for choosing
618        //whether to return T or the last value.
619    }
620
621
622    // ### %load filespec verbose print if-does-not-exist => generalized-boolean
623    private static final Primitive _LOAD = new _load();
624    private static class _load extends Primitive {
625        _load() {
626            super("%load", PACKAGE_SYS, false,
627                  "filespec verbose print if-does-not-exist");
628        }
629        @Override
630        public LispObject execute(LispObject filespec, LispObject verbose,
631                                  LispObject print, LispObject ifDoesNotExist)
632        {
633            return load(filespec, verbose, print, ifDoesNotExist, NIL);
634        }
635    }
636
637    // ### %load-returning-last-result filespec verbose print if-does-not-exist => object
638    private static final Primitive _LOAD_RETURNING_LAST_RESULT = new _load_returning_last_result();
639    private static class _load_returning_last_result extends Primitive {
640        _load_returning_last_result() {
641            super("%load-returning-last-result", PACKAGE_SYS, false,
642                  "filespec verbose print if-does-not-exist");
643        }
644        @Override
645        public LispObject execute(LispObject filespec, LispObject verbose,
646                                  LispObject print, LispObject ifDoesNotExist)
647            {
648            return load(filespec, verbose, print, ifDoesNotExist, T);
649        }
650    }
651
652    static final LispObject load(LispObject filespec,
653                                         LispObject verbose,
654                                         LispObject print,
655                                         LispObject ifDoesNotExist,
656                                         LispObject returnLastResult)
657        {
658        if (filespec instanceof Stream) {
659            if (((Stream)filespec).isOpen()) {
660                LispObject pathname;
661                if (filespec instanceof FileStream)
662                    pathname = ((FileStream)filespec).getPathname();
663                else
664                    pathname = NIL;
665                LispObject truename;
666                if (pathname instanceof Pathname)
667                    truename = pathname;
668                else
669                    truename = NIL;
670                return loadFileFromStream(pathname,
671                                          truename,
672                                          (Stream) filespec,
673                                          verbose != NIL,
674                                          print != NIL,
675                                          false,
676                                          returnLastResult != NIL);
677            }
678            // If stream is closed, fall through...
679        }
680        Pathname pathname = coerceToPathname(filespec);
681        if (pathname instanceof LogicalPathname)
682            pathname = LogicalPathname.translateLogicalPathname((LogicalPathname)pathname);
683        return load(pathname,
684                    verbose != NIL,
685                    print != NIL,
686                    ifDoesNotExist != NIL,
687                    returnLastResult != NIL);
688    }
689
690    // ### load-system-file
691    private static final Primitive LOAD_SYSTEM_FILE = new load_system_file();
692    private static class load_system_file extends Primitive {
693        load_system_file () {
694            super("load-system-file", PACKAGE_SYS, true);
695        }
696        @Override
697        public LispObject execute(LispObject arg)
698        {
699            final LispThread thread = LispThread.currentThread();
700            return loadSystemFile(arg.getStringValue(),
701                                  Symbol.LOAD_VERBOSE.symbolValue(thread) != NIL,
702                                  Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
703                                  false);
704        }
705    }
706}
Note: See TracBrowser for help on using the repository browser.