*** empty log message ***
[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
17;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18;;;;
19\f
20
21;;; This file is the first thing loaded into Guile. It adds many mundane
22;;; definitions and a few that are interesting.
23;;;
24;;; The module system (hence the hierarchical namespace) are defined in this
25;;; file.
26;;;
27
28\f
21ed9efe
MD
29;;; {Features}
30;;
31
32(define (provide sym)
33 (if (not (memq sym *features*))
34 (set! *features* (cons sym *features*))))
35
36\f
79451588
JB
37;;; {R4RS compliance}
38
39(primitive-load-path "ice-9/r4rs.scm")
40
41\f
44cf1f0f 42;;; {Simple Debugging Tools}
0f2d19dd
JB
43;;
44
45
46;; peek takes any number of arguments, writes them to the
47;; current ouput port, and returns the last argument.
48;; It is handy to wrap around an expression to look at
49;; a value each time is evaluated, e.g.:
50;;
51;; (+ 10 (troublesome-fn))
52;; => (+ 10 (pk 'troublesome-fn-returned (troublesome-fn)))
53;;
54
55(define (peek . stuff)
56 (newline)
57 (display ";;; ")
58 (write stuff)
59 (newline)
60 (car (last-pair stuff)))
61
62(define pk peek)
63
64(define (warn . stuff)
65 (with-output-to-port (current-error-port)
66 (lambda ()
67 (newline)
68 (display ";;; WARNING ")
6355358a 69 (display stuff)
0f2d19dd
JB
70 (newline)
71 (car (last-pair stuff)))))
72
73\f
79451588 74;;; {Trivial Functions}
0f2d19dd 75;;;
79451588
JB
76
77(define (id x) x)
78(define (1+ n) (+ n 1))
79(define (-1+ n) (+ n -1))
80(define 1- -1+)
81(define return-it noop)
132e5fac 82(define (and=> value procedure) (and value (procedure value)))
79451588
JB
83(define (make-hash-table k) (make-vector k '()))
84
0f2d19dd
JB
85;;; apply-to-args is functionally redunant with apply and, worse,
86;;; is less general than apply since it only takes two arguments.
87;;;
88;;; On the other hand, apply-to-args is a syntacticly convenient way to
89;;; perform binding in many circumstances when the "let" family of
90;;; of forms don't cut it. E.g.:
91;;;
92;;; (apply-to-args (return-3d-mouse-coords)
93;;; (lambda (x y z)
94;;; ...))
95;;;
96
97(define (apply-to-args args fn) (apply fn args))
98
99\f
0f2d19dd
JB
100;;; {Integer Math}
101;;;
102
0f2d19dd
JB
103(define (ipow-by-squaring x k acc proc)
104 (cond ((zero? k) acc)
105 ((= 1 k) (proc acc x))
106 (else (logical:ipow-by-squaring (proc x x)
107 (quotient k 2)
108 (if (even? k) acc (proc acc x))
109 proc))))
110
111(define string-character-length string-length)
112
113
114
115;; A convenience function for combining flag bits. Like logior, but
116;; handles the cases of 0 and 1 arguments.
117;;
118(define (flags . args)
119 (cond
120 ((null? args) 0)
121 ((null? (cdr args)) (car args))
122 (else (apply logior args))))
123
124\f
0f2d19dd
JB
125;;; {Symbol Properties}
126;;;
127
128(define (symbol-property sym prop)
129 (let ((pair (assoc prop (symbol-pref sym))))
130 (and pair (cdr pair))))
131
132(define (set-symbol-property! sym prop val)
133 (let ((pair (assoc prop (symbol-pref sym))))
134 (if pair
135 (set-cdr! pair val)
136 (symbol-pset! sym (acons prop val (symbol-pref sym))))))
137
138(define (symbol-property-remove! sym prop)
139 (let ((pair (assoc prop (symbol-pref sym))))
140 (if pair
141 (symbol-pset! sym (delq! pair (symbol-pref sym))))))
142
143\f
1e531c3a
GH
144
145;;; {Line and Delimited I/O}
146
147;;; corresponds to SCM_LINE_INCREMENTORS in libguile.
148(define scm-line-incrementors "\n")
149
150(define (read-line! string . maybe-port)
151 (let* ((port (if (pair? maybe-port)
152 (car maybe-port)
153 (current-input-port))))
154 (let* ((rv (%read-delimited! scm-line-incrementors
155 string
156 #t
157 port))
158 (terminator (car rv))
159 (nchars (cdr rv)))
160 (cond ((and (= nchars 0)
161 (eof-object? terminator))
162 terminator)
163 ((not terminator) #f)
164 (else nchars)))))
165
166(define (read-delimited! delims buf . args)
167 (let* ((num-args (length args))
168 (port (if (> num-args 0)
169 (car args)
170 (current-input-port)))
171 (handle-delim (if (> num-args 1)
172 (cadr args)
173 'trim))
174 (start (if (> num-args 2)
175 (caddr args)
176 0))
177 (end (if (> num-args 3)
178 (cadddr args)
179 (string-length buf))))
180 (let* ((rv (%read-delimited! delims
181 buf
182 (not (eq? handle-delim 'peek))
183 port
184 start
185 end))
186 (terminator (car rv))
187 (nchars (cdr rv)))
188 (cond ((or (not terminator) ; buffer filled
189 (eof-object? terminator))
190 (if (zero? nchars)
191 (if (eq? handle-delim 'split)
192 (cons terminator terminator)
193 terminator)
194 (if (eq? handle-delim 'split)
195 (cons nchars terminator)
196 nchars)))
197 (else
198 (case handle-delim
199 ((trim peek) nchars)
200 ((concat) (string-set! buf nchars terminator)
201 (+ nchars 1))
202 ((split) (cons nchars terminator))
203 (else (error "unexpected handle-delim value: "
204 handle-delim))))))))
205
206(define (read-delimited delims . args)
207 (let* ((port (if (pair? args)
208 (let ((pt (car args)))
209 (set! args (cdr args))
210 pt)
211 (current-input-port)))
212 (handle-delim (if (pair? args)
213 (car args)
214 'trim)))
215 (let loop ((substrings ())
216 (total-chars 0)
217 (buf-size 100)) ; doubled each time through.
218 (let* ((buf (make-string buf-size))
219 (rv (%read-delimited! delims
220 buf
221 (not (eq? handle-delim 'peek))
222 port))
223 (terminator (car rv))
224 (nchars (cdr rv))
225 (join-substrings
226 (lambda ()
227 (apply string-append
228 (reverse
229 (cons (if (and (eq? handle-delim 'concat)
230 (not (eof-object? terminator)))
231 (string terminator)
232 "")
233 (cons (make-shared-substring buf 0 nchars)
234 substrings))))))
235 (new-total (+ total-chars nchars)))
236 (cond ((not terminator)
237 ;; buffer filled.
238 (loop (cons (substring buf 0 nchars) substrings)
239 new-total
240 (* buf-size 2)))
241 ((eof-object? terminator)
242 (if (zero? new-total)
243 (if (eq? handle-delim 'split)
244 (cons terminator terminator)
245 terminator)
246 (if (eq? handle-delim 'split)
247 (cons (join-substrings) terminator)
248 (join-substrings))))
249 (else
250 (case handle-delim
251 ((trim peek concat) (join-substrings))
252 ((split) (cons (join-substrings) terminator))
253 (else (error "unexpected handle-delim value: "
254 handle-delim)))))))))
255
256(define (read-line . args)
257 (apply read-delimited scm-line-incrementors args))
258
259\f
0f2d19dd
JB
260;;; {Arrays}
261;;;
262
263(begin
264 (define uniform-vector? array?)
265 (define make-uniform-vector dimensions->uniform-array)
266 ; (define uniform-vector-ref array-ref)
267 (define (uniform-vector-set! u i o)
c2132276 268 (uniform-array-set1! u o i))
0f2d19dd
JB
269 (define uniform-vector-fill! array-fill!)
270 (define uniform-vector-read! uniform-array-read!)
271 (define uniform-vector-write uniform-array-write)
272
273 (define (make-array fill . args)
274 (dimensions->uniform-array args () fill))
275 (define (make-uniform-array prot . args)
276 (dimensions->uniform-array args prot))
277 (define (list->array ndim lst)
278 (list->uniform-array ndim '() lst))
279 (define (list->uniform-vector prot lst)
280 (list->uniform-array 1 prot lst))
281 (define (array-shape a)
282 (map (lambda (ind) (if (number? ind) (list 0 (+ -1 ind)) ind))
283 (array-dimensions a))))
284
285\f
286;;; {Keywords}
287;;;
288
289(define (symbol->keyword symbol)
290 (make-keyword-from-dash-symbol (symbol-append '- symbol)))
291
292(define (keyword->symbol kw)
293 (let ((sym (keyword-dash-symbol kw)))
294 (string->symbol (substring sym 1 (length sym)))))
295
296(define (kw-arg-ref args kw)
297 (let ((rem (member kw args)))
298 (and rem (pair? (cdr rem)) (cadr rem))))
299
300\f
0f2d19dd
JB
301;;; {Records}
302;;;
303
304(define record-type-vtable (make-vtable-vtable "prpr" 0))
305
306(define (record-type? obj)
307 (and (struct? obj) (eq? record-type-vtable (struct-vtable obj))))
308
309(define (make-record-type type-name fields . opt)
8e693424 310 (let ((printer-fn (and (pair? opt) (car opt))))
0f2d19dd 311 (let ((struct (make-struct record-type-vtable 0
c7c03b9f
JB
312 (make-struct-layout
313 (apply symbol-append
314 (map (lambda (f) "pw") fields)))
0f2d19dd
JB
315 type-name
316 (copy-tree fields))))
317 ;; !!! leaks printer functions
6355358a
MD
318 ;; MDJ 960919 <djurfeldt@nada.kth.se>: *fixme* need to make it
319 ;; possible to print records nicely.
320 ;(if printer-fn
321; (extend-print-style! default-print-style
322; (logior utag_struct_base (ash (struct-vtable-tag struct) 8))
323; printer-fn))
0f2d19dd
JB
324 struct)))
325
326(define (record-type-name obj)
327 (if (record-type? obj)
328 (struct-ref obj struct-vtable-offset)
329 (error 'not-a-record-type obj)))
330
331(define (record-type-fields obj)
332 (if (record-type? obj)
333 (struct-ref obj (+ 1 struct-vtable-offset))
334 (error 'not-a-record-type obj)))
335
336(define (record-constructor rtd . opt)
8e693424 337 (let ((field-names (if (pair? opt) (car opt) (record-type-fields rtd))))
0f2d19dd
JB
338 (eval `(lambda ,field-names
339 (make-struct ',rtd 0 ,@(map (lambda (f)
340 (if (memq f field-names)
341 f
342 #f))
343 (record-type-fields rtd)))))))
344
345(define (record-predicate rtd)
346 (lambda (obj) (and (struct? obj) (eq? rtd (struct-vtable obj)))))
347
348(define (record-accessor rtd field-name)
349 (let* ((pos (list-index (record-type-fields rtd) field-name)))
350 (if (not pos)
351 (error 'no-such-field field-name))
352 (eval `(lambda (obj)
353 (and (eq? ',rtd (record-type-descriptor obj))
354 (struct-ref obj ,pos))))))
355
356(define (record-modifier rtd field-name)
357 (let* ((pos (list-index (record-type-fields rtd) field-name)))
358 (if (not pos)
359 (error 'no-such-field field-name))
360 (eval `(lambda (obj val)
361 (and (eq? ',rtd (record-type-descriptor obj))
362 (struct-set! obj ,pos val))))))
363
364
365(define (record? obj)
366 (and (struct? obj) (record-type? (struct-vtable obj))))
367
368(define (record-type-descriptor obj)
369 (if (struct? obj)
370 (struct-vtable obj)
371 (error 'not-a-record obj)))
372
21ed9efe
MD
373(provide 'record)
374
0f2d19dd
JB
375\f
376;;; {Booleans}
377;;;
378
379(define (->bool x) (not (not x)))
380
381\f
382;;; {Symbols}
383;;;
384
385(define (symbol-append . args)
386 (string->symbol (apply string-append args)))
387
388(define (list->symbol . args)
389 (string->symbol (apply list->string args)))
390
391(define (symbol . args)
392 (string->symbol (apply string args)))
393
394(define (obarray-symbol-append ob . args)
395 (string->obarray-symbol (apply string-append ob args)))
396
397(define obarray-gensym
398 (let ((n -1))
399 (lambda (obarray . opt)
400 (if (null? opt)
401 (set! opt '(%%gensym)))
402 (let loop ((proposed-name (apply string-append opt)))
403 (if (string->obarray-symbol obarray proposed-name #t)
404 (loop (apply string-append (append opt (begin (set! n (1+ n)) (list (number->string n))))))
405 (string->obarray-symbol obarray proposed-name))))))
406
407(define (gensym . args) (apply obarray-gensym #f args))
408
409\f
410;;; {Lists}
411;;;
412
413(define (list-index l k)
414 (let loop ((n 0)
415 (l l))
416 (and (not (null? l))
417 (if (eq? (car l) k)
418 n
419 (loop (+ n 1) (cdr l))))))
420
421(define (make-list n init)
422 (let loop ((answer '())
423 (n n))
424 (if (<= n 0)
425 answer
426 (loop (cons init answer) (- n 1)))))
427
428
429\f
430;;; {and-map, or-map, and map-in-order}
431;;;
432;;; (and-map fn lst) is like (and (fn (car lst)) (fn (cadr lst)) (fn...) ...)
433;;; (or-map fn lst) is like (or (fn (car lst)) (fn (cadr lst)) (fn...) ...)
434;;; (map-in-order fn lst) is like (map fn lst) but definately in order of lst.
435;;;
436
437;; and-map f l
438;;
439;; Apply f to successive elements of l until exhaustion or f returns #f.
440;; If returning early, return #f. Otherwise, return the last value returned
441;; by f. If f has never been called because l is empty, return #t.
442;;
443(define (and-map f lst)
444 (let loop ((result #t)
445 (l lst))
446 (and result
447 (or (and (null? l)
448 result)
449 (loop (f (car l)) (cdr l))))))
450
451;; or-map f l
452;;
453;; Apply f to successive elements of l until exhaustion or while f returns #f.
454;; If returning early, return the return value of f.
455;;
456(define (or-map f lst)
457 (let loop ((result #f)
458 (l lst))
459 (or result
460 (and (not (null? l))
461 (loop (f (car l)) (cdr l))))))
462
463;; map-in-order
464;;
465;; Like map, but guaranteed to process the list in order.
466;;
467(define (map-in-order fn l)
468 (if (null? l)
469 '()
470 (cons (fn (car l))
471 (map-in-order fn (cdr l)))))
472
473\f
59e1116d
MD
474;;; {Hooks}
475(define (run-hooks hook)
476 (for-each (lambda (thunk) (thunk)) hook))
477
478(define add-hook!
479 (procedure->macro
480 (lambda (exp env)
481 `(let ((thunk ,(caddr exp)))
482 (if (not (memq thunk ,(cadr exp)))
483 (set! ,(cadr exp)
484 (cons thunk ,(cadr exp))))))))
485
486\f
0f2d19dd
JB
487;;; {Files}
488;;; !!!! these should be implemented using Tcl commands, not fports.
489;;;
490
6fa8995c
GH
491(define (feature? feature)
492 (and (memq feature *features*) #t))
493
3afb28ce
GH
494;; Using the vector returned by stat directly is probably not a good
495;; idea (it could just as well be a record). Hence some accessors.
496(define (stat:dev f) (vector-ref f 0))
497(define (stat:ino f) (vector-ref f 1))
498(define (stat:mode f) (vector-ref f 2))
499(define (stat:nlink f) (vector-ref f 3))
500(define (stat:uid f) (vector-ref f 4))
501(define (stat:gid f) (vector-ref f 5))
502(define (stat:rdev f) (vector-ref f 6))
503(define (stat:size f) (vector-ref f 7))
504(define (stat:atime f) (vector-ref f 8))
505(define (stat:mtime f) (vector-ref f 9))
506(define (stat:ctime f) (vector-ref f 10))
507(define (stat:blksize f) (vector-ref f 11))
508(define (stat:blocks f) (vector-ref f 12))
509
510;; derived from stat mode.
511(define (stat:type f) (vector-ref f 13))
512(define (stat:perms f) (vector-ref f 14))
513
6fa8995c
GH
514(define file-exists?
515 (if (feature? 'posix)
516 (lambda (str)
517 (access? str F_OK))
518 (lambda (str)
519 (let ((port (catch 'system-error (lambda () (open-file str OPEN_READ))
520 (lambda args #f))))
521 (if port (begin (close-port port) #t)
522 #f)))))
523
524(define file-is-directory?
525 (if (feature? 'i/o-extensions)
526 (lambda (str)
3afb28ce 527 (eq? (stat:type (stat str)) 'directory))
6fa8995c
GH
528 (lambda (str)
529 (display str)
530 (newline)
531 (let ((port (catch 'system-error
532 (lambda () (open-file (string-append str "/.")
533 OPEN_READ))
534 (lambda args #f))))
535 (if port (begin (close-port port) #t)
536 #f)))))
0f2d19dd
JB
537
538(define (has-suffix? str suffix)
539 (let ((sufl (string-length suffix))
540 (sl (string-length str)))
541 (and (> sl sufl)
542 (string=? (substring str (- sl sufl) sl) suffix))))
543
0f2d19dd
JB
544\f
545;;; {Error Handling}
546;;;
547
0f2d19dd 548(define (error . args)
21ed9efe 549 (save-stack)
2194b6f0 550 (if (null? args)
5552355a 551 (scm-error 'misc-error #f "?" #f #f)
2194b6f0
GH
552 (let loop ((msg "%s")
553 (rest (cdr args)))
554 (if (not (null? rest))
555 (loop (string-append msg " %S")
556 (cdr rest))
5552355a 557 (scm-error 'misc-error #f msg args #f)))))
be2d2c70 558
1349bd53 559;; bad-throw is the hook that is called upon a throw to a an unhandled
9a0d70e2
GH
560;; key (unless the throw has four arguments, in which case
561;; it's usually interpreted as an error throw.)
562;; If the key has a default handler (a throw-handler-default property),
0f2d19dd
JB
563;; it is applied to the throw.
564;;
1349bd53 565(define (bad-throw key . args)
0f2d19dd
JB
566 (let ((default (symbol-property key 'throw-handler-default)))
567 (or (and default (apply default key args))
2194b6f0 568 (apply error "unhandled-exception:" key args))))
0f2d19dd 569
2194b6f0
GH
570;; mostly obsolete.
571;; A number of internally defined error types were represented
0f2d19dd
JB
572;; as integers. Here is the mapping to symbolic names
573;; and error messages.
574;;
2194b6f0
GH
575;(define %%system-errors
576; '((-1 UNKNOWN "Unknown error")
577; (0 ARGn "Wrong type argument to ")
578; (1 ARG1 "Wrong type argument in position 1 to ")
579; (2 ARG2 "Wrong type argument in position 2 to ")
580; (3 ARG3 "Wrong type argument in position 3 to ")
581; (4 ARG4 "Wrong type argument in position 4 to ")
582; (5 ARG5 "Wrong type argument in position 5 to ")
583; (6 ARG5 "Wrong type argument in position 5 to ")
584; (7 ARG5 "Wrong type argument in position 5 to ")
585; (8 WNA "Wrong number of arguments to ")
586; (9 OVFLOW "Numerical overflow to ")
587; (10 OUTOFRANGE "Argument out of range to ")
588; (11 NALLOC "Could not allocate to ")
589; (12 STACK_OVFLOW "Stack overflow")
590; (13 EXIT "Exit (internal error?).")
591; (14 HUP_SIGNAL "hang-up")
592; (15 INT_SIGNAL "user interrupt")
593; (16 FPE_SIGNAL "arithmetic error")
594; (17 BUS_SIGNAL "bus error")
595; (18 SEGV_SIGNAL "segmentation violation")
596; (19 ALRM_SIGNAL "alarm")
597; (20 GC_SIGNAL "gc")
598; (21 TICK_SIGNAL "tick")))
0f2d19dd
JB
599
600
0f2d19dd
JB
601(define (alarm-thunk) #t)
602
603(define (signal-handler n)
2194b6f0
GH
604 (let* (
605 ;; these numbers are set in libguile, not the same as those
be2d2c70 606 ;; interned in posix.c for SIGSEGV etc.
2194b6f0
GH
607 ;;
608 (signal-messages `((14 . "hang-up")
609 (15 . "user interrupt")
610 (16 . "arithmetic error")
611 (17 . "bus error")
612 (18 . "segmentation violation"))))
613 (cond
614 ((= n 21) (unmask-signals) (timer-thunk))
615 ((= n 20) (unmask-signals) (gc-thunk))
616 ((= n 19) (unmask-signals) (alarm-thunk))
1c6cd8e8
MD
617 (else (set! the-last-stack
618 (make-stack #t
619 (list-ref (list %hup-thunk
620 %int-thunk
621 %fpe-thunk
622 %bus-thunk
623 %segv-thunk)
624 (- n 14))
625 1))
21ed9efe
MD
626 (set! stack-saved? #t)
627 (if (not (and (memq 'debug (debug-options-interface))
628 (eq? (stack-id the-last-stack) 'repl-stack)))
5f771ab1
MD
629 (set! the-last-stack #f))
630 (unmask-signals)
2194b6f0 631 (let ((sig-pair (assoc n signal-messages)))
5552355a
GH
632 (scm-error 'error-signal #f
633 (cdr (or sig-pair
6fa8995c 634 (cons n "Unknown signal: %s")))
5552355a
GH
635 (if sig-pair
636 #f
637 (list n))
638 (list n)))))))
2194b6f0 639
0f2d19dd 640\f
44cf1f0f
JB
641;;; {Non-polymorphic versions of POSIX functions}
642
02b754d3
GH
643(define (getgrnam name) (getgr name))
644(define (getgrgid id) (getgr id))
645(define (gethostbyaddr addr) (gethost addr))
646(define (gethostbyname name) (gethost name))
647(define (getnetbyaddr addr) (getnet addr))
648(define (getnetbyname name) (getnet name))
649(define (getprotobyname name) (getproto name))
650(define (getprotobynumber addr) (getproto addr))
651(define (getpwnam name) (getpw name))
652(define (getpwuid uid) (getpw uid))
920235cc
GH
653(define (getservbyname name proto) (getserv name proto))
654(define (getservbyport port proto) (getserv port proto))
0f2d19dd
JB
655(define (endgrent) (setgr))
656(define (endhostent) (sethost))
657(define (endnetent) (setnet))
658(define (endprotoent) (setproto))
659(define (endpwent) (setpw))
660(define (endservent) (setserv))
02b754d3
GH
661(define (getgrent) (getgr))
662(define (gethostent) (gethost))
663(define (getnetent) (getnet))
664(define (getprotoent) (getproto))
665(define (getpwent) (getpw))
666(define (getservent) (getserv))
0f2d19dd 667(define (reopen-file . args) (apply freopen args))
bce074ee
GH
668(define (setgrent) (setgr #f))
669(define (sethostent) (sethost #t))
670(define (setnetent) (setnet #t))
671(define (setprotoent) (setproto #t))
672(define (setpwent) (setpw #t))
673(define (setservent) (setserv #t))
674
675(define (passwd:name obj) (vector-ref obj 0))
676(define (passwd:passwd obj) (vector-ref obj 1))
677(define (passwd:uid obj) (vector-ref obj 2))
678(define (passwd:gid obj) (vector-ref obj 3))
679(define (passwd:gecos obj) (vector-ref obj 4))
680(define (passwd:dir obj) (vector-ref obj 5))
681(define (passwd:shell obj) (vector-ref obj 6))
682
683(define (group:name obj) (vector-ref obj 0))
684(define (group:passwd obj) (vector-ref obj 1))
685(define (group:gid obj) (vector-ref obj 2))
686(define (group:mem obj) (vector-ref obj 3))
687
688(define (hostent:name obj) (vector-ref obj 0))
689(define (hostent:aliases obj) (vector-ref obj 1))
690(define (hostent:addrtype obj) (vector-ref obj 2))
691(define (hostent:length obj) (vector-ref obj 3))
692(define (hostent:addr-list obj) (vector-ref obj 4))
693
694(define (netent:name obj) (vector-ref obj 0))
695(define (netent:aliases obj) (vector-ref obj 1))
9337637f
GH
696(define (netent:addrtype obj) (vector-ref obj 2))
697(define (netent:net obj) (vector-ref obj 3))
bce074ee
GH
698
699(define (protoent:name obj) (vector-ref obj 0))
700(define (protoent:aliases obj) (vector-ref obj 1))
701(define (protoent:proto obj) (vector-ref obj 2))
702
703(define (servent:name obj) (vector-ref obj 0))
704(define (servent:aliases obj) (vector-ref obj 1))
9337637f
GH
705(define (servent:port obj) (vector-ref obj 2))
706(define (servent:proto obj) (vector-ref obj 3))
707
708(define (sockaddr:fam obj) (vector-ref obj 0))
709(define (sockaddr:path obj) (vector-ref obj 1))
710(define (sockaddr:addr obj) (vector-ref obj 1))
711(define (sockaddr:port obj) (vector-ref obj 2))
712
713(define (utsname:sysname obj) (vector-ref obj 0))
714(define (utsname:nodename obj) (vector-ref obj 1))
715(define (utsname:release obj) (vector-ref obj 2))
716(define (utsname:version obj) (vector-ref obj 3))
717(define (utsname:machine obj) (vector-ref obj 4))
bce074ee 718
708bf0f3
GH
719(define (tm:sec obj) (vector-ref obj 0))
720(define (tm:min obj) (vector-ref obj 1))
721(define (tm:hour obj) (vector-ref obj 2))
722(define (tm:mday obj) (vector-ref obj 3))
723(define (tm:mon obj) (vector-ref obj 4))
724(define (tm:year obj) (vector-ref obj 5))
725(define (tm:wday obj) (vector-ref obj 6))
726(define (tm:yday obj) (vector-ref obj 7))
727(define (tm:isdst obj) (vector-ref obj 8))
728(define (tm:gmtoff obj) (vector-ref obj 9))
729(define (tm:zone obj) (vector-ref obj 10))
730
731(define (set-tm:sec obj val) (vector-set! obj 0 val))
732(define (set-tm:min obj val) (vector-set! obj 1 val))
733(define (set-tm:hour obj val) (vector-set! obj 2 val))
734(define (set-tm:mday obj val) (vector-set! obj 3 val))
735(define (set-tm:mon obj val) (vector-set! obj 4 val))
736(define (set-tm:year obj val) (vector-set! obj 5 val))
737(define (set-tm:wday obj val) (vector-set! obj 6 val))
738(define (set-tm:yday obj val) (vector-set! obj 7 val))
739(define (set-tm:isdst obj val) (vector-set! obj 8 val))
740(define (set-tm:gmtoff obj val) (vector-set! obj 9 val))
741(define (set-tm:zone obj val) (vector-set! obj 10 val))
742
bce074ee
GH
743(define (file-position . args) (apply ftell args))
744(define (file-set-position . args) (apply fseek args))
8b13c6b3 745
708bf0f3
GH
746(define (open-input-pipe command) (open-pipe command OPEN_READ))
747(define (open-output-pipe command) (open-pipe command OPEN_WRITE))
748
02b754d3 749(define (move->fdes port fd)
8b13c6b3
GH
750 (primitive-move->fdes port fd)
751 (set-port-revealed! port 1)
752 port)
753
754(define (release-port-handle port)
755 (let ((revealed (port-revealed port)))
756 (if (> revealed 0)
757 (set-port-revealed! port (- revealed 1)))))
0f2d19dd
JB
758
759\f
760;;; {Load Paths}
761;;;
762
0f2d19dd
JB
763;;; Here for backward compatability
764;;
765(define scheme-file-suffix (lambda () ".scm"))
766
3cab8392
JB
767(define (in-vicinity vicinity file)
768 (let ((tail (let ((len (string-length vicinity)))
769 (if (zero? len) #f
770 (string-ref vicinity (- len 1))))))
771 (string-append vicinity
772 (if (eq? tail #\/) "" "/")
773 file)))
02ceadb8 774
0f2d19dd 775\f
ef00e7f4
JB
776;;; {Help for scm_shell}
777;;; The argument-processing code used by Guile-based shells generates
778;;; Scheme code based on the argument list. This page contains help
779;;; functions for the code it generates.
780
781(define (eval-string string)
782 (call-with-input-string
783 string
784 (lambda (port)
785 (let loop ()
786 (let ((expr (read port)))
787 (if (eof-object? expr) #f
788 (begin (eval expr) (loop))))))))
789
790(define (command-line) (program-arguments))
791
792(define (load-user-init)
793 (define (has-init? dir)
794 (let ((path (in-vicinity dir ".guile")))
795 (catch 'system-error
796 (lambda ()
797 (let ((stats (stat path)))
798 (if (not (eq? (stat:type stats) 'directory))
799 path)))
800 (lambda dummy #f))))
801 (let ((path (or (has-init? (getenv "HOME"))
802 (has-init? (passwd:dir (getpw (getuid)))))))
803 (if path (primitive-load path))))
804
805\f
a06181a2
JB
806;;; {Loading by paths}
807
808;;; Load a Scheme source file named NAME, searching for it in the
809;;; directories listed in %load-path, and applying each of the file
810;;; name extensions listed in %load-extensions.
811(define (load-from-path name)
812 (start-stack 'load-stack
75a97b92 813 (primitive-load-path name)))
0f2d19dd 814
5552355a 815
0f2d19dd 816\f
0f2d19dd
JB
817;;; {Transcendental Functions}
818;;;
819;;; Derived from "Transcen.scm", Complex trancendental functions for SCM.
820;;; Copyright (C) 1992, 1993 Jerry D. Hedden.
821;;; See the file `COPYING' for terms applying to this program.
822;;;
823
824(define (exp z)
825 (if (real? z) ($exp z)
826 (make-polar ($exp (real-part z)) (imag-part z))))
827
828(define (log z)
829 (if (and (real? z) (>= z 0))
830 ($log z)
831 (make-rectangular ($log (magnitude z)) (angle z))))
832
833(define (sqrt z)
834 (if (real? z)
835 (if (negative? z) (make-rectangular 0 ($sqrt (- z)))
836 ($sqrt z))
837 (make-polar ($sqrt (magnitude z)) (/ (angle z) 2))))
838
839(define expt
840 (let ((integer-expt integer-expt))
841 (lambda (z1 z2)
842 (cond ((exact? z2)
843 (integer-expt z1 z2))
844 ((and (real? z2) (real? z1) (>= z1 0))
845 ($expt z1 z2))
846 (else
847 (exp (* z2 (log z1))))))))
848
849(define (sinh z)
850 (if (real? z) ($sinh z)
851 (let ((x (real-part z)) (y (imag-part z)))
852 (make-rectangular (* ($sinh x) ($cos y))
853 (* ($cosh x) ($sin y))))))
854(define (cosh z)
855 (if (real? z) ($cosh z)
856 (let ((x (real-part z)) (y (imag-part z)))
857 (make-rectangular (* ($cosh x) ($cos y))
858 (* ($sinh x) ($sin y))))))
859(define (tanh z)
860 (if (real? z) ($tanh z)
861 (let* ((x (* 2 (real-part z)))
862 (y (* 2 (imag-part z)))
863 (w (+ ($cosh x) ($cos y))))
864 (make-rectangular (/ ($sinh x) w) (/ ($sin y) w)))))
865
866(define (asinh z)
867 (if (real? z) ($asinh z)
868 (log (+ z (sqrt (+ (* z z) 1))))))
869
870(define (acosh z)
871 (if (and (real? z) (>= z 1))
872 ($acosh z)
873 (log (+ z (sqrt (- (* z z) 1))))))
874
875(define (atanh z)
876 (if (and (real? z) (> z -1) (< z 1))
877 ($atanh z)
878 (/ (log (/ (+ 1 z) (- 1 z))) 2)))
879
880(define (sin z)
881 (if (real? z) ($sin z)
882 (let ((x (real-part z)) (y (imag-part z)))
883 (make-rectangular (* ($sin x) ($cosh y))
884 (* ($cos x) ($sinh y))))))
885(define (cos z)
886 (if (real? z) ($cos z)
887 (let ((x (real-part z)) (y (imag-part z)))
888 (make-rectangular (* ($cos x) ($cosh y))
889 (- (* ($sin x) ($sinh y)))))))
890(define (tan z)
891 (if (real? z) ($tan z)
892 (let* ((x (* 2 (real-part z)))
893 (y (* 2 (imag-part z)))
894 (w (+ ($cos x) ($cosh y))))
895 (make-rectangular (/ ($sin x) w) (/ ($sinh y) w)))))
896
897(define (asin z)
898 (if (and (real? z) (>= z -1) (<= z 1))
899 ($asin z)
900 (* -i (asinh (* +i z)))))
901
902(define (acos z)
903 (if (and (real? z) (>= z -1) (<= z 1))
904 ($acos z)
905 (+ (/ (angle -1) 2) (* +i (asinh (* +i z))))))
906
907(define (atan z . y)
908 (if (null? y)
909 (if (real? z) ($atan z)
910 (/ (log (/ (- +i z) (+ +i z))) +2i))
911 ($atan2 z (car y))))
912
913(set! abs magnitude)
914
65495221
GH
915(define (log10 arg)
916 (/ (log arg) (log 10)))
917
0f2d19dd
JB
918\f
919;;; {User Settable Hooks}
920;;;
921;;; Parts of the C code check the bindings of these variables.
922;;;
923
924(define ticks-interrupt #f)
925(define user-interrupt #f)
926(define alarm-interrupt #f)
927(define out-of-storage #f)
928(define could-not-open #f)
929(define end-of-program #f)
930(define hang-up #f)
931(define arithmetic-error #f)
0f2d19dd
JB
932
933\f
934
935;;; {Reader Extensions}
936;;;
937
938;;; Reader code for various "#c" forms.
939;;;
940
941(define (parse-path-symbol s)
21ed9efe 942 (define (separate-fields-discarding-char ch str ret)
0f2d19dd
JB
943 (let loop ((fields '())
944 (str str))
945 (cond
946 ((string-rindex str ch)
947 => (lambda (pos) (loop (cons (make-shared-substring str (+ 1 pos)) fields)
948 (make-shared-substring str 0 pos))))
949 (else (ret (cons str fields))))))
21ed9efe 950 (separate-fields-discarding-char #\/
0f2d19dd
JB
951 s
952 (lambda (fields)
953 (map string->symbol fields))))
954
955
75a97b92
GH
956(read-hash-extend #\' (lambda (c port)
957 (read port)))
958(read-hash-extend #\. (lambda (c port)
959 (eval (read port))))
960
961(if (feature? 'array)
962 (begin
963 (let ((make-array-proc (lambda (template)
964 (lambda (c port)
965 (read:uniform-vector template port)))))
966 (for-each (lambda (char template)
967 (read-hash-extend char
968 (make-array-proc template)))
969 '(#\b #\a #\u #\e #\s #\i #\c)
970 '(#t #\a 1 -1 1.0 1/3 0+i)))
971 (let ((array-proc (lambda (c port)
972 (read:array c port))))
973 (for-each (lambda (char) (read-hash-extend char array-proc))
974 '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)))))
975
00c34e45
GH
976;; pushed to the beginning of the alist since it's used more than the
977;; others at present.
978(read-hash-extend #\/
979 (lambda (c port)
980 (let ((look (peek-char port)))
981 (if (or (eof-object? look)
982 (and (char? look)
983 (or (char-whitespace? look)
984 (string-index ")" look))))
985 '()
986 (parse-path-symbol (read port))))))
987
75a97b92
GH
988;(define (read-sharp c port)
989; (define (barf)
990; (error "unknown # object" c))
991
992; (case c
993; ((#\/) (let ((look (peek-char port)))
994; (if (or (eof-object? look)
995; (and (char? look)
996; (or (char-whitespace? look)
997; (string-index ")" look))))
998; '()
999; (parse-path-symbol (read port #t read-sharp)))))
1000; ((#\') (read port #t read-sharp))
1001; ((#\.) (eval (read port #t read-sharp)))
1002; ((#\b) (read:uniform-vector #t port))
1003; ((#\a) (read:uniform-vector #\a port))
1004; ((#\u) (read:uniform-vector 1 port))
1005; ((#\e) (read:uniform-vector -1 port))
1006; ((#\s) (read:uniform-vector 1.0 port))
1007; ((#\i) (read:uniform-vector 1/3 port))
1008; ((#\c) (read:uniform-vector 0+i port))
1009; ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
1010; (read:array c port))
1011; (else (barf))))
0f2d19dd
JB
1012
1013(define (read:array digit port)
1014 (define chr0 (char->integer #\0))
1015 (let ((rank (let readnum ((val (- (char->integer digit) chr0)))
1016 (if (char-numeric? (peek-char port))
1017 (readnum (+ (* 10 val)
1018 (- (char->integer (read-char port)) chr0)))
1019 val)))
1020 (prot (if (eq? #\( (peek-char port))
1021 '()
1022 (let ((c (read-char port)))
1023 (case c ((#\b) #t)
1024 ((#\a) #\a)
1025 ((#\u) 1)
1026 ((#\e) -1)
1027 ((#\s) 1.0)
1028 ((#\i) 1/3)
1029 ((#\c) 0+i)
1030 (else (error "read:array unknown option " c)))))))
1031 (if (eq? (peek-char port) #\()
75a97b92 1032 (list->uniform-array rank prot (read port))
0f2d19dd
JB
1033 (error "read:array list not found"))))
1034
1035(define (read:uniform-vector proto port)
1036 (if (eq? #\( (peek-char port))
75a97b92 1037 (list->uniform-array 1 proto (read port))
0f2d19dd
JB
1038 (error "read:uniform-vector list not found")))
1039
0f2d19dd
JB
1040\f
1041;;; {Command Line Options}
1042;;;
1043
1044(define (get-option argv kw-opts kw-args return)
1045 (cond
1046 ((null? argv)
1047 (return #f #f argv))
1048
1049 ((or (not (eq? #\- (string-ref (car argv) 0)))
1050 (eq? (string-length (car argv)) 1))
1051 (return 'normal-arg (car argv) (cdr argv)))
1052
1053 ((eq? #\- (string-ref (car argv) 1))
1054 (let* ((kw-arg-pos (or (string-index (car argv) #\=)
1055 (string-length (car argv))))
1056 (kw (symbol->keyword (substring (car argv) 2 kw-arg-pos)))
1057 (kw-opt? (member kw kw-opts))
1058 (kw-arg? (member kw kw-args))
1059 (arg (or (and (not (eq? kw-arg-pos (string-length (car argv))))
1060 (substring (car argv)
1061 (+ kw-arg-pos 1)
1062 (string-length (car argv))))
1063 (and kw-arg?
1064 (begin (set! argv (cdr argv)) (car argv))))))
1065 (if (or kw-opt? kw-arg?)
1066 (return kw arg (cdr argv))
1067 (return 'usage-error kw (cdr argv)))))
1068
1069 (else
1070 (let* ((char (substring (car argv) 1 2))
1071 (kw (symbol->keyword char)))
1072 (cond
1073
1074 ((member kw kw-opts)
1075 (let* ((rest-car (substring (car argv) 2 (string-length (car argv))))
1076 (new-argv (if (= 0 (string-length rest-car))
1077 (cdr argv)
1078 (cons (string-append "-" rest-car) (cdr argv)))))
1079 (return kw #f new-argv)))
1080
1081 ((member kw kw-args)
1082 (let* ((rest-car (substring (car argv) 2 (string-length (car argv))))
1083 (arg (if (= 0 (string-length rest-car))
1084 (cadr argv)
1085 rest-car))
1086 (new-argv (if (= 0 (string-length rest-car))
1087 (cddr argv)
1088 (cdr argv))))
1089 (return kw arg new-argv)))
1090
1091 (else (return 'usage-error kw argv)))))))
1092
1093(define (for-next-option proc argv kw-opts kw-args)
1094 (let loop ((argv argv))
1095 (get-option argv kw-opts kw-args
1096 (lambda (opt opt-arg argv)
1097 (and opt (proc opt opt-arg argv loop))))))
1098
1099(define (display-usage-report kw-desc)
1100 (for-each
1101 (lambda (kw)
1102 (or (eq? (car kw) #t)
1103 (eq? (car kw) 'else)
1104 (let* ((opt-desc kw)
1105 (help (cadr opt-desc))
1106 (opts (car opt-desc))
1107 (opts-proper (if (string? (car opts)) (cdr opts) opts))
1108 (arg-name (if (string? (car opts))
1109 (string-append "<" (car opts) ">")
1110 ""))
1111 (left-part (string-append
1112 (with-output-to-string
1113 (lambda ()
1114 (map (lambda (x) (display (keyword-symbol x)) (display " "))
1115 opts-proper)))
1116 arg-name))
1117 (middle-part (if (and (< (length left-part) 30)
1118 (< (length help) 40))
1119 (make-string (- 30 (length left-part)) #\ )
1120 "\n\t")))
1121 (display left-part)
1122 (display middle-part)
1123 (display help)
1124 (newline))))
1125 kw-desc))
1126
1127
1128
0f2d19dd
JB
1129(define (transform-usage-lambda cases)
1130 (let* ((raw-usage (delq! 'else (map car cases)))
1131 (usage-sans-specials (map (lambda (x)
1132 (or (and (not (list? x)) x)
1133 (and (symbol? (car x)) #t)
1134 (and (boolean? (car x)) #t)
1135 x))
1136 raw-usage))
ed440df5 1137 (usage-desc (delq! #t usage-sans-specials))
0f2d19dd
JB
1138 (kw-desc (map car usage-desc))
1139 (kw-opts (apply append (map (lambda (x) (and (not (string? (car x))) x)) kw-desc)))
1140 (kw-args (apply append (map (lambda (x) (and (string? (car x)) (cdr x))) kw-desc)))
1141 (transmogrified-cases (map (lambda (case)
1142 (cons (let ((opts (car case)))
1143 (if (or (boolean? opts) (eq? 'else opts))
1144 opts
1145 (cond
1146 ((symbol? (car opts)) opts)
1147 ((boolean? (car opts)) opts)
1148 ((string? (caar opts)) (cdar opts))
1149 (else (car opts)))))
1150 (cdr case)))
1151 cases)))
1152 `(let ((%display-usage (lambda () (display-usage-report ',usage-desc))))
1153 (lambda (%argv)
1154 (let %next-arg ((%argv %argv))
1155 (get-option %argv
1156 ',kw-opts
1157 ',kw-args
1158 (lambda (%opt %arg %new-argv)
1159 (case %opt
1160 ,@ transmogrified-cases))))))))
1161
1162
1163\f
1164
1165;;; {Low Level Modules}
1166;;;
1167;;; These are the low level data structures for modules.
1168;;;
1169;;; !!! warning: The interface to lazy binder procedures is going
1170;;; to be changed in an incompatible way to permit all the basic
1171;;; module ops to be virtualized.
1172;;;
1173;;; (make-module size use-list lazy-binding-proc) => module
1174;;; module-{obarray,uses,binder}[|-set!]
1175;;; (module? obj) => [#t|#f]
1176;;; (module-locally-bound? module symbol) => [#t|#f]
1177;;; (module-bound? module symbol) => [#t|#f]
1178;;; (module-symbol-locally-interned? module symbol) => [#t|#f]
1179;;; (module-symbol-interned? module symbol) => [#t|#f]
1180;;; (module-local-variable module symbol) => [#<variable ...> | #f]
1181;;; (module-variable module symbol) => [#<variable ...> | #f]
1182;;; (module-symbol-binding module symbol opt-value)
1183;;; => [ <obj> | opt-value | an error occurs ]
1184;;; (module-make-local-var! module symbol) => #<variable...>
1185;;; (module-add! module symbol var) => unspecified
1186;;; (module-remove! module symbol) => unspecified
1187;;; (module-for-each proc module) => unspecified
1188;;; (make-scm-module) => module ; a lazy copy of the symhash module
1189;;; (set-current-module module) => unspecified
1190;;; (current-module) => #<module...>
1191;;;
1192;;;
1193
1194\f
44cf1f0f
JB
1195;;; {Printing Modules}
1196;; This is how modules are printed. You can re-define it.
0f2d19dd
JB
1197;;
1198(define (%print-module mod port depth length style table)
1199 (display "#<" port)
1200 (display (or (module-kind mod) "module") port)
1201 (let ((name (module-name mod)))
1202 (if name
1203 (begin
1204 (display " " port)
1205 (display name port))))
1206 (display " " port)
1207 (display (number->string (object-address mod) 16) port)
1208 (display ">" port))
1209
1210;; module-type
1211;;
1212;; A module is characterized by an obarray in which local symbols
1213;; are interned, a list of modules, "uses", from which non-local
1214;; bindings can be inherited, and an optional lazy-binder which
31d50456 1215;; is a (CLOSURE module symbol) which, as a last resort, can provide
0f2d19dd
JB
1216;; bindings that would otherwise not be found locally in the module.
1217;;
1218(define module-type
31d50456 1219 (make-record-type 'module '(obarray uses binder eval-closure name kind)
8b718458 1220 %print-module))
0f2d19dd 1221
8b718458 1222;; make-module &opt size uses binder
0f2d19dd 1223;;
8b718458
JB
1224;; Create a new module, perhaps with a particular size of obarray,
1225;; initial uses list, or binding procedure.
0f2d19dd 1226;;
0f2d19dd
JB
1227(define make-module
1228 (lambda args
0f2d19dd 1229
8b718458
JB
1230 (define (parse-arg index default)
1231 (if (> (length args) index)
1232 (list-ref args index)
1233 default))
1234
1235 (if (> (length args) 3)
1236 (error "Too many args to make-module." args))
0f2d19dd 1237
8b718458
JB
1238 (let ((size (parse-arg 0 1021))
1239 (uses (parse-arg 1 '()))
1240 (binder (parse-arg 2 #f)))
0f2d19dd 1241
8b718458
JB
1242 (if (not (integer? size))
1243 (error "Illegal size to make-module." size))
1244 (if (not (and (list? uses)
1245 (and-map module? uses)))
1246 (error "Incorrect use list." uses))
0f2d19dd
JB
1247 (if (and binder (not (procedure? binder)))
1248 (error
1249 "Lazy-binder expected to be a procedure or #f." binder))
1250
8b718458
JB
1251 (let ((module (module-constructor (make-vector size '())
1252 uses binder #f #f #f)))
1253
1254 ;; We can't pass this as an argument to module-constructor,
1255 ;; because we need it to close over a pointer to the module
1256 ;; itself.
31d50456 1257 (set-module-eval-closure! module
8b718458
JB
1258 (lambda (symbol define?)
1259 (if define?
1260 (module-make-local-var! module symbol)
1261 (module-variable module symbol))))
1262
1263 module))))
0f2d19dd 1264
8b718458 1265(define module-constructor (record-constructor module-type))
0f2d19dd
JB
1266(define module-obarray (record-accessor module-type 'obarray))
1267(define set-module-obarray! (record-modifier module-type 'obarray))
1268(define module-uses (record-accessor module-type 'uses))
1269(define set-module-uses! (record-modifier module-type 'uses))
1270(define module-binder (record-accessor module-type 'binder))
1271(define set-module-binder! (record-modifier module-type 'binder))
31d50456
JB
1272(define module-eval-closure (record-accessor module-type 'eval-closure))
1273(define set-module-eval-closure! (record-modifier module-type 'eval-closure))
0f2d19dd
JB
1274(define module-name (record-accessor module-type 'name))
1275(define set-module-name! (record-modifier module-type 'name))
1276(define module-kind (record-accessor module-type 'kind))
1277(define set-module-kind! (record-modifier module-type 'kind))
1278(define module? (record-predicate module-type))
1279
8b718458 1280
0f2d19dd 1281(define (eval-in-module exp module)
31d50456 1282 (eval2 exp (module-eval-closure module)))
0f2d19dd
JB
1283
1284\f
1285;;; {Module Searching in General}
1286;;;
1287;;; We sometimes want to look for properties of a symbol
1288;;; just within the obarray of one module. If the property
1289;;; holds, then it is said to hold ``locally'' as in, ``The symbol
1290;;; DISPLAY is locally rebound in the module `safe-guile'.''
1291;;;
1292;;;
1293;;; Other times, we want to test for a symbol property in the obarray
1294;;; of M and, if it is not found there, try each of the modules in the
1295;;; uses list of M. This is the normal way of testing for some
1296;;; property, so we state these properties without qualification as
1297;;; in: ``The symbol 'fnord is interned in module M because it is
1298;;; interned locally in module M2 which is a member of the uses list
1299;;; of M.''
1300;;;
1301
1302;; module-search fn m
1303;;
1304;; return the first non-#f result of FN applied to M and then to
1305;; the modules in the uses of m, and so on recursively. If all applications
1306;; return #f, then so does this function.
1307;;
1308(define (module-search fn m v)
1309 (define (loop pos)
1310 (and (pair? pos)
1311 (or (module-search fn (car pos) v)
1312 (loop (cdr pos)))))
1313 (or (fn m v)
1314 (loop (module-uses m))))
1315
1316
1317;;; {Is a symbol bound in a module?}
1318;;;
1319;;; Symbol S in Module M is bound if S is interned in M and if the binding
1320;;; of S in M has been set to some well-defined value.
1321;;;
1322
1323;; module-locally-bound? module symbol
1324;;
1325;; Is a symbol bound (interned and defined) locally in a given module?
1326;;
1327(define (module-locally-bound? m v)
1328 (let ((var (module-local-variable m v)))
1329 (and var
1330 (variable-bound? var))))
1331
1332;; module-bound? module symbol
1333;;
1334;; Is a symbol bound (interned and defined) anywhere in a given module
1335;; or its uses?
1336;;
1337(define (module-bound? m v)
1338 (module-search module-locally-bound? m v))
1339
1340;;; {Is a symbol interned in a module?}
1341;;;
1342;;; Symbol S in Module M is interned if S occurs in
1343;;; of S in M has been set to some well-defined value.
1344;;;
1345;;; It is possible to intern a symbol in a module without providing
1346;;; an initial binding for the corresponding variable. This is done
1347;;; with:
1348;;; (module-add! module symbol (make-undefined-variable))
1349;;;
1350;;; In that case, the symbol is interned in the module, but not
1351;;; bound there. The unbound symbol shadows any binding for that
1352;;; symbol that might otherwise be inherited from a member of the uses list.
1353;;;
1354
1355(define (module-obarray-get-handle ob key)
1356 ((if (symbol? key) hashq-get-handle hash-get-handle) ob key))
1357
1358(define (module-obarray-ref ob key)
1359 ((if (symbol? key) hashq-ref hash-ref) ob key))
1360
1361(define (module-obarray-set! ob key val)
1362 ((if (symbol? key) hashq-set! hash-set!) ob key val))
1363
1364(define (module-obarray-remove! ob key)
1365 ((if (symbol? key) hashq-remove! hash-remove!) ob key))
1366
1367;; module-symbol-locally-interned? module symbol
1368;;
1369;; is a symbol interned (not neccessarily defined) locally in a given module
1370;; or its uses? Interned symbols shadow inherited bindings even if
1371;; they are not themselves bound to a defined value.
1372;;
1373(define (module-symbol-locally-interned? m v)
1374 (not (not (module-obarray-get-handle (module-obarray m) v))))
1375
1376;; module-symbol-interned? module symbol
1377;;
1378;; is a symbol interned (not neccessarily defined) anywhere in a given module
1379;; or its uses? Interned symbols shadow inherited bindings even if
1380;; they are not themselves bound to a defined value.
1381;;
1382(define (module-symbol-interned? m v)
1383 (module-search module-symbol-locally-interned? m v))
1384
1385
1386;;; {Mapping modules x symbols --> variables}
1387;;;
1388
1389;; module-local-variable module symbol
1390;; return the local variable associated with a MODULE and SYMBOL.
1391;;
1392;;; This function is very important. It is the only function that can
1393;;; return a variable from a module other than the mutators that store
1394;;; new variables in modules. Therefore, this function is the location
1395;;; of the "lazy binder" hack.
1396;;;
1397;;; If symbol is defined in MODULE, and if the definition binds symbol
1398;;; to a variable, return that variable object.
1399;;;
1400;;; If the symbols is not found at first, but the module has a lazy binder,
1401;;; then try the binder.
1402;;;
1403;;; If the symbol is not found at all, return #f.
1404;;;
1405(define (module-local-variable m v)
6fa8995c
GH
1406; (caddr
1407; (list m v
0f2d19dd
JB
1408 (let ((b (module-obarray-ref (module-obarray m) v)))
1409 (or (and (variable? b) b)
1410 (and (module-binder m)
6fa8995c
GH
1411 ((module-binder m) m v #f)))))
1412;))
0f2d19dd
JB
1413
1414;; module-variable module symbol
1415;;
1416;; like module-local-variable, except search the uses in the
1417;; case V is not found in M.
1418;;
1419(define (module-variable m v)
1420 (module-search module-local-variable m v))
1421
1422
1423;;; {Mapping modules x symbols --> bindings}
1424;;;
1425;;; These are similar to the mapping to variables, except that the
1426;;; variable is dereferenced.
1427;;;
1428
1429;; module-symbol-binding module symbol opt-value
1430;;
1431;; return the binding of a variable specified by name within
1432;; a given module, signalling an error if the variable is unbound.
1433;; If the OPT-VALUE is passed, then instead of signalling an error,
1434;; return OPT-VALUE.
1435;;
1436(define (module-symbol-local-binding m v . opt-val)
1437 (let ((var (module-local-variable m v)))
1438 (if var
1439 (variable-ref var)
1440 (if (not (null? opt-val))
1441 (car opt-val)
1442 (error "Locally unbound variable." v)))))
1443
1444;; module-symbol-binding module symbol opt-value
1445;;
1446;; return the binding of a variable specified by name within
1447;; a given module, signalling an error if the variable is unbound.
1448;; If the OPT-VALUE is passed, then instead of signalling an error,
1449;; return OPT-VALUE.
1450;;
1451(define (module-symbol-binding m v . opt-val)
1452 (let ((var (module-variable m v)))
1453 (if var
1454 (variable-ref var)
1455 (if (not (null? opt-val))
1456 (car opt-val)
1457 (error "Unbound variable." v)))))
1458
1459
1460\f
1461;;; {Adding Variables to Modules}
1462;;;
1463;;;
1464
1465
1466;; module-make-local-var! module symbol
1467;;
1468;; ensure a variable for V in the local namespace of M.
1469;; If no variable was already there, then create a new and uninitialzied
1470;; variable.
1471;;
1472(define (module-make-local-var! m v)
1473 (or (let ((b (module-obarray-ref (module-obarray m) v)))
1474 (and (variable? b) b))
1475 (and (module-binder m)
1476 ((module-binder m) m v #t))
1477 (begin
1478 (let ((answer (make-undefined-variable v)))
1479 (module-obarray-set! (module-obarray m) v answer)
1480 answer))))
1481
1482;; module-add! module symbol var
1483;;
1484;; ensure a particular variable for V in the local namespace of M.
1485;;
1486(define (module-add! m v var)
1487 (if (not (variable? var))
1488 (error "Bad variable to module-add!" var))
1489 (module-obarray-set! (module-obarray m) v var))
1490
1491;; module-remove!
1492;;
1493;; make sure that a symbol is undefined in the local namespace of M.
1494;;
1495(define (module-remove! m v)
1496 (module-obarray-remove! (module-obarray m) v))
1497
1498(define (module-clear! m)
1499 (vector-fill! (module-obarray m) '()))
1500
1501;; MODULE-FOR-EACH -- exported
1502;;
1503;; Call PROC on each symbol in MODULE, with arguments of (SYMBOL VARIABLE).
1504;;
1505(define (module-for-each proc module)
1506 (let ((obarray (module-obarray module)))
1507 (do ((index 0 (+ index 1))
1508 (end (vector-length obarray)))
1509 ((= index end))
1510 (for-each
1511 (lambda (bucket)
1512 (proc (car bucket) (cdr bucket)))
1513 (vector-ref obarray index)))))
1514
1515
1516(define (module-map proc module)
1517 (let* ((obarray (module-obarray module))
1518 (end (vector-length obarray)))
1519
1520 (let loop ((i 0)
1521 (answer '()))
1522 (if (= i end)
1523 answer
1524 (loop (+ 1 i)
1525 (append!
1526 (map (lambda (bucket)
1527 (proc (car bucket) (cdr bucket)))
1528 (vector-ref obarray i))
1529 answer))))))
1530\f
1531
1532;;; {Low Level Bootstrapping}
1533;;;
1534
1535;; make-root-module
1536
21ed9efe 1537;; A root module uses the symhash table (the system's privileged
0f2d19dd
JB
1538;; obarray). Being inside a root module is like using SCM without
1539;; any module system.
1540;;
1541
1542
31d50456 1543(define (root-module-closure m s define?)
0f2d19dd
JB
1544 (let ((bi (and (symbol-interned? #f s)
1545 (builtin-variable s))))
1546 (and bi
1547 (or define? (variable-bound? bi))
1548 (begin
1549 (module-add! m s bi)
1550 bi))))
1551
1552(define (make-root-module)
31d50456 1553 (make-module 1019 '() root-module-closure))
0f2d19dd
JB
1554
1555
1556;; make-scm-module
1557
1558;; An scm module is a module into which the lazy binder copies
1559;; variable bindings from the system symhash table. The mapping is
1560;; one way only; newly introduced bindings in an scm module are not
1561;; copied back into the system symhash table (and can be used to override
1562;; bindings from the symhash table).
1563;;
1564
1565(define (make-scm-module)
8b718458 1566 (make-module 1019 '()
0f2d19dd
JB
1567 (lambda (m s define?)
1568 (let ((bi (and (symbol-interned? #f s)
1569 (builtin-variable s))))
1570 (and bi
1571 (variable-bound? bi)
1572 (begin
1573 (module-add! m s bi)
1574 bi))))))
1575
1576
1577
1578
1579;; the-module
1580;;
1581(define the-module #f)
1582
1583;; set-current-module module
1584;;
1585;; set the current module as viewed by the normalizer.
1586;;
1587(define (set-current-module m)
1588 (set! the-module m)
1589 (if m
31d50456
JB
1590 (set! *top-level-lookup-closure* (module-eval-closure the-module))
1591 (set! *top-level-lookup-closure* #f)))
0f2d19dd
JB
1592
1593
1594;; current-module
1595;;
1596;; return the current module as viewed by the normalizer.
1597;;
1598(define (current-module) the-module)
1599\f
1600;;; {Module-based Loading}
1601;;;
1602
1603(define (save-module-excursion thunk)
1604 (let ((inner-module (current-module))
1605 (outer-module #f))
1606 (dynamic-wind (lambda ()
1607 (set! outer-module (current-module))
1608 (set-current-module inner-module)
1609 (set! inner-module #f))
1610 thunk
1611 (lambda ()
1612 (set! inner-module (current-module))
1613 (set-current-module outer-module)
1614 (set! outer-module #f)))))
1615
0f2d19dd
JB
1616(define basic-load load)
1617
0f2d19dd
JB
1618(define (load-module . args)
1619 (save-module-excursion (lambda () (apply basic-load args))))
1620
1621
1622\f
44cf1f0f 1623;;; {MODULE-REF -- exported}
0f2d19dd
JB
1624;;
1625;; Returns the value of a variable called NAME in MODULE or any of its
1626;; used modules. If there is no such variable, then if the optional third
1627;; argument DEFAULT is present, it is returned; otherwise an error is signaled.
1628;;
1629(define (module-ref module name . rest)
1630 (let ((variable (module-variable module name)))
1631 (if (and variable (variable-bound? variable))
1632 (variable-ref variable)
1633 (if (null? rest)
1634 (error "No variable named" name 'in module)
1635 (car rest) ; default value
1636 ))))
1637
1638;; MODULE-SET! -- exported
1639;;
1640;; Sets the variable called NAME in MODULE (or in a module that MODULE uses)
1641;; to VALUE; if there is no such variable, an error is signaled.
1642;;
1643(define (module-set! module name value)
1644 (let ((variable (module-variable module name)))
1645 (if variable
1646 (variable-set! variable value)
1647 (error "No variable named" name 'in module))))
1648
1649;; MODULE-DEFINE! -- exported
1650;;
1651;; Sets the variable called NAME in MODULE to VALUE; if there is no such
1652;; variable, it is added first.
1653;;
1654(define (module-define! module name value)
1655 (let ((variable (module-local-variable module name)))
1656 (if variable
1657 (variable-set! variable value)
1658 (module-add! module name (make-variable value name)))))
1659
ed218d98
MV
1660;; MODULE-DEFINED? -- exported
1661;;
1662;; Return #t iff NAME is defined in MODULE (or in a module that MODULE
1663;; uses)
1664;;
1665(define (module-defined? module name)
1666 (let ((variable (module-variable module name)))
1667 (and variable (variable-bound? variable))))
1668
0f2d19dd
JB
1669;; MODULE-USE! module interface
1670;;
1671;; Add INTERFACE to the list of interfaces used by MODULE.
1672;;
1673(define (module-use! module interface)
1674 (set-module-uses! module
1675 (cons interface (delq! interface (module-uses module)))))
1676
1677\f
0f2d19dd
JB
1678;;; {Recursive Namespaces}
1679;;;
1680;;;
1681;;; A hierarchical namespace emerges if we consider some module to be
1682;;; root, and variables bound to modules as nested namespaces.
1683;;;
1684;;; The routines in this file manage variable names in hierarchical namespace.
1685;;; Each variable name is a list of elements, looked up in successively nested
1686;;; modules.
1687;;;
0dd5491c 1688;;; (nested-ref some-root-module '(foo bar baz))
0f2d19dd
JB
1689;;; => <value of a variable named baz in the module bound to bar in
1690;;; the module bound to foo in some-root-module>
1691;;;
1692;;;
1693;;; There are:
1694;;;
1695;;; ;; a-root is a module
1696;;; ;; name is a list of symbols
1697;;;
0dd5491c
MD
1698;;; nested-ref a-root name
1699;;; nested-set! a-root name val
1700;;; nested-define! a-root name val
1701;;; nested-remove! a-root name
0f2d19dd
JB
1702;;;
1703;;;
1704;;; (current-module) is a natural choice for a-root so for convenience there are
1705;;; also:
1706;;;
0dd5491c
MD
1707;;; local-ref name == nested-ref (current-module) name
1708;;; local-set! name val == nested-set! (current-module) name val
1709;;; local-define! name val == nested-define! (current-module) name val
1710;;; local-remove! name == nested-remove! (current-module) name
0f2d19dd
JB
1711;;;
1712
1713
0dd5491c 1714(define (nested-ref root names)
0f2d19dd
JB
1715 (let loop ((cur root)
1716 (elts names))
1717 (cond
1718 ((null? elts) cur)
1719 ((not (module? cur)) #f)
1720 (else (loop (module-ref cur (car elts) #f) (cdr elts))))))
1721
0dd5491c 1722(define (nested-set! root names val)
0f2d19dd
JB
1723 (let loop ((cur root)
1724 (elts names))
1725 (if (null? (cdr elts))
1726 (module-set! cur (car elts) val)
1727 (loop (module-ref cur (car elts)) (cdr elts)))))
1728
0dd5491c 1729(define (nested-define! root names val)
0f2d19dd
JB
1730 (let loop ((cur root)
1731 (elts names))
1732 (if (null? (cdr elts))
1733 (module-define! cur (car elts) val)
1734 (loop (module-ref cur (car elts)) (cdr elts)))))
1735
0dd5491c 1736(define (nested-remove! root names)
0f2d19dd
JB
1737 (let loop ((cur root)
1738 (elts names))
1739 (if (null? (cdr elts))
1740 (module-remove! cur (car elts))
1741 (loop (module-ref cur (car elts)) (cdr elts)))))
1742
0dd5491c
MD
1743(define (local-ref names) (nested-ref (current-module) names))
1744(define (local-set! names val) (nested-set! (current-module) names val))
1745(define (local-define names val) (nested-define! (current-module) names val))
1746(define (local-remove names) (nested-remove! (current-module) names))
0f2d19dd
JB
1747
1748
1749\f
44cf1f0f 1750;;; {#/app}
0f2d19dd
JB
1751;;;
1752;;; The root of conventionally named objects not directly in the top level.
1753;;;
1754;;; #/app/modules
1755;;; #/app/modules/guile
1756;;;
1757;;; The directory of all modules and the standard root module.
1758;;;
1759
1760(define (module-public-interface m) (module-ref m '%module-public-interface #f))
1761(define (set-module-public-interface! m i) (module-define! m '%module-public-interface i))
1762(define the-root-module (make-root-module))
1763(define the-scm-module (make-scm-module))
1764(set-module-public-interface! the-root-module the-scm-module)
1765(set-module-name! the-root-module 'the-root-module)
1766(set-module-name! the-scm-module 'the-scm-module)
1767
1768(set-current-module the-root-module)
1769
1770(define app (make-module 31))
0dd5491c
MD
1771(local-define '(app modules) (make-module 31))
1772(local-define '(app modules guile) the-root-module)
0f2d19dd
JB
1773
1774;; (define-special-value '(app modules new-ws) (lambda () (make-scm-module)))
1775
0209ca9a 1776(define (resolve-module name . maybe-autoload)
0f2d19dd 1777 (let ((full-name (append '(app modules) name)))
0dd5491c 1778 (let ((already (local-ref full-name)))
0f2d19dd
JB
1779 (or already
1780 (begin
0209ca9a 1781 (if (or (null? maybe-autoload) (car maybe-autoload))
d0cbd20c
MV
1782 (or (try-module-autoload name)
1783 (try-module-dynamic-link name)))
0f2d19dd
JB
1784 (make-modules-in (current-module) full-name))))))
1785
1786(define (beautify-user-module! module)
1787 (if (not (module-public-interface module))
1788 (let ((interface (make-module 31)))
1789 (set-module-name! interface (module-name module))
1790 (set-module-kind! interface 'interface)
1791 (set-module-public-interface! module interface)))
cc7f066c
MD
1792 (if (and (not (memq the-scm-module (module-uses module)))
1793 (not (eq? module the-root-module)))
0f2d19dd
JB
1794 (set-module-uses! module (append (module-uses module) (list the-scm-module)))))
1795
1796(define (make-modules-in module name)
1797 (if (null? name)
1798 module
1799 (cond
1800 ((module-ref module (car name) #f) => (lambda (m) (make-modules-in m (cdr name))))
1801 (else (let ((m (make-module 31)))
1802 (set-module-kind! m 'directory)
1803 (set-module-name! m (car name))
1804 (module-define! module (car name) m)
1805 (make-modules-in m (cdr name)))))))
1806
1807(define (resolve-interface name)
1808 (let ((module (resolve-module name)))
1809 (and module (module-public-interface module))))
1810
1811
1812(define %autoloader-developer-mode #t)
1813
1814(define (process-define-module args)
1815 (let* ((module-id (car args))
0209ca9a 1816 (module (resolve-module module-id #f))
0f2d19dd
JB
1817 (kws (cdr args)))
1818 (beautify-user-module! module)
0209ca9a
MV
1819 (let loop ((kws kws)
1820 (reversed-interfaces '()))
1821 (if (null? kws)
1822 (for-each (lambda (interface)
1823 (module-use! module interface))
1824 reversed-interfaces)
04798288
MD
1825 (case (cond ((keyword? (car kws))
1826 (keyword->symbol (car kws)))
90268b35
MD
1827 ((and (symbol? (car kws))
1828 (eq? (string-ref (car kws) 0) #\:))
04798288 1829 (string->symbol (substring (car kws) 1)))
90268b35 1830 (else #f))
04798288 1831 ((use-module)
0209ca9a
MV
1832 (if (not (pair? (cdr kws)))
1833 (error "unrecognized defmodule argument" kws))
1834 (let* ((used-name (cadr kws))
1835 (used-module (resolve-module used-name)))
1836 (if (not (module-ref used-module '%module-public-interface #f))
1837 (begin
1838 ((if %autoloader-developer-mode warn error)
1839 "no code for module" (module-name used-module))
1840 (beautify-user-module! used-module)))
1841 (let ((interface (module-public-interface used-module)))
1842 (if (not interface)
1843 (error "missing interface for use-module" used-module))
1844 (loop (cddr kws) (cons interface reversed-interfaces)))))
1845 (else
1846 (error "unrecognized defmodule argument" kws)))))
0f2d19dd
JB
1847 module))
1848\f
44cf1f0f 1849;;; {Autoloading modules}
0f2d19dd
JB
1850
1851(define autoloads-in-progress '())
1852
1853(define (try-module-autoload module-name)
6fa8995c 1854
0f2d19dd
JB
1855 (define (sfx name) (string-append name (scheme-file-suffix)))
1856 (let* ((reverse-name (reverse module-name))
1857 (name (car reverse-name))
1858 (dir-hint-module-name (reverse (cdr reverse-name)))
1859 (dir-hint (apply symbol-append (map (lambda (elt) (symbol-append elt "/")) dir-hint-module-name))))
0209ca9a 1860 (resolve-module dir-hint-module-name #f)
0f2d19dd
JB
1861 (and (not (autoload-done-or-in-progress? dir-hint name))
1862 (let ((didit #f))
1863 (dynamic-wind
1864 (lambda () (autoload-in-progress! dir-hint name))
1865 (lambda ()
1866 (let loop ((dirs %load-path))
1867 (and (not (null? dirs))
1868 (or
1869 (let ((d (car dirs))
1870 (trys (list
1871 dir-hint
1872 (sfx dir-hint)
1873 (in-vicinity dir-hint name)
1874 (in-vicinity dir-hint (sfx name)))))
1875 (and (or-map (lambda (f)
1876 (let ((full (in-vicinity d f)))
1877 full
6fa8995c
GH
1878 (and (file-exists? full)
1879 (not (file-is-directory? full))
0f2d19dd
JB
1880 (begin
1881 (save-module-excursion
1882 (lambda ()
5552355a
GH
1883 (load (string-append
1884 d "/" f))))
0f2d19dd
JB
1885 #t))))
1886 trys)
1887 (begin
1888 (set! didit #t)
1889 #t)))
1890 (loop (cdr dirs))))))
1891 (lambda () (set-autoloaded! dir-hint name didit)))
1892 didit))))
1893
d0cbd20c
MV
1894;;; Dynamic linking of modules
1895
1896;; Initializing a module that is written in C is a two step process.
1897;; First the module's `module init' function is called. This function
1898;; is expected to call `scm_register_module_xxx' to register the `real
1899;; init' function. Later, when the module is referenced for the first
1900;; time, this real init function is called in the right context. See
1901;; gtcltk-lib/gtcltk-module.c for an example.
1902;;
1903;; The code for the module can be in a regular shared library (so that
1904;; the `module init' function will be called when libguile is
1905;; initialized). Or it can be dynamically linked.
1906;;
1907;; You can safely call `scm_register_module_xxx' before libguile
1908;; itself is initialized. You could call it from an C++ constructor
1909;; of a static object, for example.
1910;;
1911;; To make your Guile extension into a dynamic linkable module, follow
1912;; these easy steps:
1913;;
1914;; - Find a name for your module, like #/ice-9/gtcltk
1915;; - Write a function with a name like
1916;;
1917;; scm_init_ice_9_gtcltk_module
1918;;
1919;; This is your `module init' function. It should call
1920;;
1921;; scm_register_module_xxx ("ice-9 gtcltk", scm_init_gtcltk);
1922;;
1923;; "ice-9 gtcltk" is the C version of the module name. Slashes are
1924;; replaced by spaces, the rest is untouched. `scm_init_gtcltk' is
ed218d98 1925;; the real init function that executes the usual initializations
d0cbd20c
MV
1926;; like making new smobs, etc.
1927;;
1928;; - Make a shared library with your code and a name like
1929;;
1930;; ice-9/libgtcltk.so
1931;;
1932;; and put it somewhere in %load-path.
1933;;
1934;; - Then you can simply write `:use-module #/ice-9/gtcltk' and it
1935;; will be linked automatically.
1936;;
1937;; This is all very experimental.
1938
1939(define (split-c-module-name str)
1940 (let loop ((rev '())
1941 (start 0)
1942 (pos 0)
1943 (end (string-length str)))
1944 (cond
1945 ((= pos end)
1946 (reverse (cons (string->symbol (substring str start pos)) rev)))
1947 ((eq? (string-ref str pos) #\space)
1948 (loop (cons (string->symbol (substring str start pos)) rev)
1949 (+ pos 1)
1950 (+ pos 1)
1951 end))
1952 (else
1953 (loop rev start (+ pos 1) end)))))
1954
1955(define (convert-c-registered-modules dynobj)
1956 (let ((res (map (lambda (c)
1957 (list (split-c-module-name (car c)) (cdr c) dynobj))
1958 (c-registered-modules))))
1959 (c-clear-registered-modules)
1960 res))
1961
1962(define registered-modules (convert-c-registered-modules #f))
1963
1964(define (init-dynamic-module modname)
1965 (or-map (lambda (modinfo)
1966 (if (equal? (car modinfo) modname)
1967 (let ((mod (resolve-module modname #f)))
1968 (save-module-excursion
1969 (lambda ()
1970 (set-current-module mod)
1971 (dynamic-call (cadr modinfo) (caddr modinfo))
1972 (set-module-public-interface! mod mod)))
1973 (set! registered-modules (delq! modinfo registered-modules))
1974 #t)
1975 #f))
1976 registered-modules))
1977
1978(define (dynamic-maybe-call name dynobj)
1979 (catch #t ; could use false-if-exception here
1980 (lambda ()
1981 (dynamic-call name dynobj))
1982 (lambda args
1983 #f)))
1984
ed218d98
MV
1985(define (dynamic-maybe-link filename)
1986 (catch #t ; could use false-if-exception here
1987 (lambda ()
1988 (dynamic-link filename))
1989 (lambda args
1990 #f)))
1991
d0cbd20c
MV
1992(define (find-and-link-dynamic-module module-name)
1993 (define (make-init-name mod-name)
1994 (string-append 'scm_init
1995 (list->string (map (lambda (c)
1996 (if (or (char-alphabetic? c)
1997 (char-numeric? c))
1998 c
1999 #\_))
2000 (string->list mod-name)))
2001 '_module))
2002 (let ((libname
2003 (let loop ((dirs "")
2004 (syms module-name))
2005 (cond
2006 ((null? (cdr syms))
2007 (string-append dirs "lib" (car syms) ".so"))
2008 (else
2009 (loop (string-append dirs (car syms) "/") (cdr syms))))))
2010 (init (make-init-name (apply string-append
2011 (map (lambda (s)
2012 (string-append "_" s))
2013 module-name)))))
2014 ;; (pk 'libname libname 'init init)
2015 (or-map
2016 (lambda (dir)
2017 (let ((full (in-vicinity dir libname)))
2018 ;; (pk 'trying full)
2019 (if (file-exists? full)
2020 (begin
2021 (link-dynamic-module full init)
2022 #t)
2023 #f)))
2024 %load-path)))
2025
2026(define (link-dynamic-module filename initname)
ed218d98
MV
2027 (let ((dynobj (dynamic-maybe-link filename)))
2028 (if dynobj
2029 (if (dynamic-maybe-call initname dynobj)
2030 (set! registered-modules
2031 (append! (convert-c-registered-modules dynobj)
2032 registered-modules))
2033 (begin
2034 (pk 'no_init)
2035 (dynamic-unlink dynobj))))))
2036
d0cbd20c
MV
2037(define (try-module-dynamic-link module-name)
2038 (or (init-dynamic-module module-name)
2039 (and (find-and-link-dynamic-module module-name)
2040 (init-dynamic-module module-name))))
2041
ed218d98
MV
2042
2043
0f2d19dd
JB
2044(define autoloads-done '((guile . guile)))
2045
2046(define (autoload-done-or-in-progress? p m)
2047 (let ((n (cons p m)))
2048 (->bool (or (member n autoloads-done)
2049 (member n autoloads-in-progress)))))
2050
2051(define (autoload-done! p m)
2052 (let ((n (cons p m)))
2053 (set! autoloads-in-progress
2054 (delete! n autoloads-in-progress))
2055 (or (member n autoloads-done)
2056 (set! autoloads-done (cons n autoloads-done)))))
2057
2058(define (autoload-in-progress! p m)
2059 (let ((n (cons p m)))
2060 (set! autoloads-done
2061 (delete! n autoloads-done))
2062 (set! autoloads-in-progress (cons n autoloads-in-progress))))
2063
2064(define (set-autoloaded! p m done?)
2065 (if done?
2066 (autoload-done! p m)
2067 (let ((n (cons p m)))
2068 (set! autoloads-done (delete! n autoloads-done))
2069 (set! autoloads-in-progress (delete! n autoloads-in-progress)))))
2070
2071
2072
2073
2074\f
2075;;; {Macros}
2076;;;
2077
9591db87
MD
2078(define macro-table (make-weak-key-hash-table 523))
2079(define xformer-table (make-weak-key-hash-table 523))
0f2d19dd
JB
2080
2081(define (defmacro? m) (hashq-ref macro-table m))
2082(define (assert-defmacro?! m) (hashq-set! macro-table m #t))
2083(define (defmacro-transformer m) (hashq-ref xformer-table m))
2084(define (set-defmacro-transformer! m t) (hashq-set! xformer-table m t))
2085
2086(define defmacro:transformer
2087 (lambda (f)
2088 (let* ((xform (lambda (exp env)
2089 (copy-tree (apply f (cdr exp)))))
2090 (a (procedure->memoizing-macro xform)))
2091 (assert-defmacro?! a)
2092 (set-defmacro-transformer! a f)
2093 a)))
2094
2095
2096(define defmacro
2097 (let ((defmacro-transformer
2098 (lambda (name parms . body)
2099 (let ((transformer `(lambda ,parms ,@body)))
2100 `(define ,name
2101 (,(lambda (transformer)
2102 (defmacro:transformer transformer))
2103 ,transformer))))))
2104 (defmacro:transformer defmacro-transformer)))
2105
2106(define defmacro:syntax-transformer
2107 (lambda (f)
2108 (procedure->syntax
2109 (lambda (exp env)
2110 (copy-tree (apply f (cdr exp)))))))
2111
ed218d98
MV
2112
2113;; XXX - should the definition of the car really be looked up in the
2114;; current module?
2115
0f2d19dd
JB
2116(define (macroexpand-1 e)
2117 (cond
2118 ((pair? e) (let* ((a (car e))
ed218d98 2119 (val (and (symbol? a) (local-ref (list a)))))
0f2d19dd
JB
2120 (if (defmacro? val)
2121 (apply (defmacro-transformer val) (cdr e))
2122 e)))
2123 (#t e)))
2124
2125(define (macroexpand e)
2126 (cond
2127 ((pair? e) (let* ((a (car e))
ed218d98 2128 (val (and (symbol? a) (local-ref (list a)))))
0f2d19dd
JB
2129 (if (defmacro? val)
2130 (macroexpand (apply (defmacro-transformer val) (cdr e)))
2131 e)))
2132 (#t e)))
2133
2134(define gentemp
2135 (let ((*gensym-counter* -1))
2136 (lambda ()
2137 (set! *gensym-counter* (+ *gensym-counter* 1))
2138 (string->symbol
2139 (string-append "scm:G" (number->string *gensym-counter*))))))
2140
2141
2142\f
2143
2144;;; {Running Repls}
2145;;;
2146
2147(define (repl read evaler print)
75a97b92 2148 (let loop ((source (read (current-input-port))))
0f2d19dd 2149 (print (evaler source))
75a97b92 2150 (loop (read (current-input-port)))))
0f2d19dd
JB
2151
2152;; A provisional repl that acts like the SCM repl:
2153;;
2154(define scm-repl-silent #f)
2155(define (assert-repl-silence v) (set! scm-repl-silent v))
2156
21ed9efe
MD
2157(define *unspecified* (if #f #f))
2158(define (unspecified? v) (eq? v *unspecified*))
2159
2160(define scm-repl-print-unspecified #f)
2161(define (assert-repl-print-unspecified v) (set! scm-repl-print-unspecified v))
2162
79451588 2163(define scm-repl-verbose #f)
0f2d19dd
JB
2164(define (assert-repl-verbosity v) (set! scm-repl-verbose v))
2165
e6875011 2166(define scm-repl-prompt "guile> ")
0f2d19dd 2167
e6875011
MD
2168(define (set-repl-prompt! v) (set! scm-repl-prompt v))
2169
d5d34fa1
MD
2170(define (default-lazy-handler key . args)
2171 (save-stack lazy-handler-dispatch)
2172 (apply throw key args))
2173
2174(define apply-frame-handler default-lazy-handler)
2175(define exit-frame-handler default-lazy-handler)
2176
2177(define (lazy-handler-dispatch key . args)
2178 (case key
2179 ((apply-frame)
2180 (apply apply-frame-handler key args))
2181 ((exit-frame)
2182 (apply exit-frame-handler key args))
2183 (else
2184 (apply default-lazy-handler key args))))
0f2d19dd 2185
59e1116d
MD
2186(define abort-hook '())
2187
0f2d19dd 2188(define (error-catching-loop thunk)
8e44e7a0
GH
2189 (let ((status #f))
2190 (define (loop first)
2191 (let ((next
2192 (catch #t
9a0d70e2 2193
8e44e7a0
GH
2194 (lambda ()
2195 (lazy-catch #t
2196 (lambda ()
2197 (dynamic-wind
2198 (lambda () (unmask-signals))
2199 (lambda ()
2200 (first)
2201
2202 ;; This line is needed because mark
2203 ;; doesn't do closures quite right.
2204 ;; Unreferenced locals should be
2205 ;; collected.
2206 ;;
2207 (set! first #f)
2208 (let loop ((v (thunk)))
2209 (loop (thunk)))
2210 #f)
2211 (lambda () (mask-signals))))
2212
2213 lazy-handler-dispatch))
2214
2215 (lambda (key . args)
2216 (case key
2217 ((quit)
2218 (read-line) ; discard trailing junk and linefeed.
2219 (force-output)
2220 (set! status args)
2221 #f)
2222
2223 ((switch-repl)
2224 (apply throw 'switch-repl args))
2225
2226 ((abort)
2227 ;; This is one of the closures that require
2228 ;; (set! first #f) above
2229 ;;
2230 (lambda ()
2231 (run-hooks abort-hook)
2232 (force-output)
2233 (display "ABORT: " (current-error-port))
2234 (write args (current-error-port))
2235 (newline (current-error-port))
2236 (if (and (not has-shown-debugger-hint?)
2237 (not (memq 'backtrace
2238 (debug-options-interface)))
2239 (stack? the-last-stack))
2240 (begin
2241 (newline (current-error-port))
2242 (display
2243 "Type \"(backtrace)\" to get more information.\n"
2244 (current-error-port))
2245 (set! has-shown-debugger-hint? #t)))
2246 (set! stack-saved? #f)))
2247
2248 (else
2249 ;; This is the other cons-leak closure...
2250 (lambda ()
2251 (cond ((= (length args) 4)
2252 (apply handle-system-error key args))
2253 (else
2254 (apply bad-throw key args))))))))))
2255 (if next (loop next) status)))
2256 (loop (lambda () #t))))
0f2d19dd 2257
d590bbf6 2258;;(define the-last-stack #f) Defined by scm_init_backtrace ()
21ed9efe
MD
2259(define stack-saved? #f)
2260
2261(define (save-stack . narrowing)
2262 (cond (stack-saved?)
2263 ((not (memq 'debug (debug-options-interface)))
2264 (set! the-last-stack #f)
2265 (set! stack-saved? #t))
2266 (else
2267 (set! the-last-stack
2268 (case (stack-id #t)
2269 ((repl-stack)
2270 (apply make-stack #t save-stack eval narrowing))
2271 ((load-stack)
2272 (apply make-stack #t save-stack gsubr-apply narrowing))
2273 ((tk-stack)
2274 (apply make-stack #t save-stack tk-stack-mark narrowing))
2275 ((#t)
e6875011 2276 (apply make-stack #t save-stack 0 1 narrowing))
21ed9efe
MD
2277 (else (let ((id (stack-id #t)))
2278 (and (procedure? id)
2279 (apply make-stack #t save-stack id narrowing))))))
2280 (set! stack-saved? #t))))
1c6cd8e8 2281
59e1116d
MD
2282(define before-error-hook '())
2283(define after-error-hook '())
2284(define before-backtrace-hook '())
2285(define after-backtrace-hook '())
1c6cd8e8 2286
21ed9efe
MD
2287(define has-shown-debugger-hint? #f)
2288
35c5db87
GH
2289(define (handle-system-error key . args)
2290 (let ((cep (current-error-port)))
21ed9efe
MD
2291 (cond ((not (stack? the-last-stack)))
2292 ((memq 'backtrace (debug-options-interface))
59e1116d 2293 (run-hooks before-backtrace-hook)
21ed9efe
MD
2294 (newline cep)
2295 (display-backtrace the-last-stack cep)
2296 (newline cep)
59e1116d
MD
2297 (run-hooks after-backtrace-hook)))
2298 (run-hooks before-error-hook)
c27659c8 2299 (apply display-error the-last-stack cep args)
59e1116d 2300 (run-hooks after-error-hook)
35c5db87
GH
2301 (force-output cep)
2302 (throw 'abort key)))
21ed9efe 2303
0f2d19dd
JB
2304(define (quit . args)
2305 (apply throw 'quit args))
2306
7950df7c
GH
2307(define exit quit)
2308
d590bbf6
MD
2309;;(define has-shown-backtrace-hint? #f) Defined by scm_init_backtrace ()
2310
2311;; Replaced by C code:
2312;;(define (backtrace)
2313;; (if the-last-stack
2314;; (begin
2315;; (newline)
2316;; (display-backtrace the-last-stack (current-output-port))
2317;; (newline)
2318;; (if (and (not has-shown-backtrace-hint?)
2319;; (not (memq 'backtrace (debug-options-interface))))
2320;; (begin
2321;; (display
2322;;"Type \"(debug-enable 'backtrace)\" if you would like a backtrace
2323;;automatically if an error occurs in the future.\n")
2324;; (set! has-shown-backtrace-hint? #t))))
2325;; (display "No backtrace available.\n")))
21ed9efe 2326
0f2d19dd
JB
2327(define (error-catching-repl r e p)
2328 (error-catching-loop (lambda () (p (e (r))))))
2329
2330(define (gc-run-time)
2331 (cdr (assq 'gc-time-taken (gc-stats))))
2332
59e1116d
MD
2333(define before-read-hook '())
2334(define after-read-hook '())
1c6cd8e8 2335
0f2d19dd
JB
2336(define (scm-style-repl)
2337 (letrec (
2338 (start-gc-rt #f)
2339 (start-rt #f)
2340 (repl-report-reset (lambda () #f))
2341 (repl-report-start-timing (lambda ()
2342 (set! start-gc-rt (gc-run-time))
2343 (set! start-rt (get-internal-run-time))))
2344 (repl-report (lambda ()
2345 (display ";;; ")
2346 (display (inexact->exact
2347 (* 1000 (/ (- (get-internal-run-time) start-rt)
2348 internal-time-units-per-second))))
2349 (display " msec (")
2350 (display (inexact->exact
2351 (* 1000 (/ (- (gc-run-time) start-gc-rt)
2352 internal-time-units-per-second))))
2353 (display " msec in gc)\n")))
2354 (-read (lambda ()
2355 (if scm-repl-prompt
2356 (begin
e6875011
MD
2357 (display (cond ((string? scm-repl-prompt)
2358 scm-repl-prompt)
2359 ((thunk? scm-repl-prompt)
2360 (scm-repl-prompt))
2361 (else "> ")))
0f2d19dd
JB
2362 (force-output)
2363 (repl-report-reset)))
59e1116d 2364 (run-hooks before-read-hook)
75a97b92 2365 (let ((val (read (current-input-port))))
59e1116d 2366 (run-hooks after-read-hook)
0f2d19dd
JB
2367 (if (eof-object? val)
2368 (begin
7950df7c 2369 (repl-report-start-timing)
0f2d19dd
JB
2370 (if scm-repl-verbose
2371 (begin
2372 (newline)
2373 (display ";;; EOF -- quitting")
2374 (newline)))
2375 (quit 0)))
2376 val)))
2377
2378 (-eval (lambda (sourc)
2379 (repl-report-start-timing)
4cdee789 2380 (start-stack 'repl-stack (eval sourc))))
0f2d19dd
JB
2381
2382 (-print (lambda (result)
2383 (if (not scm-repl-silent)
2384 (begin
21ed9efe
MD
2385 (if (or scm-repl-print-unspecified
2386 (not (unspecified? result)))
2387 (begin
2388 (write result)
2389 (newline)))
0f2d19dd
JB
2390 (if scm-repl-verbose
2391 (repl-report))
2392 (force-output)))))
2393
8e44e7a0 2394 (-quit (lambda (args)
0f2d19dd
JB
2395 (if scm-repl-verbose
2396 (begin
2397 (display ";;; QUIT executed, repl exitting")
2398 (newline)
2399 (repl-report)))
8e44e7a0 2400 args))
0f2d19dd
JB
2401
2402 (-abort (lambda ()
2403 (if scm-repl-verbose
2404 (begin
2405 (display ";;; ABORT executed.")
2406 (newline)
2407 (repl-report)))
2408 (repl -read -eval -print))))
2409
8e44e7a0
GH
2410 (let ((status (error-catching-repl -read
2411 -eval
2412 -print)))
2413 (-quit status))))
2414
0f2d19dd 2415
8e44e7a0
GH
2416;(define (stand-alone-repl)
2417; (let ((oport (current-input-port)))
2418; (set-current-input-port *stdin*)
2419; (scm-style-repl)
2420; (set-current-input-port oport)))
0f2d19dd
JB
2421
2422
2423\f
44cf1f0f 2424;;; {IOTA functions: generating lists of numbers}
0f2d19dd
JB
2425
2426(define (reverse-iota n) (if (> n 0) (cons (1- n) (reverse-iota (1- n))) '()))
2427(define (iota n) (list-reverse! (reverse-iota n)))
2428
2429\f
2430;;; {While}
2431;;;
2432;;; with `continue' and `break'.
2433;;;
2434
2435(defmacro while (cond . body)
2436 `(letrec ((continue (lambda () (or (not ,cond) (begin (begin ,@ body) (continue)))))
2437 (break (lambda val (apply throw 'break val))))
2438 (catch 'break
2439 (lambda () (continue))
2440 (lambda v (cadr v)))))
2441
2442
2443\f
2444
2445;;; {Macros}
2446;;;
2447
2448;; actually....hobbit might be able to hack these with a little
2449;; coaxing
2450;;
2451
2452(defmacro define-macro (first . rest)
2453 (let ((name (if (symbol? first) first (car first)))
2454 (transformer
2455 (if (symbol? first)
2456 (car rest)
2457 `(lambda ,(cdr first) ,@rest))))
2458 `(define ,name (defmacro:transformer ,transformer))))
2459
2460
2461(defmacro define-syntax-macro (first . rest)
2462 (let ((name (if (symbol? first) first (car first)))
2463 (transformer
2464 (if (symbol? first)
2465 (car rest)
2466 `(lambda ,(cdr first) ,@rest))))
2467 `(define ,name (defmacro:syntax-transformer ,transformer))))
2468\f
2469;;; {Module System Macros}
2470;;;
2471
2472(defmacro define-module args
2473 `(let* ((process-define-module process-define-module)
2474 (set-current-module set-current-module)
2475 (module (process-define-module ',args)))
2476 (set-current-module module)
2477 module))
2478
89da9036
MV
2479;; the guts of the use-modules macro. add the interfaces of the named
2480;; modules to the use-list of the current module, in order
2481(define (process-use-modules module-names)
2482 (for-each (lambda (module-name)
2483 (let ((mod-iface (resolve-interface module-name)))
2484 (or mod-iface
2485 (error "no such module" module-name))
2486 (module-use! (current-module) mod-iface)))
2487 (reverse module-names)))
2488
33cf699f 2489(defmacro use-modules modules
89da9036 2490 `(process-use-modules ',modules))
33cf699f 2491
0f2d19dd
JB
2492(define define-private define)
2493
2494(defmacro define-public args
2495 (define (syntax)
2496 (error "bad syntax" (list 'define-public args)))
2497 (define (defined-name n)
2498 (cond
2499 ((symbol? n) n)
2500 ((pair? n) (defined-name (car n)))
2501 (else (syntax))))
2502 (cond
2503 ((null? args) (syntax))
2504
2505 (#t (let ((name (defined-name (car args))))
2506 `(begin
2507 (let ((public-i (module-public-interface (current-module))))
2508 ;; Make sure there is a local variable:
2509 ;;
2510 (module-define! (current-module)
2511 ',name
2512 (module-ref (current-module) ',name #f))
2513
2514 ;; Make sure that local is exported:
2515 ;;
2516 (module-add! public-i ',name (module-variable (current-module) ',name)))
2517
2518 ;; Now (re)define the var normally.
2519 ;;
2520 (define-private ,@ args))))))
2521
2522
2523
2524(defmacro defmacro-public args
2525 (define (syntax)
2526 (error "bad syntax" (list 'defmacro-public args)))
2527 (define (defined-name n)
2528 (cond
2529 ((symbol? n) n)
2530 (else (syntax))))
2531 (cond
2532 ((null? args) (syntax))
2533
2534 (#t (let ((name (defined-name (car args))))
2535 `(begin
2536 (let ((public-i (module-public-interface (current-module))))
2537 ;; Make sure there is a local variable:
2538 ;;
2539 (module-define! (current-module)
2540 ',name
2541 (module-ref (current-module) ',name #f))
2542
2543 ;; Make sure that local is exported:
2544 ;;
2545 (module-add! public-i ',name (module-variable (current-module) ',name)))
2546
2547 ;; Now (re)define the var normally.
2548 ;;
2549 (defmacro ,@ args))))))
2550
2551
2552
2553
0f2d19dd 2554(define load load-module)
1c6cd8e8
MD
2555;(define (load . args)
2556; (start-stack 'load-stack (apply load-module args)))
0f2d19dd
JB
2557
2558
2559\f
44cf1f0f 2560;;; {I/O functions for Tcl channels (disabled)}
0f2d19dd
JB
2561
2562;; (define in-ch (get-standard-channel TCL_STDIN))
2563;; (define out-ch (get-standard-channel TCL_STDOUT))
2564;; (define err-ch (get-standard-channel TCL_STDERR))
2565;;
2566;; (define inp (%make-channel-port in-ch "r"))
2567;; (define outp (%make-channel-port out-ch "w"))
2568;; (define errp (%make-channel-port err-ch "w"))
2569;;
2570;; (define %system-char-ready? char-ready?)
2571;;
2572;; (define (char-ready? p)
2573;; (if (not (channel-port? p))
2574;; (%system-char-ready? p)
2575;; (let* ((channel (%channel-port-channel p))
2576;; (old-blocking (channel-option-ref channel :blocking)))
2577;; (dynamic-wind
2578;; (lambda () (set-channel-option the-root-tcl-interpreter channel :blocking "0"))
2579;; (lambda () (not (eof-object? (peek-char p))))
2580;; (lambda () (set-channel-option the-root-tcl-interpreter channel :blocking old-blocking))))))
2581;;
2582;; (define (top-repl)
2583;; (with-input-from-port inp
2584;; (lambda ()
2585;; (with-output-to-port outp
2586;; (lambda ()
2587;; (with-error-to-port errp
2588;; (lambda ()
2589;; (scm-style-repl))))))))
2590;;
2591;; (set-current-input-port inp)
2592;; (set-current-output-port outp)
2593;; (set-current-error-port errp)
2594
8e44e7a0 2595(define (top-repl)
1a36eef2 2596 (scm-style-repl))
0f2d19dd 2597
02b754d3
GH
2598(defmacro false-if-exception (expr)
2599 `(catch #t (lambda () ,expr)
2600 (lambda args #f)))
2601
0f2d19dd 2602\f
44cf1f0f 2603;;; {Calling Conventions}
0f2d19dd
JB
2604(define-module (ice-9 calling))
2605
2606;;;;
0f2d19dd
JB
2607;;;
2608;;; This file contains a number of macros that support
2609;;; common calling conventions.
2610
2611;;;
2612;;; with-excursion-function <vars> proc
2613;;; <vars> is an unevaluated list of names that are bound in the caller.
2614;;; proc is a procedure, called:
2615;;; (proc excursion)
2616;;;
2617;;; excursion is a procedure isolates all changes to <vars>
2618;;; in the dynamic scope of the call to proc. In other words,
2619;;; the values of <vars> are saved when proc is entered, and when
2620;;; proc returns, those values are restored. Values are also restored
2621;;; entering and leaving the call to proc non-locally, such as using
2622;;; call-with-current-continuation, error, or throw.
2623;;;
2624(defmacro-public with-excursion-function (vars proc)
2625 `(,proc ,(excursion-function-syntax vars)))
2626
2627
2628
2629;;; with-getter-and-setter <vars> proc
2630;;; <vars> is an unevaluated list of names that are bound in the caller.
2631;;; proc is a procedure, called:
2632;;; (proc getter setter)
2633;;;
2634;;; getter and setter are procedures used to access
2635;;; or modify <vars>.
2636;;;
2637;;; setter, called with keywords arguments, modifies the named
2638;;; values. If "foo" and "bar" are among <vars>, then:
2639;;;
2640;;; (setter :foo 1 :bar 2)
2641;;; == (set! foo 1 bar 2)
2642;;;
2643;;; getter, called with just keywords, returns
2644;;; a list of the corresponding values. For example,
2645;;; if "foo" and "bar" are among the <vars>, then
2646;;;
2647;;; (getter :foo :bar)
2648;;; => (<value-of-foo> <value-of-bar>)
2649;;;
2650;;; getter, called with no arguments, returns a list of all accepted
2651;;; keywords and the corresponding values. If "foo" and "bar" are
2652;;; the *only* <vars>, then:
2653;;;
2654;;; (getter)
2655;;; => (:foo <value-of-bar> :bar <value-of-foo>)
2656;;;
2657;;; The unusual calling sequence of a getter supports too handy
2658;;; idioms:
2659;;;
2660;;; (apply setter (getter)) ;; save and restore
2661;;;
2662;;; (apply-to-args (getter :foo :bar) ;; fetch and bind
2663;;; (lambda (foo bar) ....))
2664;;;
2665;;; ;; [ "apply-to-args" is just like two-argument "apply" except that it
2666;;; ;; takes its arguments in a different order.
2667;;;
2668;;;
2669(defmacro-public with-getter-and-setter (vars proc)
2670 `(,proc ,@ (getter-and-setter-syntax vars)))
2671
2672;;; with-getter vars proc
2673;;; A short-hand for a call to with-getter-and-setter.
2674;;; The procedure is called:
2675;;; (proc getter)
2676;;;
2677(defmacro-public with-getter (vars proc)
2678 `(,proc ,(car (getter-and-setter-syntax vars))))
2679
2680
2681;;; with-delegating-getter-and-setter <vars> get-delegate set-delegate proc
2682;;; Compose getters and setters.
2683;;;
2684;;; <vars> is an unevaluated list of names that are bound in the caller.
2685;;;
2686;;; get-delegate is called by the new getter to extend the set of
2687;;; gettable variables beyond just <vars>
2688;;; set-delegate is called by the new setter to extend the set of
2689;;; gettable variables beyond just <vars>
2690;;;
2691;;; proc is a procedure that is called
2692;;; (proc getter setter)
2693;;;
2694(defmacro-public with-delegating-getter-and-setter (vars get-delegate set-delegate proc)
2695 `(,proc ,@ (delegating-getter-and-setter-syntax vars get-delegate set-delegate)))
2696
2697
2698;;; with-delegating-getter-and-setter <vars> get-delegate set-delegate proc
2699;;; <vars> is an unevaluated list of names that are bound in the caller.
2700;;; proc is called:
2701;;;
2702;;; (proc excursion getter setter)
2703;;;
2704;;; See also:
2705;;; with-getter-and-setter
2706;;; with-excursion-function
2707;;;
2708(defmacro-public with-excursion-getter-and-setter (vars proc)
2709 `(,proc ,(excursion-function-syntax vars)
2710 ,@ (getter-and-setter-syntax vars)))
2711
2712
2713(define (excursion-function-syntax vars)
2714 (let ((saved-value-names (map gensym vars))
2715 (tmp-var-name (gensym 'temp))
2716 (swap-fn-name (gensym 'swap))
2717 (thunk-name (gensym 'thunk)))
2718 `(lambda (,thunk-name)
2719 (letrec ((,tmp-var-name #f)
2720 (,swap-fn-name
2721 (lambda () ,@ (map (lambda (n sn) `(set! ,tmp-var-name ,n ,n ,sn ,sn ,tmp-var-name))
2722 vars saved-value-names)))
2723 ,@ (map (lambda (sn n) `(,sn ,n)) saved-value-names vars))
2724 (dynamic-wind
2725 ,swap-fn-name
2726 ,thunk-name
2727 ,swap-fn-name)))))
2728
2729
2730(define (getter-and-setter-syntax vars)
2731 (let ((args-name (gensym 'args))
2732 (an-arg-name (gensym 'an-arg))
2733 (new-val-name (gensym 'new-value))
2734 (loop-name (gensym 'loop))
2735 (kws (map symbol->keyword vars)))
2736 (list `(lambda ,args-name
2737 (let ,loop-name ((,args-name ,args-name))
2738 (if (null? ,args-name)
2739 ,(if (null? kws)
2740 ''()
2741 `(let ((all-vals (,loop-name ',kws)))
2742 (let ,loop-name ((vals all-vals)
2743 (kws ',kws))
2744 (if (null? vals)
2745 '()
2746 `(,(car kws) ,(car vals) ,@(,loop-name (cdr vals) (cdr kws)))))))
2747 (map (lambda (,an-arg-name)
2748 (case ,an-arg-name
2749 ,@ (append
2750 (map (lambda (kw v) `((,kw) ,v)) kws vars)
2751 `((else (throw 'bad-get-option ,an-arg-name))))))
2752 ,args-name))))
2753
2754 `(lambda ,args-name
2755 (let ,loop-name ((,args-name ,args-name))
2756 (or (null? ,args-name)
2757 (null? (cdr ,args-name))
2758 (let ((,an-arg-name (car ,args-name))
2759 (,new-val-name (cadr ,args-name)))
2760 (case ,an-arg-name
2761 ,@ (append
2762 (map (lambda (kw v) `((,kw) (set! ,v ,new-val-name))) kws vars)
2763 `((else (throw 'bad-set-option ,an-arg-name)))))
2764 (,loop-name (cddr ,args-name)))))))))
2765
2766(define (delegating-getter-and-setter-syntax vars get-delegate set-delegate)
2767 (let ((args-name (gensym 'args))
2768 (an-arg-name (gensym 'an-arg))
2769 (new-val-name (gensym 'new-value))
2770 (loop-name (gensym 'loop))
2771 (kws (map symbol->keyword vars)))
2772 (list `(lambda ,args-name
2773 (let ,loop-name ((,args-name ,args-name))
2774 (if (null? ,args-name)
2775 (append!
2776 ,(if (null? kws)
2777 ''()
2778 `(let ((all-vals (,loop-name ',kws)))
2779 (let ,loop-name ((vals all-vals)
2780 (kws ',kws))
2781 (if (null? vals)
2782 '()
2783 `(,(car kws) ,(car vals) ,@(,loop-name (cdr vals) (cdr kws)))))))
2784 (,get-delegate))
2785 (map (lambda (,an-arg-name)
2786 (case ,an-arg-name
2787 ,@ (append
2788 (map (lambda (kw v) `((,kw) ,v)) kws vars)
2789 `((else (car (,get-delegate ,an-arg-name)))))))
2790 ,args-name))))
2791
2792 `(lambda ,args-name
2793 (let ,loop-name ((,args-name ,args-name))
2794 (or (null? ,args-name)
2795 (null? (cdr ,args-name))
2796 (let ((,an-arg-name (car ,args-name))
2797 (,new-val-name (cadr ,args-name)))
2798 (case ,an-arg-name
2799 ,@ (append
2800 (map (lambda (kw v) `((,kw) (set! ,v ,new-val-name))) kws vars)
2801 `((else (,set-delegate ,an-arg-name ,new-val-name)))))
2802 (,loop-name (cddr ,args-name)))))))))
2803
2804
2805
2806
2807;;; with-configuration-getter-and-setter <vars-etc> proc
2808;;;
2809;;; Create a getter and setter that can trigger arbitrary computation.
2810;;;
2811;;; <vars-etc> is a list of variable specifiers, explained below.
2812;;; proc is called:
2813;;;
2814;;; (proc getter setter)
2815;;;
2816;;; Each element of the <vars-etc> list is of the form:
2817;;;
2818;;; (<var> getter-hook setter-hook)
2819;;;
2820;;; Both hook elements are evaluated; the variable name is not.
2821;;; Either hook may be #f or procedure.
2822;;;
2823;;; A getter hook is a thunk that returns a value for the corresponding
2824;;; variable. If omitted (#f is passed), the binding of <var> is
2825;;; returned.
2826;;;
2827;;; A setter hook is a procedure of one argument that accepts a new value
2828;;; for the corresponding variable. If omitted, the binding of <var>
2829;;; is simply set using set!.
2830;;;
2831(defmacro-public with-configuration-getter-and-setter (vars-etc proc)
2832 `((lambda (simpler-get simpler-set body-proc)
2833 (with-delegating-getter-and-setter ()
2834 simpler-get simpler-set body-proc))
2835
2836 (lambda (kw)
2837 (case kw
2838 ,@(map (lambda (v) `((,(symbol->keyword (car v)))
2839 ,(cond
2840 ((cadr v) => list)
2841 (else `(list ,(car v))))))
2842 vars-etc)))
2843
2844 (lambda (kw new-val)
2845 (case kw
2846 ,@(map (lambda (v) `((,(symbol->keyword (car v)))
2847 ,(cond
2848 ((caddr v) => (lambda (proc) `(,proc new-val)))
2849 (else `(set! ,(car v) new-val)))))
2850 vars-etc)))
2851
2852 ,proc))
2853
2854(defmacro-public with-delegating-configuration-getter-and-setter (vars-etc delegate-get delegate-set proc)
2855 `((lambda (simpler-get simpler-set body-proc)
2856 (with-delegating-getter-and-setter ()
2857 simpler-get simpler-set body-proc))
2858
2859 (lambda (kw)
2860 (case kw
2861 ,@(append! (map (lambda (v) `((,(symbol->keyword (car v)))
2862 ,(cond
2863 ((cadr v) => list)
2864 (else `(list ,(car v))))))
2865 vars-etc)
2866 `((else (,delegate-get kw))))))
2867
2868 (lambda (kw new-val)
2869 (case kw
2870 ,@(append! (map (lambda (v) `((,(symbol->keyword (car v)))
2871 ,(cond
2872 ((caddr v) => (lambda (proc) `(,proc new-val)))
2873 (else `(set! ,(car v) new-val)))))
2874 vars-etc)
2875 `((else (,delegate-set kw new-val))))))
2876
2877 ,proc))
2878
2879
2880;;; let-configuration-getter-and-setter <vars-etc> proc
2881;;;
2882;;; This procedure is like with-configuration-getter-and-setter (q.v.)
2883;;; except that each element of <vars-etc> is:
2884;;;
2885;;; (<var> initial-value getter-hook setter-hook)
2886;;;
2887;;; Unlike with-configuration-getter-and-setter, let-configuration-getter-and-setter
2888;;; introduces bindings for the variables named in <vars-etc>.
2889;;; It is short-hand for:
2890;;;
2891;;; (let ((<var1> initial-value-1)
2892;;; (<var2> initial-value-2)
2893;;; ...)
2894;;; (with-configuration-getter-and-setter ((<var1> v1-get v1-set) ...) proc))
2895;;;
2896(defmacro-public let-with-configuration-getter-and-setter (vars-etc proc)
2897 `(let ,(map (lambda (v) `(,(car v) ,(cadr v))) vars-etc)
2898 (with-configuration-getter-and-setter ,(map (lambda (v) `(,(car v) ,(caddr v) ,(cadddr v))) vars-etc)
2899 ,proc)))
2900
2901
2902
2903\f
44cf1f0f
JB
2904;;; {Implementation of COMMON LISP list functions for Scheme}
2905
0f2d19dd
JB
2906(define-module (ice-9 common-list))
2907
2908;;"comlist.scm" Implementation of COMMON LISP list functions for Scheme
2909; Copyright (C) 1991, 1993, 1995 Aubrey Jaffer.
2910;
2911;Permission to copy this software, to redistribute it, and to use it
2912;for any purpose is granted, subject to the following restrictions and
2913;understandings.
2914;
2915;1. Any copy made of this software must include this copyright notice
2916;in full.
2917;
2918;2. I have made no warrantee or representation that the operation of
2919;this software will be error-free, and I am under no obligation to
2920;provide any services, by way of maintenance, update, or otherwise.
2921;
2922;3. In conjunction with products arising from the use of this
2923;material, there shall be no use of my name in any advertising,
2924;promotional, or sales literature without prior written consent in
2925;each case.
2926
0f2d19dd
JB
2927;;;From: hugh@ear.mit.edu (Hugh Secker-Walker)
2928(define-public (make-list k . init)
2929 (set! init (if (pair? init) (car init)))
2930 (do ((k k (+ -1 k))
2931 (result '() (cons init result)))
2932 ((<= k 0) result)))
2933
2934(define-public (adjoin e l) (if (memq e l) l (cons e l)))
2935
2936(define-public (union l1 l2)
2937 (cond ((null? l1) l2)
2938 ((null? l2) l1)
2939 (else (union (cdr l1) (adjoin (car l1) l2)))))
2940
2941(define-public (intersection l1 l2)
2942 (cond ((null? l1) l1)
2943 ((null? l2) l2)
2944 ((memv (car l1) l2) (cons (car l1) (intersection (cdr l1) l2)))
2945 (else (intersection (cdr l1) l2))))
2946
2947(define-public (set-difference l1 l2)
2948 (cond ((null? l1) l1)
2949 ((memv (car l1) l2) (set-difference (cdr l1) l2))
2950 (else (cons (car l1) (set-difference (cdr l1) l2)))))
2951
2952(define-public (reduce-init p init l)
2953 (if (null? l)
2954 init
2955 (reduce-init p (p init (car l)) (cdr l))))
2956
2957(define-public (reduce p l)
2958 (cond ((null? l) l)
2959 ((null? (cdr l)) (car l))
2960 (else (reduce-init p (car l) (cdr l)))))
2961
2962(define-public (some pred l . rest)
2963 (cond ((null? rest)
2964 (let mapf ((l l))
2965 (and (not (null? l))
2966 (or (pred (car l)) (mapf (cdr l))))))
2967 (else (let mapf ((l l) (rest rest))
2968 (and (not (null? l))
2969 (or (apply pred (car l) (map car rest))
2970 (mapf (cdr l) (map cdr rest))))))))
2971
2972(define-public (every pred l . rest)
2973 (cond ((null? rest)
2974 (let mapf ((l l))
2975 (or (null? l)
2976 (and (pred (car l)) (mapf (cdr l))))))
2977 (else (let mapf ((l l) (rest rest))
2978 (or (null? l)
2979 (and (apply pred (car l) (map car rest))
2980 (mapf (cdr l) (map cdr rest))))))))
2981
2982(define-public (notany pred . ls) (not (apply some pred ls)))
2983
2984(define-public (notevery pred . ls) (not (apply every pred ls)))
2985
2986(define-public (find-if t l)
2987 (cond ((null? l) #f)
2988 ((t (car l)) (car l))
2989 (else (find-if t (cdr l)))))
2990
2991(define-public (member-if t l)
2992 (cond ((null? l) #f)
2993 ((t (car l)) l)
2994 (else (member-if t (cdr l)))))
2995
2996(define-public (remove-if p l)
2997 (cond ((null? l) '())
2998 ((p (car l)) (remove-if p (cdr l)))
2999 (else (cons (car l) (remove-if p (cdr l))))))
3000
3001(define-public (delete-if! pred list)
3002 (let delete-if ((list list))
3003 (cond ((null? list) '())
3004 ((pred (car list)) (delete-if (cdr list)))
3005 (else
3006 (set-cdr! list (delete-if (cdr list)))
3007 list))))
3008
3009(define-public (delete-if-not! pred list)
3010 (let delete-if ((list list))
3011 (cond ((null? list) '())
3012 ((not (pred (car list))) (delete-if (cdr list)))
3013 (else
3014 (set-cdr! list (delete-if (cdr list)))
3015 list))))
3016
3017(define-public (butlast lst n)
3018 (letrec ((l (- (length lst) n))
3019 (bl (lambda (lst n)
3020 (cond ((null? lst) lst)
3021 ((positive? n)
3022 (cons (car lst) (bl (cdr lst) (+ -1 n))))
3023 (else '())))))
3024 (bl lst (if (negative? n)
3025 (slib:error "negative argument to butlast" n)
3026 l))))
3027
3028(define-public (and? . args)
3029 (cond ((null? args) #t)
3030 ((car args) (apply and? (cdr args)))
3031 (else #f)))
3032
3033(define-public (or? . args)
3034 (cond ((null? args) #f)
3035 ((car args) #t)
3036 (else (apply or? (cdr args)))))
3037
3038(define-public (has-duplicates? lst)
3039 (cond ((null? lst) #f)
3040 ((member (car lst) (cdr lst)) #t)
3041 (else (has-duplicates? (cdr lst)))))
3042
3043(define-public (list* x . y)
3044 (define (list*1 x)
3045 (if (null? (cdr x))
3046 (car x)
3047 (cons (car x) (list*1 (cdr x)))))
3048 (if (null? y)
3049 x
3050 (cons x (list*1 y))))
3051
3052;; pick p l
3053;; Apply P to each element of L, returning a list of elts
3054;; for which P returns a non-#f value.
3055;;
3056(define-public (pick p l)
3057 (let loop ((s '())
3058 (l l))
3059 (cond
3060 ((null? l) s)
3061 ((p (car l)) (loop (cons (car l) s) (cdr l)))
3062 (else (loop s (cdr l))))))
3063
3064;; pick p l
3065;; Apply P to each element of L, returning a list of the
3066;; non-#f return values of P.
3067;;
3068(define-public (pick-mappings p l)
3069 (let loop ((s '())
3070 (l l))
3071 (cond
3072 ((null? l) s)
3073 ((p (car l)) => (lambda (mapping) (loop (cons mapping s) (cdr l))))
3074 (else (loop s (cdr l))))))
3075
3076(define-public (uniq l)
3077 (if (null? l)
3078 '()
3079 (let ((u (uniq (cdr l))))
3080 (if (memq (car l) u)
3081 u
3082 (cons (car l) u)))))
3083
3084\f
44cf1f0f
JB
3085;;; {Functions for browsing modules}
3086
0f2d19dd
JB
3087(define-module (ice-9 ls)
3088 :use-module (ice-9 common-list))
3089
0f2d19dd
JB
3090;;;;
3091;;; local-definitions-in root name
8b718458
JB
3092;;; Returns a list of names defined locally in the named
3093;;; subdirectory of root.
0f2d19dd 3094;;; definitions-in root name
8b718458
JB
3095;;; Returns a list of all names defined in the named
3096;;; subdirectory of root. The list includes alll locally
3097;;; defined names as well as all names inherited from a
3098;;; member of a use-list.
0f2d19dd
JB
3099;;;
3100;;; A convenient interface for examining the nature of things:
3101;;;
3102;;; ls . various-names
3103;;;
8b718458
JB
3104;;; With just one argument, interpret that argument as the
3105;;; name of a subdirectory of the current module and
3106;;; return a list of names defined there.
0f2d19dd 3107;;;
8b718458
JB
3108;;; With more than one argument, still compute
3109;;; subdirectory lists, but return a list:
0f2d19dd
JB
3110;;; ((<subdir-name> . <names-defined-there>)
3111;;; (<subdir-name> . <names-defined-there>)
3112;;; ...)
3113;;;
3114
3115(define-public (local-definitions-in root names)
0dd5491c 3116 (let ((m (nested-ref root names))
0f2d19dd
JB
3117 (answer '()))
3118 (if (not (module? m))
3119 (set! answer m)
3120 (module-for-each (lambda (k v) (set! answer (cons k answer))) m))
3121 answer))
3122
3123(define-public (definitions-in root names)
0dd5491c 3124 (let ((m (nested-ref root names)))
0f2d19dd
JB
3125 (if (not (module? m))
3126 m
3127 (reduce union
3128 (cons (local-definitions-in m '())
8b718458
JB
3129 (map (lambda (m2) (definitions-in m2 '()))
3130 (module-uses m)))))))
0f2d19dd
JB
3131
3132(define-public (ls . various-refs)
3133 (and various-refs
3134 (if (cdr various-refs)
3135 (map (lambda (ref)
3136 (cons ref (definitions-in (current-module) ref)))
3137 various-refs)
3138 (definitions-in (current-module) (car various-refs)))))
3139
3140(define-public (lls . various-refs)
3141 (and various-refs
3142 (if (cdr various-refs)
3143 (map (lambda (ref)
3144 (cons ref (local-definitions-in (current-module) ref)))
3145 various-refs)
3146 (local-definitions-in (current-module) (car various-refs)))))
3147
0dd5491c 3148(define-public (recursive-local-define name value)
0f2d19dd
JB
3149 (let ((parent (reverse! (cdr (reverse name)))))
3150 (and parent (make-modules-in (current-module) parent))
0dd5491c 3151 (local-define name value)))
0f2d19dd 3152\f
44cf1f0f
JB
3153;;; {Queues}
3154
0f2d19dd
JB
3155(define-module (ice-9 q))
3156
3157;;;; Copyright (C) 1995 Free Software Foundation, Inc.
3158;;;;
3159;;;; This program is free software; you can redistribute it and/or modify
3160;;;; it under the terms of the GNU General Public License as published by
3161;;;; the Free Software Foundation; either version 2, or (at your option)
3162;;;; any later version.
3163;;;;
3164;;;; This program is distributed in the hope that it will be useful,
3165;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
3166;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3167;;;; GNU General Public License for more details.
3168;;;;
3169;;;; You should have received a copy of the GNU General Public License
3170;;;; along with this software; see the file COPYING. If not, write to
3171;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
3172;;;;
3173
0f2d19dd
JB
3174;;;;
3175;;; Q: Based on the interface to
3176;;;
3177;;; "queue.scm" Queues/Stacks for Scheme
3178;;; Written by Andrew Wilcox (awilcox@astro.psu.edu) on April 1, 1992.
3179;;;
3180
0f2d19dd
JB
3181;;;;
3182;;; {Q}
3183;;;
3184;;; A list is just a bunch of cons pairs that follows some constrains, right?
3185;;; Association lists are the same. Hash tables are just vectors and association
3186;;; lists. You can print them, read them, write them as constants, pun them off as other data
3187;;; structures etc. This is good. This is lisp. These structures are fast and compact
3188;;; and easy to manipulate arbitrarily because of their simple, regular structure and
3189;;; non-disjointedness (associations being lists and so forth).
3190;;;
3191;;; So I figured, queues should be the same -- just a "subtype" of cons-pair
3192;;; structures in general.
3193;;;
3194;;; A queue is a cons pair:
3195;;; ( <the-q> . <last-pair> )
3196;;;
3197;;; <the-q> is a list of things in the q. New elements go at the end of that list.
3198;;;
3199;;; <last-pair> is #f if the q is empty, and otherwise is the last pair of <the-q>.
3200;;;
3201;;; q's print nicely, but alas, they do not read well because the eq?-ness of
3202;;; <last-pair> and (last-pair <the-q>) is lost by read. The procedure
3203;;;
3204;;; (sync-q! q)
3205;;;
3206;;; recomputes and resets the <last-pair> component of a queue.
3207;;;
3208
3209(define-public (sync-q! obj) (set-cdr! obj (and (car obj) (last-pair (car obj)))))
3210
3211;;; make-q
3212;;; return a new q.
3213;;;
3214(define-public (make-q) (cons '() '()))
3215
3216;;; q? obj
3217;;; Return true if obj is a Q.
3218;;; An object is a queue if it is equal? to '(#f . #f) or
3219;;; if it is a pair P with (list? (car P)) and (eq? (cdr P) (last-pair P)).
3220;;;
3221(define-public (q? obj) (and (pair? obj)
3222 (or (and (null? (car obj))
3223 (null? (cdr obj)))
3224 (and
3225 (list? (car obj))
3226 (eq? (cdr obj) (last-pair (car obj)))))))
3227
3228;;; q-empty? obj
3229;;;
3230(define-public (q-empty? obj) (null? (car obj)))
3231
3232;;; q-empty-check q
3233;;; Throw a q-empty exception if Q is empty.
3234(define-public (q-empty-check q) (if (q-empty? q) (throw 'q-empty q)))
3235
3236
3237;;; q-front q
3238;;; Return the first element of Q.
3239(define-public (q-front q) (q-empty-check q) (caar q))
3240
3241;;; q-front q
3242;;; Return the last element of Q.
3243(define-public (q-rear q) (q-empty-check q) (cadr q))
3244
3245;;; q-remove! q obj
3246;;; Remove all occurences of obj from Q.
3247(define-public (q-remove! q obj)
3248 (while (memq obj (car q))
3249 (set-car! q (delq! obj (car q))))
3250 (set-cdr! q (last-pair (car q))))
3251
3252;;; q-push! q obj
3253;;; Add obj to the front of Q
3254(define-public (q-push! q d)
3255 (let ((h (cons d (car q))))
3256 (set-car! q h)
3257 (if (null? (cdr q))
3258 (set-cdr! q h))))
3259
3260;;; enq! q obj
3261;;; Add obj to the rear of Q
3262(define-public (enq! q d)
3263 (let ((h (cons d '())))
3264 (if (not (null? (cdr q)))
3265 (set-cdr! (cdr q) h)
3266 (set-car! q h))
3267 (set-cdr! q h)))
3268
3269;;; q-pop! q
3270;;; Take the front of Q and return it.
3271(define-public (q-pop! q)
3272 (q-empty-check q)
3273 (let ((it (caar q))
3274 (next (cdar q)))
3275 (if (not next)
3276 (set-cdr! q #f))
3277 (set-car! q next)
3278 it))
3279
3280;;; deq! q
3281;;; Take the front of Q and return it.
3282(define-public deq! q-pop!)
3283
3284;;; q-length q
3285;;; Return the number of enqueued elements.
3286;;;
3287(define-public (q-length q) (length (car q)))
3288
3289
3290
3291\f
44cf1f0f
JB
3292;;; {The runq data structure}
3293
0f2d19dd
JB
3294(define-module (ice-9 runq)
3295 :use-module (ice-9 q))
3296
0f2d19dd
JB
3297;;;; Copyright (C) 1996 Free Software Foundation, Inc.
3298;;;;
3299;;;; This program is free software; you can redistribute it and/or modify
3300;;;; it under the terms of the GNU General Public License as published by
3301;;;; the Free Software Foundation; either version 2, or (at your option)
3302;;;; any later version.
3303;;;;
3304;;;; This program is distributed in the hope that it will be useful,
3305;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
3306;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3307;;;; GNU General Public License for more details.
3308;;;;
3309;;;; You should have received a copy of the GNU General Public License
3310;;;; along with this software; see the file COPYING. If not, write to
3311;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
3312;;;;
3313
0f2d19dd 3314;;;;
0f2d19dd
JB
3315;;;
3316;;; One way to schedule parallel computations in a serial environment is
3317;;; to explicitly divide each task up into small, finite execution time,
3318;;; strips. Then you interleave the execution of strips from various
3319;;; tasks to achieve a kind of parallelism. Runqs are a handy data
3320;;; structure for this style of programming.
3321;;;
3322;;; We use thunks (nullary procedures) and lists of thunks to represent
3323;;; strips. By convention, the return value of a strip-thunk must either
3324;;; be another strip or the value #f.
3325;;;
3326;;; A runq is a procedure that manages a queue of strips. Called with no
3327;;; arguments, it processes one strip from the queue. Called with
3328;;; arguments, the arguments form a control message for the queue. The
3329;;; first argument is a symbol which is the message selector.
3330;;;
3331;;; A strip is processed this way: If the strip is a thunk, the thunk is
3332;;; called -- if it returns a strip, that strip is added back to the
3333;;; queue. To process a strip which is a list of thunks, the CAR of that
3334;;; list is called. After a call to that CAR, there are 0, 1, or 2 strips
3335;;; -- perhaps one returned by the thunk, and perhaps the CDR of the
3336;;; original strip if that CDR is not nil. The runq puts whichever of
3337;;; these strips exist back on the queue. (The exact order in which
3338;;; strips are put back on the queue determines the scheduling behavior of
3339;;; a particular queue -- it's a parameter.)
3340;;;
3341;;;
3342
3343
3344
3345;;;;
3346;;; (runq-control q msg . args)
3347;;;
3348;;; processes in the default way the control messages that
3349;;; can be sent to a runq. Q should be an ordinary
3350;;; Q (see utils/q.scm).
3351;;;
3352;;; The standard runq messages are:
3353;;;
3354;;; 'add! strip0 strip1... ;; to enqueue one or more strips
3355;;; 'enqueue! strip0 strip1... ;; to enqueue one or more strips
3356;;; 'push! strip0 ... ;; add strips to the front of the queue
3357;;; 'empty? ;; true if it is
3358;;; 'length ;; how many strips in the queue?
3359;;; 'kill! ;; empty the queue
3360;;; else ;; throw 'not-understood
3361;;;
3362(define-public (runq-control q msg . args)
3363 (case msg
3364 ((add!) (for-each (lambda (t) (enq! q t)) args) '*unspecified*)
3365 ((enque!) (for-each (lambda (t) (enq! q t)) args) '*unspecified*)
3366 ((push!) (for-each (lambda (t) (q-push! q t)) args) '*unspecified*)
3367 ((empty?) (q-empty? q))
3368 ((length) (q-length q))
3369 ((kill!) (set! q (make-q)))
3370 (else (throw 'not-understood msg args))))
3371
3372(define (run-strip thunk) (catch #t thunk (lambda ign (warn 'runq-strip thunk ign) #f)))
3373
3374;;;;
3375;;; make-void-runq
3376;;;
3377;;; Make a runq that discards all messages except "length", for which
3378;;; it returns 0.
3379;;;
3380(define-public (make-void-runq)
3381 (lambda opts
3382 (and opts
3383 (apply-to-args opts
3384 (lambda (msg . args)
3385 (case msg
3386 ((length) 0)
3387 (else #f)))))))
3388
3389;;;;
3390;;; (make-fair-runq)
3391;;;
3392;;; Returns a runq procedure.
3393;;; Called with no arguments, the procedure processes one strip from the queue.
3394;;; Called with arguments, it uses runq-control.
3395;;;
3396;;; In a fair runq, if a strip returns a new strip X, X is added
3397;;; to the end of the queue, meaning it will be the last to execute
3398;;; of all the remaining procedures.
3399;;;
3400(define-public (make-fair-runq)
3401 (letrec ((q (make-q))
3402 (self
3403 (lambda ctl
3404 (if ctl
3405 (apply runq-control q ctl)
3406 (and (not (q-empty? q))
3407 (let ((next-strip (deq! q)))
3408 (cond
3409 ((procedure? next-strip) (let ((k (run-strip next-strip)))
3410 (and k (enq! q k))))
3411 ((pair? next-strip) (let ((k (run-strip (car next-strip))))
3412 (and k (enq! q k)))
3413 (if (not (null? (cdr next-strip)))
3414 (enq! q (cdr next-strip)))))
3415 self))))))
3416 self))
3417
3418
3419;;;;
3420;;; (make-exclusive-runq)
3421;;;
3422;;; Returns a runq procedure.
3423;;; Called with no arguments, the procedure processes one strip from the queue.
3424;;; Called with arguments, it uses runq-control.
3425;;;
3426;;; In an exclusive runq, if a strip W returns a new strip X, X is added
3427;;; to the front of the queue, meaning it will be the next to execute
3428;;; of all the remaining procedures.
3429;;;
3430;;; An exception to this occurs if W was the CAR of a list of strips.
3431;;; In that case, after the return value of W is pushed onto the front
3432;;; of the queue, the CDR of the list of strips is pushed in front
3433;;; of that (if the CDR is not nil). This way, the rest of the thunks
3434;;; in the list that contained W have priority over the return value of W.
3435;;;
3436(define-public (make-exclusive-runq)
3437 (letrec ((q (make-q))
3438 (self
3439 (lambda ctl
3440 (if ctl
3441 (apply runq-control q ctl)
3442 (and (not (q-empty? q))
3443 (let ((next-strip (deq! q)))
3444 (cond
3445 ((procedure? next-strip) (let ((k (run-strip next-strip)))
3446 (and k (q-push! q k))))
3447 ((pair? next-strip) (let ((k (run-strip (car next-strip))))
3448 (and k (q-push! q k)))
3449 (if (not (null? (cdr next-strip)))
3450 (q-push! q (cdr next-strip)))))
3451 self))))))
3452 self))
3453
3454
3455;;;;
3456;;; (make-subordinate-runq-to superior basic-inferior)
3457;;;
3458;;; Returns a runq proxy for the runq basic-inferior.
3459;;;
3460;;; The proxy watches for operations on the basic-inferior that cause
3461;;; a transition from a queue length of 0 to a non-zero length and
3462;;; vice versa. While the basic-inferior queue is not empty,
3463;;; the proxy installs a task on the superior runq. Each strip
3464;;; of that task processes N strips from the basic-inferior where
3465;;; N is the length of the basic-inferior queue when the proxy
3466;;; strip is entered. [Countless scheduling variations are possible.]
3467;;;
3468(define-public (make-subordinate-runq-to superior-runq basic-runq)
3469 (let ((runq-task (cons #f #f)))
3470 (set-car! runq-task
3471 (lambda ()
3472 (if (basic-runq 'empty?)
3473 (set-cdr! runq-task #f)
3474 (do ((n (basic-runq 'length) (1- n)))
3475 ((<= n 0) #f)
3476 (basic-runq)))))
3477 (letrec ((self
3478 (lambda ctl
3479 (if (not ctl)
3480 (let ((answer (basic-runq)))
3481 (self 'empty?)
3482 answer)
3483 (begin
3484 (case (car ctl)
3485 ((suspend) (set-cdr! runq-task #f))
3486 (else (let ((answer (apply basic-runq ctl)))
3487 (if (and (not (cdr runq-task)) (not (basic-runq 'empty?)))
3488 (begin
3489 (set-cdr! runq-task runq-task)
3490 (superior-runq 'add! runq-task)))
3491 answer))))))))
3492 self)))
3493
3494;;;;
3495;;; (define fork-strips (lambda args args))
3496;;; Return a strip that starts several strips in
3497;;; parallel. If this strip is enqueued on a fair
3498;;; runq, strips of the parallel subtasks will run
3499;;; round-robin style.
3500;;;
3501(define fork-strips (lambda args args))
3502
3503
3504;;;;
3505;;; (strip-sequence . strips)
3506;;;
3507;;; Returns a new strip which is the concatenation of the argument strips.
3508;;;
3509(define-public ((strip-sequence . strips))
3510 (let loop ((st (let ((a strips)) (set! strips #f) a)))
3511 (and (not (null? st))
3512 (let ((then ((car st))))
3513 (if then
3514 (lambda () (loop (cons then (cdr st))))
3515 (lambda () (loop (cdr st))))))))
3516
3517
3518;;;;
3519;;; (fair-strip-subtask . initial-strips)
3520;;;
3521;;; Returns a new strip which is the synchronos, fair,
3522;;; parallel execution of the argument strips.
3523;;;
3524;;;
3525;;;
3526(define-public (fair-strip-subtask . initial-strips)
3527 (let ((st (make-fair-runq)))
3528 (apply st 'add! initial-strips)
3529 st))
3530
3531\f
44cf1f0f 3532;;; {String Fun}
0f2d19dd 3533
0f2d19dd
JB
3534(define-module (ice-9 string-fun))
3535
0f2d19dd 3536;;;;
0f2d19dd
JB
3537;;;
3538;;; Various string funcitons, particularly those that take
3539;;; advantage of the "shared substring" capability.
3540;;;
3541\f
44cf1f0f 3542;;; {String Fun: Dividing Strings Into Fields}
0f2d19dd
JB
3543;;;
3544;;; The names of these functions are very regular.
3545;;; Here is a grammar of a call to one of these:
3546;;;
3547;;; <string-function-invocation>
3548;;; := (<action>-<seperator-disposition>-<seperator-determination> <seperator-param> <str> <ret>)
3549;;;
3550;;; <str> = the string
3551;;;
3552;;; <ret> = The continuation. String functions generally return
3553;;; multiple values by passing them to this procedure.
3554;;;
3555;;; <action> = split
3556;;; | separate-fields
3557;;;
3558;;; "split" means to divide a string into two parts.
3559;;; <ret> will be called with two arguments.
3560;;;
3561;;; "separate-fields" means to divide a string into as many
3562;;; parts as possible. <ret> will be called with
3563;;; however many fields are found.
3564;;;
3565;;; <seperator-disposition> = before
3566;;; | after
3567;;; | discarding
3568;;;
3569;;; "before" means to leave the seperator attached to
3570;;; the beginning of the field to its right.
3571;;; "after" means to leave the seperator attached to
3572;;; the end of the field to its left.
3573;;; "discarding" means to discard seperators.
3574;;;
3575;;; Other dispositions might be handy. For example, "isolate"
3576;;; could mean to treat the separator as a field unto itself.
3577;;;
3578;;; <seperator-determination> = char
3579;;; | predicate
3580;;;
3581;;; "char" means to use a particular character as field seperator.
3582;;; "predicate" means to check each character using a particular predicate.
3583;;;
3584;;; Other determinations might be handy. For example, "character-set-member".
3585;;;
3586;;; <seperator-param> = A parameter that completes the meaning of the determinations.
3587;;; For example, if the determination is "char", then this parameter
3588;;; says which character. If it is "predicate", the parameter is the
3589;;; predicate.
3590;;;
3591;;;
3592;;; For example:
3593;;;
3594;;; (separate-fields-discarding-char #\, "foo, bar, baz, , bat" list)
3595;;; => ("foo" " bar" " baz" " " " bat")
3596;;;
3597;;; (split-after-char #\- 'an-example-of-split list)
3598;;; => ("an-" "example-of-split")
3599;;;
3600;;; As an alternative to using a determination "predicate", or to trying to do anything
3601;;; complicated with these functions, consider using regular expressions.
3602;;;
3603
3604(define-public (split-after-char char str ret)
3605 (let ((end (cond
3606 ((string-index str char) => 1+)
3607 (else (string-length str)))))
3608 (ret (make-shared-substring str 0 end)
3609 (make-shared-substring str end))))
3610
3611(define-public (split-before-char char str ret)
3612 (let ((end (or (string-index str char)
3613 (string-length str))))
3614 (ret (make-shared-substring str 0 end)
3615 (make-shared-substring str end))))
3616
3617(define-public (split-discarding-char char str ret)
3618 (let ((end (string-index str char)))
3619 (if (not end)
3620 (ret str "")
3621 (ret (make-shared-substring str 0 end)
3622 (make-shared-substring str (1+ end))))))
3623
3624(define-public (split-after-char-last char str ret)
3625 (let ((end (cond
3626 ((string-rindex str char) => 1+)
3627 (else 0))))
3628 (ret (make-shared-substring str 0 end)
3629 (make-shared-substring str end))))
3630
3631(define-public (split-before-char-last char str ret)
3632 (let ((end (or (string-rindex str char) 0)))
3633 (ret (make-shared-substring str 0 end)
3634 (make-shared-substring str end))))
3635
3636(define-public (split-discarding-char-last char str ret)
3637 (let ((end (string-rindex str char)))
3638 (if (not end)
3639 (ret str "")
3640 (ret (make-shared-substring str 0 end)
3641 (make-shared-substring str (1+ end))))))
3642
3643(define (split-before-predicate pred str ret)
3644 (let loop ((n 0))
3645 (cond
3646 ((= n (length str)) (ret str ""))
3647 ((not (pred (string-ref str n))) (loop (1+ n)))
3648 (else (ret (make-shared-substring str 0 n)
3649 (make-shared-substring str n))))))
3650(define (split-after-predicate pred str ret)
3651 (let loop ((n 0))
3652 (cond
3653 ((= n (length str)) (ret str ""))
3654 ((not (pred (string-ref str n))) (loop (1+ n)))
3655 (else (ret (make-shared-substring str 0 (1+ n))
3656 (make-shared-substring str (1+ n)))))))
3657
3658(define (split-discarding-predicate pred str ret)
3659 (let loop ((n 0))
3660 (cond
3661 ((= n (length str)) (ret str ""))
3662 ((not (pred (string-ref str n))) (loop (1+ n)))
3663 (else (ret (make-shared-substring str 0 n)
3664 (make-shared-substring str (1+ n)))))))
3665
21ed9efe 3666(define-public (separate-fields-discarding-char ch str ret)
0f2d19dd
JB
3667 (let loop ((fields '())
3668 (str str))
3669 (cond
3670 ((string-rindex str ch)
3671 => (lambda (pos) (loop (cons (make-shared-substring str (+ 1 w)) fields)
3672 (make-shared-substring str 0 w))))
3673 (else (ret (cons str fields))))))
3674
21ed9efe 3675(define-public (separate-fields-after-char ch str ret)
0f2d19dd
JB
3676 (let loop ((fields '())
3677 (str str))
3678 (cond
3679 ((string-rindex str ch)
3680 => (lambda (pos) (loop (cons (make-shared-substring str (+ 1 w)) fields)
3681 (make-shared-substring str 0 (+ 1 w)))))
3682 (else (ret (cons str fields))))))
3683
21ed9efe 3684(define-public (separate-fields-before-char ch str ret)
0f2d19dd
JB
3685 (let loop ((fields '())
3686 (str str))
3687 (cond
3688 ((string-rindex str ch)
3689 => (lambda (pos) (loop (cons (make-shared-substring str w) fields)
3690 (make-shared-substring str 0 w))))
3691 (else (ret (cons str fields))))))
3692
3693\f
44cf1f0f 3694;;; {String Fun: String Prefix Predicates}
0f2d19dd
JB
3695;;;
3696;;; Very simple:
3697;;;
21ed9efe 3698;;; (define-public ((string-prefix-predicate pred?) prefix str)
0f2d19dd
JB
3699;;; (and (<= (length prefix) (length str))
3700;;; (pred? prefix (make-shared-substring str 0 (length prefix)))))
3701;;;
3702;;; (define-public string-prefix=? (string-prefix-predicate string=?))
3703;;;
3704
3705(define-public ((string-prefix-predicate pred?) prefix str)
3706 (and (<= (length prefix) (length str))
3707 (pred? prefix (make-shared-substring str 0 (length prefix)))))
3708
3709(define-public string-prefix=? (string-prefix-predicate string=?))
3710
3711\f
44cf1f0f 3712;;; {String Fun: Strippers}
0f2d19dd
JB
3713;;;
3714;;; <stripper> = sans-<removable-part>
3715;;;
3716;;; <removable-part> = surrounding-whitespace
3717;;; | trailing-whitespace
3718;;; | leading-whitespace
3719;;; | final-newline
3720;;;
3721
3722(define-public (sans-surrounding-whitespace s)
3723 (let ((st 0)
3724 (end (string-length s)))
3725 (while (and (< st (string-length s))
3726 (char-whitespace? (string-ref s st)))
3727 (set! st (1+ st)))
3728 (while (and (< 0 end)
3729 (char-whitespace? (string-ref s (1- end))))
3730 (set! end (1- end)))
3731 (if (< end st)
3732 ""
3733 (make-shared-substring s st end))))
3734
3735(define-public (sans-trailing-whitespace s)
3736 (let ((st 0)
3737 (end (string-length s)))
3738 (while (and (< 0 end)
3739 (char-whitespace? (string-ref s (1- end))))
3740 (set! end (1- end)))
3741 (if (< end st)
3742 ""
3743 (make-shared-substring s st end))))
3744
3745(define-public (sans-leading-whitespace s)
3746 (let ((st 0)
3747 (end (string-length s)))
3748 (while (and (< st (string-length s))
3749 (char-whitespace? (string-ref s st)))
3750 (set! st (1+ st)))
3751 (if (< end st)
3752 ""
3753 (make-shared-substring s st end))))
3754
3755(define-public (sans-final-newline str)
3756 (cond
3757 ((= 0 (string-length str))
3758 str)
3759
3760 ((char=? #\nl (string-ref str (1- (string-length str))))
3761 (make-shared-substring str 0 (1- (string-length str))))
3762
3763 (else str)))
3764\f
44cf1f0f 3765;;; {String Fun: has-trailing-newline?}
0f2d19dd
JB
3766;;;
3767
3768(define-public (has-trailing-newline? str)
3769 (and (< 0 (string-length str))
3770 (char=? #\nl (string-ref str (1- (string-length str))))))
3771
3772
3773\f
44cf1f0f 3774;;; {String Fun: with-regexp-parts}
0f2d19dd
JB
3775
3776(define-public (with-regexp-parts regexp fields str return fail)
3777 (let ((parts (regexec regexp str fields)))
3778 (if (number? parts)
3779 (fail parts)
3780 (apply return parts))))
3781
3782\f
c56634ba
MD
3783;;; {Load debug extension code if debug extensions present.}
3784;;;
3785;;; *fixme* This is a temporary solution.
3786;;;
0f2d19dd 3787
c56634ba 3788(if (memq 'debug-extensions *features*)
90895e5c
MD
3789 (define-module (guile) :use-module (ice-9 debug)))
3790
3791\f
90d5e280
MD
3792;;; {Load session support if present.}
3793;;;
3794;;; *fixme* This is a temporary solution.
3795;;;
3796
3797(if (%search-load-path "ice-9/session.scm")
3798 (define-module (guile) :use-module (ice-9 session)))
3799
3800\f
90895e5c
MD
3801;;; {Load thread code if threads are present.}
3802;;;
3803;;; *fixme* This is a temporary solution.
3804;;;
3805
3806(if (memq 'threads *features*)
3807 (define-module (guile) :use-module (ice-9 threads)))
3808
21ed9efe
MD
3809\f
3810;;; {Load emacs interface support if emacs option is given.}
3811;;;
3812;;; *fixme* This is a temporary solution.
3813;;;
3814
2e3fbd8d
MD
3815(if (and (module-defined? the-root-module 'use-emacs-interface)
3816 use-emacs-interface)
21ed9efe
MD
3817 (define-module (guile) :use-module (ice-9 emacs)))
3818
3819\f
3820
90895e5c 3821(define-module (guile))
6fa8995c
GH
3822
3823(append! %load-path (cons "." ()))