*** empty log message ***
[bpt/guile.git] / ice-9 / boot-9.scm
CommitLineData
0f2d19dd
JB
1;;; installed-scm-file
2
e3306d80 3;;;; Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
0f2d19dd
JB
4;;;;
5;;;; This program is free software; you can redistribute it and/or modify
6;;;; it under the terms of the GNU General Public License as published by
7;;;; the Free Software Foundation; either version 2, or (at your option)
8;;;; any later version.
9;;;;
10;;;; This program is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13;;;; GNU General Public License for more details.
14;;;;
15;;;; You should have received a copy of the GNU General Public License
16;;;; along with this software; see the file COPYING. If not, write to
15328041
JB
17;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18;;;; Boston, MA 02111-1307 USA
0f2d19dd
JB
19;;;;
20\f
21
22;;; This file is the first thing loaded into Guile. It adds many mundane
23;;; definitions and a few that are interesting.
24;;;
25;;; The module system (hence the hierarchical namespace) are defined in this
26;;; file.
27;;;
28
29\f
21ed9efe
MD
30;;; {Features}
31;;
32
33(define (provide sym)
34 (if (not (memq sym *features*))
35 (set! *features* (cons sym *features*))))
36
50706e94
JB
37;;; Return #t iff FEATURE is available to this Guile interpreter.
38;;; In SLIB, provided? also checks to see if the module is available.
39;;; We should do that too, but don't.
40(define (provided? feature)
41 (and (memq feature *features*) #t))
42
21ed9efe 43\f
79451588
JB
44;;; {R4RS compliance}
45
46(primitive-load-path "ice-9/r4rs.scm")
47
48\f
44cf1f0f 49;;; {Simple Debugging Tools}
0f2d19dd
JB
50;;
51
52
53;; peek takes any number of arguments, writes them to the
54;; current ouput port, and returns the last argument.
55;; It is handy to wrap around an expression to look at
56;; a value each time is evaluated, e.g.:
57;;
58;; (+ 10 (troublesome-fn))
59;; => (+ 10 (pk 'troublesome-fn-returned (troublesome-fn)))
60;;
61
62(define (peek . stuff)
63 (newline)
64 (display ";;; ")
65 (write stuff)
66 (newline)
67 (car (last-pair stuff)))
68
69(define pk peek)
70
71(define (warn . stuff)
72 (with-output-to-port (current-error-port)
73 (lambda ()
74 (newline)
75 (display ";;; WARNING ")
6355358a 76 (display stuff)
0f2d19dd
JB
77 (newline)
78 (car (last-pair stuff)))))
79
80\f
79451588 81;;; {Trivial Functions}
0f2d19dd 82;;;
79451588
JB
83
84(define (id x) x)
85(define (1+ n) (+ n 1))
86(define (-1+ n) (+ n -1))
87(define 1- -1+)
88(define return-it noop)
132e5fac 89(define (and=> value procedure) (and value (procedure value)))
79451588
JB
90(define (make-hash-table k) (make-vector k '()))
91
0f2d19dd
JB
92;;; apply-to-args is functionally redunant with apply and, worse,
93;;; is less general than apply since it only takes two arguments.
94;;;
95;;; On the other hand, apply-to-args is a syntacticly convenient way to
96;;; perform binding in many circumstances when the "let" family of
97;;; of forms don't cut it. E.g.:
98;;;
99;;; (apply-to-args (return-3d-mouse-coords)
100;;; (lambda (x y z)
101;;; ...))
102;;;
103
104(define (apply-to-args args fn) (apply fn args))
105
106\f
0f2d19dd
JB
107;;; {Integer Math}
108;;;
109
0f2d19dd
JB
110(define (ipow-by-squaring x k acc proc)
111 (cond ((zero? k) acc)
112 ((= 1 k) (proc acc x))
52c5a23a
JB
113 (else (ipow-by-squaring (proc x x)
114 (quotient k 2)
115 (if (even? k) acc (proc acc x))
116 proc))))
0f2d19dd
JB
117
118(define string-character-length string-length)
119
120
121
122;; A convenience function for combining flag bits. Like logior, but
123;; handles the cases of 0 and 1 arguments.
124;;
125(define (flags . args)
126 (cond
127 ((null? args) 0)
128 ((null? (cdr args)) (car args))
129 (else (apply logior args))))
130
131\f
0f2d19dd
JB
132;;; {Symbol Properties}
133;;;
134
135(define (symbol-property sym prop)
136 (let ((pair (assoc prop (symbol-pref sym))))
137 (and pair (cdr pair))))
138
139(define (set-symbol-property! sym prop val)
140 (let ((pair (assoc prop (symbol-pref sym))))
141 (if pair
142 (set-cdr! pair val)
143 (symbol-pset! sym (acons prop val (symbol-pref sym))))))
144
145(define (symbol-property-remove! sym prop)
146 (let ((pair (assoc prop (symbol-pref sym))))
147 (if pair
148 (symbol-pset! sym (delq! pair (symbol-pref sym))))))
149
150\f
1e531c3a
GH
151
152;;; {Line and Delimited I/O}
153
154;;; corresponds to SCM_LINE_INCREMENTORS in libguile.
155(define scm-line-incrementors "\n")
156
157(define (read-line! string . maybe-port)
158 (let* ((port (if (pair? maybe-port)
159 (car maybe-port)
160 (current-input-port))))
161 (let* ((rv (%read-delimited! scm-line-incrementors
162 string
163 #t
164 port))
165 (terminator (car rv))
166 (nchars (cdr rv)))
167 (cond ((and (= nchars 0)
168 (eof-object? terminator))
169 terminator)
170 ((not terminator) #f)
171 (else nchars)))))
172
173(define (read-delimited! delims buf . args)
174 (let* ((num-args (length args))
175 (port (if (> num-args 0)
176 (car args)
177 (current-input-port)))
178 (handle-delim (if (> num-args 1)
179 (cadr args)
180 'trim))
181 (start (if (> num-args 2)
182 (caddr args)
183 0))
184 (end (if (> num-args 3)
185 (cadddr args)
186 (string-length buf))))
187 (let* ((rv (%read-delimited! delims
188 buf
189 (not (eq? handle-delim 'peek))
190 port
191 start
192 end))
193 (terminator (car rv))
194 (nchars (cdr rv)))
195 (cond ((or (not terminator) ; buffer filled
196 (eof-object? terminator))
197 (if (zero? nchars)
198 (if (eq? handle-delim 'split)
199 (cons terminator terminator)
200 terminator)
201 (if (eq? handle-delim 'split)
202 (cons nchars terminator)
203 nchars)))
204 (else
205 (case handle-delim
206 ((trim peek) nchars)
e3306d80 207 ((concat) (string-set! buf (+ nchars start) terminator)
1e531c3a
GH
208 (+ nchars 1))
209 ((split) (cons nchars terminator))
210 (else (error "unexpected handle-delim value: "
211 handle-delim))))))))
212
213(define (read-delimited delims . args)
214 (let* ((port (if (pair? args)
215 (let ((pt (car args)))
216 (set! args (cdr args))
217 pt)
218 (current-input-port)))
219 (handle-delim (if (pair? args)
220 (car args)
221 'trim)))
222 (let loop ((substrings ())
223 (total-chars 0)
224 (buf-size 100)) ; doubled each time through.
225 (let* ((buf (make-string buf-size))
226 (rv (%read-delimited! delims
227 buf
228 (not (eq? handle-delim 'peek))
229 port))
230 (terminator (car rv))
231 (nchars (cdr rv))
232 (join-substrings
233 (lambda ()
234 (apply string-append
235 (reverse
236 (cons (if (and (eq? handle-delim 'concat)
237 (not (eof-object? terminator)))
238 (string terminator)
239 "")
240 (cons (make-shared-substring buf 0 nchars)
241 substrings))))))
242 (new-total (+ total-chars nchars)))
243 (cond ((not terminator)
244 ;; buffer filled.
245 (loop (cons (substring buf 0 nchars) substrings)
246 new-total
247 (* buf-size 2)))
248 ((eof-object? terminator)
249 (if (zero? new-total)
250 (if (eq? handle-delim 'split)
251 (cons terminator terminator)
252 terminator)
253 (if (eq? handle-delim 'split)
254 (cons (join-substrings) terminator)
255 (join-substrings))))
256 (else
257 (case handle-delim
258 ((trim peek concat) (join-substrings))
259 ((split) (cons (join-substrings) terminator))
848f2a01
TP
260
261
1e531c3a
GH
262 (else (error "unexpected handle-delim value: "
263 handle-delim)))))))))
848f2a01
TP
264
265;;; read-line [PORT [HANDLE-DELIM]] reads a newline-terminated string
266;;; from PORT. The return value depends on the value of HANDLE-DELIM,
267;;; which may be one of the symbols `trim', `concat', `peek' and
268;;; `split'. If it is `trim' (the default), the trailing newline is
269;;; removed and the string is returned. If `concat', the string is
270;;; returned with the trailing newline intact. If `peek', the newline
271;;; is left in the input port buffer and the string is returned. If
272;;; `split', the newline is split from the string and read-line
273;;; returns a pair consisting of the truncated string and the newline.
274
1e531c3a 275(define (read-line . args)
848f2a01
TP
276 (let* ((port (if (null? args)
277 (current-input-port)
278 (car args)))
279 (handle-delim (if (> (length args) 1)
280 (cadr args)
281 'trim))
282 (line/delim (%read-line port))
283 (line (car line/delim))
284 (delim (cdr line/delim)))
285 (case handle-delim
286 ((trim) line)
287 ((split) line/delim)
288 ((concat) (if (and (string? line) (char? delim))
289 (string-append line (string delim))
290 line))
291 ((peek) (if (char? delim)
292 (unread-char delim port))
293 line)
294 (else
295 (error "unexpected handle-delim value: " handle-delim)))))
1e531c3a
GH
296
297\f
0f2d19dd
JB
298;;; {Arrays}
299;;;
300
301(begin
302 (define uniform-vector? array?)
303 (define make-uniform-vector dimensions->uniform-array)
304 ; (define uniform-vector-ref array-ref)
305 (define (uniform-vector-set! u i o)
c2132276 306 (uniform-array-set1! u o i))
0f2d19dd
JB
307 (define uniform-vector-fill! array-fill!)
308 (define uniform-vector-read! uniform-array-read!)
309 (define uniform-vector-write uniform-array-write)
310
311 (define (make-array fill . args)
312 (dimensions->uniform-array args () fill))
313 (define (make-uniform-array prot . args)
314 (dimensions->uniform-array args prot))
315 (define (list->array ndim lst)
316 (list->uniform-array ndim '() lst))
317 (define (list->uniform-vector prot lst)
318 (list->uniform-array 1 prot lst))
319 (define (array-shape a)
320 (map (lambda (ind) (if (number? ind) (list 0 (+ -1 ind)) ind))
321 (array-dimensions a))))
322
323\f
324;;; {Keywords}
325;;;
326
327(define (symbol->keyword symbol)
328 (make-keyword-from-dash-symbol (symbol-append '- symbol)))
329
330(define (keyword->symbol kw)
331 (let ((sym (keyword-dash-symbol kw)))
11b05261 332 (string->symbol (substring sym 1 (string-length sym)))))
0f2d19dd
JB
333
334(define (kw-arg-ref args kw)
335 (let ((rem (member kw args)))
336 (and rem (pair? (cdr rem)) (cadr rem))))
337
338\f
fa7e9274 339
9f9aa47b 340;;; {Structs}
fa7e9274
MV
341
342(define (struct-layout s)
9f9aa47b 343 (struct-ref (struct-vtable s) vtable-index-layout))
fa7e9274
MV
344
345\f
0f2d19dd
JB
346;;; {Records}
347;;;
348
fa7e9274
MV
349;; Printing records: by default, records are printed as
350;;
351;; #<type-name field1: val1 field2: val2 ...>
352;;
353;; You can change that by giving a custom printing function to
354;; MAKE-RECORD-TYPE (after the list of field symbols). This function
355;; will be called like
356;;
357;; (<printer> object port)
358;;
359;; It should print OBJECT to PORT.
360
cf8f1a90 361(define (inherit-print-state old-port new-port)
8a30733e
MD
362 (if (get-print-state old-port)
363 (port-with-print-state new-port (get-print-state old-port))
cf8f1a90
MV
364 new-port))
365
9f9aa47b 366;; 0: type-name, 1: fields
fa7e9274 367(define record-type-vtable
9f9aa47b
MD
368 (make-vtable-vtable "prpr" 0
369 (lambda (s p)
370 (cond ((eq? s record-type-vtable)
371 (display "#<record-type-vtable>" p))
372 (else
373 (display "#<record-type " p)
374 (display (record-type-name s) p)
375 (display ">" p))))))
0f2d19dd
JB
376
377(define (record-type? obj)
378 (and (struct? obj) (eq? record-type-vtable (struct-vtable obj))))
379
380(define (make-record-type type-name fields . opt)
8e693424 381 (let ((printer-fn (and (pair? opt) (car opt))))
0f2d19dd 382 (let ((struct (make-struct record-type-vtable 0
c7c03b9f
JB
383 (make-struct-layout
384 (apply symbol-append
385 (map (lambda (f) "pw") fields)))
9f9aa47b
MD
386 (or printer-fn
387 (lambda (s p)
388 (display "#<" p)
389 (display type-name p)
390 (let loop ((fields fields)
391 (off 0))
392 (cond
393 ((not (null? fields))
394 (display " " p)
395 (display (car fields) p)
396 (display ": " p)
397 (display (struct-ref s off) p)
398 (loop (cdr fields) (+ 1 off)))))
399 (display ">" p)))
0f2d19dd
JB
400 type-name
401 (copy-tree fields))))
c8eed875
MD
402 ;; Temporary solution: Associate a name to the record type descriptor
403 ;; so that the object system can create a wrapper class for it.
404 (set-struct-vtable-name! struct (if (symbol? type-name)
405 type-name
406 (string->symbol type-name)))
0f2d19dd
JB
407 struct)))
408
409(define (record-type-name obj)
410 (if (record-type? obj)
9f9aa47b 411 (struct-ref obj vtable-offset-user)
0f2d19dd
JB
412 (error 'not-a-record-type obj)))
413
414(define (record-type-fields obj)
415 (if (record-type? obj)
9f9aa47b 416 (struct-ref obj (+ 1 vtable-offset-user))
0f2d19dd
JB
417 (error 'not-a-record-type obj)))
418
419(define (record-constructor rtd . opt)
8e693424 420 (let ((field-names (if (pair? opt) (car opt) (record-type-fields rtd))))
0f2d19dd
JB
421 (eval `(lambda ,field-names
422 (make-struct ',rtd 0 ,@(map (lambda (f)
423 (if (memq f field-names)
424 f
425 #f))
426 (record-type-fields rtd)))))))
427
428(define (record-predicate rtd)
429 (lambda (obj) (and (struct? obj) (eq? rtd (struct-vtable obj)))))
430
431(define (record-accessor rtd field-name)
432 (let* ((pos (list-index (record-type-fields rtd) field-name)))
433 (if (not pos)
434 (error 'no-such-field field-name))
435 (eval `(lambda (obj)
436 (and (eq? ',rtd (record-type-descriptor obj))
437 (struct-ref obj ,pos))))))
438
439(define (record-modifier rtd field-name)
440 (let* ((pos (list-index (record-type-fields rtd) field-name)))
441 (if (not pos)
442 (error 'no-such-field field-name))
443 (eval `(lambda (obj val)
444 (and (eq? ',rtd (record-type-descriptor obj))
445 (struct-set! obj ,pos val))))))
446
447
448(define (record? obj)
449 (and (struct? obj) (record-type? (struct-vtable obj))))
450
451(define (record-type-descriptor obj)
452 (if (struct? obj)
453 (struct-vtable obj)
454 (error 'not-a-record obj)))
455
21ed9efe
MD
456(provide 'record)
457
0f2d19dd
JB
458\f
459;;; {Booleans}
460;;;
461
462(define (->bool x) (not (not x)))
463
464\f
465;;; {Symbols}
466;;;
467
468(define (symbol-append . args)
469 (string->symbol (apply string-append args)))
470
471(define (list->symbol . args)
472 (string->symbol (apply list->string args)))
473
474(define (symbol . args)
475 (string->symbol (apply string args)))
476
477(define (obarray-symbol-append ob . args)
478 (string->obarray-symbol (apply string-append ob args)))
479
e672f1b5
MD
480(define (obarray-gensym obarray . opt)
481 (if (null? opt)
482 (gensym "%%gensym" obarray)
483 (gensym (car opt) obarray)))
0f2d19dd
JB
484
485\f
486;;; {Lists}
487;;;
488
489(define (list-index l k)
490 (let loop ((n 0)
491 (l l))
492 (and (not (null? l))
493 (if (eq? (car l) k)
494 n
495 (loop (+ n 1) (cdr l))))))
496
75fd4fb6
JB
497(define (make-list n . init)
498 (if (pair? init) (set! init (car init)))
0f2d19dd
JB
499 (let loop ((answer '())
500 (n n))
501 (if (<= n 0)
502 answer
503 (loop (cons init answer) (- n 1)))))
504
505
506\f
1729d8ff
MD
507;;; {Multiple return values}
508
509(define *values-rtd*
510 (make-record-type "values"
511 '(values)))
512
513(define values
514 (let ((make-values (record-constructor *values-rtd*)))
515 (lambda x
516 (if (and (not (null? x))
517 (null? (cdr x)))
518 (car x)
519 (make-values x)))))
520
521(define call-with-values
522 (let ((access-values (record-accessor *values-rtd* 'values))
523 (values-predicate? (record-predicate *values-rtd*)))
524 (lambda (producer consumer)
525 (let ((result (producer)))
526 (if (values-predicate? result)
527 (apply consumer (access-values result))
528 (consumer result))))))
529
87cfc5da 530(provide 'values)
1729d8ff
MD
531
532\f
3e3cec45 533;;; {and-map and or-map}
0f2d19dd
JB
534;;;
535;;; (and-map fn lst) is like (and (fn (car lst)) (fn (cadr lst)) (fn...) ...)
536;;; (or-map fn lst) is like (or (fn (car lst)) (fn (cadr lst)) (fn...) ...)
537;;; (map-in-order fn lst) is like (map fn lst) but definately in order of lst.
538;;;
539
540;; and-map f l
541;;
542;; Apply f to successive elements of l until exhaustion or f returns #f.
543;; If returning early, return #f. Otherwise, return the last value returned
544;; by f. If f has never been called because l is empty, return #t.
545;;
546(define (and-map f lst)
547 (let loop ((result #t)
548 (l lst))
549 (and result
550 (or (and (null? l)
551 result)
552 (loop (f (car l)) (cdr l))))))
553
554;; or-map f l
555;;
556;; Apply f to successive elements of l until exhaustion or while f returns #f.
557;; If returning early, return the return value of f.
558;;
559(define (or-map f lst)
560 (let loop ((result #f)
561 (l lst))
562 (or result
563 (and (not (null? l))
564 (loop (f (car l)) (cdr l))))))
565
59e1116d 566\f
0f2d19dd 567;;; {Files}
0f2d19dd 568;;;
249cdba6
TP
569;;; If no one can explain this comment to me by 31 Jan 1998, I will
570;;; assume it is meaningless and remove it. -twp
571;;; !!!! these should be implemented using Tcl commands, not fports.
0f2d19dd 572
6fa8995c
GH
573(define (feature? feature)
574 (and (memq feature *features*) #t))
575
3afb28ce
GH
576;; Using the vector returned by stat directly is probably not a good
577;; idea (it could just as well be a record). Hence some accessors.
578(define (stat:dev f) (vector-ref f 0))
579(define (stat:ino f) (vector-ref f 1))
580(define (stat:mode f) (vector-ref f 2))
581(define (stat:nlink f) (vector-ref f 3))
582(define (stat:uid f) (vector-ref f 4))
583(define (stat:gid f) (vector-ref f 5))
584(define (stat:rdev f) (vector-ref f 6))
585(define (stat:size f) (vector-ref f 7))
586(define (stat:atime f) (vector-ref f 8))
587(define (stat:mtime f) (vector-ref f 9))
588(define (stat:ctime f) (vector-ref f 10))
589(define (stat:blksize f) (vector-ref f 11))
590(define (stat:blocks f) (vector-ref f 12))
591
592;; derived from stat mode.
593(define (stat:type f) (vector-ref f 13))
594(define (stat:perms f) (vector-ref f 14))
595
6fa8995c
GH
596(define file-exists?
597 (if (feature? 'posix)
598 (lambda (str)
599 (access? str F_OK))
600 (lambda (str)
601 (let ((port (catch 'system-error (lambda () (open-file str OPEN_READ))
602 (lambda args #f))))
603 (if port (begin (close-port port) #t)
604 #f)))))
605
606(define file-is-directory?
607 (if (feature? 'i/o-extensions)
608 (lambda (str)
3afb28ce 609 (eq? (stat:type (stat str)) 'directory))
6fa8995c
GH
610 (lambda (str)
611 (display str)
612 (newline)
613 (let ((port (catch 'system-error
614 (lambda () (open-file (string-append str "/.")
615 OPEN_READ))
616 (lambda args #f))))
617 (if port (begin (close-port port) #t)
618 #f)))))
0f2d19dd
JB
619
620(define (has-suffix? str suffix)
621 (let ((sufl (string-length suffix))
622 (sl (string-length str)))
623 (and (> sl sufl)
624 (string=? (substring str (- sl sufl) sl) suffix))))
625
0f2d19dd
JB
626\f
627;;; {Error Handling}
628;;;
629
0f2d19dd 630(define (error . args)
21ed9efe 631 (save-stack)
2194b6f0 632 (if (null? args)
5552355a 633 (scm-error 'misc-error #f "?" #f #f)
2194b6f0
GH
634 (let loop ((msg "%s")
635 (rest (cdr args)))
636 (if (not (null? rest))
637 (loop (string-append msg " %S")
638 (cdr rest))
5552355a 639 (scm-error 'misc-error #f msg args #f)))))
be2d2c70 640
1349bd53 641;; bad-throw is the hook that is called upon a throw to a an unhandled
9a0d70e2
GH
642;; key (unless the throw has four arguments, in which case
643;; it's usually interpreted as an error throw.)
644;; If the key has a default handler (a throw-handler-default property),
0f2d19dd
JB
645;; it is applied to the throw.
646;;
1349bd53 647(define (bad-throw key . args)
0f2d19dd
JB
648 (let ((default (symbol-property key 'throw-handler-default)))
649 (or (and default (apply default key args))
2194b6f0 650 (apply error "unhandled-exception:" key args))))
0f2d19dd 651
0f2d19dd 652\f
44cf1f0f
JB
653;;; {Non-polymorphic versions of POSIX functions}
654
02b754d3
GH
655(define (getgrnam name) (getgr name))
656(define (getgrgid id) (getgr id))
657(define (gethostbyaddr addr) (gethost addr))
658(define (gethostbyname name) (gethost name))
659(define (getnetbyaddr addr) (getnet addr))
660(define (getnetbyname name) (getnet name))
661(define (getprotobyname name) (getproto name))
662(define (getprotobynumber addr) (getproto addr))
663(define (getpwnam name) (getpw name))
664(define (getpwuid uid) (getpw uid))
920235cc
GH
665(define (getservbyname name proto) (getserv name proto))
666(define (getservbyport port proto) (getserv port proto))
0f2d19dd
JB
667(define (endgrent) (setgr))
668(define (endhostent) (sethost))
669(define (endnetent) (setnet))
670(define (endprotoent) (setproto))
671(define (endpwent) (setpw))
672(define (endservent) (setserv))
02b754d3
GH
673(define (getgrent) (getgr))
674(define (gethostent) (gethost))
675(define (getnetent) (getnet))
676(define (getprotoent) (getproto))
677(define (getpwent) (getpw))
678(define (getservent) (getserv))
bce074ee
GH
679(define (setgrent) (setgr #f))
680(define (sethostent) (sethost #t))
681(define (setnetent) (setnet #t))
682(define (setprotoent) (setproto #t))
683(define (setpwent) (setpw #t))
684(define (setservent) (setserv #t))
685
686(define (passwd:name obj) (vector-ref obj 0))
687(define (passwd:passwd obj) (vector-ref obj 1))
688(define (passwd:uid obj) (vector-ref obj 2))
689(define (passwd:gid obj) (vector-ref obj 3))
690(define (passwd:gecos obj) (vector-ref obj 4))
691(define (passwd:dir obj) (vector-ref obj 5))
692(define (passwd:shell obj) (vector-ref obj 6))
693
694(define (group:name obj) (vector-ref obj 0))
695(define (group:passwd obj) (vector-ref obj 1))
696(define (group:gid obj) (vector-ref obj 2))
697(define (group:mem obj) (vector-ref obj 3))
698
699(define (hostent:name obj) (vector-ref obj 0))
700(define (hostent:aliases obj) (vector-ref obj 1))
701(define (hostent:addrtype obj) (vector-ref obj 2))
702(define (hostent:length obj) (vector-ref obj 3))
703(define (hostent:addr-list obj) (vector-ref obj 4))
704
705(define (netent:name obj) (vector-ref obj 0))
706(define (netent:aliases obj) (vector-ref obj 1))
9337637f
GH
707(define (netent:addrtype obj) (vector-ref obj 2))
708(define (netent:net obj) (vector-ref obj 3))
bce074ee
GH
709
710(define (protoent:name obj) (vector-ref obj 0))
711(define (protoent:aliases obj) (vector-ref obj 1))
712(define (protoent:proto obj) (vector-ref obj 2))
713
714(define (servent:name obj) (vector-ref obj 0))
715(define (servent:aliases obj) (vector-ref obj 1))
9337637f
GH
716(define (servent:port obj) (vector-ref obj 2))
717(define (servent:proto obj) (vector-ref obj 3))
718
719(define (sockaddr:fam obj) (vector-ref obj 0))
720(define (sockaddr:path obj) (vector-ref obj 1))
721(define (sockaddr:addr obj) (vector-ref obj 1))
722(define (sockaddr:port obj) (vector-ref obj 2))
723
724(define (utsname:sysname obj) (vector-ref obj 0))
725(define (utsname:nodename obj) (vector-ref obj 1))
726(define (utsname:release obj) (vector-ref obj 2))
727(define (utsname:version obj) (vector-ref obj 3))
728(define (utsname:machine obj) (vector-ref obj 4))
bce074ee 729
708bf0f3
GH
730(define (tm:sec obj) (vector-ref obj 0))
731(define (tm:min obj) (vector-ref obj 1))
732(define (tm:hour obj) (vector-ref obj 2))
733(define (tm:mday obj) (vector-ref obj 3))
734(define (tm:mon obj) (vector-ref obj 4))
735(define (tm:year obj) (vector-ref obj 5))
736(define (tm:wday obj) (vector-ref obj 6))
737(define (tm:yday obj) (vector-ref obj 7))
738(define (tm:isdst obj) (vector-ref obj 8))
739(define (tm:gmtoff obj) (vector-ref obj 9))
740(define (tm:zone obj) (vector-ref obj 10))
741
742(define (set-tm:sec obj val) (vector-set! obj 0 val))
743(define (set-tm:min obj val) (vector-set! obj 1 val))
744(define (set-tm:hour obj val) (vector-set! obj 2 val))
745(define (set-tm:mday obj val) (vector-set! obj 3 val))
746(define (set-tm:mon obj val) (vector-set! obj 4 val))
747(define (set-tm:year obj val) (vector-set! obj 5 val))
748(define (set-tm:wday obj val) (vector-set! obj 6 val))
749(define (set-tm:yday obj val) (vector-set! obj 7 val))
750(define (set-tm:isdst obj val) (vector-set! obj 8 val))
751(define (set-tm:gmtoff obj val) (vector-set! obj 9 val))
752(define (set-tm:zone obj val) (vector-set! obj 10 val))
753
6afcd3b2
GH
754(define (tms:clock obj) (vector-ref obj 0))
755(define (tms:utime obj) (vector-ref obj 1))
756(define (tms:stime obj) (vector-ref obj 2))
757(define (tms:cutime obj) (vector-ref obj 3))
758(define (tms:cstime obj) (vector-ref obj 4))
759
bce074ee
GH
760(define (file-position . args) (apply ftell args))
761(define (file-set-position . args) (apply fseek args))
8b13c6b3 762
e38303a2
GH
763(define (move->fdes fd/port fd)
764 (cond ((integer? fd/port)
7a6f1ffa 765 (dup->fdes fd/port fd)
e38303a2
GH
766 (close fd/port)
767 fd)
768 (else
769 (primitive-move->fdes fd/port fd)
770 (set-port-revealed! fd/port 1)
771 fd/port)))
8b13c6b3
GH
772
773(define (release-port-handle port)
774 (let ((revealed (port-revealed port)))
775 (if (> revealed 0)
776 (set-port-revealed! port (- revealed 1)))))
0f2d19dd 777
e38303a2 778(define (dup->port port/fd mode . maybe-fd)
7a6f1ffa 779 (let ((port (fdopen (apply dup->fdes port/fd maybe-fd)
e38303a2
GH
780 mode)))
781 (if (pair? maybe-fd)
782 (set-port-revealed! port 1))
783 port))
784
785(define (dup->inport port/fd . maybe-fd)
786 (apply dup->port port/fd "r" maybe-fd))
787
788(define (dup->outport port/fd . maybe-fd)
789 (apply dup->port port/fd "w" maybe-fd))
790
e38303a2
GH
791(define (dup port/fd . maybe-fd)
792 (if (integer? port/fd)
793 (apply dup->fdes port/fd maybe-fd)
794 (apply dup->port port/fd (port-mode port/fd) maybe-fd)))
795
796(define (duplicate-port port modes)
797 (dup->port port modes))
798
799(define (fdes->inport fdes)
800 (let loop ((rest-ports (fdes->ports fdes)))
801 (cond ((null? rest-ports)
802 (let ((result (fdopen fdes "r")))
803 (set-port-revealed! result 1)
804 result))
805 ((input-port? (car rest-ports))
806 (set-port-revealed! (car rest-ports)
807 (+ (port-revealed (car rest-ports)) 1))
808 (car rest-ports))
809 (else
810 (loop (cdr rest-ports))))))
811
812(define (fdes->outport fdes)
813 (let loop ((rest-ports (fdes->ports fdes)))
814 (cond ((null? rest-ports)
815 (let ((result (fdopen fdes "w")))
816 (set-port-revealed! result 1)
817 result))
818 ((output-port? (car rest-ports))
819 (set-port-revealed! (car rest-ports)
820 (+ (port-revealed (car rest-ports)) 1))
821 (car rest-ports))
822 (else
823 (loop (cdr rest-ports))))))
824
825(define (port->fdes port)
826 (set-port-revealed! port (+ (port-revealed port) 1))
827 (fileno port))
828
956055a9
GH
829(define (setenv name value)
830 (if value
831 (putenv (string-append name "=" value))
832 (putenv name)))
833
0f2d19dd
JB
834\f
835;;; {Load Paths}
836;;;
837
0f2d19dd
JB
838;;; Here for backward compatability
839;;
840(define scheme-file-suffix (lambda () ".scm"))
841
3cab8392
JB
842(define (in-vicinity vicinity file)
843 (let ((tail (let ((len (string-length vicinity)))
534a0099
MD
844 (if (zero? len)
845 #f
3cab8392
JB
846 (string-ref vicinity (- len 1))))))
847 (string-append vicinity
534a0099
MD
848 (if (or (not tail)
849 (eq? tail #\/))
850 ""
851 "/")
3cab8392 852 file)))
02ceadb8 853
0f2d19dd 854\f
ef00e7f4
JB
855;;; {Help for scm_shell}
856;;; The argument-processing code used by Guile-based shells generates
857;;; Scheme code based on the argument list. This page contains help
858;;; functions for the code it generates.
859
ef00e7f4
JB
860(define (command-line) (program-arguments))
861
5aa7fe69
JB
862;; This is mostly for the internal use of the code generated by
863;; scm_compile_shell_switches.
ef00e7f4
JB
864(define (load-user-init)
865 (define (has-init? dir)
866 (let ((path (in-vicinity dir ".guile")))
867 (catch 'system-error
868 (lambda ()
869 (let ((stats (stat path)))
870 (if (not (eq? (stat:type stats) 'directory))
871 path)))
872 (lambda dummy #f))))
4cd2a3e6
JB
873 (let ((path (or (has-init? (or (getenv "HOME") "/"))
874 (has-init? (passwd:dir (getpw (getuid)))))))
ef00e7f4
JB
875 (if path (primitive-load path))))
876
877\f
a06181a2
JB
878;;; {Loading by paths}
879
880;;; Load a Scheme source file named NAME, searching for it in the
881;;; directories listed in %load-path, and applying each of the file
882;;; name extensions listed in %load-extensions.
883(define (load-from-path name)
884 (start-stack 'load-stack
75a97b92 885 (primitive-load-path name)))
0f2d19dd 886
5552355a 887
0f2d19dd 888\f
0f2d19dd
JB
889;;; {Transcendental Functions}
890;;;
891;;; Derived from "Transcen.scm", Complex trancendental functions for SCM.
0543c9b7 892;;; Written by Jerry D. Hedden, (C) FSF.
0f2d19dd
JB
893;;; See the file `COPYING' for terms applying to this program.
894;;;
895
896(define (exp z)
897 (if (real? z) ($exp z)
898 (make-polar ($exp (real-part z)) (imag-part z))))
899
900(define (log z)
901 (if (and (real? z) (>= z 0))
902 ($log z)
903 (make-rectangular ($log (magnitude z)) (angle z))))
904
905(define (sqrt z)
906 (if (real? z)
907 (if (negative? z) (make-rectangular 0 ($sqrt (- z)))
908 ($sqrt z))
909 (make-polar ($sqrt (magnitude z)) (/ (angle z) 2))))
910
911(define expt
912 (let ((integer-expt integer-expt))
913 (lambda (z1 z2)
914 (cond ((exact? z2)
915 (integer-expt z1 z2))
916 ((and (real? z2) (real? z1) (>= z1 0))
917 ($expt z1 z2))
918 (else
919 (exp (* z2 (log z1))))))))
920
921(define (sinh z)
922 (if (real? z) ($sinh z)
923 (let ((x (real-part z)) (y (imag-part z)))
924 (make-rectangular (* ($sinh x) ($cos y))
925 (* ($cosh x) ($sin y))))))
926(define (cosh z)
927 (if (real? z) ($cosh z)
928 (let ((x (real-part z)) (y (imag-part z)))
929 (make-rectangular (* ($cosh x) ($cos y))
930 (* ($sinh x) ($sin y))))))
931(define (tanh z)
932 (if (real? z) ($tanh z)
933 (let* ((x (* 2 (real-part z)))
934 (y (* 2 (imag-part z)))
935 (w (+ ($cosh x) ($cos y))))
936 (make-rectangular (/ ($sinh x) w) (/ ($sin y) w)))))
937
938(define (asinh z)
939 (if (real? z) ($asinh z)
940 (log (+ z (sqrt (+ (* z z) 1))))))
941
942(define (acosh z)
943 (if (and (real? z) (>= z 1))
944 ($acosh z)
945 (log (+ z (sqrt (- (* z z) 1))))))
946
947(define (atanh z)
948 (if (and (real? z) (> z -1) (< z 1))
949 ($atanh z)
950 (/ (log (/ (+ 1 z) (- 1 z))) 2)))
951
952(define (sin z)
953 (if (real? z) ($sin z)
954 (let ((x (real-part z)) (y (imag-part z)))
955 (make-rectangular (* ($sin x) ($cosh y))
956 (* ($cos x) ($sinh y))))))
957(define (cos z)
958 (if (real? z) ($cos z)
959 (let ((x (real-part z)) (y (imag-part z)))
960 (make-rectangular (* ($cos x) ($cosh y))
961 (- (* ($sin x) ($sinh y)))))))
962(define (tan z)
963 (if (real? z) ($tan z)
964 (let* ((x (* 2 (real-part z)))
965 (y (* 2 (imag-part z)))
966 (w (+ ($cos x) ($cosh y))))
967 (make-rectangular (/ ($sin x) w) (/ ($sinh y) w)))))
968
969(define (asin z)
970 (if (and (real? z) (>= z -1) (<= z 1))
971 ($asin z)
972 (* -i (asinh (* +i z)))))
973
974(define (acos z)
975 (if (and (real? z) (>= z -1) (<= z 1))
976 ($acos z)
977 (+ (/ (angle -1) 2) (* +i (asinh (* +i z))))))
978
979(define (atan z . y)
980 (if (null? y)
981 (if (real? z) ($atan z)
982 (/ (log (/ (- +i z) (+ +i z))) +2i))
983 ($atan2 z (car y))))
984
985(set! abs magnitude)
986
65495221
GH
987(define (log10 arg)
988 (/ (log arg) (log 10)))
989
0f2d19dd 990\f
0f2d19dd
JB
991
992;;; {Reader Extensions}
993;;;
994
995;;; Reader code for various "#c" forms.
996;;;
997
75a97b92
GH
998(read-hash-extend #\' (lambda (c port)
999 (read port)))
1000(read-hash-extend #\. (lambda (c port)
1001 (eval (read port))))
1002
1003(if (feature? 'array)
1004 (begin
1005 (let ((make-array-proc (lambda (template)
1006 (lambda (c port)
1007 (read:uniform-vector template port)))))
1008 (for-each (lambda (char template)
1009 (read-hash-extend char
1010 (make-array-proc template)))
c8f11b97
MD
1011 '(#\b #\a #\u #\e #\s #\i #\c #\y #\h)
1012 '(#t #\a 1 -1 1.0 1/3 0+i #\nul s)))
75a97b92
GH
1013 (let ((array-proc (lambda (c port)
1014 (read:array c port))))
1015 (for-each (lambda (char) (read-hash-extend char array-proc))
1016 '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)))))
1017
0f2d19dd
JB
1018(define (read:array digit port)
1019 (define chr0 (char->integer #\0))
1020 (let ((rank (let readnum ((val (- (char->integer digit) chr0)))
1021 (if (char-numeric? (peek-char port))
1022 (readnum (+ (* 10 val)
1023 (- (char->integer (read-char port)) chr0)))
1024 val)))
1025 (prot (if (eq? #\( (peek-char port))
1026 '()
1027 (let ((c (read-char port)))
1028 (case c ((#\b) #t)
1029 ((#\a) #\a)
1030 ((#\u) 1)
1031 ((#\e) -1)
1032 ((#\s) 1.0)
1033 ((#\i) 1/3)
1034 ((#\c) 0+i)
1035 (else (error "read:array unknown option " c)))))))
1036 (if (eq? (peek-char port) #\()
75a97b92 1037 (list->uniform-array rank prot (read port))
0f2d19dd
JB
1038 (error "read:array list not found"))))
1039
1040(define (read:uniform-vector proto port)
1041 (if (eq? #\( (peek-char port))
75a97b92 1042 (list->uniform-array 1 proto (read port))
0f2d19dd
JB
1043 (error "read:uniform-vector list not found")))
1044
0f2d19dd
JB
1045\f
1046;;; {Command Line Options}
1047;;;
1048
1049(define (get-option argv kw-opts kw-args return)
1050 (cond
1051 ((null? argv)
1052 (return #f #f argv))
1053
1054 ((or (not (eq? #\- (string-ref (car argv) 0)))
1055 (eq? (string-length (car argv)) 1))
1056 (return 'normal-arg (car argv) (cdr argv)))
1057
1058 ((eq? #\- (string-ref (car argv) 1))
1059 (let* ((kw-arg-pos (or (string-index (car argv) #\=)
1060 (string-length (car argv))))
1061 (kw (symbol->keyword (substring (car argv) 2 kw-arg-pos)))
1062 (kw-opt? (member kw kw-opts))
1063 (kw-arg? (member kw kw-args))
1064 (arg (or (and (not (eq? kw-arg-pos (string-length (car argv))))
1065 (substring (car argv)
1066 (+ kw-arg-pos 1)
1067 (string-length (car argv))))
1068 (and kw-arg?
1069 (begin (set! argv (cdr argv)) (car argv))))))
1070 (if (or kw-opt? kw-arg?)
1071 (return kw arg (cdr argv))
1072 (return 'usage-error kw (cdr argv)))))
1073
1074 (else
1075 (let* ((char (substring (car argv) 1 2))
1076 (kw (symbol->keyword char)))
1077 (cond
1078
1079 ((member kw kw-opts)
1080 (let* ((rest-car (substring (car argv) 2 (string-length (car argv))))
1081 (new-argv (if (= 0 (string-length rest-car))
1082 (cdr argv)
1083 (cons (string-append "-" rest-car) (cdr argv)))))
1084 (return kw #f new-argv)))
1085
1086 ((member kw kw-args)
1087 (let* ((rest-car (substring (car argv) 2 (string-length (car argv))))
1088 (arg (if (= 0 (string-length rest-car))
1089 (cadr argv)
1090 rest-car))
1091 (new-argv (if (= 0 (string-length rest-car))
1092 (cddr argv)
1093 (cdr argv))))
1094 (return kw arg new-argv)))
1095
1096 (else (return 'usage-error kw argv)))))))
1097
1098(define (for-next-option proc argv kw-opts kw-args)
1099 (let loop ((argv argv))
1100 (get-option argv kw-opts kw-args
1101 (lambda (opt opt-arg argv)
1102 (and opt (proc opt opt-arg argv loop))))))
1103
1104(define (display-usage-report kw-desc)
1105 (for-each
1106 (lambda (kw)
1107 (or (eq? (car kw) #t)
1108 (eq? (car kw) 'else)
1109 (let* ((opt-desc kw)
1110 (help (cadr opt-desc))
1111 (opts (car opt-desc))
1112 (opts-proper (if (string? (car opts)) (cdr opts) opts))
1113 (arg-name (if (string? (car opts))
1114 (string-append "<" (car opts) ">")
1115 ""))
1116 (left-part (string-append
1117 (with-output-to-string
1118 (lambda ()
1119 (map (lambda (x) (display (keyword-symbol x)) (display " "))
1120 opts-proper)))
1121 arg-name))
11b05261
MD
1122 (middle-part (if (and (< (string-length left-part) 30)
1123 (< (string-length help) 40))
1124 (make-string (- 30 (string-length left-part)) #\ )
0f2d19dd
JB
1125 "\n\t")))
1126 (display left-part)
1127 (display middle-part)
1128 (display help)
1129 (newline))))
1130 kw-desc))
1131
1132
1133
0f2d19dd
JB
1134(define (transform-usage-lambda cases)
1135 (let* ((raw-usage (delq! 'else (map car cases)))
1136 (usage-sans-specials (map (lambda (x)
1137 (or (and (not (list? x)) x)
1138 (and (symbol? (car x)) #t)
1139 (and (boolean? (car x)) #t)
1140 x))
1141 raw-usage))
ed440df5 1142 (usage-desc (delq! #t usage-sans-specials))
0f2d19dd
JB
1143 (kw-desc (map car usage-desc))
1144 (kw-opts (apply append (map (lambda (x) (and (not (string? (car x))) x)) kw-desc)))
1145 (kw-args (apply append (map (lambda (x) (and (string? (car x)) (cdr x))) kw-desc)))
1146 (transmogrified-cases (map (lambda (case)
1147 (cons (let ((opts (car case)))
1148 (if (or (boolean? opts) (eq? 'else opts))
1149 opts
1150 (cond
1151 ((symbol? (car opts)) opts)
1152 ((boolean? (car opts)) opts)
1153 ((string? (caar opts)) (cdar opts))
1154 (else (car opts)))))
1155 (cdr case)))
1156 cases)))
1157 `(let ((%display-usage (lambda () (display-usage-report ',usage-desc))))
1158 (lambda (%argv)
1159 (let %next-arg ((%argv %argv))
1160 (get-option %argv
1161 ',kw-opts
1162 ',kw-args
1163 (lambda (%opt %arg %new-argv)
1164 (case %opt
1165 ,@ transmogrified-cases))))))))
1166
1167
1168\f
1169
1170;;; {Low Level Modules}
1171;;;
1172;;; These are the low level data structures for modules.
1173;;;
1174;;; !!! warning: The interface to lazy binder procedures is going
1175;;; to be changed in an incompatible way to permit all the basic
1176;;; module ops to be virtualized.
1177;;;
1178;;; (make-module size use-list lazy-binding-proc) => module
1179;;; module-{obarray,uses,binder}[|-set!]
1180;;; (module? obj) => [#t|#f]
1181;;; (module-locally-bound? module symbol) => [#t|#f]
1182;;; (module-bound? module symbol) => [#t|#f]
1183;;; (module-symbol-locally-interned? module symbol) => [#t|#f]
1184;;; (module-symbol-interned? module symbol) => [#t|#f]
1185;;; (module-local-variable module symbol) => [#<variable ...> | #f]
1186;;; (module-variable module symbol) => [#<variable ...> | #f]
1187;;; (module-symbol-binding module symbol opt-value)
1188;;; => [ <obj> | opt-value | an error occurs ]
1189;;; (module-make-local-var! module symbol) => #<variable...>
1190;;; (module-add! module symbol var) => unspecified
1191;;; (module-remove! module symbol) => unspecified
1192;;; (module-for-each proc module) => unspecified
1193;;; (make-scm-module) => module ; a lazy copy of the symhash module
1194;;; (set-current-module module) => unspecified
1195;;; (current-module) => #<module...>
1196;;;
1197;;;
1198
1199\f
44cf1f0f
JB
1200;;; {Printing Modules}
1201;; This is how modules are printed. You can re-define it.
fa7e9274
MV
1202;; (Redefining is actually more complicated than simply redefining
1203;; %print-module because that would only change the binding and not
1204;; the value stored in the vtable that determines how record are
1205;; printed. Sigh.)
1206
1207(define (%print-module mod port) ; unused args: depth length style table)
0f2d19dd
JB
1208 (display "#<" port)
1209 (display (or (module-kind mod) "module") port)
1210 (let ((name (module-name mod)))
1211 (if name
1212 (begin
1213 (display " " port)
1214 (display name port))))
1215 (display " " port)
1216 (display (number->string (object-address mod) 16) port)
1217 (display ">" port))
1218
1219;; module-type
1220;;
1221;; A module is characterized by an obarray in which local symbols
1222;; are interned, a list of modules, "uses", from which non-local
1223;; bindings can be inherited, and an optional lazy-binder which
31d50456 1224;; is a (CLOSURE module symbol) which, as a last resort, can provide
0f2d19dd
JB
1225;; bindings that would otherwise not be found locally in the module.
1226;;
1227(define module-type
7a0ff2f8 1228 (make-record-type 'module
1777c18b
MD
1229 '(obarray uses binder eval-closure transformer name kind
1230 observers weak-observers observer-id)
8b718458 1231 %print-module))
0f2d19dd 1232
8b718458 1233;; make-module &opt size uses binder
0f2d19dd 1234;;
8b718458
JB
1235;; Create a new module, perhaps with a particular size of obarray,
1236;; initial uses list, or binding procedure.
0f2d19dd 1237;;
0f2d19dd
JB
1238(define make-module
1239 (lambda args
0f2d19dd 1240
8b718458
JB
1241 (define (parse-arg index default)
1242 (if (> (length args) index)
1243 (list-ref args index)
1244 default))
1245
1246 (if (> (length args) 3)
1247 (error "Too many args to make-module." args))
0f2d19dd 1248
8b718458
JB
1249 (let ((size (parse-arg 0 1021))
1250 (uses (parse-arg 1 '()))
1251 (binder (parse-arg 2 #f)))
0f2d19dd 1252
8b718458
JB
1253 (if (not (integer? size))
1254 (error "Illegal size to make-module." size))
1255 (if (not (and (list? uses)
1256 (and-map module? uses)))
1257 (error "Incorrect use list." uses))
0f2d19dd
JB
1258 (if (and binder (not (procedure? binder)))
1259 (error
1260 "Lazy-binder expected to be a procedure or #f." binder))
1261
8b718458 1262 (let ((module (module-constructor (make-vector size '())
1777c18b
MD
1263 uses binder #f #f #f #f
1264 '()
1265 (make-weak-value-hash-table 31)
1266 0)))
8b718458
JB
1267
1268 ;; We can't pass this as an argument to module-constructor,
1269 ;; because we need it to close over a pointer to the module
1270 ;; itself.
31d50456 1271 (set-module-eval-closure! module
8b718458
JB
1272 (lambda (symbol define?)
1273 (if define?
1274 (module-make-local-var! module symbol)
1275 (module-variable module symbol))))
1276
1277 module))))
0f2d19dd 1278
8b718458 1279(define module-constructor (record-constructor module-type))
0f2d19dd
JB
1280(define module-obarray (record-accessor module-type 'obarray))
1281(define set-module-obarray! (record-modifier module-type 'obarray))
1282(define module-uses (record-accessor module-type 'uses))
1283(define set-module-uses! (record-modifier module-type 'uses))
1284(define module-binder (record-accessor module-type 'binder))
1285(define set-module-binder! (record-modifier module-type 'binder))
631c1902
MD
1286
1287;; NOTE: This binding is used in libguile/modules.c.
31d50456 1288(define module-eval-closure (record-accessor module-type 'eval-closure))
631c1902 1289
7a0ff2f8
MD
1290(define module-transformer (record-accessor module-type 'transformer))
1291(define set-module-transformer! (record-modifier module-type 'transformer))
0f2d19dd
JB
1292(define module-name (record-accessor module-type 'name))
1293(define set-module-name! (record-modifier module-type 'name))
1294(define module-kind (record-accessor module-type 'kind))
1295(define set-module-kind! (record-modifier module-type 'kind))
1777c18b
MD
1296(define module-observers (record-accessor module-type 'observers))
1297(define set-module-observers! (record-modifier module-type 'observers))
1298(define module-weak-observers (record-accessor module-type 'weak-observers))
1299(define module-observer-id (record-accessor module-type 'observer-id))
1300(define set-module-observer-id! (record-modifier module-type 'observer-id))
0f2d19dd
JB
1301(define module? (record-predicate module-type))
1302
edc185c7
MD
1303(define set-module-eval-closure!
1304 (let ((setter (record-modifier module-type 'eval-closure)))
1305 (lambda (module closure)
1306 (setter module closure)
1307 ;; Make it possible to lookup the module from the environment.
1308 ;; This implementation is correct since an eval closure can belong
1309 ;; to maximally one module.
1310 (set-procedure-property! closure 'module module))))
8b718458 1311
0f2d19dd 1312(define (eval-in-module exp module)
31d50456 1313 (eval2 exp (module-eval-closure module)))
0f2d19dd
JB
1314
1315\f
1777c18b
MD
1316;;; {Observer protocol}
1317;;;
1318
1319(define (module-observe module proc)
1320 (set-module-observers! module (cons proc (module-observers module)))
1321 (cons module proc))
1322
1323(define (module-observe-weak module proc)
1324 (let ((id (module-observer-id module)))
1325 (hash-set! (module-weak-observers module) id proc)
1326 (set-module-observer-id! module (+ 1 id))
1327 (cons module id)))
1328
1329(define (module-unobserve token)
1330 (let ((module (car token))
1331 (id (cdr token)))
1332 (if (integer? id)
1333 (hash-remove! (module-weak-observers module) id)
1334 (set-module-observers! module (delq1! id (module-observers module)))))
1335 *unspecified*)
1336
1a961d7e 1337(define (module-modified m)
1777c18b
MD
1338 (for-each (lambda (proc) (proc m)) (module-observers m))
1339 (hash-fold (lambda (id proc res) (proc m)) #f (module-weak-observers m)))
1340
1341\f
0f2d19dd
JB
1342;;; {Module Searching in General}
1343;;;
1344;;; We sometimes want to look for properties of a symbol
1345;;; just within the obarray of one module. If the property
1346;;; holds, then it is said to hold ``locally'' as in, ``The symbol
1347;;; DISPLAY is locally rebound in the module `safe-guile'.''
1348;;;
1349;;;
1350;;; Other times, we want to test for a symbol property in the obarray
1351;;; of M and, if it is not found there, try each of the modules in the
1352;;; uses list of M. This is the normal way of testing for some
1353;;; property, so we state these properties without qualification as
1354;;; in: ``The symbol 'fnord is interned in module M because it is
1355;;; interned locally in module M2 which is a member of the uses list
1356;;; of M.''
1357;;;
1358
1359;; module-search fn m
1360;;
1361;; return the first non-#f result of FN applied to M and then to
1362;; the modules in the uses of m, and so on recursively. If all applications
1363;; return #f, then so does this function.
1364;;
1365(define (module-search fn m v)
1366 (define (loop pos)
1367 (and (pair? pos)
1368 (or (module-search fn (car pos) v)
1369 (loop (cdr pos)))))
1370 (or (fn m v)
1371 (loop (module-uses m))))
1372
1373
1374;;; {Is a symbol bound in a module?}
1375;;;
1376;;; Symbol S in Module M is bound if S is interned in M and if the binding
1377;;; of S in M has been set to some well-defined value.
1378;;;
1379
1380;; module-locally-bound? module symbol
1381;;
1382;; Is a symbol bound (interned and defined) locally in a given module?
1383;;
1384(define (module-locally-bound? m v)
1385 (let ((var (module-local-variable m v)))
1386 (and var
1387 (variable-bound? var))))
1388
1389;; module-bound? module symbol
1390;;
1391;; Is a symbol bound (interned and defined) anywhere in a given module
1392;; or its uses?
1393;;
1394(define (module-bound? m v)
1395 (module-search module-locally-bound? m v))
1396
1397;;; {Is a symbol interned in a module?}
1398;;;
1399;;; Symbol S in Module M is interned if S occurs in
1400;;; of S in M has been set to some well-defined value.
1401;;;
1402;;; It is possible to intern a symbol in a module without providing
1403;;; an initial binding for the corresponding variable. This is done
1404;;; with:
1405;;; (module-add! module symbol (make-undefined-variable))
1406;;;
1407;;; In that case, the symbol is interned in the module, but not
1408;;; bound there. The unbound symbol shadows any binding for that
1409;;; symbol that might otherwise be inherited from a member of the uses list.
1410;;;
1411
1412(define (module-obarray-get-handle ob key)
1413 ((if (symbol? key) hashq-get-handle hash-get-handle) ob key))
1414
1415(define (module-obarray-ref ob key)
1416 ((if (symbol? key) hashq-ref hash-ref) ob key))
1417
1418(define (module-obarray-set! ob key val)
1419 ((if (symbol? key) hashq-set! hash-set!) ob key val))
1420
1421(define (module-obarray-remove! ob key)
1422 ((if (symbol? key) hashq-remove! hash-remove!) ob key))
1423
1424;; module-symbol-locally-interned? module symbol
1425;;
1426;; is a symbol interned (not neccessarily defined) locally in a given module
1427;; or its uses? Interned symbols shadow inherited bindings even if
1428;; they are not themselves bound to a defined value.
1429;;
1430(define (module-symbol-locally-interned? m v)
1431 (not (not (module-obarray-get-handle (module-obarray m) v))))
1432
1433;; module-symbol-interned? module symbol
1434;;
1435;; is a symbol interned (not neccessarily defined) anywhere in a given module
1436;; or its uses? Interned symbols shadow inherited bindings even if
1437;; they are not themselves bound to a defined value.
1438;;
1439(define (module-symbol-interned? m v)
1440 (module-search module-symbol-locally-interned? m v))
1441
1442
1443;;; {Mapping modules x symbols --> variables}
1444;;;
1445
1446;; module-local-variable module symbol
1447;; return the local variable associated with a MODULE and SYMBOL.
1448;;
1449;;; This function is very important. It is the only function that can
1450;;; return a variable from a module other than the mutators that store
1451;;; new variables in modules. Therefore, this function is the location
1452;;; of the "lazy binder" hack.
1453;;;
1454;;; If symbol is defined in MODULE, and if the definition binds symbol
1455;;; to a variable, return that variable object.
1456;;;
1457;;; If the symbols is not found at first, but the module has a lazy binder,
1458;;; then try the binder.
1459;;;
1460;;; If the symbol is not found at all, return #f.
1461;;;
1462(define (module-local-variable m v)
6fa8995c
GH
1463; (caddr
1464; (list m v
0f2d19dd
JB
1465 (let ((b (module-obarray-ref (module-obarray m) v)))
1466 (or (and (variable? b) b)
1467 (and (module-binder m)
6fa8995c
GH
1468 ((module-binder m) m v #f)))))
1469;))
0f2d19dd
JB
1470
1471;; module-variable module symbol
1472;;
1473;; like module-local-variable, except search the uses in the
1474;; case V is not found in M.
1475;;
1476(define (module-variable m v)
1477 (module-search module-local-variable m v))
1478
1479
1480;;; {Mapping modules x symbols --> bindings}
1481;;;
1482;;; These are similar to the mapping to variables, except that the
1483;;; variable is dereferenced.
1484;;;
1485
1486;; module-symbol-binding module symbol opt-value
1487;;
1488;; return the binding of a variable specified by name within
1489;; a given module, signalling an error if the variable is unbound.
1490;; If the OPT-VALUE is passed, then instead of signalling an error,
1491;; return OPT-VALUE.
1492;;
1493(define (module-symbol-local-binding m v . opt-val)
1494 (let ((var (module-local-variable m v)))
1495 (if var
1496 (variable-ref var)
1497 (if (not (null? opt-val))
1498 (car opt-val)
1499 (error "Locally unbound variable." v)))))
1500
1501;; module-symbol-binding module symbol opt-value
1502;;
1503;; return the binding of a variable specified by name within
1504;; a given module, signalling an error if the variable is unbound.
1505;; If the OPT-VALUE is passed, then instead of signalling an error,
1506;; return OPT-VALUE.
1507;;
1508(define (module-symbol-binding m v . opt-val)
1509 (let ((var (module-variable m v)))
1510 (if var
1511 (variable-ref var)
1512 (if (not (null? opt-val))
1513 (car opt-val)
1514 (error "Unbound variable." v)))))
1515
1516
1517\f
1518;;; {Adding Variables to Modules}
1519;;;
1520;;;
1521
1522
1523;; module-make-local-var! module symbol
1524;;
1525;; ensure a variable for V in the local namespace of M.
1526;; If no variable was already there, then create a new and uninitialzied
1527;; variable.
1528;;
1529(define (module-make-local-var! m v)
1530 (or (let ((b (module-obarray-ref (module-obarray m) v)))
1777c18b
MD
1531 (and (variable? b)
1532 (begin
1a961d7e 1533 (module-modified m)
1777c18b 1534 b)))
0f2d19dd
JB
1535 (and (module-binder m)
1536 ((module-binder m) m v #t))
1537 (begin
1538 (let ((answer (make-undefined-variable v)))
1539 (module-obarray-set! (module-obarray m) v answer)
1a961d7e 1540 (module-modified m)
0f2d19dd
JB
1541 answer))))
1542
1543;; module-add! module symbol var
1544;;
1545;; ensure a particular variable for V in the local namespace of M.
1546;;
1547(define (module-add! m v var)
1548 (if (not (variable? var))
1549 (error "Bad variable to module-add!" var))
1777c18b 1550 (module-obarray-set! (module-obarray m) v var)
1a961d7e 1551 (module-modified m))
0f2d19dd
JB
1552
1553;; module-remove!
1554;;
1555;; make sure that a symbol is undefined in the local namespace of M.
1556;;
1557(define (module-remove! m v)
1777c18b 1558 (module-obarray-remove! (module-obarray m) v)
1a961d7e 1559 (module-modified m))
0f2d19dd
JB
1560
1561(define (module-clear! m)
1777c18b 1562 (vector-fill! (module-obarray m) '())
1a961d7e 1563 (module-modified m))
0f2d19dd
JB
1564
1565;; MODULE-FOR-EACH -- exported
1566;;
1567;; Call PROC on each symbol in MODULE, with arguments of (SYMBOL VARIABLE).
1568;;
1569(define (module-for-each proc module)
1570 (let ((obarray (module-obarray module)))
1571 (do ((index 0 (+ index 1))
1572 (end (vector-length obarray)))
1573 ((= index end))
1574 (for-each
1575 (lambda (bucket)
1576 (proc (car bucket) (cdr bucket)))
1577 (vector-ref obarray index)))))
1578
1579
1580(define (module-map proc module)
1581 (let* ((obarray (module-obarray module))
1582 (end (vector-length obarray)))
1583
1584 (let loop ((i 0)
1585 (answer '()))
1586 (if (= i end)
1587 answer
1588 (loop (+ 1 i)
1589 (append!
1590 (map (lambda (bucket)
1591 (proc (car bucket) (cdr bucket)))
1592 (vector-ref obarray i))
1593 answer))))))
1594\f
1595
1596;;; {Low Level Bootstrapping}
1597;;;
1598
1599;; make-root-module
1600
21ed9efe 1601;; A root module uses the symhash table (the system's privileged
0f2d19dd
JB
1602;; obarray). Being inside a root module is like using SCM without
1603;; any module system.
1604;;
1605
1606
31d50456 1607(define (root-module-closure m s define?)
0f2d19dd
JB
1608 (let ((bi (and (symbol-interned? #f s)
1609 (builtin-variable s))))
1610 (and bi
1611 (or define? (variable-bound? bi))
1612 (begin
1613 (module-add! m s bi)
1614 bi))))
1615
1616(define (make-root-module)
31d50456 1617 (make-module 1019 '() root-module-closure))
0f2d19dd
JB
1618
1619
1620;; make-scm-module
1621
1622;; An scm module is a module into which the lazy binder copies
1623;; variable bindings from the system symhash table. The mapping is
1624;; one way only; newly introduced bindings in an scm module are not
1625;; copied back into the system symhash table (and can be used to override
1626;; bindings from the symhash table).
1627;;
1628
1629(define (make-scm-module)
8b718458 1630 (make-module 1019 '()
0f2d19dd
JB
1631 (lambda (m s define?)
1632 (let ((bi (and (symbol-interned? #f s)
1633 (builtin-variable s))))
1634 (and bi
1635 (variable-bound? bi)
1636 (begin
1637 (module-add! m s bi)
1638 bi))))))
1639
1640
1641
1642
1643;; the-module
631c1902
MD
1644;;
1645;; NOTE: This binding is used in libguile/modules.c.
1646;;
0f2d19dd
JB
1647(define the-module #f)
1648
7a0ff2f8 1649;; scm:eval-transformer
d43f8c97 1650;;
7a0ff2f8 1651(define scm:eval-transformer #f)
d43f8c97 1652
0f2d19dd
JB
1653;; set-current-module module
1654;;
1655;; set the current module as viewed by the normalizer.
1656;;
631c1902
MD
1657;; NOTE: This binding is used in libguile/modules.c.
1658;;
0f2d19dd 1659(define (set-current-module m)
7a0ff2f8
MD
1660 (set! the-module m)
1661 (if m
1662 (begin
1663 (set! *top-level-lookup-closure* (module-eval-closure the-module))
1664 (set! scm:eval-transformer (module-transformer the-module)))
1665 (set! *top-level-lookup-closure* #f)))
0f2d19dd
JB
1666
1667
1668;; current-module
1669;;
1670;; return the current module as viewed by the normalizer.
1671;;
1672(define (current-module) the-module)
1673\f
1674;;; {Module-based Loading}
1675;;;
1676
1677(define (save-module-excursion thunk)
1678 (let ((inner-module (current-module))
1679 (outer-module #f))
1680 (dynamic-wind (lambda ()
1681 (set! outer-module (current-module))
1682 (set-current-module inner-module)
1683 (set! inner-module #f))
1684 thunk
1685 (lambda ()
1686 (set! inner-module (current-module))
1687 (set-current-module outer-module)
1688 (set! outer-module #f)))))
1689
0f2d19dd
JB
1690(define basic-load load)
1691
c6775c40
MD
1692(define (load-module filename)
1693 (save-module-excursion
1694 (lambda ()
1695 (let ((oldname (and (current-load-port)
1696 (port-filename (current-load-port)))))
1697 (basic-load (if (and oldname
1698 (> (string-length filename) 0)
1699 (not (char=? (string-ref filename 0) #\/))
1700 (not (string=? (dirname oldname) ".")))
1701 (string-append (dirname oldname) "/" filename)
1702 filename))))))
0f2d19dd
JB
1703
1704
1705\f
44cf1f0f 1706;;; {MODULE-REF -- exported}
0f2d19dd
JB
1707;;
1708;; Returns the value of a variable called NAME in MODULE or any of its
1709;; used modules. If there is no such variable, then if the optional third
1710;; argument DEFAULT is present, it is returned; otherwise an error is signaled.
1711;;
1712(define (module-ref module name . rest)
1713 (let ((variable (module-variable module name)))
1714 (if (and variable (variable-bound? variable))
1715 (variable-ref variable)
1716 (if (null? rest)
1717 (error "No variable named" name 'in module)
1718 (car rest) ; default value
1719 ))))
1720
1721;; MODULE-SET! -- exported
1722;;
1723;; Sets the variable called NAME in MODULE (or in a module that MODULE uses)
1724;; to VALUE; if there is no such variable, an error is signaled.
1725;;
1726(define (module-set! module name value)
1727 (let ((variable (module-variable module name)))
1728 (if variable
1729 (variable-set! variable value)
1730 (error "No variable named" name 'in module))))
1731
1732;; MODULE-DEFINE! -- exported
1733;;
1734;; Sets the variable called NAME in MODULE to VALUE; if there is no such
1735;; variable, it is added first.
1736;;
1737(define (module-define! module name value)
1738 (let ((variable (module-local-variable module name)))
1739 (if variable
1777c18b
MD
1740 (begin
1741 (variable-set! variable value)
1a961d7e 1742 (module-modified module))
0f2d19dd
JB
1743 (module-add! module name (make-variable value name)))))
1744
ed218d98
MV
1745;; MODULE-DEFINED? -- exported
1746;;
1747;; Return #t iff NAME is defined in MODULE (or in a module that MODULE
1748;; uses)
1749;;
1750(define (module-defined? module name)
1751 (let ((variable (module-variable module name)))
1752 (and variable (variable-bound? variable))))
1753
0f2d19dd
JB
1754;; MODULE-USE! module interface
1755;;
1756;; Add INTERFACE to the list of interfaces used by MODULE.
1757;;
1758(define (module-use! module interface)
1759 (set-module-uses! module
1777c18b 1760 (cons interface (delq! interface (module-uses module))))
1a961d7e 1761 (module-modified module))
0f2d19dd
JB
1762
1763\f
0f2d19dd
JB
1764;;; {Recursive Namespaces}
1765;;;
1766;;;
1767;;; A hierarchical namespace emerges if we consider some module to be
1768;;; root, and variables bound to modules as nested namespaces.
1769;;;
1770;;; The routines in this file manage variable names in hierarchical namespace.
1771;;; Each variable name is a list of elements, looked up in successively nested
1772;;; modules.
1773;;;
0dd5491c 1774;;; (nested-ref some-root-module '(foo bar baz))
0f2d19dd
JB
1775;;; => <value of a variable named baz in the module bound to bar in
1776;;; the module bound to foo in some-root-module>
1777;;;
1778;;;
1779;;; There are:
1780;;;
1781;;; ;; a-root is a module
1782;;; ;; name is a list of symbols
1783;;;
0dd5491c
MD
1784;;; nested-ref a-root name
1785;;; nested-set! a-root name val
1786;;; nested-define! a-root name val
1787;;; nested-remove! a-root name
0f2d19dd
JB
1788;;;
1789;;;
1790;;; (current-module) is a natural choice for a-root so for convenience there are
1791;;; also:
1792;;;
0dd5491c
MD
1793;;; local-ref name == nested-ref (current-module) name
1794;;; local-set! name val == nested-set! (current-module) name val
1795;;; local-define! name val == nested-define! (current-module) name val
1796;;; local-remove! name == nested-remove! (current-module) name
0f2d19dd
JB
1797;;;
1798
1799
0dd5491c 1800(define (nested-ref root names)
0f2d19dd
JB
1801 (let loop ((cur root)
1802 (elts names))
1803 (cond
1804 ((null? elts) cur)
1805 ((not (module? cur)) #f)
1806 (else (loop (module-ref cur (car elts) #f) (cdr elts))))))
1807
0dd5491c 1808(define (nested-set! root names val)
0f2d19dd
JB
1809 (let loop ((cur root)
1810 (elts names))
1811 (if (null? (cdr elts))
1812 (module-set! cur (car elts) val)
1813 (loop (module-ref cur (car elts)) (cdr elts)))))
1814
0dd5491c 1815(define (nested-define! root names val)
0f2d19dd
JB
1816 (let loop ((cur root)
1817 (elts names))
1818 (if (null? (cdr elts))
1819 (module-define! cur (car elts) val)
1820 (loop (module-ref cur (car elts)) (cdr elts)))))
1821
0dd5491c 1822(define (nested-remove! root names)
0f2d19dd
JB
1823 (let loop ((cur root)
1824 (elts names))
1825 (if (null? (cdr elts))
1826 (module-remove! cur (car elts))
1827 (loop (module-ref cur (car elts)) (cdr elts)))))
1828
0dd5491c
MD
1829(define (local-ref names) (nested-ref (current-module) names))
1830(define (local-set! names val) (nested-set! (current-module) names val))
1831(define (local-define names val) (nested-define! (current-module) names val))
1832(define (local-remove names) (nested-remove! (current-module) names))
0f2d19dd
JB
1833
1834
1835\f
8bb7330c 1836;;; {The (app) module}
0f2d19dd
JB
1837;;;
1838;;; The root of conventionally named objects not directly in the top level.
1839;;;
8bb7330c
JB
1840;;; (app modules)
1841;;; (app modules guile)
0f2d19dd
JB
1842;;;
1843;;; The directory of all modules and the standard root module.
1844;;;
1845
edc185c7
MD
1846(define (module-public-interface m)
1847 (module-ref m '%module-public-interface #f))
1848(define (set-module-public-interface! m i)
1849 (module-define! m '%module-public-interface i))
1850(define (set-system-module! m s)
1851 (set-procedure-property! (module-eval-closure m) 'system-module s))
0f2d19dd
JB
1852(define the-root-module (make-root-module))
1853(define the-scm-module (make-scm-module))
1854(set-module-public-interface! the-root-module the-scm-module)
1855(set-module-name! the-root-module 'the-root-module)
1856(set-module-name! the-scm-module 'the-scm-module)
edc185c7 1857(for-each set-system-module! (list the-root-module the-scm-module) '(#t #t))
0f2d19dd
JB
1858
1859(set-current-module the-root-module)
1860
1861(define app (make-module 31))
0dd5491c
MD
1862(local-define '(app modules) (make-module 31))
1863(local-define '(app modules guile) the-root-module)
0f2d19dd
JB
1864
1865;; (define-special-value '(app modules new-ws) (lambda () (make-scm-module)))
1866
432558b9
MD
1867(define (try-load-module name)
1868 (or (try-module-linked name)
1869 (try-module-autoload name)
1870 (try-module-dynamic-link name)))
1871
1f60d9d2
MD
1872;; NOTE: This binding is used in libguile/modules.c.
1873;;
0209ca9a 1874(define (resolve-module name . maybe-autoload)
0f2d19dd 1875 (let ((full-name (append '(app modules) name)))
0dd5491c 1876 (let ((already (local-ref full-name)))
432558b9
MD
1877 (if already
1878 ;; The module already exists...
1879 (if (and (or (null? maybe-autoload) (car maybe-autoload))
1880 (not (module-ref already '%module-public-interface #f)))
1881 ;; ...but we are told to load and it doesn't contain source, so
1882 (begin
1883 (try-load-module name)
1884 already)
1885 ;; simply return it.
1886 already)
3e3cec45 1887 (begin
432558b9 1888 ;; Try to autoload it if we are told so
3e3cec45 1889 (if (or (null? maybe-autoload) (car maybe-autoload))
432558b9
MD
1890 (try-load-module name))
1891 ;; Get/create it.
3e3cec45 1892 (make-modules-in (current-module) full-name))))))
0f2d19dd
JB
1893
1894(define (beautify-user-module! module)
3e3cec45
MD
1895 (let ((interface (module-public-interface module)))
1896 (if (or (not interface)
1897 (eq? interface module))
1898 (let ((interface (make-module 31)))
1899 (set-module-name! interface (module-name module))
1900 (set-module-kind! interface 'interface)
1901 (set-module-public-interface! module interface))))
cc7f066c
MD
1902 (if (and (not (memq the-scm-module (module-uses module)))
1903 (not (eq? module the-root-module)))
0f2d19dd
JB
1904 (set-module-uses! module (append (module-uses module) (list the-scm-module)))))
1905
631c1902
MD
1906;; NOTE: This binding is used in libguile/modules.c.
1907;;
0f2d19dd
JB
1908(define (make-modules-in module name)
1909 (if (null? name)
1910 module
1911 (cond
3e3cec45
MD
1912 ((module-ref module (car name) #f)
1913 => (lambda (m) (make-modules-in m (cdr name))))
0f2d19dd
JB
1914 (else (let ((m (make-module 31)))
1915 (set-module-kind! m 'directory)
1916 (set-module-name! m (car name))
1917 (module-define! module (car name) m)
1918 (make-modules-in m (cdr name)))))))
1919
1920(define (resolve-interface name)
1921 (let ((module (resolve-module name)))
1922 (and module (module-public-interface module))))
1923
1924
1925(define %autoloader-developer-mode #t)
1926
1927(define (process-define-module args)
1928 (let* ((module-id (car args))
0209ca9a 1929 (module (resolve-module module-id #f))
0f2d19dd
JB
1930 (kws (cdr args)))
1931 (beautify-user-module! module)
0209ca9a
MV
1932 (let loop ((kws kws)
1933 (reversed-interfaces '()))
1934 (if (null? kws)
1935 (for-each (lambda (interface)
1936 (module-use! module interface))
1937 reversed-interfaces)
f714ca8e
MD
1938 (let ((keyword (cond ((keyword? (car kws))
1939 (keyword->symbol (car kws)))
1940 ((and (symbol? (car kws))
1941 (eq? (string-ref (car kws) 0) #\:))
1942 (string->symbol (substring (car kws) 1)))
1943 (else #f))))
1944 (case keyword
1945 ((use-module use-syntax)
1946 (if (not (pair? (cdr kws)))
1947 (error "unrecognized defmodule argument" kws))
1948 (let* ((used-name (cadr kws))
1949 (used-module (resolve-module used-name)))
45a02a29
MD
1950 (if (not (module-ref used-module
1951 '%module-public-interface
1952 #f))
3e3cec45 1953 (begin
45a02a29
MD
1954 ((if %autoloader-developer-mode warn error)
1955 "no code for module" (module-name used-module))
1956 (beautify-user-module! used-module)))
1957 (let ((interface (module-public-interface used-module)))
1958 (if (not interface)
1959 (error "missing interface for use-module"
1960 used-module))
1961 (if (eq? keyword 'use-syntax)
7cbaee0c
MD
1962 (set-module-transformer!
1963 module
45a02a29
MD
1964 (module-ref interface (car (last-pair used-name))
1965 #f)))
1966 (loop (cddr kws)
1967 (cons interface reversed-interfaces)))))
71225060
MD
1968 ((autoload)
1969 (if (not (and (pair? (cdr kws)) (pair? (cddr kws))))
1970 (error "unrecognized defmodule argument" kws))
1971 (loop (cdddr kws)
1972 (cons (make-autoload-interface module
1973 (cadr kws)
1974 (caddr kws))
1975 reversed-interfaces)))
edc185c7
MD
1976 ((no-backtrace)
1977 (set-system-module! module #t)
1978 (loop (cdr kws) reversed-interfaces))
f714ca8e
MD
1979 (else
1980 (error "unrecognized defmodule argument" kws))))))
0f2d19dd 1981 module))
71225060
MD
1982
1983;;; {Autoload}
1984
1985(define (make-autoload-interface module name bindings)
1986 (let ((b (lambda (a sym definep)
1987 (and (memq sym bindings)
1988 (let ((i (module-public-interface (resolve-module name))))
1989 (if (not i)
1990 (error "missing interface for module" name))
1991 ;; Replace autoload-interface with interface
1992 (set-car! (memq a (module-uses module)) i)
1993 (module-local-variable i sym))))))
1994 (module-constructor #() #f b #f #f name 'autoload)))
1995
0f2d19dd 1996\f
44cf1f0f 1997;;; {Autoloading modules}
0f2d19dd
JB
1998
1999(define autoloads-in-progress '())
2000
2001(define (try-module-autoload module-name)
6fa8995c 2002
0f2d19dd
JB
2003 (define (sfx name) (string-append name (scheme-file-suffix)))
2004 (let* ((reverse-name (reverse module-name))
2005 (name (car reverse-name))
2006 (dir-hint-module-name (reverse (cdr reverse-name)))
2007 (dir-hint (apply symbol-append (map (lambda (elt) (symbol-append elt "/")) dir-hint-module-name))))
0209ca9a 2008 (resolve-module dir-hint-module-name #f)
0f2d19dd
JB
2009 (and (not (autoload-done-or-in-progress? dir-hint name))
2010 (let ((didit #f))
2011 (dynamic-wind
2012 (lambda () (autoload-in-progress! dir-hint name))
2013 (lambda ()
2014 (let loop ((dirs %load-path))
2015 (and (not (null? dirs))
2016 (or
2017 (let ((d (car dirs))
2018 (trys (list
2019 dir-hint
2020 (sfx dir-hint)
2021 (in-vicinity dir-hint name)
2022 (in-vicinity dir-hint (sfx name)))))
2023 (and (or-map (lambda (f)
2024 (let ((full (in-vicinity d f)))
2025 full
6fa8995c
GH
2026 (and (file-exists? full)
2027 (not (file-is-directory? full))
0f2d19dd
JB
2028 (begin
2029 (save-module-excursion
2030 (lambda ()
5552355a
GH
2031 (load (string-append
2032 d "/" f))))
0f2d19dd
JB
2033 #t))))
2034 trys)
2035 (begin
2036 (set! didit #t)
2037 #t)))
2038 (loop (cdr dirs))))))
2039 (lambda () (set-autoloaded! dir-hint name didit)))
2040 didit))))
2041
71225060 2042\f
d0cbd20c
MV
2043;;; Dynamic linking of modules
2044
2045;; Initializing a module that is written in C is a two step process.
2046;; First the module's `module init' function is called. This function
2047;; is expected to call `scm_register_module_xxx' to register the `real
2048;; init' function. Later, when the module is referenced for the first
2049;; time, this real init function is called in the right context. See
2050;; gtcltk-lib/gtcltk-module.c for an example.
2051;;
2052;; The code for the module can be in a regular shared library (so that
2053;; the `module init' function will be called when libguile is
2054;; initialized). Or it can be dynamically linked.
2055;;
2056;; You can safely call `scm_register_module_xxx' before libguile
2057;; itself is initialized. You could call it from an C++ constructor
2058;; of a static object, for example.
2059;;
2060;; To make your Guile extension into a dynamic linkable module, follow
2061;; these easy steps:
2062;;
8bb7330c 2063;; - Find a name for your module, like (ice-9 gtcltk)
d0cbd20c
MV
2064;; - Write a function with a name like
2065;;
2066;; scm_init_ice_9_gtcltk_module
2067;;
2068;; This is your `module init' function. It should call
2069;;
2070;; scm_register_module_xxx ("ice-9 gtcltk", scm_init_gtcltk);
2071;;
2072;; "ice-9 gtcltk" is the C version of the module name. Slashes are
2073;; replaced by spaces, the rest is untouched. `scm_init_gtcltk' is
ed218d98 2074;; the real init function that executes the usual initializations
d0cbd20c
MV
2075;; like making new smobs, etc.
2076;;
2077;; - Make a shared library with your code and a name like
2078;;
2079;; ice-9/libgtcltk.so
2080;;
2081;; and put it somewhere in %load-path.
2082;;
8bb7330c 2083;; - Then you can simply write `:use-module (ice-9 gtcltk)' and it
d0cbd20c
MV
2084;; will be linked automatically.
2085;;
2086;; This is all very experimental.
2087
2088(define (split-c-module-name str)
2089 (let loop ((rev '())
2090 (start 0)
2091 (pos 0)
2092 (end (string-length str)))
2093 (cond
2094 ((= pos end)
2095 (reverse (cons (string->symbol (substring str start pos)) rev)))
2096 ((eq? (string-ref str pos) #\space)
2097 (loop (cons (string->symbol (substring str start pos)) rev)
2098 (+ pos 1)
2099 (+ pos 1)
2100 end))
2101 (else
2102 (loop rev start (+ pos 1) end)))))
2103
2104(define (convert-c-registered-modules dynobj)
2105 (let ((res (map (lambda (c)
2106 (list (split-c-module-name (car c)) (cdr c) dynobj))
2107 (c-registered-modules))))
2108 (c-clear-registered-modules)
2109 res))
2110
3e3cec45
MD
2111(define registered-modules '())
2112
2113(define (register-modules dynobj)
2114 (set! registered-modules
2115 (append! (convert-c-registered-modules dynobj)
2116 registered-modules)))
2117
d0cbd20c 2118(define (init-dynamic-module modname)
3e3cec45
MD
2119 ;; Register any linked modules which has been registered on the C level
2120 (register-modules #f)
d0cbd20c
MV
2121 (or-map (lambda (modinfo)
2122 (if (equal? (car modinfo) modname)
c04e89c7
MD
2123 (begin
2124 (set! registered-modules (delq! modinfo registered-modules))
2125 (let ((mod (resolve-module modname #f)))
2126 (save-module-excursion
2127 (lambda ()
2128 (set-current-module mod)
2129 (set-module-public-interface! mod mod)
2130 (dynamic-call (cadr modinfo) (caddr modinfo))
2131 ))
2132 #t))
d0cbd20c
MV
2133 #f))
2134 registered-modules))
2135
2136(define (dynamic-maybe-call name dynobj)
2137 (catch #t ; could use false-if-exception here
2138 (lambda ()
2139 (dynamic-call name dynobj))
2140 (lambda args
2141 #f)))
2142
ed218d98
MV
2143(define (dynamic-maybe-link filename)
2144 (catch #t ; could use false-if-exception here
2145 (lambda ()
2146 (dynamic-link filename))
2147 (lambda args
2148 #f)))
2149
d0cbd20c
MV
2150(define (find-and-link-dynamic-module module-name)
2151 (define (make-init-name mod-name)
2152 (string-append 'scm_init
2153 (list->string (map (lambda (c)
2154 (if (or (char-alphabetic? c)
2155 (char-numeric? c))
2156 c
2157 #\_))
2158 (string->list mod-name)))
2159 '_module))
ebd79f62
TP
2160
2161 ;; Put the subdirectory for this module in the car of SUBDIR-AND-LIBNAME,
2162 ;; and the `libname' (the name of the module prepended by `lib') in the cdr
2163 ;; field. For example, if MODULE-NAME is the list (inet tcp-ip udp), then
2164 ;; SUBDIR-AND-LIBNAME will be the pair ("inet/tcp-ip" . "libudp").
2165 (let ((subdir-and-libname
d0cbd20c
MV
2166 (let loop ((dirs "")
2167 (syms module-name))
ebd79f62
TP
2168 (if (null? (cdr syms))
2169 (cons dirs (string-append "lib" (car syms)))
2170 (loop (string-append dirs (car syms) "/") (cdr syms)))))
d0cbd20c
MV
2171 (init (make-init-name (apply string-append
2172 (map (lambda (s)
2173 (string-append "_" s))
2174 module-name)))))
ebd79f62
TP
2175 (let ((subdir (car subdir-and-libname))
2176 (libname (cdr subdir-and-libname)))
2177
2178 ;; Now look in each dir in %LOAD-PATH for `subdir/libfoo.la'. If that
2179 ;; file exists, fetch the dlname from that file and attempt to link
2180 ;; against it. If `subdir/libfoo.la' does not exist, or does not seem
2181 ;; to name any shared library, look for `subdir/libfoo.so' instead and
2182 ;; link against that.
2183 (let check-dirs ((dir-list %load-path))
2184 (if (null? dir-list)
2185 #f
2186 (let* ((dir (in-vicinity (car dir-list) subdir))
2187 (sharlib-full
2188 (or (try-using-libtool-name dir libname)
2189 (try-using-sharlib-name dir libname))))
2190 (if (and sharlib-full (file-exists? sharlib-full))
2191 (link-dynamic-module sharlib-full init)
2192 (check-dirs (cdr dir-list)))))))))
2193
2194(define (try-using-libtool-name libdir libname)
ebd79f62
TP
2195 (let ((libtool-filename (in-vicinity libdir
2196 (string-append libname ".la"))))
2197 (and (file-exists? libtool-filename)
5ef4ef4e
MD
2198 (with-input-from-file libtool-filename
2199 (lambda ()
2200 (let loop ((ln (read-line)))
2201 (cond ((eof-object? ln) #f)
49e5d550 2202 ((and (> (string-length ln) 9)
5ef4ef4e
MD
2203 (string=? "dlname='" (substring ln 0 8))
2204 (string-index ln #\' 8))
2205 =>
2206 (lambda (end)
2207 (in-vicinity libdir (substring ln 8 end))))
2208 (else (loop (read-line))))))))))
ebd79f62
TP
2209
2210(define (try-using-sharlib-name libdir libname)
2211 (in-vicinity libdir (string-append libname ".so")))
d0cbd20c
MV
2212
2213(define (link-dynamic-module filename initname)
3e3cec45
MD
2214 ;; Register any linked modules which has been registered on the C level
2215 (register-modules #f)
6b856182
MV
2216 (let ((dynobj (dynamic-link filename)))
2217 (dynamic-call initname dynobj)
3e3cec45 2218 (register-modules dynobj)))
a4f9b1f6
MD
2219
2220(define (try-module-linked module-name)
2221 (init-dynamic-module module-name))
2222
d0cbd20c 2223(define (try-module-dynamic-link module-name)
a4f9b1f6
MD
2224 (and (find-and-link-dynamic-module module-name)
2225 (init-dynamic-module module-name)))
d0cbd20c 2226
ed218d98
MV
2227
2228
0f2d19dd
JB
2229(define autoloads-done '((guile . guile)))
2230
2231(define (autoload-done-or-in-progress? p m)
2232 (let ((n (cons p m)))
2233 (->bool (or (member n autoloads-done)
2234 (member n autoloads-in-progress)))))
2235
2236(define (autoload-done! p m)
2237 (let ((n (cons p m)))
2238 (set! autoloads-in-progress
2239 (delete! n autoloads-in-progress))
2240 (or (member n autoloads-done)
2241 (set! autoloads-done (cons n autoloads-done)))))
2242
2243(define (autoload-in-progress! p m)
2244 (let ((n (cons p m)))
2245 (set! autoloads-done
2246 (delete! n autoloads-done))
2247 (set! autoloads-in-progress (cons n autoloads-in-progress))))
2248
2249(define (set-autoloaded! p m done?)
2250 (if done?
2251 (autoload-done! p m)
2252 (let ((n (cons p m)))
2253 (set! autoloads-done (delete! n autoloads-done))
2254 (set! autoloads-in-progress (delete! n autoloads-in-progress)))))
2255
2256
2257
2258
2259\f
2260;;; {Macros}
2261;;;
2262
7a0ff2f8
MD
2263(define (primitive-macro? m)
2264 (and (macro? m)
2265 (not (macro-transformer m))))
2266
2267;;; {Defmacros}
2268;;;
9591db87
MD
2269(define macro-table (make-weak-key-hash-table 523))
2270(define xformer-table (make-weak-key-hash-table 523))
0f2d19dd
JB
2271
2272(define (defmacro? m) (hashq-ref macro-table m))
2273(define (assert-defmacro?! m) (hashq-set! macro-table m #t))
2274(define (defmacro-transformer m) (hashq-ref xformer-table m))
2275(define (set-defmacro-transformer! m t) (hashq-set! xformer-table m t))
2276
2277(define defmacro:transformer
2278 (lambda (f)
2279 (let* ((xform (lambda (exp env)
2280 (copy-tree (apply f (cdr exp)))))
2281 (a (procedure->memoizing-macro xform)))
2282 (assert-defmacro?! a)
2283 (set-defmacro-transformer! a f)
2284 a)))
2285
2286
2287(define defmacro
2288 (let ((defmacro-transformer
2289 (lambda (name parms . body)
2290 (let ((transformer `(lambda ,parms ,@body)))
2291 `(define ,name
2292 (,(lambda (transformer)
2293 (defmacro:transformer transformer))
2294 ,transformer))))))
2295 (defmacro:transformer defmacro-transformer)))
2296
2297(define defmacro:syntax-transformer
2298 (lambda (f)
2299 (procedure->syntax
2300 (lambda (exp env)
2301 (copy-tree (apply f (cdr exp)))))))
2302
ed218d98
MV
2303
2304;; XXX - should the definition of the car really be looked up in the
2305;; current module?
2306
0f2d19dd
JB
2307(define (macroexpand-1 e)
2308 (cond
2309 ((pair? e) (let* ((a (car e))
ed218d98 2310 (val (and (symbol? a) (local-ref (list a)))))
0f2d19dd
JB
2311 (if (defmacro? val)
2312 (apply (defmacro-transformer val) (cdr e))
2313 e)))
2314 (#t e)))
2315
2316(define (macroexpand e)
2317 (cond
2318 ((pair? e) (let* ((a (car e))
ed218d98 2319 (val (and (symbol? a) (local-ref (list a)))))
0f2d19dd
JB
2320 (if (defmacro? val)
2321 (macroexpand (apply (defmacro-transformer val) (cdr e)))
2322 e)))
2323 (#t e)))
2324
e672f1b5
MD
2325(define (gentemp)
2326 (gensym "scm:G"))
0f2d19dd 2327
534a0099 2328(provide 'defmacro)
0f2d19dd
JB
2329
2330\f
2331
83b38198
MD
2332;;; {Run-time options}
2333
16b8ebbe
MD
2334((let* ((names '((eval-options-interface
2335 (eval-options eval-enable eval-disable)
2336 (eval-set!))
2337
2338 (debug-options-interface
83b38198
MD
2339 (debug-options debug-enable debug-disable)
2340 (debug-set!))
2341
2342 (evaluator-traps-interface
2343 (traps trap-enable trap-disable)
2344 (trap-set!))
2345
2346 (read-options-interface
2347 (read-options read-enable read-disable)
2348 (read-set!))
2349
2350 (print-options-interface
2351 (print-options print-enable print-disable)
2352 (print-set!))
e586be78
MD
2353
2354 (readline-options-interface
2355 (readline-options readline-enable readline-disable)
2356 (readline-set!))
83b38198
MD
2357 ))
2358 (option-name car)
2359 (option-value cadr)
2360 (option-documentation caddr)
2361
2362 (print-option (lambda (option)
2363 (display (option-name option))
2364 (if (< (string-length
2365 (symbol->string (option-name option)))
2366 8)
2367 (display #\tab))
2368 (display #\tab)
2369 (display (option-value option))
2370 (display #\tab)
2371 (display (option-documentation option))
2372 (newline)))
2373
2374 ;; Below follows the macros defining the run-time option interfaces.
2375
2376 (make-options (lambda (interface)
2377 `(lambda args
2378 (cond ((null? args) (,interface))
45456413 2379 ((list? (car args))
83b38198 2380 (,interface (car args)) (,interface))
2f110c3c 2381 (else (for-each ,print-option
83b38198
MD
2382 (,interface #t)))))))
2383
2384 (make-enable (lambda (interface)
2385 `(lambda flags
2386 (,interface (append flags (,interface)))
2387 (,interface))))
2388
2389 (make-disable (lambda (interface)
2390 `(lambda flags
2391 (let ((options (,interface)))
2392 (for-each (lambda (flag)
2393 (set! options (delq! flag options)))
2394 flags)
2395 (,interface options)
2396 (,interface)))))
2397
2398 (make-set! (lambda (interface)
2399 `((name exp)
2400 (,'quasiquote
2401 (begin (,interface (append (,interface)
2402 (list '(,'unquote name)
2403 (,'unquote exp))))
2404 (,interface))))))
2405 )
2406 (procedure->macro
2407 (lambda (exp env)
2408 (cons 'begin
2409 (apply append
2410 (map (lambda (group)
2411 (let ((interface (car group)))
2412 (append (map (lambda (name constructor)
2413 `(define ,name
2414 ,(constructor interface)))
2415 (cadr group)
2416 (list make-options
2417 make-enable
2418 make-disable))
2419 (map (lambda (name constructor)
2420 `(defmacro ,name
2421 ,@(constructor interface)))
2422 (caddr group)
2423 (list make-set!)))))
2424 names)))))))
2425
2426\f
2427
0f2d19dd
JB
2428;;; {Running Repls}
2429;;;
2430
2431(define (repl read evaler print)
75a97b92 2432 (let loop ((source (read (current-input-port))))
0f2d19dd 2433 (print (evaler source))
75a97b92 2434 (loop (read (current-input-port)))))
0f2d19dd
JB
2435
2436;; A provisional repl that acts like the SCM repl:
2437;;
2438(define scm-repl-silent #f)
2439(define (assert-repl-silence v) (set! scm-repl-silent v))
2440
21ed9efe
MD
2441(define *unspecified* (if #f #f))
2442(define (unspecified? v) (eq? v *unspecified*))
2443
2444(define scm-repl-print-unspecified #f)
2445(define (assert-repl-print-unspecified v) (set! scm-repl-print-unspecified v))
2446
79451588 2447(define scm-repl-verbose #f)
0f2d19dd
JB
2448(define (assert-repl-verbosity v) (set! scm-repl-verbose v))
2449
e6875011 2450(define scm-repl-prompt "guile> ")
0f2d19dd 2451
e6875011
MD
2452(define (set-repl-prompt! v) (set! scm-repl-prompt v))
2453
d5d34fa1
MD
2454(define (default-lazy-handler key . args)
2455 (save-stack lazy-handler-dispatch)
2456 (apply throw key args))
2457
45456413 2458(define enter-frame-handler default-lazy-handler)
d5d34fa1
MD
2459(define apply-frame-handler default-lazy-handler)
2460(define exit-frame-handler default-lazy-handler)
2461
2462(define (lazy-handler-dispatch key . args)
2463 (case key
2464 ((apply-frame)
2465 (apply apply-frame-handler key args))
2466 ((exit-frame)
2467 (apply exit-frame-handler key args))
45456413
MD
2468 ((enter-frame)
2469 (apply enter-frame-handler key args))
d5d34fa1
MD
2470 (else
2471 (apply default-lazy-handler key args))))
0f2d19dd 2472
3e3cec45 2473(define abort-hook (make-hook))
59e1116d 2474
28d8ab3c
GH
2475;; these definitions are used if running a script.
2476;; otherwise redefined in error-catching-loop.
2477(define (set-batch-mode?! arg) #t)
2478(define (batch-mode?) #t)
4bbbcd5c 2479
0f2d19dd 2480(define (error-catching-loop thunk)
4bbbcd5c
GH
2481 (let ((status #f)
2482 (interactive #t))
8e44e7a0
GH
2483 (define (loop first)
2484 (let ((next
2485 (catch #t
9a0d70e2 2486
8e44e7a0
GH
2487 (lambda ()
2488 (lazy-catch #t
2489 (lambda ()
2490 (dynamic-wind
2491 (lambda () (unmask-signals))
2492 (lambda ()
45456413
MD
2493 (with-traps
2494 (lambda ()
2495 (first)
8e44e7a0 2496
45456413
MD
2497 ;; This line is needed because mark
2498 ;; doesn't do closures quite right.
2499 ;; Unreferenced locals should be
2500 ;; collected.
2501 ;;
2502 (set! first #f)
2503 (let loop ((v (thunk)))
2504 (loop (thunk)))
2505 #f)))
8e44e7a0
GH
2506 (lambda () (mask-signals))))
2507
2508 lazy-handler-dispatch))
2509
2510 (lambda (key . args)
2511 (case key
2512 ((quit)
8e44e7a0
GH
2513 (set! status args)
2514 #f)
2515
2516 ((switch-repl)
2517 (apply throw 'switch-repl args))
2518
2519 ((abort)
2520 ;; This is one of the closures that require
2521 ;; (set! first #f) above
2522 ;;
2523 (lambda ()
04efd24d 2524 (run-hook abort-hook)
e13c54c4 2525 (force-output (current-output-port))
8e44e7a0
GH
2526 (display "ABORT: " (current-error-port))
2527 (write args (current-error-port))
2528 (newline (current-error-port))
4bbbcd5c 2529 (if interactive
e13c54c4
JB
2530 (begin
2531 (if (and
2532 (not has-shown-debugger-hint?)
2533 (not (memq 'backtrace
2534 (debug-options-interface)))
2535 (stack? (fluid-ref the-last-stack)))
2536 (begin
2537 (newline (current-error-port))
2538 (display
2539 "Type \"(backtrace)\" to get more information.\n"
2540 (current-error-port))
2541 (set! has-shown-debugger-hint? #t)))
2542 (force-output (current-error-port)))
2543 (begin
2544 (primitive-exit 1)))
8e44e7a0
GH
2545 (set! stack-saved? #f)))
2546
2547 (else
2548 ;; This is the other cons-leak closure...
2549 (lambda ()
2550 (cond ((= (length args) 4)
2551 (apply handle-system-error key args))
2552 (else
2553 (apply bad-throw key args))))))))))
2554 (if next (loop next) status)))
5f5f2642
MD
2555 (set! set-batch-mode?! (lambda (arg)
2556 (cond (arg
2557 (set! interactive #f)
2558 (restore-signals))
2559 (#t
2560 (error "sorry, not implemented")))))
2561 (set! batch-mode? (lambda () (not interactive)))
8e44e7a0 2562 (loop (lambda () #t))))
0f2d19dd 2563
8bb7f646 2564;;(define the-last-stack (make-fluid)) Defined by scm_init_backtrace ()
21ed9efe
MD
2565(define stack-saved? #f)
2566
2567(define (save-stack . narrowing)
edc185c7
MD
2568 (or stack-saved?
2569 (cond ((not (memq 'debug (debug-options-interface)))
2570 (fluid-set! the-last-stack #f)
2571 (set! stack-saved? #t))
2572 (else
2573 (fluid-set!
2574 the-last-stack
2575 (case (stack-id #t)
2576 ((repl-stack)
2577 (apply make-stack #t save-stack eval #t 0 narrowing))
2578 ((load-stack)
2579 (apply make-stack #t save-stack 0 #t 0 narrowing))
2580 ((tk-stack)
2581 (apply make-stack #t save-stack tk-stack-mark #t 0 narrowing))
2582 ((#t)
2583 (apply make-stack #t save-stack 0 1 narrowing))
2584 (else
2585 (let ((id (stack-id #t)))
2586 (and (procedure? id)
2587 (apply make-stack #t save-stack id #t 0 narrowing))))))
2588 (set! stack-saved? #t)))))
1c6cd8e8 2589
3e3cec45
MD
2590(define before-error-hook (make-hook))
2591(define after-error-hook (make-hook))
2592(define before-backtrace-hook (make-hook))
2593(define after-backtrace-hook (make-hook))
1c6cd8e8 2594
21ed9efe
MD
2595(define has-shown-debugger-hint? #f)
2596
35c5db87
GH
2597(define (handle-system-error key . args)
2598 (let ((cep (current-error-port)))
8bb7f646 2599 (cond ((not (stack? (fluid-ref the-last-stack))))
21ed9efe 2600 ((memq 'backtrace (debug-options-interface))
04efd24d 2601 (run-hook before-backtrace-hook)
21ed9efe 2602 (newline cep)
8bb7f646 2603 (display-backtrace (fluid-ref the-last-stack) cep)
21ed9efe 2604 (newline cep)
04efd24d
MD
2605 (run-hook after-backtrace-hook)))
2606 (run-hook before-error-hook)
8bb7f646 2607 (apply display-error (fluid-ref the-last-stack) cep args)
04efd24d 2608 (run-hook after-error-hook)
35c5db87
GH
2609 (force-output cep)
2610 (throw 'abort key)))
21ed9efe 2611
0f2d19dd
JB
2612(define (quit . args)
2613 (apply throw 'quit args))
2614
7950df7c
GH
2615(define exit quit)
2616
d590bbf6
MD
2617;;(define has-shown-backtrace-hint? #f) Defined by scm_init_backtrace ()
2618
2619;; Replaced by C code:
2620;;(define (backtrace)
8bb7f646 2621;; (if (fluid-ref the-last-stack)
d590bbf6
MD
2622;; (begin
2623;; (newline)
8bb7f646 2624;; (display-backtrace (fluid-ref the-last-stack) (current-output-port))
d590bbf6
MD
2625;; (newline)
2626;; (if (and (not has-shown-backtrace-hint?)
2627;; (not (memq 'backtrace (debug-options-interface))))
2628;; (begin
2629;; (display
2630;;"Type \"(debug-enable 'backtrace)\" if you would like a backtrace
2631;;automatically if an error occurs in the future.\n")
2632;; (set! has-shown-backtrace-hint? #t))))
2633;; (display "No backtrace available.\n")))
21ed9efe 2634
0f2d19dd
JB
2635(define (error-catching-repl r e p)
2636 (error-catching-loop (lambda () (p (e (r))))))
2637
2638(define (gc-run-time)
2639 (cdr (assq 'gc-time-taken (gc-stats))))
2640
3e3cec45
MD
2641(define before-read-hook (make-hook))
2642(define after-read-hook (make-hook))
1c6cd8e8 2643
dc5c2038
MD
2644;;; The default repl-reader function. We may override this if we've
2645;;; the readline library.
2646(define repl-reader
2647 (lambda (prompt)
2648 (display prompt)
2649 (force-output)
04efd24d 2650 (run-hook before-read-hook)
dc5c2038
MD
2651 (read (current-input-port))))
2652
0f2d19dd
JB
2653(define (scm-style-repl)
2654 (letrec (
2655 (start-gc-rt #f)
2656 (start-rt #f)
0f2d19dd
JB
2657 (repl-report-start-timing (lambda ()
2658 (set! start-gc-rt (gc-run-time))
2659 (set! start-rt (get-internal-run-time))))
2660 (repl-report (lambda ()
2661 (display ";;; ")
2662 (display (inexact->exact
2663 (* 1000 (/ (- (get-internal-run-time) start-rt)
2664 internal-time-units-per-second))))
2665 (display " msec (")
2666 (display (inexact->exact
2667 (* 1000 (/ (- (gc-run-time) start-gc-rt)
2668 internal-time-units-per-second))))
2669 (display " msec in gc)\n")))
480977d0
JB
2670
2671 (consume-trailing-whitespace
2672 (lambda ()
2673 (let ((ch (peek-char)))
2674 (cond
2675 ((eof-object? ch))
2676 ((or (char=? ch #\space) (char=? ch #\tab))
2677 (read-char)
2678 (consume-trailing-whitespace))
2679 ((char=? ch #\newline)
2680 (read-char))))))
0f2d19dd 2681 (-read (lambda ()
dc5c2038
MD
2682 (let ((val
2683 (let ((prompt (cond ((string? scm-repl-prompt)
2684 scm-repl-prompt)
2685 ((thunk? scm-repl-prompt)
2686 (scm-repl-prompt))
2687 (scm-repl-prompt "> ")
2688 (else ""))))
2689 (repl-reader prompt))))
2690
480977d0 2691 ;; As described in R4RS, the READ procedure updates the
e13c54c4 2692 ;; port to point to the first character past the end of
480977d0
JB
2693 ;; the external representation of the object. This
2694 ;; means that it doesn't consume the newline typically
2695 ;; found after an expression. This means that, when
2696 ;; debugging Guile with GDB, GDB gets the newline, which
2697 ;; it often interprets as a "continue" command, making
2698 ;; breakpoints kind of useless. So, consume any
2699 ;; trailing newline here, as well as any whitespace
2700 ;; before it.
e13c54c4
JB
2701 ;; But not if EOF, for control-D.
2702 (if (not (eof-object? val))
2703 (consume-trailing-whitespace))
04efd24d 2704 (run-hook after-read-hook)
0f2d19dd
JB
2705 (if (eof-object? val)
2706 (begin
7950df7c 2707 (repl-report-start-timing)
0f2d19dd
JB
2708 (if scm-repl-verbose
2709 (begin
2710 (newline)
2711 (display ";;; EOF -- quitting")
2712 (newline)))
2713 (quit 0)))
2714 val)))
2715
2716 (-eval (lambda (sourc)
2717 (repl-report-start-timing)
4cdee789 2718 (start-stack 'repl-stack (eval sourc))))
0f2d19dd
JB
2719
2720 (-print (lambda (result)
2721 (if (not scm-repl-silent)
2722 (begin
21ed9efe
MD
2723 (if (or scm-repl-print-unspecified
2724 (not (unspecified? result)))
2725 (begin
2726 (write result)
2727 (newline)))
0f2d19dd
JB
2728 (if scm-repl-verbose
2729 (repl-report))
2730 (force-output)))))
2731
8e44e7a0 2732 (-quit (lambda (args)
0f2d19dd
JB
2733 (if scm-repl-verbose
2734 (begin
2735 (display ";;; QUIT executed, repl exitting")
2736 (newline)
2737 (repl-report)))
8e44e7a0 2738 args))
0f2d19dd
JB
2739
2740 (-abort (lambda ()
2741 (if scm-repl-verbose
2742 (begin
2743 (display ";;; ABORT executed.")
2744 (newline)
2745 (repl-report)))
2746 (repl -read -eval -print))))
2747
8e44e7a0
GH
2748 (let ((status (error-catching-repl -read
2749 -eval
2750 -print)))
2751 (-quit status))))
2752
0f2d19dd 2753
0f2d19dd 2754\f
44cf1f0f 2755;;; {IOTA functions: generating lists of numbers}
0f2d19dd 2756
e69cd299
MD
2757(define (iota n)
2758 (let loop ((count (1- n)) (result '()))
2759 (if (< count 0) result
2760 (loop (1- count) (cons count result)))))
0f2d19dd
JB
2761
2762\f
2763;;; {While}
2764;;;
2765;;; with `continue' and `break'.
2766;;;
2767
2768(defmacro while (cond . body)
2769 `(letrec ((continue (lambda () (or (not ,cond) (begin (begin ,@ body) (continue)))))
2770 (break (lambda val (apply throw 'break val))))
2771 (catch 'break
2772 (lambda () (continue))
2773 (lambda v (cadr v)))))
2774
7398c2c2
MD
2775;;; {collect}
2776;;;
2777;;; Similar to `begin' but returns a list of the results of all constituent
2778;;; forms instead of the result of the last form.
2779;;; (The definition relies on the current left-to-right
2780;;; order of evaluation of operands in applications.)
2781
2782(defmacro collect forms
2783 (cons 'list forms))
0f2d19dd 2784
8a6a8671
MV
2785;;; {with-fluids}
2786
2787;; with-fluids is a convenience wrapper for the builtin procedure
2788;; `with-fluids*'. The syntax is just like `let':
2789;;
2790;; (with-fluids ((fluid val)
2791;; ...)
2792;; body)
2793
2794(defmacro with-fluids (bindings . body)
2795 `(with-fluids* (list ,@(map car bindings)) (list ,@(map cadr bindings))
2796 (lambda () ,@body)))
2797
dc61592f
MD
2798;;; Environments
2799
2800(define the-environment
2801 (procedure->syntax
2802 (lambda (x e)
2803 e)))
2804
9705d5c2 2805(define (environment-module env)
baa47a94 2806 (let ((closure (and (pair? env) (car (last-pair env)))))
edc185c7 2807 (and closure (procedure-property closure 'module))))
bf3c93d1 2808
0f2d19dd
JB
2809\f
2810
2811;;; {Macros}
2812;;;
2813
2814;; actually....hobbit might be able to hack these with a little
2815;; coaxing
2816;;
2817
2818(defmacro define-macro (first . rest)
2819 (let ((name (if (symbol? first) first (car first)))
2820 (transformer
2821 (if (symbol? first)
2822 (car rest)
2823 `(lambda ,(cdr first) ,@rest))))
2824 `(define ,name (defmacro:transformer ,transformer))))
2825
2826
2827(defmacro define-syntax-macro (first . rest)
2828 (let ((name (if (symbol? first) first (car first)))
2829 (transformer
2830 (if (symbol? first)
2831 (car rest)
2832 `(lambda ,(cdr first) ,@rest))))
2833 `(define ,name (defmacro:syntax-transformer ,transformer))))
2834\f
2835;;; {Module System Macros}
2836;;;
2837
2838(defmacro define-module args
2839 `(let* ((process-define-module process-define-module)
2840 (set-current-module set-current-module)
2841 (module (process-define-module ',args)))
2842 (set-current-module module)
2843 module))
2844
89da9036
MV
2845;; the guts of the use-modules macro. add the interfaces of the named
2846;; modules to the use-list of the current module, in order
2847(define (process-use-modules module-names)
2848 (for-each (lambda (module-name)
2849 (let ((mod-iface (resolve-interface module-name)))
2850 (or mod-iface
2851 (error "no such module" module-name))
2852 (module-use! (current-module) mod-iface)))
2853 (reverse module-names)))
2854
33cf699f 2855(defmacro use-modules modules
89da9036 2856 `(process-use-modules ',modules))
33cf699f 2857
cf266109 2858(defmacro use-syntax (spec)
7cbaee0c
MD
2859 `(begin
2860 ,@(if (pair? spec)
2861 `((process-use-modules ',(list spec))
2862 (set-module-transformer! (current-module)
2863 ,(car (last-pair spec))))
2864 `((set-module-transformer! (current-module) ,spec)))
2865 (set! scm:eval-transformer (module-transformer (current-module)))))
7a0ff2f8 2866
0f2d19dd
JB
2867(define define-private define)
2868
2869(defmacro define-public args
2870 (define (syntax)
2871 (error "bad syntax" (list 'define-public args)))
2872 (define (defined-name n)
2873 (cond
3c5af9ef
JB
2874 ((symbol? n) n)
2875 ((pair? n) (defined-name (car n)))
2876 (else (syntax))))
0f2d19dd 2877 (cond
3c5af9ef
JB
2878 ((null? args) (syntax))
2879
2880 (#t (let ((name (defined-name (car args))))
2881 `(begin
2882 (let ((public-i (module-public-interface (current-module))))
2883 ;; Make sure there is a local variable:
2884 ;;
2885 (module-define! (current-module)
2886 ',name
2887 (module-ref (current-module) ',name #f))
0f2d19dd 2888
3c5af9ef
JB
2889 ;; Make sure that local is exported:
2890 ;;
2891 (module-add! public-i ',name
2892 (module-variable (current-module) ',name)))
0f2d19dd 2893
3c5af9ef
JB
2894 ;; Now (re)define the var normally. Bernard URBAN
2895 ;; suggests we use eval here to accomodate Hobbit; it lets
2896 ;; the interpreter handle the define-private form, which
2897 ;; Hobbit can't digest.
2898 (eval '(define-private ,@ args)))))))
0f2d19dd
JB
2899
2900
2901
2902(defmacro defmacro-public args
2903 (define (syntax)
2904 (error "bad syntax" (list 'defmacro-public args)))
2905 (define (defined-name n)
2906 (cond
2907 ((symbol? n) n)
2908 (else (syntax))))
2909 (cond
2910 ((null? args) (syntax))
2911
2912 (#t (let ((name (defined-name (car args))))
2913 `(begin
2914 (let ((public-i (module-public-interface (current-module))))
2915 ;; Make sure there is a local variable:
2916 ;;
2917 (module-define! (current-module)
2918 ',name
2919 (module-ref (current-module) ',name #f))
2920
2921 ;; Make sure that local is exported:
2922 ;;
2923 (module-add! public-i ',name (module-variable (current-module) ',name)))
2924
2925 ;; Now (re)define the var normally.
2926 ;;
2927 (defmacro ,@ args))))))
2928
2929
a0cc0a01
MD
2930(defmacro export names
2931 `(let* ((m (current-module))
2932 (public-i (module-public-interface m)))
2933 (for-each (lambda (name)
2934 ;; Make sure there is a local variable:
2935 (module-define! m name (module-ref m name #f))
2936 ;; Make sure that local is exported:
2937 (module-add! public-i name (module-variable m name)))
2938 ',names)))
2939
2940(define export-syntax export)
2941
2942
0f2d19dd
JB
2943
2944
0f2d19dd
JB
2945(define load load-module)
2946
2947
2948\f
9aca88c3
JB
2949;;; {Load emacs interface support if emacs option is given.}
2950
2951(define (load-emacs-interface)
2952 (if (memq 'debug-extensions *features*)
2953 (debug-enable 'backtrace))
2954 (define-module (guile-user) :use-module (ice-9 emacs)))
2955
2956\f
44cf1f0f 2957;;; {I/O functions for Tcl channels (disabled)}
0f2d19dd
JB
2958
2959;; (define in-ch (get-standard-channel TCL_STDIN))
2960;; (define out-ch (get-standard-channel TCL_STDOUT))
2961;; (define err-ch (get-standard-channel TCL_STDERR))
2962;;
2963;; (define inp (%make-channel-port in-ch "r"))
2964;; (define outp (%make-channel-port out-ch "w"))
2965;; (define errp (%make-channel-port err-ch "w"))
2966;;
2967;; (define %system-char-ready? char-ready?)
2968;;
2969;; (define (char-ready? p)
2970;; (if (not (channel-port? p))
2971;; (%system-char-ready? p)
2972;; (let* ((channel (%channel-port-channel p))
2973;; (old-blocking (channel-option-ref channel :blocking)))
2974;; (dynamic-wind
2975;; (lambda () (set-channel-option the-root-tcl-interpreter channel :blocking "0"))
2976;; (lambda () (not (eof-object? (peek-char p))))
2977;; (lambda () (set-channel-option the-root-tcl-interpreter channel :blocking old-blocking))))))
2978;;
2979;; (define (top-repl)
2980;; (with-input-from-port inp
2981;; (lambda ()
2982;; (with-output-to-port outp
2983;; (lambda ()
2984;; (with-error-to-port errp
2985;; (lambda ()
2986;; (scm-style-repl))))))))
2987;;
2988;; (set-current-input-port inp)
2989;; (set-current-output-port outp)
2990;; (set-current-error-port errp)
2991
e1a191a8
GH
2992;; this is just (scm-style-repl) with a wrapper to install and remove
2993;; signal handlers.
8e44e7a0 2994(define (top-repl)
9aca88c3
JB
2995
2996 ;; Load emacs interface support if emacs option is given.
2997 (if (and (module-defined? the-root-module 'use-emacs-interface)
2998 use-emacs-interface)
2999 (load-emacs-interface))
3000
4fdf8b2c
MD
3001 ;; Place the user in the guile-user module.
3002 (define-module (guile-user))
3003
e1a191a8
GH
3004 (let ((old-handlers #f)
3005 (signals `((,SIGINT . "User interrupt")
3006 (,SIGFPE . "Arithmetic error")
3007 (,SIGBUS . "Bad memory access (bus error)")
3008 (,SIGSEGV . "Bad memory access (Segmentation violation)"))))
3009
3010 (dynamic-wind
3011
3012 ;; call at entry
3013 (lambda ()
3014 (let ((make-handler (lambda (msg)
3015 (lambda (sig)
096d5f90 3016 (save-stack %deliver-signals)
e1a191a8
GH
3017 (scm-error 'signal
3018 #f
3019 msg
3020 #f
3021 (list sig))))))
3022 (set! old-handlers
3023 (map (lambda (sig-msg)
3024 (sigaction (car sig-msg)
3025 (make-handler (cdr sig-msg))))
3026 signals))))
3027
3028 ;; the protected thunk.
3029 (lambda ()
dc5c2038
MD
3030
3031 ;; If we've got readline, use it to prompt the user. This is a
3032 ;; kludge, but we'll fix it soon. At least we only get
3033 ;; readline involved when we're actually running the repl.
3034 (if (and (memq 'readline *features*)
279ba8c0 3035 (isatty? (current-input-port))
dc5c2038
MD
3036 (not (and (module-defined? the-root-module
3037 'use-emacs-interface)
3038 use-emacs-interface)))
04efd24d 3039 (let ((read-hook (lambda () (run-hook before-read-hook))))
dc5c2038
MD
3040 (set-current-input-port (readline-port))
3041 (set! repl-reader
3042 (lambda (prompt)
3043 (dynamic-wind
3044 (lambda ()
dd6ba905 3045 (set-readline-prompt! prompt "... ")
dc5c2038
MD
3046 (set-readline-read-hook! read-hook))
3047 (lambda () (read))
3048 (lambda ()
dd6ba905 3049 (set-readline-prompt! "" "")
dc5c2038 3050 (set-readline-read-hook! #f)))))))
2055a1bc 3051 (let ((status (scm-style-repl)))
04efd24d 3052 (run-hook exit-hook)
2055a1bc 3053 status))
e1a191a8
GH
3054
3055 ;; call at exit.
3056 (lambda ()
3057 (map (lambda (sig-msg old-handler)
3058 (if (not (car old-handler))
3059 ;; restore original C handler.
3060 (sigaction (car sig-msg) #f)
3061 ;; restore Scheme handler, SIG_IGN or SIG_DFL.
3062 (sigaction (car sig-msg)
3063 (car old-handler)
3064 (cdr old-handler))))
3065 signals old-handlers)))))
0f2d19dd 3066
02b754d3
GH
3067(defmacro false-if-exception (expr)
3068 `(catch #t (lambda () ,expr)
3069 (lambda args #f)))
3070
2055a1bc
MD
3071;;; This hook is run at the very end of an interactive session.
3072;;;
3e3cec45 3073(define exit-hook (make-hook))
2055a1bc 3074
13e341bb
MD
3075;;; Load readline code into root module if readline primitives are available.
3076;;;
3077;;; Ideally, we wouldn't do this until we were sure we were actually
3078;;; going to enter the repl, but autoloading individual functions is
3079;;; clumsy at the moment.
3080(if (and (memq 'readline *features*)
3081 (isatty? (current-input-port)))
3082 (begin
3083 (define-module (guile) :use-module (ice-9 readline))
39bc9948 3084 (define-module (guile-user) :use-module (ice-9 readline))))
13e341bb
MD
3085
3086\f
3087;;; {Load debug extension code into user module if debug extensions present.}
c56634ba
MD
3088;;;
3089;;; *fixme* This is a temporary solution.
3090;;;
0f2d19dd 3091
c56634ba 3092(if (memq 'debug-extensions *features*)
39bc9948 3093 (define-module (guile-user) :use-module (ice-9 debug)))
90895e5c
MD
3094
3095\f
13e341bb 3096;;; {Load session support into user module if present.}
90d5e280
MD
3097;;;
3098;;; *fixme* This is a temporary solution.
3099;;;
3100
3101(if (%search-load-path "ice-9/session.scm")
39bc9948 3102 (define-module (guile-user) :use-module (ice-9 session)))
f246e585 3103
13e341bb 3104;;; {Load thread code into user module if threads are present.}
90895e5c
MD
3105;;;
3106;;; *fixme* This is a temporary solution.
3107;;;
3108
3109(if (memq 'threads *features*)
39bc9948 3110 (define-module (guile-user) :use-module (ice-9 threads)))
90895e5c 3111
21ed9efe 3112\f
05817d9e
JB
3113;;; {Load regexp code if regexp primitives are available.}
3114
3115(if (memq 'regex *features*)
5ef4ef4e 3116 (define-module (guile-user) :use-module (ice-9 regex)))
05817d9e
JB
3117
3118\f
13e341bb
MD
3119(define-module (guile))
3120
9946dd45
JB
3121;;; {Check that the interpreter and scheme code match up.}
3122
3123(let ((show-line
3124 (lambda args
3125 (with-output-to-port (current-error-port)
3126 (lambda ()
3127 (display (car (command-line)))
3128 (display ": ")
3129 (for-each (lambda (string) (display string))
3130 args)
3131 (newline))))))
3132
3133 (load-from-path "ice-9/version.scm")
3134
3135 (if (not (string=?
3136 (libguile-config-stamp) ; from the interprpreter
3137 (ice-9-config-stamp))) ; from the Scheme code
3138 (begin
3139 (show-line "warning: different versions of libguile and ice-9:")
3140 (show-line "libguile: configured on " (libguile-config-stamp))
3141 (show-line "ice-9: configured on " (ice-9-config-stamp)))))
3142
13e341bb 3143(append! %load-path (cons "." ()))
21ed9efe 3144