source: project/chicken/branches/prerelease/chicken-more-macros.scm @ 9381

Last change on this file since 9381 was 9381, checked in by Ivan Raikov, 12 years ago

Merged trunk into prerelease

File size: 29.2 KB
Line 
1;;;; chicken-more-macros.scm - More syntax extensions
2;
3; Copyright (c) 2000-2007, Felix L. Winkelmann
4; Copyright (c) 2008, The Chicken Team
5; All rights reserved.
6;
7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
8; conditions are met:
9;
10;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
11;     disclaimer.
12;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
13;     disclaimer in the documentation and/or other materials provided with the distribution.
14;   Neither the name of the author nor the names of its contributors may be used to endorse or promote
15;     products derived from this software without specific prior written permission.
16;
17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25; POSSIBILITY OF SUCH DAMAGE.
26
27
28(##sys#provide 'chicken-more-macros)
29
30
31;;; Non-standard macros:
32
33(##sys#register-macro 
34 'define-record
35 (let ((symbol->string symbol->string)
36       (string->symbol string->symbol)
37       (string-append string-append) )
38   (lambda (name . slots)
39     (##sys#check-syntax 'define-record name 'symbol)
40     (##sys#check-syntax 'define-record slots '#(symbol 0))
41     (let ([prefix (symbol->string name)]
42           [setters (memq #:record-setters ##sys#features)]
43           [nsprefix (##sys#qualified-symbol-prefix name)] )
44       `(begin
45          (define ,(##sys#string->qualified-symbol nsprefix (string-append "make-" prefix))
46            (lambda ,slots (##sys#make-structure ',name ,@slots)) )
47          (define ,(##sys#string->qualified-symbol nsprefix (string-append prefix "?"))
48            (lambda (x) (##sys#structure? x ',name)) )
49          ,@(let mapslots ((slots slots) (i 1))
50              (if (eq? slots '())
51                  slots
52                  (let* ((slotname (symbol->string (##sys#slot slots 0)))
53                         (setr (##sys#string->qualified-symbol nsprefix (string-append prefix "-" slotname "-set!")))
54                         (getr (##sys#string->qualified-symbol nsprefix (string-append prefix "-" slotname)) ) )
55                    (cons
56                     `(begin
57                        (define ,setr
58                          (lambda (x val)
59                            (##core#check (##sys#check-structure x ',name))
60                            (##sys#block-set! x ,i val) ) )
61                        (define ,getr
62                          ,(if setters
63                               `(getter-with-setter
64                                 (lambda (x) 
65                                   (##core#check (##sys#check-structure x ',name))
66                                   (##sys#block-ref x ,i) )
67                                 ,setr)
68                               `(lambda (x)
69                                  (##core#check (##sys#check-structure x ',name))
70                                  (##sys#block-ref x ,i) ) ) ) )
71                     (mapslots (##sys#slot slots 1) (fx+ i 1)) ) ) ) ) ) ) ) ) )
72
73(##sys#register-macro
74 'receive
75 (lambda (vars . rest)
76   (if (null? rest)
77       `(##sys#call-with-values (lambda () ,vars) ##sys#list)
78       (begin
79         (##sys#check-syntax 'receive vars 'lambda-list)
80         (##sys#check-syntax 'receive rest '(_ . _))
81         (if (and (pair? vars) (null? (cdr vars)))
82             `(let ((,(car vars) ,(car rest)))
83                ,@(cdr rest))
84             `(##sys#call-with-values 
85               (lambda () ,(car rest))
86               (lambda ,vars ,@(cdr rest)) ) ) ) ) ) )
87
88(##sys#register-macro
89 'time 
90 (let ((gensym gensym))
91   (lambda exps
92     (let ((rvar (gensym 't)))
93       `(begin
94          (##sys#start-timer)
95          (##sys#call-with-values 
96           (lambda () ,@exps)
97           (lambda ,rvar
98             (##sys#display-times (##sys#stop-timer))
99             (##sys#apply ##sys#values ,rvar) ) ) ) ) ) ) )
100
101(##sys#register-macro
102 'declare
103 (lambda specs 
104   `(##core#declare ,@(##sys#map (lambda (x) `(quote ,x)) specs)) ) ); hides specifiers from macroexpand
105
106(##sys#register-macro
107 'include
108 (let ([with-input-from-file with-input-from-file]
109       [read read]
110       [reverse reverse] )
111   (lambda (filename)
112     (let ((path (##sys#resolve-include-filename filename #t)))
113       (when (load-verbose) (print "; including " path " ..."))
114       `(begin
115          ,@(with-input-from-file path
116              (lambda ()
117                (fluid-let ((##sys#current-source-filename path))
118                  (do ([x (read) (read)]
119                       [xs '() (cons x xs)] )
120                      ((eof-object? x) 
121                       (reverse xs))) ) ) ) ) ) ) ) )
122
123(##sys#register-macro
124 'assert
125 (lambda (exp . msg-and-args)
126   (let ((msg (if (eq? '() msg-and-args)
127                  `(##core#immutable '"assertion failed")
128                  (##sys#slot msg-and-args 0) ) ) )
129     `(if (##core#check ,exp)
130          (##core#undefined)
131          (##sys#error ,msg ',exp ,@(if (fx> (length msg-and-args) 1)
132                                  (##sys#slot msg-and-args 1)
133                                  '() ) ) ) ) ) )
134
135(##sys#register-macro
136 'ensure
137 (lambda (pred exp . args)
138   (let ([tmp (gensym)])
139     `(let ([,tmp ,exp])
140        (if (##core#check (,pred ,tmp))
141            ,tmp
142            (##sys#signal-hook
143             #:type-error
144             ,@(if (pair? args)
145                   args
146                   `((##core#immutable '"argument has incorrect type") ,tmp ',pred) ) ) ) ) ) ) )
147
148(##sys#register-macro
149 'fluid-let
150 (let ((gensym gensym))
151   (lambda (clauses . body)
152     (##sys#check-syntax 'fluid-let clauses '#((symbol _) 0))
153     (let ((ids (##sys#map car clauses))
154           (new-tmps (##sys#map (lambda (x) (gensym)) clauses))
155           (old-tmps (##sys#map (lambda (x) (gensym)) clauses)))
156       `(let (,@(map ##sys#list new-tmps (##sys#map cadr clauses))
157              ,@(map ##sys#list old-tmps
158                     (let loop ((n (length clauses)))
159                       (if (eq? n 0)
160                           '()
161                           (cons #f (loop (fx- n 1))) ) ) ) )
162          (##sys#dynamic-wind
163              (lambda ()
164                ,@(map (lambda (ot id) `(##core#set! ,ot ,id))
165                       old-tmps ids)
166                ,@(map (lambda (id nt) `(##core#set! ,id ,nt))
167                       ids new-tmps)
168                (##sys#void) )
169              (lambda () ,@body)
170              (lambda ()
171                ,@(map (lambda (nt id) `(##core#set! ,nt ,id))
172                       new-tmps ids)
173                ,@(map (lambda (id ot) `(##core#set! ,id ,ot))
174                       ids old-tmps)
175                (##sys#void) ) ) ) ) ) ) )
176
177(##sys#register-macro
178 'eval-when
179 (lambda (situations . body)
180   (let ([e #f]
181         [c #f]
182         [l #f] 
183         [body `(begin ,@body)] )
184     (let loop ([ss situations])
185       (if (pair? ss)
186           (begin
187             (case (##sys#slot ss 0)
188               [(eval) (set! e #t)]
189               [(load run-time) (set! l #t)]
190               [(compile compile-time) (set! c #t)]
191               [else (##sys#error "invalid situation specifier" (##sys#slot ss 0))] )
192             (loop (##sys#slot ss 1)) ) ) )
193     (if (memq '#:compiling ##sys#features)
194         (cond [(and c l) `(##core#compiletimetoo ,body)]
195               [c `(##core#compiletimeonly ,body)]
196               [l body]
197               [else '(##core#undefined)] )
198         (if e 
199             body
200             '(##core#undefined) ) ) ) ) )
201
202(##sys#register-macro
203 'parameterize 
204 (let ([car car]
205       [cadr cadr] 
206       [map map] )
207   (lambda (bindings . body)
208     (##sys#check-syntax 'parameterize bindings '#((_ _) 0))
209     (let* ([swap (gensym)]
210            [params (##sys#map car bindings)]
211            [vals (##sys#map cadr bindings)]
212            [aliases (##sys#map (lambda (z) (gensym)) params)]
213            [aliases2 (##sys#map (lambda (z) (gensym)) params)] )
214       `(let ,(##sys#append (map ##sys#list aliases params) (map ##sys#list aliases2 vals))
215          (let ((,swap (lambda ()
216                         ,@(map (lambda (a a2) `(let ((t (,a))) (,a ,a2) (##core#set! ,a2 t)))
217                                aliases aliases2) ) ) )
218            (##sys#dynamic-wind 
219                ,swap
220                (lambda () ,@body)
221                ,swap) ) ) ) ) ) )
222
223(##sys#register-macro
224 'when
225 (lambda (test . body)
226   `(if ,test (begin ,@body)) ) )
227
228(##sys#register-macro
229 'unless
230 (lambda (test . body)
231   `(if ,test (##core#undefined) (begin ,@body)) ) )
232
233(let* ((map map)
234       (assign
235        (lambda (vars exp)
236          (##sys#check-syntax 'set!-values/define-values vars '#(symbol 0))
237          (cond ((null? vars)
238                 ;; may this be simply "exp"?
239                 `(##sys#call-with-values (lambda () ,exp) (lambda () (##core#undefined))) )
240                ((null? (cdr vars))
241                 `(##core#set! ,(car vars) ,exp)) 
242                (else
243                 (let ([aliases (map gensym vars)])
244                   `(##sys#call-with-values
245                     (lambda () ,exp)
246                     (lambda ,aliases
247                       ,@(map (lambda (v a) `(##core#set! ,v ,a)) vars aliases) ) ) ) ) ) ) ) )
248  (##sys#register-macro 'set!-values assign)
249  (##sys#register-macro 'define-values assign) )
250
251(##sys#register-macro-2
252 'let-values
253 (letrec ((append* (lambda (il l)
254                      (if (not (pair? il))
255                          (cons il l)
256                          (cons (car il)
257                                (append* (cdr il) l)))))
258            (map* (lambda (proc l)
259                    (cond ((null? l) '())
260                          ((not (pair? l)) (proc l))
261                          (else (cons (proc (car l)) (map* proc (cdr l))))))))
262   (lambda (form)
263     (##sys#check-syntax 'let-values form '(#(_ 0) . #(_ 1)))
264     (let* ([vbindings (car form)]
265            [body (cdr form)]
266            [llists (map car vbindings)]
267            [vars (let loop ((llists llists) (acc '()))
268                    (if (null? llists)
269                        acc
270                        (let* ((llist (car llists))
271                               (new-acc
272                                (cond ((list? llist) (append llist acc))
273                                      ((pair? llist) (append* llist acc))
274                                      (else (cons llist acc)))))
275                          (loop (cdr llists) new-acc))))]
276            [aliases (map (lambda (v) (cons v (gensym v))) vars)]
277            [lookup (lambda (v) (cdr (assq v aliases)))]
278            [llists2 (let loop ((llists llists) (acc '()))
279                       (if (null? llists)
280                           (reverse acc)
281                           (let* ((llist (car llists))
282                                  (new-acc
283                                   (cond ((not (pair? llist)) (cons (lookup llist) acc))
284                                         (else (cons (map* lookup llist) acc)))))
285                             (loop (cdr llists) new-acc))))])
286       (let fold ([llists llists]
287                  [exps (map (lambda (x) (cadr x)) vbindings)]
288                  [llists2 llists2] )
289         (cond ((null? llists)
290                `(let ,(map (lambda (v) (##sys#list v (lookup v))) vars) ,@body) )
291               ((and (pair? (car llists2)) (null? (cdar llists2)))
292                `(let ((,(caar llists2) ,(car exps)))
293                   ,(fold (cdr llists) (cdr exps) (cdr llists2)) ) )
294               (else
295                `(##sys#call-with-values
296                  (lambda () ,(car exps))
297                  (lambda ,(car llists2) ,(fold (cdr llists) (cdr exps) (cdr llists2))) ) ) ) ) ) ) ) )
298
299(##sys#register-macro-2
300 'let*-values
301 (lambda (form)
302   (##sys#check-syntax 'let*-values form '(#(_ 0) . #(_ 1)))
303   (let ([vbindings (car form)]
304         [body (cdr form)] )
305     (let fold ([vbindings vbindings])
306       (if (null? vbindings)
307           `(let () ,@body)
308           `(let-values (,(car vbindings))
309              ,(fold (cdr vbindings))) ) ) ) ) )
310
311(##sys#register-macro-2 
312 'letrec-values
313 (lambda (form)
314   (##sys#check-syntax 'letrec-values form '(#(_ 0) . #(_ 1)))
315   (let* ([vbindings (car form)]
316          [body (cdr form)] 
317          [vars (apply ##sys#append (map (lambda (x) (car x)) vbindings))] 
318          [aliases (map (lambda (v) (cons v (gensym v))) vars)] 
319          [lookup (lambda (v) (cdr (assq v aliases)))] )
320     `(let ,(map (lambda (v) (##sys#list v '(##core#undefined))) vars)
321        ,@(map (lambda (vb)
322                 `(##sys#call-with-values (lambda () ,(cadr vb))
323                    (lambda ,(map lookup (car vb))
324                      ,@(map (lambda (v) `(##core#set! ,v ,(lookup v))) (car vb)) ) ) )
325               vbindings)
326        ,@body) ) ) )
327
328(##sys#register-macro
329 'nth-value
330 (lambda (i exp)
331   (let ([v (gensym)])
332     `(##sys#call-with-values
333       (lambda () ,exp)
334       (lambda ,v (list-ref ,v ,i)) ) ) ) )
335
336(letrec ([quotify-proc 
337           (lambda (xs id)
338             (##sys#check-syntax id xs '#(_ 1))
339             (let* ([head (car xs)]
340                    [name (if (pair? head) (car head) head)]
341                    [val (if (pair? head)
342                           `(lambda ,(cdr head) ,@(cdr xs))
343                           (cadr xs) ) ] )
344               (when (or (not (pair? val)) (not (eq? 'lambda (car val))))
345                 (syntax-error 'define-inline "invalid substitution form - must be lambda"
346                               name) )
347               (list (list 'quote name) val) ) ) ] )
348  (##sys#register-macro-2 
349   'define-inline
350   (lambda (form) `(##core#define-inline ,@(quotify-proc form 'define-inline)))) )
351
352(##sys#register-macro-2
353 'define-constant
354 (lambda (form)
355   (##sys#check-syntax 'define-constant form '(symbol _))
356   `(##core#define-constant ',(car form) ,(cadr form)) ) )
357
358(##sys#register-macro-2
359 'and-let*
360   (lambda (forms)
361     (##sys#check-syntax 'and-let* forms '(#(_ 0) . #(_ 1)))
362     (if (or (not (list? forms)) (fx< (length forms) 2))
363         (##sys#syntax-error-hook "syntax error in 'and-let*' form" forms) 
364         (let ([bindings (##sys#slot forms 0)]
365               [body (##sys#slot forms 1)] )
366           (let fold ([bs bindings])
367             (if (null? bs)
368                 `(begin ,@body)
369                 (let ([b (##sys#slot bs 0)]
370                       [bs2 (##sys#slot bs 1)] )
371                   (cond [(not-pair? b) `(if ,b ,(fold bs2) #f)]
372                         [(null? (##sys#slot b 1)) `(if ,(##sys#slot b 0) ,(fold bs2) #f)]
373                         [else
374                          (let ([var (##sys#slot b 0)])
375                            `(let ((,var ,(cadr b)))
376                               (if ,var ,(fold bs2) #f) ) ) ] ) ) ) ) ) ) ) )
377
378(##sys#register-macro-2
379 'select
380 (let ((gensym gensym))
381   (lambda (form)
382     (let ((exp (car form))
383           (body (cdr form)) )
384       (let ((tmp (gensym)))
385         `(let ((,tmp ,exp))
386            ,(let expand ((clauses body))
387               (if (not (pair? clauses))
388                   '(##core#undefined)
389                   (let ((clause (##sys#slot clauses 0))
390                         (rclauses (##sys#slot clauses 1)) )
391                     (##sys#check-syntax 'select clause '#(_ 1))
392                     (if (eq? 'else (car clause))
393                         `(begin ,@(cdr clause))
394                         `(if (or ,@(map (lambda (x) `(eqv? ,tmp ,x)) 
395                                         (car clause) ) )
396                              (begin ,@(cdr clause)) 
397                              ,(expand rclauses) ) ) ) ) ) ) ) ) ) ) )
398
399(##sys#register-macro-2                 ; DEPRECATED
400 'switch
401 (let ((gensym gensym))
402   (lambda (form)
403     (let ((exp (car form))
404           (body (cdr form)) )
405       (let ((tmp (gensym)))
406         `(let ((,tmp ,exp))
407            ,(let expand ((clauses body))
408               (if (not (pair? clauses))
409                   '(##core#undefined)
410                   (let ((clause (##sys#slot clauses 0))
411                         (rclauses (##sys#slot clauses 1)) )
412                     (##sys#check-syntax 'switch clause '#(_ 1))
413                     (if (eq? 'else (car clause))
414                         `(begin ,@(cdr clause))
415                         `(if (eqv? ,tmp ,(car clause))
416                              (begin ,@(cdr clause)) 
417                              ,(expand rclauses) ) ) ) ) ) ) ) ) ) ) )
418
419
420;;; Optional argument handling:
421
422;;; Copyright (C) 1996 by Olin Shivers.
423;;;
424;;; This file defines three macros for parsing optional arguments to procs:
425;;;     (LET-OPTIONALS  arg-list ((var1 default1) ...) . body)
426;;;     (LET-OPTIONALS* arg-list ((var1 default1) ...) . body)
427;;;     (:OPTIONAL rest-arg default-exp)
428;;;
429;;; The LET-OPTIONALS macro is defined using the Clinger/Rees
430;;; explicit-renaming low-level macro system. You'll have to do some work to
431;;; port it to another macro system.
432;;;
433;;; The LET-OPTIONALS* and :OPTIONAL macros are defined with simple
434;;; high-level macros, and should be portable to any R4RS system.
435;;;
436;;; These macros are all careful to evaluate their default forms *only* if
437;;; their values are needed.
438;;;
439;;; The only non-R4RS dependencies in the macros are ERROR
440;;; and CALL-WITH-VALUES.
441;;;     -Olin
442
443;;; (LET-OPTIONALS arg-list ((var1 default1) ...)
444;;;   body
445;;;   ...)
446;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
447;;; This form is for binding a procedure's optional arguments to either
448;;; the passed-in values or a default.
449;;;
450;;; The expression takes a rest list ARG-LIST and binds the VARi to
451;;; the elements of the rest list. When there are no more elements, then
452;;; the remaining VARi are bound to their corresponding DEFAULTi values.
453;;; It is an error if there are more args than variables.
454;;;
455;;; - The default expressions are *not* evaluated unless needed.
456;;;
457;;; - When evaluated, the default expressions are carried out in the *outer*
458;;;   environment. That is, the DEFAULTi forms do *not* see any of the VARi
459;;;   bindings.
460;;;
461;;;   I originally wanted to have the DEFAULTi forms get eval'd in a LET*
462;;;   style scope -- DEFAULT3 would see VAR1 and VAR2, etc. But this is
463;;;   impossible to implement without side effects or redundant conditional
464;;;   tests. If I drop this requirement, I can use the efficient expansion
465;;;   shown below. If you need LET* scope, use the less-efficient
466;;;   LET-OPTIONALS* form defined below.
467;;;
468;;; Example:
469;;; (define (read-string! str . maybe-args)
470;;;   (let-optionals maybe-args ((port (current-input-port))
471;;;                              (start 0)
472;;;                              (end (string-length str)))
473;;;     ...))
474;;;
475;;; expands to:
476;;;
477;;; (let* ((body (lambda (port start end) ...))
478;;;        (end-def (lambda (%port %start) (body %port %start <end-default>)))
479;;;        (start-def (lambda (%port) (end-def %port <start-default>)))
480;;;        (port-def  (lambda () (start-def <port-def>))))
481;;;   (if (null? rest) (port-def)
482;;;       (let ((%port (car rest))
483;;;             (rest (cdr rest)))
484;;;       (if (null? rest) (start-def %port)
485;;;           (let ((%start (car rest))
486;;;                 (rest (cdr rest)))
487;;;             (if (null? rest) (end-def %port %start)
488;;;                 (let ((%end (car rest))
489;;;                       (rest (cdr rest)))
490;;;                   (if (null? rest) (body %port %start %end)
491;;;                       (error ...)))))))))
492
493
494;;; (LET-OPTIONALS args ((var1 default1) ...) body1 ...)
495
496(define-macro (let-optionals arg-list var/defs . body)
497
498  ;; This guy makes the END-DEF, START-DEF, PORT-DEF definitions above.
499  ;; I wish I had a reasonable loop macro.
500
501  (define (make-default-procs vars body-proc defaulter-names defs rename)
502    (let recur ((vars (reverse vars))
503                (defaulter-names (reverse defaulter-names))
504                (defs (reverse defs))
505                (next-guy body-proc))
506      (if (null? vars) '()
507          (let ((vars (cdr vars)))
508            `((,(car defaulter-names)
509               (lambda ,(reverse vars)
510                 (,next-guy ,@(reverse vars) ,(car defs))))
511              . ,(recur vars
512                        (cdr defaulter-names)
513                        (cdr defs)
514                        (car defaulter-names)))))))
515
516
517    ;; This guy makes the (IF (NULL? REST) (PORT-DEF) ...) tree above.
518
519  (define (make-if-tree vars defaulters body-proc rest rename)
520    (let recur ((vars vars) (defaulters defaulters) (non-defaults '()))
521      (if (null? vars)
522          `(if (##core#check (null? ,rest))
523               (,body-proc . ,(reverse non-defaults))
524               (##sys#error (##core#immutable '"too many optional arguments") ,rest))
525          (let ((v (car vars)))
526            `(if (null? ,rest)
527                 (,(car defaulters) . ,(reverse non-defaults))
528                 (let ((,v (car ,rest))
529                       (,rest (cdr ,rest)))
530                   ,(recur (cdr vars)
531                           (cdr defaulters)
532                           (cons v non-defaults))))))))
533
534  (##sys#check-syntax 'let-optionals var/defs '#((symbol _) 0))
535  (##sys#check-syntax 'let-optionals body '#(_ 1))
536  (let* ((vars (map car var/defs))
537         (prefix-sym (lambda (prefix sym)
538                       (string->symbol (string-append prefix (symbol->string sym)))))
539
540         ;; Private vars, one for each user var.
541         ;; We prefix the % to help keep macro-expanded code from being
542         ;; too confusing.
543         (vars2 (map (lambda (v) (gensym (prefix-sym "%" v)))
544                     vars))
545
546         (defs (map cadr var/defs))
547         (body-proc (gensym 'body))
548
549         ;; A private var, bound to the value of the ARG-LIST expression.
550         (rest-var (gensym '%rest))
551
552         (defaulter-names (map (lambda (var) (gensym (prefix-sym "def-" var)))
553                               vars))
554
555         (defaulters (make-default-procs vars2 body-proc
556                                         defaulter-names defs gensym))
557         (if-tree (make-if-tree vars2 defaulter-names body-proc
558                                rest-var gensym)))
559
560    `(let* ((,rest-var ,arg-list)
561            (,body-proc (lambda ,vars . ,body))
562            . ,defaulters)
563       ,if-tree) ) )
564
565
566;;; (:optional rest-arg default-exp)
567;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
568;;; This form is for evaluating optional arguments and their defaults
569;;; in simple procedures that take a *single* optional argument. It is
570;;; a macro so that the default will not be computed unless it is needed.
571;;;
572;;; REST-ARG is a rest list from a lambda -- e.g., R in
573;;;     (lambda (a b . r) ...)
574;;; - If REST-ARG has 0 elements, evaluate DEFAULT-EXP and return that.
575;;; - If REST-ARG has 1 element, return that element.
576;;; - If REST-ARG has >1 element, error.
577
578(define-macro (optional rest default-exp)
579  (let ([var (gensym)])
580    `(let ((,var ,rest))
581       (if (null? ,var) 
582           ,default-exp
583           (if (##core#check (null? (cdr ,var)))
584               (car ,var)
585               (##sys#error (##core#immutable '"too many optional arguments") ,var))))))
586
587(define-macro (:optional . args)        ; DEPRECATED to avoid conflicts with keyword-style prefix
588  `(optional ,@args) )
589
590
591;;; (LET-OPTIONALS* args ((var1 default1) ... [rest]) body1 ...)
592;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
593;;; This is just like LET-OPTIONALS, except that the DEFAULTi forms
594;;; are evaluated in a LET*-style environment. That is, DEFAULT3 is evaluated
595;;; within the scope of VAR1 and VAR2, and so forth.
596;;;
597;;; - If the last form in the ((var1 default1) ...) list is not a
598;;;   (VARi DEFAULTi) pair, but a simple variable REST, then it is
599;;;   bound to any left-over values. For example, if we have VAR1 through
600;;;   VAR7, and ARGS has 9 values, then REST will be bound to the list of
601;;;   the two values of ARGS. If ARGS is too short, causing defaults to
602;;;   be used, then REST is bound to '().
603;;; - If there is no REST variable, then it is an error to have excess
604;;;   values in the ARGS list.
605
606(define-macro (let-optionals* args var/defs . body)
607  (##sys#check-syntax 'let-optionals* var/defs '#(_ 0))
608  (##sys#check-syntax 'let-optionals* body '#(_ 1))
609  (let ([rvar (gensym)])
610    `(let ((,rvar ,args))
611       ,(let loop ([args rvar] [vardefs var/defs])
612          (if (null? vardefs)
613              `(if (##core#check (null? ,args))
614                   (let () ,@body)
615                   (##sys#error (##core#immutable '"too many optional arguments") ,args) )
616              (let ([head (car vardefs)])
617                (if (pair? head)
618                    (let ([rvar2 (gensym)])
619                      `(let ((,(car head) (if (null? ,args) ,(cadr head) (car ,args)))
620                             (,rvar2 (if (null? ,args) '() (cdr ,args))) )
621                         ,(loop rvar2 (cdr vardefs)) ) )
622                    `(let ((,head ,args)) ,@body) ) ) ) ) ) ) )
623
624
625;;; case-lambda (SRFI-16):
626
627(define-macro (case-lambda . clauses)
628  (define (genvars n)
629    (let loop ([i 0])
630      (if (fx>= i n)
631          '()
632          (cons (gensym) (loop (fx+ i 1))) ) ) )
633  (##sys#check-syntax 'case-lambda clauses '#(_ 0))
634  (require 'srfi-1)                     ; Urgh...
635  (let* ((mincount (apply min (map (lambda (c)
636                                     (##sys#decompose-lambda-list 
637                                      (car c)
638                                      (lambda (vars argc rest) argc) ) )
639                                   clauses) ) ) 
640         (minvars (genvars mincount))
641         (rvar (gensym)) 
642         (lvar (gensym)) )
643    `(lambda ,(append minvars rvar)
644       (let ((,lvar (length ,rvar)))
645         ,(fold-right
646           (lambda (c body)
647             (##sys#decompose-lambda-list
648              (car c)
649              (lambda (vars argc rest)
650                (##sys#check-syntax 'case-lambda (car c) 'lambda-list)
651                `(if ,(let ([a2 (fx- argc mincount)])
652                        (if rest
653                            (if (zero? a2)
654                                #t
655                                `(fx>= ,lvar ,a2) )
656                            `(fx= ,lvar ,a2) ) )
657                     ,(receive
658                       (vars1 vars2) (split-at! (take vars argc) mincount)
659                       (let ((bindings
660                              (let build ((vars2 vars2) (vrest rvar))
661                                (if (null? vars2)
662                                    (cond (rest `(let ((,rest ,vrest)) ,@(cdr c)))
663                                          ((null? (cddr c)) (cadr c))
664                                          (else `(let () ,@(cdr c))) )
665                                    (let ((vrest2 (gensym)))
666                                      `(let ((,(car vars2) (car ,vrest))
667                                             (,vrest2 (cdr ,vrest)) )
668                                         ,(if (pair? (cdr vars2))
669                                              (build (cdr vars2) vrest2)
670                                              (build '() vrest2) ) ) ) ) ) ) )
671                         (if (null? vars1)
672                             bindings
673                             `(let ,(map list vars1 minvars) ,bindings) ) ) )
674                     ,body) ) ) )
675           '(##core#check (##sys#error (##core#immutable '"no matching clause in call to 'case-lambda' form")))
676           clauses) ) ) ) )
677
678
679;;; Record printing:
680
681(define-macro (define-record-printer head . body)
682  (cond [(pair? head)
683         (##sys#check-syntax 'define-record-printer (cons head body) '((symbol symbol symbol) . #(_ 1)))
684         `(##sys#register-record-printer ',(##sys#slot head 0) (lambda ,(##sys#slot head 1) ,@body)) ]
685        [else
686         (##sys#check-syntax 'define-record-printer (cons head body) '(symbol _))
687         `(##sys#register-record-printer ',head ,@body) ] ) )
688
689
690;;; Exceptions:
691
692(define-macro (handle-exceptions var handler . body)
693  (let ([k (gensym)]
694        [args (gensym)] )
695    `((call-with-current-continuation
696       (lambda (,k)
697         (with-exception-handler
698          (lambda (,var) (,k (lambda () ,handler)))
699          (lambda ()
700            (##sys#call-with-values
701             (lambda () ,@body)
702             (lambda ,args (,k (lambda () (##sys#apply ##sys#values ,args)))) ) ) ) ) ) ) ) )
703
704(define-macro (condition-case exp . clauses)
705  (let ([exvar (gensym)]
706        [kvar (gensym)] )
707    (define (parse-clause c)
708      (let* ([var (and (symbol? (car c)) (car c))]
709             [kinds (if var (cadr c) (car c))]
710             [body (if var (cddr c) (cdr c))] )
711        (if (null? kinds)
712            `(else
713              ,(if var
714                   `(let ([,var ,exvar]) ,@body)
715                   `(let () ,@body) ) )
716            `((and ,kvar ,@(map (lambda (k) `(memv ',k ,kvar)) kinds))
717              ,(if var
718                   `(let ([,var ,exvar]) ,@body)
719                   `(let () ,@body) ) ) ) ) )
720    `(handle-exceptions ,exvar
721         (let ([,kvar (and (##sys#structure? ,exvar 'condition) (##sys#slot ,exvar 1))])
722           (cond ,@(map parse-clause clauses)
723                 (else (##sys#signal ,exvar)) ) )
724       ,exp) ) )
725
726
727;;; SRFI-9:
728
729(define-macro (define-record-type t conser pred . slots)
730  (let ([vars (cdr conser)]
731        [slotnames (map car slots)] )
732    `(begin
733       (define ,conser
734         (##sys#make-structure 
735          ',t 
736          ,@(map (lambda (sname)
737                   (if (memq sname vars)
738                       sname
739                       '(##sys#void) ) )
740                 slotnames) ) )
741       (define (,pred x) (##sys#structure? x ',t))
742       ,@(let loop ([slots slots] [i 1])
743           (if (null? slots)
744               '()
745               (let* ([slot (car slots)]
746                      (setters (memq #:record-setters ##sys#features))
747                      (setr? (pair? (cddr slot))) 
748                      (getr `(lambda (x)
749                               (##core#check (##sys#check-structure x ',t))
750                               (##sys#block-ref x ,i) ) ) )
751                 `(,@(if setr?
752                         `((define (,(caddr slot) x y)
753                             (##core#check (##sys#check-structure x ',t))
754                             (##sys#block-set! x ,i y)) )
755                         '() )
756                   (define ,(cadr slot) 
757                     ,(if (and setr? setters)
758                          `(getter-with-setter ,getr ,(caddr slot))
759                          getr) )
760                   ,@(loop (cdr slots) (add1 i)) ) ) ) ) ) ) )
761
762
763;;; Compile-time `require':
764
765(define-macro (require-for-syntax . names)
766  (##sys#check-syntax 'require-for-syntax names '#(_ 0))
767  `(##core#require-for-syntax ,@names) )
768
769(define-macro (require-extension . ids)
770  (##sys#check-syntax 'require-extension ids '#(_ 0))
771  `(##core#require-extension ,@(map (lambda (x) (list 'quote x)) ids) ) )
772
773(define-macro (use . ids)
774  (##sys#check-syntax 'use ids '#(_ 0))
775  `(##core#require-extension ,@(map (lambda (x) (list 'quote x)) ids) ) )
776
777
778;;; SRFI-26:
779
780(define-macro (cut . more)
781  (let loop ([xs more] [vars '()] [vals '()] [rest #f])
782    (if (null? xs)
783        (let ([rvars (reverse vars)]
784              [rvals (reverse vals)] )
785          (if rest
786              (let ([rv (gensym)])
787                `(lambda (,@rvars . ,rv)
788                   (apply ,(car rvals) ,@(cdr rvals) ,rv) ) )
789              `(lambda ,rvars ((begin ,(car rvals)) ,@(cdr rvals)) ) ) )
790        (case (car xs)
791          [(<>)
792           (let ([v (gensym)])
793             (loop (cdr xs) (cons v vars) (cons v vals) #f) ) ]
794          [(<...>) (loop '() vars vals #t)]
795          [else (loop (cdr xs) vars (cons (car xs) vals) #f)] ) ) ) )
796
797(define-macro (cute . more)
798  (let loop ([xs more] [vars '()] [bs '()] [vals '()] [rest #f])
799    (if (null? xs)
800        (let ([rvars (reverse vars)]
801              [rvals (reverse vals)] )
802          (if rest
803              (let ([rv (gensym)])
804                `(let ,bs
805                   (lambda (,@rvars . ,rv)
806                     (apply ,(car rvals) ,@(cdr rvals) ,rv) ) ) )
807              `(let ,bs
808                 (lambda ,rvars (,(car rvals) ,@(cdr rvals)) ) ) ) )
809        (case (car xs)
810          [(<>)
811           (let ([v (gensym)])
812             (loop (cdr xs) (cons v vars) bs (cons v vals) #f) ) ]
813          [(<...>) (loop '() vars bs vals #t)]
814          [else
815           (let ([v (gensym)])
816             (loop (cdr xs) vars (cons (list v (car xs)) bs) (cons v vals) #f) ) ] ) ) ) )
817
818
819;;; SRFI-13:
820
821(define-macro (let-string-start+end s-e-r proc s-exp args-exp . body)
822  (if (pair? (cddr s-e-r))
823      `(receive (,(caddr s-e-r) ,(car s-e-r) ,(cadr s-e-r))
824           (string-parse-start+end ,proc ,s-exp ,args-exp)
825         ,@body)
826      `(receive ,s-e-r
827           (string-parse-final-start+end ,proc ,s-exp ,args-exp)
828         ,@body) ) )
829
830
831;;; Extension helper:
832
833(define-macro (define-extension name . clauses)
834  (let loop ((s '()) (d '()) (cs clauses) (exports #f))
835    (cond ((null? cs)
836           (let ((exps (if exports `(declare (export ,@exports)) '(begin))))
837             `(cond-expand
838               (chicken-compile-shared ,exps ,@d)
839               ((not compiling) ,@d)
840               (else
841                (declare (unit ,name))
842                ,exps
843                (provide ',name) 
844                ,@s) ) ) )
845          ((and (pair? cs) (pair? (car cs)))
846           (let ((t (caar cs))
847                 (next (cdr cs)) )
848             (cond ((eq? 'static t) (loop (cons `(begin ,@(cdar cs)) s) d next exports))
849                   ((eq? 'dynamic t) (loop s (cons `(begin ,@(cdar cs)) d) next exports))
850                   ((eq? 'export t) (loop s d next (append (or exports '()) (cdar cs))))
851                   (else (syntax-error 'define-extension "invalid clause specifier" (caar cs))) ) ) )
852          (else (syntax-error 'define-extension "invalid clause syntax" cs)) ) ) )
853
854
855;;; SRFI-31
856
857(define-macro (rec head . args)
858  (if (pair? head)
859      `(letrec ((,(car head) (lambda ,(cdr head) ,@args))) ,(car head))
860      `(letrec ((,head ,@args)) ,head)))
861
862
863;;; Definitions available at macroexpansion-time:
864
865(define-macro (define-for-syntax head . body)
866  (let* ((body (if (null? body) '((void)) body))
867         (name (if (pair? head) (car head) head)) 
868         (body (if (pair? head) `(lambda ,(cdr head) ,@body) (car body))))
869    (if (symbol? name)
870        (##sys#setslot name 0 (eval body))
871        (syntax-error 'define-for-syntax "invalid identifier" name) )
872    (if ##sys#enable-runtime-macros
873        `(define ,name ,body)
874        '(begin) ) ) )
875
876
877;;; Register features provided by this file
878
879(eval-when (compile load eval)
880  (register-feature! 'srfi-8 'srfi-16 'srfi-26 'srfi-31 'srfi-15 'srfi-11) )
Note: See TracBrowser for help on using the repository browser.