From d656401927393487e28e1b765f868822370c1be3 Mon Sep 17 00:00:00 2001 From: William Harold Newman Date: Mon, 14 Apr 2003 01:42:14 +0000 Subject: [PATCH] 0.pre8.58: Do EVAL of one --eval form before READ of the next --eval form. (to avoid package gotchas reported by dan_b) --- NEWS | 10 ++++++-- doc/sbcl.1 | 14 +++++------ src/code/toplevel.lisp | 64 ++++++++++++++++++++++++++++-------------------- tests/toplevel.sh | 27 ++++++++++++++++++++ version.lisp-expr | 2 +- 5 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 tests/toplevel.sh diff --git a/NEWS b/NEWS index 6fca07c..38017d6 100644 --- a/NEWS +++ b/NEWS @@ -1613,8 +1613,8 @@ changes in sbcl-0.7.14 relative to sbcl-0.7.13: changes in sbcl-0.8.0 relative to sbcl-0.7.14 * The old distinction between CL:CLASS objects and SB-PCL:CLASS - objects has been removed. The return value from CL:FIND-CLASS is - now a CLOS class, and likewise that of CL:CLASS-OF; + objects has been eliminated. The return value from CL:FIND-CLASS + is now a CLOS class, and likewise that of CL:CLASS-OF; CL:BUILT-IN-CLASS, CL:STRUCTURE-CLASS and CL:STANDARD-CLASS name CLOS classes. * An interface to the MetaObject Protocol, as described in Kiczales, @@ -1628,6 +1628,12 @@ changes in sbcl-0.8.0 relative to sbcl-0.7.14 addresses instead of being hardcoded per-port. Users affected by this probably have to be doing advanced things with shared libraries, and will know who they are. + * minor incompatible change: Previously, all --eval forms used were + processed with READ before any of them were processed with EVAL. + Now each --eval form is processed with both READ and EVAL before + the next --eval form is processed. (Thus package operations like + sbcl --eval "(defpackage :foo)" --eval "(print 'foo::bar)" now work + as the user might reasonably expect.) * minor incompatible change: *STANDARD-INPUT* is now only an INPUT-STREAM, not a BIDIRECTIONAL-STREAM. (thanks to Antonio Martinez) diff --git a/doc/sbcl.1 b/doc/sbcl.1 index d7093b1..98204ae 100644 --- a/doc/sbcl.1 +++ b/doc/sbcl.1 @@ -309,9 +309,9 @@ initialization file to be read, but on a Unix system "--userinit .TP 3 .B --eval After executing any initialization file, but before starting the -read-eval-print loop on standard input, evaluate the command given. -More than one --eval option can be used, and all will be executed, in -the order they appear on the command line. +read-eval-print loop on standard input, read and evaluate the command +given. More than one --eval option can be used, and all will be read +and executed, in the order they appear on the command line. .TP 3 .B --load This is equivalent to --eval '(load "")'. The special @@ -344,10 +344,10 @@ command.) Regardless of the order in which --sysinit, --userinit, and --eval options appear on the command line, the sysinit file, if it exists, is loaded first; then the userinit file, if it exists, is loaded; then -any --eval commands are executed in sequence; then the read-eval-print -loop is started on standard input. At any step, error conditions or -commands such as SB-EXT:QUIT can cause execution to be terminated -before proceeding to subsequent steps. +any --eval commands are read and executed in sequence; then the +read-eval-print loop is started on standard input. At any step, error +conditions or commands such as SB-EXT:QUIT can cause execution to be +terminated before proceeding to subsequent steps. Note that when running SBCL with the --core option, using a core file created by a user call to the SB-EXT:SAVE-LISP-AND-DIE, the toplevel diff --git a/src/code/toplevel.lisp b/src/code/toplevel.lisp index d779e57..f245850 100644 --- a/src/code/toplevel.lisp +++ b/src/code/toplevel.lisp @@ -298,12 +298,22 @@ (/show0 "entering TOPLEVEL-INIT") (setf sb!thread::*session-lock* (sb!thread:make-mutex :name "the terminal")) (sb!thread::get-foreground) - (let ((sysinit nil) ; value of --sysinit option - (userinit nil) ; value of --userinit option - (reversed-evals nil) ; values of --eval options, in reverse order; and - ; also --load options, translated into --eval - (noprint nil) ; Has a --noprint option been seen? - (options (rest *posix-argv*))) ; skipping program name + (let (;; value of --sysinit option + (sysinit nil) + ;; value of --userinit option + (userinit nil) + ;; values of --eval options, in reverse order; and also any + ;; other options (like --load) which're translated into --eval + ;; + ;; The values are stored as strings, so that they can be + ;; passed to READ only after their predecessors have been + ;; EVALed, so that things work when e.g. REQUIRE in one EVAL + ;; form creates a package referred to in the next EVAL form. + (reversed-evals nil) + ;; Has a --noprint option been seen? + (noprint nil) + ;; everything in *POSIX-ARGV* except for argv[0]=programname + (options (rest *posix-argv*))) (declare (type list options)) @@ -338,22 +348,11 @@ (setf userinit (pop-option)))) ((string= option "--eval") (pop-option) - (let ((eval-as-string (pop-option))) - (with-input-from-string (eval-stream eval-as-string) - (let* ((eof-marker (cons :eof :eof)) - (eval (read eval-stream nil eof-marker)) - (eof (read eval-stream nil eof-marker))) - (cond ((eq eval eof-marker) - (error "unable to parse ~S" - eval-as-string)) - ((not (eq eof eof-marker)) - (error "more than one expression in ~S" - eval-as-string)) - (t - (push eval reversed-evals))))))) + (push (pop-option) reversed-evals)) ((string= option "--load") (pop-option) - (push `(load ,(pop-option)) reversed-evals)) + (push (concatenate 'string "(LOAD \"" (pop-option) "\")") + reversed-evals)) ((string= option "--noprint") (pop-option) (setf noprint t)) @@ -363,10 +362,10 @@ ((string= option "--noprogrammer") (warn "treating deprecated --noprogrammer as --disable-debugger") (pop-option) - (push '(disable-debugger) reversed-evals)) + (push "(DISABLE-DEBUGGER)" reversed-evals)) ((string= option "--disable-debugger") (pop-option) - (push '(disable-debugger) reversed-evals)) + (push "(DISABLE-DEBUGGER)" reversed-evals)) ((string= option "--end-toplevel-options") (pop-option) (return)) @@ -387,7 +386,7 @@ (return))))))) (/show0 "done with LOOP WHILE OPTIONS DO in TOPLEVEL-INIT") - ;; Excise all the options that we processed, so that only + ;; Delete all the options that we processed, so that only ;; user-level options are left visible to user code. (setf (rest *posix-argv*) options) @@ -444,10 +443,23 @@ ;; Process --eval options. (/show0 "handling --eval options in TOPLEVEL-INIT") - (dolist (eval (reverse reversed-evals)) + (dolist (expr-as-string (reverse reversed-evals)) (/show0 "handling one --eval option in TOPLEVEL-INIT") - (eval eval) - (flush-standard-output-streams))) + (let ((expr (with-input-from-string (eval-stream + expr-as-string) + (let* ((eof-marker (cons :eof :eof)) + (result (read eval-stream nil eof-marker)) + (eof (read eval-stream nil eof-marker))) + (cond ((eq result eof-marker) + (error "unable to parse ~S" + expr-as-string)) + ((not (eq eof eof-marker)) + (error "more than one expression in ~S" + expr-as-string)) + (t + result)))))) + (eval expr) + (flush-standard-output-streams)))) (continue () :report "Continue anyway (skipping to toplevel read/eval/print loop)." diff --git a/tests/toplevel.sh b/tests/toplevel.sh new file mode 100644 index 0000000..c089c04 --- /dev/null +++ b/tests/toplevel.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# tests related to the toplevel interface: command line parsing +# and outer REPL + +# This software is part of the SBCL system. See the README file for +# more information. +# +# While most of SBCL is derived from the CMU CL system, the test +# files (like this one) were written from scratch after the fork +# from CMU CL. +# +# This software is in the public domain and is provided with +# absolutely no warranty. See the COPYING and CREDITS files for +# more information. + +testfile=${TMPDIR:-/tmp}/sbcl-toplevel-test-$$.tmp + +# Until sbcl-0.pre8, all --eval arguments were parsed before any of +# them were executed, making it impossible for --eval forms to refer +# to packages created by --eval forms. +${SBCL:-sbcl} --eval "(defpackage :foo)" --eval "(print 'foo::bar)" \ + < /dev/null > $testfile +if [ "`grep -c FOO::BAR $testfile`" != 1 ] ; then + echo failed DEFPACKAGE-then-PRINT from --eval form + exit 1 +fi diff --git a/version.lisp-expr b/version.lisp-expr index 97fe437..432773c 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -18,4 +18,4 @@ ;;; versions, especially for internal versions off the main CVS ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".) -"0.pre8.57" +"0.pre8.58" -- 1.7.10.4