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