Commit | Line | Data |
---|---|---|
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) |