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