BSD 4_2 development
[unix-history] / usr / lib / lisp / toplevel.l
CommitLineData
9bb8b5f1
C
1(setq rcs-toplevel-
2 "$Header: /usr/lib/lisp/RCS/toplevel.l,v 1.2 83/03/27 18:10:28 jkf Exp $")
3
4;;
5;; toplevel.l -[Mon Mar 21 14:25:44 1983 by jkf]-
6;;
7;; toplevel read eval print loop
8;;
9
10
11; special atoms:
12(declare (special debug-level-count break-level-count
13 errlist tpl-errlist user-top-level
14 franz-not-virgin piport ER%tpl ER%all
15 $ldprint evalhook funcallhook
16 franz-minor-version-number
17 top-level-print top-level-read
18 top-level-eof * ** *** + ++ +++ ^w)
19 (localf autorunlisp cvtsearchpathtolist)
20 (macros t))
21
22(setq top-level-eof (gensym 'Q)
23 tpl-errlist nil
24 errlist nil
25 user-top-level nil
26 top-level-print nil
27 top-level-read nil)
28
29;--- read and print functions are user-selectable by just
30; assigning another value to top-level-print and top-level-read
31;
32(defmacro top-print (&rest args)
33 `(cond (top-level-print (funcall top-level-print ,@args))
34 (t (print ,@args))))
35
36(defmacro top-read (&rest args)
37 `(cond ((and top-level-read
38 (getd top-level-read))
39 (funcall top-level-read ,@args))
40 (t (read ,@args))))
41
42;------------------------------------------------------
43; Top level function for franz jkf, march 1980
44;
45; The following function contains the top-level read, eval, print
46; loop. With the help of the error handling functions,
47; break-err-handler and debug-err-handler, franz-top-level provides
48; a reasonable enviroment for working with franz lisp.
49;
50
51(def franz-top-level
52 (lambda nil
53 (putd 'reset (getd 'franz-reset))
54 (username-to-dir-flush-cache) ; clear tilde expansion knowledge
55 (cond ((or (not (boundp 'franz-not-virgin))
56 (null franz-not-virgin))
57 (setq franz-not-virgin t
58 + nil ++ nil +++ nil
59 * nil ** nil *** nil)
60 (setq ER%tpl 'break-err-handler)
61 (cond ((not (autorunlisp))
62 (patom (status version))
63 ; franz-minor-version-number defined in version.l
64 (cond ((boundp 'franz-minor-version-number)
65 (patom franz-minor-version-number)))
66 (terpr)
67 (read-in-lisprc-file)))))
68
69 ; loop forever
70 (do ((+*) (-) (retval))
71 (nil)
72 (setq retval
73 (*catch
74 '(top-level-catch break-catch)
75 ; begin or return to top level
76 (progn
77 (setq debug-level-count 0 break-level-count 0
78 evalhook nil funcallhook nil)
79 (cond (tpl-errlist (mapc 'eval tpl-errlist)))
80 (do ((^w nil nil))
81 (nil)
82 (cond (user-top-level (funcall user-top-level))
83 (t (patom "-> ")
84 (cond ((eq top-level-eof
85 (setq -
86 (car (errset (top-read nil
87 top-level-eof)))))
88 (cond ((not (status isatty))
89 (exit)))
90 (cond ((null (status ignoreeof))
91 (terpr)
92 (print 'Goodbye)
93 (terpr)
94 (exit))
95 (t (terpr)
96 (setq - ''EOF)))))
97 (setq +* (eval -))
98 ; update list of old forms
99 (let ((val -))
100 (let ((o+ +) (o++ ++))
101 (setq + val
102 ++ o+
103 +++ o++)))
104 ; update list of old values
105 (let ((val +*))
106 (let ((o* *) (o** **))
107 (setq * val
108 ** o*
109 *** o**)))
110 (top-print +*)
111 (terpr)))))))
112 (terpr)
113 (patom "[Return to top level]")
114 (terpr)
115 (cond ((eq 'reset retval) (old-reset-function))))))
116
117
118
119
120\f
121; debug-err-handler is the clb of ER%all when we are doing debugging
122; and we want to catch all errors.
123; It is just a read eval print loop with errset.
124; the only way to leave is:
125; (reset) just back to top level
126; (return x) return the value to the error checker.
127; if nil is returned then we will continue as if the error
128; didn't occur. Otherwise if the returned value is a list,
129; then if the error is continuable, the car of that list
130; will be returned to recontinue computation.
131; ^D continue as if this handler wasn't called.
132; the form of errmsgs is:
133; (error_type unique_id continuable message_string other_args ...)
134;
135(def debug-err-handler
136 (lexpr (n)
137 ((lambda (message debug-level-count retval ^w piport)
138 (cond ((greaterp n 0)
139 (print 'Error:)
140 (mapc '(lambda (a) (patom " ") (patom a) )
141 (cdddr (arg 1)))
142 (terpr)))
143 (setq ER%all 'debug-err-handler)
144 (do ((retval)) (nil)
145 (cond ((dtpr
146 (setq retval
147 (errset
148 (do ((form)) (nil)
149 (patom "D<")
150 (patom debug-level-count)
151 (patom ">: ")
152 (cond ((eq top-level-eof
153 (setq form
154 (top-read nil
155 top-level-eof)))
156 (cond ((null (status isatty))
157 (exit)))
158 (return nil))
159 ((and (dtpr form)
160 (eq 'return
161 (car form)))
162 (return (eval (cadr form))))
163 (t (setq form (eval form))
164 (top-print form)
165 (terpr)))))))
166 (return (car retval))))))
167 nil
168 (add1 debug-level-count)
169 nil
170 nil
171 nil)))
172\f
173; this is the break handler, it should be tied to
174; ER%tpl always.
175; it is entered if there is an error which no one wants to handle.
176; We loop forever, printing out our error level until someone
177; types a ^D which goes to the next break level above us (or the
178; top-level if there are no break levels above us.
179; a (return n) will return that value to the error message
180; which called us, if that is possible (that is if the error is
181; continuable)
182;
183(def break-err-handler
184 (lexpr (n)
185 ((lambda (message break-level-count retval rettype ^w piport)
186 (cond ((greaterp n 0)
187 (print 'Error:)
188 (mapc '(lambda (a) (patom " ") (patom a) )
189 (cdddr (arg 1)))
190 (terpr)
191 (cond ((caddr (arg 1)) (setq rettype 'contuab))
192 (t (setq rettype nil))))
193 (t (setq rettype 'localcall)))
194
195 (do nil (nil)
196 (cond ((dtpr
197 (setq retval
198 (*catch 'break-catch
199 (do ((form)) (nil)
200 (patom "<")
201 (patom break-level-count)
202 (patom ">: ")
203 (cond ((eq top-level-eof
204 (setq form
205 (top-read
206 nil
207 top-level-eof)))
208 (cond ((null (status isatty))
209 (exit)))
210 (eval 1) ; force interrupt check
211 (return (sub1 break-level-count)))
212 ((and (dtpr form)
213 (eq 'return (car form)))
214 (cond ((or (eq rettype 'contuab)
215 (eq rettype 'localcall))
216 (return (ncons (eval (cadr form)))))
217 (t (patom "Can't continue from this error")
218 (terpr))))
219 ((and (dtpr form) (eq 'retbrk (car form)))
220 (cond ((numberp (setq form (eval (cadr form))))
221 (return form))
222 (t (return (sub1 break-level-count)))))
223 (t (setq form (eval form))
224 (top-print form)
225 (terpr)))))))
226 (return (cond ((eq rettype 'localcall)
227 (car retval))
228 (t retval))))
229 ((lessp retval break-level-count)
230 (setq tpl-errlist errlist)
231 (*throw 'break-catch retval))
232 (t (terpr)))))
233 nil
234 (add1 break-level-count)
235 nil
236 nil
237 nil
238 nil)))
239\f
240(defvar debug-error-handler 'debug-err-handler) ; name of function to get
241 ; control on ER%all error
242(def debugging
243 (lambda (val)
244 (cond (val (setq ER%all debug-error-handler)
245 (sstatus translink nil)
246 (*rset t))
247 (t (setq ER%all nil)))))
248
249
250; the problem with this definition for break is that we are
251; forced to put an errset around the break-err-handler. This means
252; that we will never get break errors, since all errors will be
253; caught by our errset (better ours than one higher up though).
254; perhaps the solution is to automatically turn debugmode on.
255;
256(defmacro break (message &optional (pred t))
257 `(*break ,pred ',message))
258
259(def *break
260 (lambda (pred message)
261 (let ((^w nil))
262 (cond ((not (boundp 'break-level-count)) (setq break-level-count 1)))
263 (cond (pred (terpr)
264 (patom "Break ")
265 (patom message)
266 (terpr)
267 (do ((form))
268 (nil)
269 (cond ((dtpr (setq form (errset (break-err-handler))))
270 (return (car form))))))))))
271
272
273; this reset function is designed to work with the franz-top-level.
274; When franz-top-level begins, it makes franz-reset be reset.
275; when a reset occurs now, we set the global variable tpl-errlist to
276; the current value of errlist and throw to top level. At top level,
277; then tpl-errlist will be evaluated.
278;
279(def franz-reset
280 (lambda nil
281 (setq tpl-errlist errlist)
282 (errset (*throw 'top-level-catch 'reset)
283 nil)
284 (old-reset-function)))
285
286
287(declare (special $ldprint))
288
289;--- read-in-lisprc-file
290; search for a lisp init file. Look first in . then in $HOME
291; look first for .o , then .l and then "",
292; look for file bodies .lisprc and then lisprc
293;
294(def read-in-lisprc-file
295 (lambda nil
296 (setq break-level-count 0 ; do this in case break
297 debug-level-count 0) ; occurs during readin
298 (*catch '(break-catch top-level-catch)
299 (do ((dirs `("." ,(getenv 'HOME)) (cdr dirs))
300 ($ldprint nil $ldprint)) ; prevent messages
301 ((null dirs))
302 (cond ((do ((name '(".lisprc" "lisprc") (cdr name)))
303 ((null name))
304 (cond ((do ((ext '(".o" ".l" "") (cdr ext))
305 (file))
306 ((null ext))
307 (cond ((probef
308 (setq file
309 (concat (car dirs)
310 "/"
311 (car name)
312 (car ext))))
313 (cond ((atom (errset (load file)))
314 (patom
315 "Error loading lisp init file ")
316 (print file)
317 (terpr)
318 (return 'error)))
319 (return t))))
320 (return t))))
321 (return t)))))))
322
323(putd 'top-level (getd 'franz-top-level))
324
325; if this is the first time this file has been read in, then
326; make franz-reset be the reset function, but remember the original
327; reset function as old-reset-function. We need the old reset function
328; if we are going to allow the user to change top-levels, for in
329; order to do that we really have to jump all the way up to the top.
330(cond ((null (getd 'old-reset-function))
331 (putd 'old-reset-function (getd 'reset))))
332
333
334;---- autoloader functions
335
336(def undef-func-handler
337 (lambda (args)
338 (prog (funcnam file)
339 (setq funcnam (caddddr args))
340 (cond ((symbolp funcnam)
341 (cond ((setq file (or (get funcnam 'autoload)
342 (get funcnam 'macro-autoload)))
343 (cond ($ldprint
344 (patom "[autoload ") (patom file)
345 (patom "]")(terpr)))
346 (load file))
347 (t (return nil)))
348 (cond ((getd funcnam) (return (ncons funcnam)))
349 (t (patom "Autoload file " ) (print file)
350 (patom " does not contain function ")
351 (print funcnam)
352 (terpr)
353 (return nil))))))))
354
355(setq ER%undef 'undef-func-handler)
356
357(declare (special $ldprint))
358;--- autorunlisp :: check if this lisp is supposed to run a program right
359; away.
360;
361(defun autorunlisp nil
362 (cond ((and (> (argv -1) 2) (equal (argv 1) '-f))
363 (let ((progname (argv 2))
364 ($ldprint nil)
365 (searchlist nil)) ; don't give fasl messages
366 (setq searchlist (cvtsearchpathtolist (getenv 'PATH)))
367 ; give two args to load to insure that a fasl is done.
368 (cond ((null
369 (errset (load-autorunobject progname searchlist)))
370 (exit 0))
371 (t t))))))
372
373
374(defun cvtsearchpathtolist (path)
375 (do ((x (explodec path) (cdr x))
376 (names nil)
377 (cur nil))
378 ((null x)
379 (nreverse names))
380 (cond ((or (eq ': (car x))
381 (and (null (cdr x)) (setq cur (cons (car x) cur))))
382 (cond (cur (setq names (cons (implode (nreverse cur))
383 names))
384 (setq cur nil))
385 (t (setq names (cons '|.| names)))))
386 (t (setq cur (cons (car x) cur))))))
387
388(defun load-autorunobject (name search)
389 (cond ((memq (getchar name 1) '(/ |.|))
390 (cond ((probef name) (fasl name))
391 (t (error "From lisp autorun: can't find file to load"))))
392 (t (do ((xx search (cdr xx))
393 (fullname))
394 ((null xx) (error "Can't find file to execute "))
395 (cond ((probef (setq fullname (concat (car xx) "/" name)))
396 (return (fasl-a-file fullname nil nil))))))))
397
398;--- command-line-args :: return a list of the command line arguments
399; The list does not include the name of the program being executed (argv 0).
400; It also doesn't include the autorun flag and arg.
401;
402(defun command-line-args ()
403 (do ((res nil (cons (argv i) res))
404 (i (1- (argv -1)) (1- i)))
405 ((<& i 1)
406 (if (and (eq '-f (car res))
407 (cdr res))
408 then (cddr res)
409 else res))))
410
411(defun debug fexpr (args)
412 (load 'fix) ; load in fix package
413 (eval (cons 'debug args))) ; enter debug through eval
414
415;-- default autoloader properties
416
417(putprop 'trace (concat lisp-library-directory "/trace") 'autoload)
418(putprop 'step (concat lisp-library-directory "/step") 'autoload)
419(putprop 'editf (concat lisp-library-directory "/cmuedit") 'autoload)
420(putprop 'editv (concat lisp-library-directory "/cmuedit") 'autoload)
421(putprop 'editp (concat lisp-library-directory "/cmuedit") 'autoload)
422(putprop 'edite (concat lisp-library-directory "/cmuedit") 'autoload)
423
424(putprop 'defstruct (concat lisp-library-directory "/struct") 'macro-autoload)
425(putprop 'defstruct-expand-ref-macro
426 (concat lisp-library-directory "/struct") 'autoload)
427(putprop 'defstruct-expand-cons-macro
428 (concat lisp-library-directory "/struct") 'autoload)
429
430(putprop 'loop (concat lisp-library-directory "/loop") 'macro-autoload)
431(putprop 'defflavor
432 (concat lisp-library-directory "/flavors") 'macro-autoload)
433(putprop 'defflavor1
434 (concat lisp-library-directory "/flavors") 'autoload)
435
436(putprop 'format (concat lisp-library-directory "/format") 'autoload)
437(putprop 'ferror (concat lisp-library-directory "/format") 'autoload)
438
439(putprop 'make-hash-table
440 (concat lisp-library-directory "/hash") 'autoload)
441(putprop 'make-equal-hash-table
442 (concat lisp-library-directory "/hash") 'autoload)
443
444(putprop 'describe (concat lisp-library-directory "/describe") 'autoload)
445
446(putprop 'cgol (concat lisp-library-directory "/cgol") 'autoload)
447
448; probably should be in franz so we don't have to autoload
449(putprop 'displace (concat lisp-library-directory "/machacks") 'autoload)