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

Last change on this file was 13604, checked in by ehuelsmann, 14 years ago

Bump FASL format because of the now supported circularity: even though
we're backward compatible, older versions aren't forward compatible.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.9 KB
Line 
1/*
2 * Load.java
3 *
4 * Copyright (C) 2002-2007 Peter Graves
5 * $Id: Load.java 13604 2011-09-20 20:26:31Z 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 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.princToString(), 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            String name = Pathname.uriEncode(truename.name.getStringValue());
157            if (n.startsWith("jar:")) {
158                n = "jar:" + n + "!/" + name + "."
159                    + COMPILE_FILE_INIT_FASL_TYPE;
160            } else {
161                n = "jar:file:" + Pathname.uriEncode(n) + "!/" + name + "."
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.princToString().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    static final Symbol _FASL_VERSION_ =
346        exportConstant("*FASL-VERSION*", PACKAGE_SYS, Fixnum.getInstance(38));
347
348    // ### *fasl-external-format*
349    // internal symbol
350    private static final Symbol _FASL_EXTERNAL_FORMAT_ =
351        internConstant("*FASL-EXTERNAL-FORMAT*", PACKAGE_SYS,
352                       new SimpleString("UTF-8"));
353
354    // ### *fasl-uninterned-symbols*
355    // internal symbol
356    /**
357     * This variable gets bound to NIL upon loading a FASL, but
358     * gets set to a vector of symbols as one of the first actions
359     * by the FASL itself.
360     *
361     */
362    public static final Symbol _FASL_UNINTERNED_SYMBOLS_ =
363        internSpecial("*FASL-UNINTERNED-SYMBOLS*", PACKAGE_SYS, NIL);
364
365    // Function to access the uninterned symbols "array"
366    public final static LispObject getUninternedSymbol(int n) {
367        LispThread thread = LispThread.currentThread();
368        LispObject uninternedSymbols =
369            Load._FASL_UNINTERNED_SYMBOLS_.symbolValue(thread);
370
371        if (! (uninternedSymbols instanceof Cons)) // it must be a vector
372            return uninternedSymbols.AREF(n);
373
374        // During normal loading, we won't get to this bit, however,
375        // with eval-when processing, we may need to fall back to
376        // *FASL-UNINTERNED-SYMBOLS* being an alist structure
377        LispObject label = LispInteger.getInstance(n);
378        while (uninternedSymbols != NIL)
379            {
380                LispObject item = uninternedSymbols.car();
381                if (label.eql(item.cdr()))
382                  return item.car();
383
384                uninternedSymbols = uninternedSymbols.cdr();
385            }
386        return error(new LispError("No entry for uninterned symbol."));
387    }
388
389
390    // ### init-fasl &key version
391    private static final Primitive INIT_FASL = new init_fasl();
392    private static class init_fasl extends Primitive {
393        init_fasl() {
394            super("init-fasl", PACKAGE_SYS, true, "&key version");
395        }
396        @Override
397        public LispObject execute(LispObject first, LispObject second)
398
399        {
400            final LispThread thread = LispThread.currentThread();
401            if (first == Keyword.VERSION) {
402                if (second.eql(_FASL_VERSION_.getSymbolValue())) {
403                    // OK
404                    thread.bindSpecial(_FASL_UNINTERNED_SYMBOLS_, NIL);
405                    thread.bindSpecial(_SOURCE_, NIL);
406                    return faslLoadStream(thread);
407                }
408            }
409            return
410                error(new SimpleError("FASL version mismatch; found '"
411                        + second.princToString() + "' but expected '"
412                        + _FASL_VERSION_.getSymbolValue().princToString()
413                        + "' in "
414                        + Symbol.LOAD_PATHNAME.symbolValue(thread).princToString()));
415        }
416    }
417
418    private static final LispObject loadFileFromStream(Pathname pathname,
419                                                       Pathname truename,
420                                                       Stream in,
421                                                       boolean verbose,
422                                                       boolean print,
423                                                       boolean auto)
424        {
425            return loadFileFromStream(pathname == null ? NIL : pathname,
426                                      truename == null ? NIL : truename,
427                                      in, verbose, print, auto, false);
428    }
429
430    private static Symbol[] savedSpecials =
431        new Symbol[] { // CLHS Specified
432                       Symbol.CURRENT_READTABLE, Symbol._PACKAGE_,
433                       // Compiler policy
434                       _SPEED_, _SPACE_, _SAFETY_, _DEBUG_, _EXPLAIN_ };
435
436    // A nil TRUENAME signals a load from stream which has no possible path
437    private static final LispObject loadFileFromStream(LispObject pathname,
438                                                       LispObject truename,
439                                                       Stream in,
440                                                       boolean verbose,
441                                                       boolean print,
442                                                       boolean auto,
443                                                       boolean returnLastResult)
444
445    {
446        long start = System.currentTimeMillis();
447        final LispThread thread = LispThread.currentThread();
448        final SpecialBindingsMark mark = thread.markSpecialBindings();
449
450        for (Symbol special : savedSpecials)
451            thread.bindSpecialToCurrentValue(special);
452
453        int loadDepth = Fixnum.getValue(_LOAD_DEPTH_.symbolValue(thread));
454        thread.bindSpecial(_LOAD_DEPTH_, Fixnum.getInstance(++loadDepth));
455        final String prefix = getLoadVerbosePrefix(loadDepth);
456        try {
457            thread.bindSpecial(Symbol.LOAD_PATHNAME, pathname);
458
459            // The motivation behind the following piece of complexity
460            // is the need to preserve the semantics of
461            // *LOAD-TRUENAME* as always containing the truename of
462            // the current "Lisp file".  Since an ABCL packed FASL
463            // actually has a Lisp file (aka "the init FASL") and one
464            // or more Java classes from the compiler, we endeavor to
465            // make *LOAD-TRUENAME* refer to the "overall" truename so
466            // that a (LOAD *LOAD-TRUENAME*) would be equivalent to
467            // reloading the complete current "Lisp file".  If this
468            // value diverges from the "true" truename, we set the
469            // symbol SYS::*LOAD-TRUENAME-FASL* to that divergent
470            // value.  Currently the only code that uses this value is
471            // Lisp.readFunctionBytes().
472            Pathname truePathname = null;
473            if (!truename.equals(NIL)) {
474                truePathname = new Pathname(((Pathname)truename).getNamestring());
475                String type = truePathname.type.getStringValue();
476                if (type.equals(COMPILE_FILE_TYPE)
477                    || type.equals(COMPILE_FILE_INIT_FASL_TYPE.toString())) {
478                    Pathname truenameFasl = new Pathname(truePathname);
479                    thread.bindSpecial(Symbol.LOAD_TRUENAME_FASL, truenameFasl);
480                }
481                if (truePathname.type.getStringValue()
482                    .equals(COMPILE_FILE_INIT_FASL_TYPE.getStringValue())
483                    && truePathname.isJar()) {
484                    if (truePathname.device.cdr() != NIL ) {
485                        // We set *LOAD-TRUENAME* to the argument that
486                        // a user would pass to LOAD.
487                        Pathname enclosingJar = (Pathname)truePathname.device.cdr().car();
488                        truePathname.device = new Cons(truePathname.device.car(), NIL);
489                        truePathname.host = NIL;
490                        truePathname.directory = enclosingJar.directory;
491                        if (truePathname.directory.car().equals(Keyword.RELATIVE)) {
492                            truePathname.directory.setCar(Keyword.ABSOLUTE);
493                        }
494                        truePathname.name = enclosingJar.name;
495                        truePathname.type = enclosingJar.type;
496                        truePathname.invalidateNamestring();
497                    } else {
498                        // XXX There is something fishy in the asymmetry
499                        // between the "jar:jar:http:" and "jar:jar:file:"
500                        // cases but this currently passes the tests.
501                        if (!(truePathname.device.car() instanceof AbstractString)) {
502                            truePathname = (Pathname)truePathname.device.car();
503                            truePathname.invalidateNamestring();
504                        }
505                    }
506                    thread.bindSpecial(Symbol.LOAD_TRUENAME, truePathname);
507                } else {
508                    thread.bindSpecial(Symbol.LOAD_TRUENAME, truename);
509                }
510            } else {
511                thread.bindSpecial(Symbol.LOAD_TRUENAME, truename);
512            }
513            thread.bindSpecial(_SOURCE_,
514                               pathname != null ? pathname : NIL);
515            if (verbose) {
516                Stream out = getStandardOutput();
517                out.freshLine();
518                out._writeString(prefix);
519                out._writeString(auto ? " Autoloading " : " Loading ");
520                out._writeString(!truename.equals(NIL) ? truePathname.princToString() : "stream");
521                out._writeLine(" ...");
522                out._finishOutput();
523                LispObject result = loadStream(in, print, thread, returnLastResult);
524                long elapsed = System.currentTimeMillis() - start;
525                out.freshLine();
526                out._writeString(prefix);
527                out._writeString(auto ? " Autoloaded " : " Loaded ");
528                out._writeString(!truename.equals(NIL) ? truePathname.princToString() : "stream");
529                out._writeString(" (");
530                out._writeString(String.valueOf(((float)elapsed)/1000));
531                out._writeLine(" seconds)");
532                out._finishOutput();
533                return result;
534            } else
535                return loadStream(in, print, thread, returnLastResult);
536        }
537        finally {
538            thread.resetSpecialBindings(mark);
539        }
540    }
541
542    public static String getLoadVerbosePrefix(int loadDepth)
543    {
544        StringBuilder sb = new StringBuilder(";");
545        for (int i = loadDepth - 1; i-- > 0;)
546            sb.append(' ');
547        return sb.toString();
548    }
549
550    private static final LispObject loadStream(Stream in, boolean print,
551                                               LispThread thread, boolean returnLastResult)
552
553    {
554        final SpecialBindingsMark mark = thread.markSpecialBindings();
555        thread.bindSpecial(_LOAD_STREAM_, in);
556        SpecialBinding sourcePositionBinding =
557            thread.bindSpecial(_SOURCE_POSITION_, Fixnum.ZERO);
558        try {
559            final Environment env = new Environment();
560            LispObject result = NIL;
561            while (true) {
562                sourcePositionBinding.value = Fixnum.getInstance(in.getOffset());
563                LispObject obj = in.read(false, EOF, false,
564                                         thread, Stream.currentReadtable);
565                if (obj == EOF)
566                    break;
567    result = eval(obj, env, thread);
568                if (print) {
569                    Stream out =
570                        checkCharacterOutputStream(Symbol.STANDARD_OUTPUT.symbolValue(thread));
571                    out._writeLine(result.printObject());
572                    out._finishOutput();
573                }
574            }
575            if(returnLastResult) {
576                return result;
577            } else {
578                return T;
579            }
580        }
581        finally {
582            thread.resetSpecialBindings(mark);
583        }
584    }
585
586    static final LispObject faslLoadStream(LispThread thread)
587    {
588        Stream in = (Stream) _LOAD_STREAM_.symbolValue(thread);
589        final Environment env = new Environment();
590        final SpecialBindingsMark mark = thread.markSpecialBindings();
591        LispObject result = NIL;
592        try {
593            thread.bindSpecial(AUTOLOADING_CACHE,
594                               AutoloadedFunctionProxy.makePreloadingContext());
595
596            // Same bindings are established in Lisp.readObjectFromString()
597            thread.bindSpecial(Symbol.READ_BASE, LispInteger.getInstance(10));
598            thread.bindSpecial(Symbol.READ_EVAL, Symbol.T);
599            thread.bindSpecial(Symbol.READ_SUPPRESS, Nil.NIL);
600
601            in.setExternalFormat(_FASL_EXTERNAL_FORMAT_.symbolValue(thread));
602            while (true) {
603                LispObject obj = in.read(false, EOF, false,  // should be 'true' once we
604                                                             // have a FASL wide object table
605                                         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.