~ chicken-core (chicken-5) /chicken-syntax.scm
Trap1;;;; chicken-syntax.scm - non-standard syntax extensions
2;
3; Copyright (c) 2008-2022, The CHICKEN Team
4; Copyright (c) 2000-2007, Felix L. Winkelmann
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(declare
29 (unit chicken-syntax)
30 (uses expand internal)
31 (disable-interrupts)
32 (fixnum) )
33
34;; IMPORTANT: These macros expand directly into fully qualified names
35;; from the scrutinizer and support modules.
36
37#+(not debugbuild)
38(declare
39 (no-bound-checks)
40 (no-procedure-checks))
41
42(import (scheme)
43 (chicken base)
44 (chicken fixnum)
45 (chicken syntax)
46 (chicken internal)
47 (chicken platform))
48
49(include "common-declarations.scm")
50(include "mini-srfi-1.scm")
51
52;;; Exceptions:
53(set! ##sys#chicken.condition-macro-environment
54 (let ((me0 (##sys#macro-environment)))
55
56(##sys#extend-macro-environment
57 'handle-exceptions
58 `((call-with-current-continuation . scheme#call-with-current-continuation))
59 (##sys#er-transformer
60 (lambda (form r c)
61 (##sys#check-syntax 'handle-exceptions form '(_ variable _ . _))
62 (let ((k (r 'k))
63 (args (r 'args)))
64 `((,(r 'call-with-current-continuation)
65 (##core#lambda
66 (,k)
67 (chicken.condition#with-exception-handler
68 (##core#lambda (,(cadr form)) (,k (##core#lambda () ,(caddr form))))
69 (##core#lambda
70 ()
71 (##sys#call-with-values
72 (##core#lambda () ,@(cdddr form))
73 (##core#lambda
74 ,args
75 (,k (##core#lambda () (##sys#apply ##sys#values ,args))))))))))))))
76
77(##sys#extend-macro-environment
78 'condition-case
79 `((memv . scheme#memv))
80 (##sys#er-transformer
81 (lambda (form r c)
82 (##sys#check-syntax 'condition-case form '(_ _ . _))
83 (let ((exvar (r 'exvar))
84 (kvar (r 'kvar))
85 (%and (r 'and))
86 (%memv (r 'memv))
87 (%else (r 'else)))
88 (define (parse-clause c)
89 (let* ((var (and (symbol? (car c)) (car c)))
90 (kinds (if var (cadr c) (car c)))
91 (body (if var
92 `(##core#let ((,var ,exvar)) ,@(cddr c))
93 `(##core#let () ,@(cdr c)))))
94 (if (null? kinds)
95 `(,%else ,body)
96 `((,%and ,kvar ,@(map (lambda (k)
97 `(,%memv (##core#quote ,k) ,kvar)) kinds))
98 ,body))))
99 `(,(r 'handle-exceptions) ,exvar
100 (##core#let ((,kvar (,%and (##sys#structure? ,exvar
101 (##core#quote condition))
102 (##sys#slot ,exvar 1))))
103 ,(let ((clauses (map parse-clause (cddr form))))
104 `(,(r 'cond)
105 ,@clauses
106 ,@(if (assq %else clauses)
107 `() ; Don't generate two else clauses
108 `((,%else (chicken.condition#signal ,exvar)))))))
109 ,(cadr form))))))
110
111(macro-subset me0 ##sys#default-macro-environment)))
112
113
114;;; type-related syntax
115
116(set! ##sys#chicken.type-macro-environment
117 (let ((me0 (##sys#macro-environment)))
118
119(##sys#extend-macro-environment
120 ': '()
121 (##sys#er-transformer
122 (lambda (x r c)
123 (##sys#check-syntax ': x '(_ symbol _ . _))
124 (if (not (memq #:compiling ##sys#features))
125 '(##core#undefined)
126 (let* ((type1 (strip-syntax (caddr x)))
127 (name1 (cadr x)))
128 ;; we need pred/pure info, so not using
129 ;; "chicken.compiler.scrutinizer#check-and-validate-type"
130 (let-values (((type pred pure)
131 (chicken.compiler.scrutinizer#validate-type
132 type1
133 (strip-syntax name1))))
134 (cond ((not type)
135 (syntax-error ': "invalid type syntax" name1 type1))
136 (else
137 `(##core#declare
138 (type (,name1 ,type1 ,@(cdddr x)))
139 ,@(if pure `((pure ,name1)) '())
140 ,@(if pred `((predicate (,name1 ,pred))) '()))))))))))
141
142(##sys#extend-macro-environment
143 'the '()
144 (##sys#er-transformer
145 (lambda (x r c)
146 (##sys#check-syntax 'the x '(_ _ _))
147 (if (not (memq #:compiling ##sys#features))
148 (caddr x)
149 `(##core#the ,(chicken.compiler.scrutinizer#check-and-validate-type (cadr x) 'the)
150 #t
151 ,(caddr x))))))
152
153(##sys#extend-macro-environment
154 'assume '()
155 (syntax-rules ()
156 ((_ ((var type) ...) body ...)
157 (let ((var (the type var)) ...) body ...))))
158
159(##sys#extend-macro-environment
160 'define-specialization '()
161 (##sys#er-transformer
162 (lambda (x r c)
163 (cond ((not (memq #:compiling ##sys#features)) '(##core#undefined))
164 (else
165 (##sys#check-syntax 'define-specialization x '(_ (variable . #(_ 0)) _ . #(_ 0 1)))
166 (let* ((head (cadr x))
167 (name (car head))
168 (args (cdr head))
169 (alias (gensym name))
170 (rtypes (and (pair? (cdddr x)) (strip-syntax (caddr x))))
171 (%define (r 'define))
172 (body (if rtypes (cadddr x) (caddr x))))
173 (let loop ((args args) (anames '()) (atypes '()))
174 (cond ((null? args)
175 (let ((anames (reverse anames))
176 (atypes (reverse atypes))
177 (spec
178 `(,alias ,@(let loop2 ((anames anames) (i 1))
179 (if (null? anames)
180 '()
181 (cons (vector i)
182 (loop2 (cdr anames) (fx+ i 1))))))))
183 `(##core#begin
184 (##core#local-specialization
185 ,name
186 ,alias
187 ,(cons atypes
188 (if (and rtypes (pair? rtypes))
189 (list
190 (map (cut chicken.compiler.scrutinizer#check-and-validate-type
191 <>
192 'define-specialization)
193 rtypes)
194 spec)
195 (list spec))))
196 (##core#declare (inline ,alias) (hide ,alias))
197 (,%define (,alias ,@anames)
198 (##core#let ,(map (lambda (an at)
199 (list an `(##core#the ,at #t ,an)))
200 anames atypes)
201 ,body)))))
202 (else
203 (let ((arg (car args)))
204 (cond ((symbol? arg)
205 (loop (cdr args) (cons arg anames) (cons '* atypes)))
206 ((and (list? arg) (fx= 2 (length arg)) (symbol? (car arg)))
207 (loop
208 (cdr args)
209 (cons (car arg) anames)
210 (cons
211 (chicken.compiler.scrutinizer#check-and-validate-type
212 (cadr arg)
213 'define-specialization)
214 atypes)))
215 (else (syntax-error
216 'define-specialization
217 "invalid argument syntax" arg head)))))))))))))
218
219(##sys#extend-macro-environment
220 'compiler-typecase '()
221 (##sys#er-transformer
222 (lambda (x r c)
223 (##sys#check-syntax 'compiler-typecase x '(_ _ . #((_ . #(_ 1)) 1)))
224 (let ((val (memq #:compiling ##sys#features))
225 (var (gensym))
226 (ln (get-line-number x)))
227 `(##core#let ((,var ,(cadr x)))
228 (##core#typecase
229 ,ln
230 ,var ; must be variable (see: CPS transform)
231 ,@(map (lambda (clause)
232 (let ((hd (strip-syntax (car clause))))
233 (list
234 (if (eq? hd 'else)
235 'else
236 (if val
237 (chicken.compiler.scrutinizer#check-and-validate-type
238 hd
239 'compiler-typecase)
240 hd))
241 `(##core#begin ,@(cdr clause)))))
242 (cddr x))))))))
243
244(##sys#extend-macro-environment
245 'define-type '()
246 (##sys#er-transformer
247 (lambda (x r c)
248 (##sys#check-syntax 'define-type x '(_ variable _))
249 (cond ((not (memq #:compiling ##sys#features)) '(##core#undefined))
250 (else
251 (let ((name (strip-syntax (cadr x)))
252 (%quote (r 'quote))
253 (t0 (strip-syntax (caddr x))))
254 `(##core#elaborationtimeonly
255 (##sys#put/restore!
256 (,%quote ,name)
257 (,%quote ##compiler#type-abbreviation)
258 (,%quote
259 ,(chicken.compiler.scrutinizer#check-and-validate-type
260 t0 'define-type name))))))))))
261
262(macro-subset me0 ##sys#default-macro-environment)))
263
264;;; Syntax-related syntax (for use in macro transformers)
265
266(set! ##sys#chicken.syntax-macro-environment
267 (let ((me0 (##sys#macro-environment)))
268
269(##sys#extend-macro-environment
270 'syntax
271 '()
272 (##sys#er-transformer
273 (lambda (x r c)
274 (##sys#check-syntax 'syntax x '(_ _))
275 `(##core#syntax ,(cadr x)))))
276
277(##sys#extend-macro-environment
278 'begin-for-syntax '()
279 (##sys#er-transformer
280 (lambda (x r c)
281 (##sys#check-syntax 'begin-for-syntax x '(_ . #(_ 0)))
282 (##sys#register-meta-expression `(##core#begin ,@(cdr x)))
283 `(##core#elaborationtimeonly (##core#begin ,@(cdr x))))))
284
285(##sys#extend-macro-environment
286 'define-for-syntax '()
287 (##sys#er-transformer
288 (lambda (form r c)
289 (##sys#check-syntax 'define-for-syntax form '(_ _ . _))
290 `(,(r 'begin-for-syntax)
291 (,(r 'define) ,@(cdr form))))))
292
293
294;;; Compiler syntax
295
296(##sys#extend-macro-environment
297 'define-compiler-syntax '()
298 (syntax-rules ()
299 ((_ name)
300 (##core#define-compiler-syntax name #f))
301 ((_ name transformer)
302 (##core#define-compiler-syntax name transformer))))
303
304(##sys#extend-macro-environment
305 'let-compiler-syntax '()
306 (syntax-rules ()
307 ((_ (binding ...) body ...)
308 (##core#let-compiler-syntax (binding ...) body ...))))
309
310(macro-subset me0 ##sys#default-macro-environment)))
311
312
313;;; Non-standard macros that provide core/"base" functionality:
314
315(set! ##sys#chicken.base-macro-environment
316 (let ((me0 (##sys#macro-environment)))
317
318(##sys#extend-macro-environment
319 'define-constant
320 '()
321 (##sys#er-transformer
322 (lambda (form r c)
323 (##sys#check-syntax 'define-constant form '(_ variable _))
324 `(##core#define-constant ,@(cdr form)))))
325
326(##sys#extend-macro-environment
327 'define-record '()
328 (##sys#er-transformer
329 (lambda (x r c)
330 (##sys#check-syntax 'define-record x '(_ variable . _))
331 (let* ((type-name (cadr x))
332 (plain-name (strip-syntax type-name))
333 (prefix (symbol->string plain-name))
334 (tag (if (##sys#current-module)
335 (symbol-append
336 (##sys#module-name (##sys#current-module)) '|#| plain-name)
337 plain-name))
338 (slots (cddr x))
339 (%define (r 'define))
340 (%setter (r 'chicken.base#setter))
341 (%getter-with-setter (r 'chicken.base#getter-with-setter))
342 (slotnames
343 (map (lambda (slot)
344 (cond ((symbol? slot) slot)
345 ((and (pair? slot)
346 (c (car slot) %setter)
347 (pair? (cdr slot))
348 (symbol? (cadr slot))
349 (null? (cddr slot)))
350 (cadr slot))
351 (else
352 (syntax-error
353 'define-record "invalid slot specification" slot))))
354 slots)))
355 `(##core#begin
356 (,%define ,type-name (##core#quote ,tag))
357 (,%define
358 ,(string->symbol (string-append "make-" prefix))
359 (##core#lambda
360 ,slotnames
361 (##sys#make-structure (##core#quote ,tag) ,@slotnames)))
362 (,%define
363 ,(string->symbol (string-append prefix "?"))
364 (##core#lambda (x) (##sys#structure? x (##core#quote ,tag))))
365 ,@(let mapslots ((slots slots) (i 1))
366 (if (eq? slots '())
367 slots
368 (let* ((a (car slots))
369 (has-setter (not (symbol? a)))
370 (slotname (symbol->string (if has-setter (cadr a) a)))
371 (setr (string->symbol (string-append prefix "-" slotname "-set!")))
372 (getr (string->symbol (string-append prefix "-" slotname)))
373 (setrcode
374 `(##core#lambda
375 (x val)
376 (##core#check (##sys#check-structure x (##core#quote ,tag)))
377 (##sys#block-set! x ,i val) ) ))
378 (cons
379 `(##core#begin
380 ,@(if has-setter
381 '()
382 `((,%define ,setr ,setrcode)))
383 (,%define
384 ,getr
385 ,(if has-setter
386 `(,%getter-with-setter
387 (##core#lambda
388 (x)
389 (##core#check (##sys#check-structure x (##core#quote ,tag)))
390 (##sys#block-ref x ,i) )
391 ,setrcode)
392 `(##core#lambda
393 (x)
394 (##core#check (##sys#check-structure x (##core#quote ,tag)))
395 (##sys#block-ref x ,i) ) ) ) )
396 (mapslots (##sys#slot slots 1) (fx+ i 1)) ) ) ) ) ) ) ) ) )
397
398(##sys#extend-macro-environment
399 'receive
400 '()
401 (##sys#er-transformer
402 (lambda (form r c)
403 (##sys#check-syntax 'receive form '(_ _ . #(_ 0)))
404 (cond ((null? (cddr form))
405 `(##sys#call-with-values (##core#lambda () ,@(cdr form)) ##sys#list) )
406 (else
407 (##sys#check-syntax 'receive form '(_ lambda-list _ . #(_ 1)))
408 (let ((vars (cadr form))
409 (exp (caddr form))
410 (rest (cdddr form)))
411 (if (and (pair? vars) (null? (cdr vars)))
412 `(##core#let ((,(car vars) ,exp)) ,@rest)
413 `(##sys#call-with-values
414 (##core#lambda () ,exp)
415 (##core#lambda ,vars ,@rest)) ) ) ) ) )))
416
417(##sys#extend-macro-environment
418 'declare '()
419 (##sys#er-transformer
420 (lambda (form r c)
421 `(##core#declare ,@(cdr form)))))
422
423(##sys#extend-macro-environment
424 'delay-force
425 '()
426 (##sys#er-transformer
427 (lambda (form r c)
428 (##sys#check-syntax 'delay-force form '(_ _))
429 `(##sys#make-promise (##core#lambda () ,(cadr form))))))
430
431(##sys#extend-macro-environment
432 'include '()
433 (##sys#er-transformer
434 (lambda (form r c)
435 (##sys#check-syntax 'include form '(_ string))
436 `(##core#include ,(cadr form) #f))))
437
438(##sys#extend-macro-environment
439 'include-relative '()
440 (##sys#er-transformer
441 (lambda (form r c)
442 (##sys#check-syntax 'include-relative form '(_ string))
443 `(##core#include ,(cadr form) ,##sys#current-source-filename))))
444
445(##sys#extend-macro-environment
446 'fluid-let '()
447 (##sys#er-transformer
448 (lambda (form r c)
449 (##sys#check-syntax 'fluid-let form '(_ #((variable _) 0) . _))
450 (let* ((clauses (cadr form))
451 (body (cddr form))
452 (ids (##sys#map car clauses))
453 (new-tmps (##sys#map (lambda (x) (r (gensym))) clauses))
454 (old-tmps (##sys#map (lambda (x) (r (gensym))) clauses)))
455 `(##core#let
456 (,@(map ##sys#list new-tmps (##sys#map cadr clauses))
457 ,@(map ##sys#list old-tmps
458 (let loop ((n (length clauses)))
459 (if (eq? n 0)
460 '()
461 (cons #f (loop (fx- n 1))) ) ) ) )
462 (##sys#dynamic-wind
463 (##core#lambda ()
464 ,@(map (lambda (ot id) `(##core#set! ,ot ,id))
465 old-tmps ids)
466 ,@(map (lambda (id nt) `(##core#set! ,id ,nt))
467 ids new-tmps)
468 (##core#undefined) )
469 (##core#lambda () ,@body)
470 (##core#lambda ()
471 ,@(map (lambda (nt id) `(##core#set! ,nt ,id))
472 new-tmps ids)
473 ,@(map (lambda (id ot) `(##core#set! ,id ,ot))
474 ids old-tmps)
475 (##core#undefined) ) ) ) ) )))
476
477(##sys#extend-macro-environment
478 'parameterize '()
479 (##sys#er-transformer
480 (lambda (form r c)
481 (define (pname p)
482 (if (symbol? p)
483 (gensym p)
484 (gensym "parameter")))
485 (##sys#check-syntax 'parameterize form '#(_ 2))
486 (let* ((bindings (cadr form))
487 (body (cddr form))
488 (convert? (r 'convert?))
489 (params (##sys#map car bindings))
490 (vals (##sys#map cadr bindings))
491 (param-aliases (##sys#map (lambda (z) (r (pname z))) params))
492 (saveds (##sys#map (lambda (z) (r (gensym 'saved))) params))
493 (temps (##sys#map (lambda (z) (r (gensym 'tmp))) params)) )
494 `(##core#let
495 ,(map ##sys#list param-aliases params) ; These may be expressions
496 (##core#let
497 ,(map ##sys#list saveds vals)
498 (##core#let
499 ;; Inner names are actually set. This hides the exact
500 ;; ordering of the let if any call/cc is used in the
501 ;; value expressions (see first example in #1336).
502 ,(map ##sys#list saveds saveds)
503 (##core#let
504 ((,convert? (##core#the boolean #t #t))) ; Convert only first time extent is entered!
505 (##sys#dynamic-wind
506 (##core#lambda ()
507 (##core#let
508 ;; First, call converters (which may throw exceptions!)
509 ,(map (lambda (p s temp)
510 `(,temp (##core#if ,convert? (,p ,s #t #f) ,s)))
511 param-aliases saveds temps)
512 ;; Save current values so we can restore them later
513 ,@(map (lambda (p s) `(##core#set! ,s (,p)))
514 param-aliases saveds)
515 ;; Set parameters to their new values. This can't fail.
516 ,@(map (lambda (p t) `(,p ,t #f #t)) param-aliases temps)
517 ;; Remember we already converted (only call converters once!)
518 (##core#set! ,convert? #f)))
519 (##core#lambda () ,@body)
520 (##core#lambda ()
521 (##core#let
522 ;; Remember the current value of each parameter.
523 ,(map (lambda (p s temp) `(,temp (,p)))
524 param-aliases saveds temps)
525 ;; Restore each parameter to its old value.
526 ,@(map (lambda (p s) `(,p ,s #f #t)) param-aliases saveds)
527 ;; Save current value for later re-invocations.
528 ,@(map (lambda (s temp) `(##core#set! ,s ,temp))
529 saveds temps))))))))))))
530
531(##sys#extend-macro-environment
532 'require-library
533 '()
534 (##sys#er-transformer
535 (lambda (x r c)
536 `(##core#begin
537 ,@(map (lambda (x)
538 (let-values (((name lib _ _ _ _) (##sys#decompose-import x r c 'import)))
539 (if (not lib)
540 '(##core#undefined)
541 `(##core#require ,lib ,name))))
542 (cdr x))))))
543
544(##sys#extend-macro-environment
545 'when '()
546 (##sys#er-transformer
547 (lambda (form r c)
548 (##sys#check-syntax 'when form '#(_ 2))
549 `(##core#if ,(cadr form)
550 (##core#begin ,@(cddr form))))))
551
552(##sys#extend-macro-environment
553 'unless '()
554 (##sys#er-transformer
555 (lambda (form r c)
556 (##sys#check-syntax 'unless form '#(_ 2))
557 `(##core#if ,(cadr form)
558 (##core#undefined)
559 (##core#begin ,@(cddr form))))))
560
561(##sys#extend-macro-environment
562 'set!-values '()
563 (##sys#er-transformer
564 (lambda (form r c)
565 (##sys#check-syntax 'set!-values form '(_ lambda-list _))
566 (##sys#expand-multiple-values-assignment (cadr form) (caddr form)))))
567
568(set! chicken.syntax#define-values-definition
569 (##sys#extend-macro-environment
570 'define-values '()
571 (##sys#er-transformer
572 (lambda (form r c)
573 (##sys#check-syntax 'define-values form '(_ lambda-list _))
574 `(##core#begin
575 ,@(##sys#decompose-lambda-list
576 (cadr form)
577 (lambda (vars argc rest)
578 (for-each (lambda (nm)
579 (let ((name (##sys#get nm '##core#macro-alias nm)))
580 (##sys#register-export name (##sys#current-module))))
581 vars)
582 (map (lambda (nm) `(##core#ensure-toplevel-definition ,nm))
583 vars)))
584 ,(##sys#expand-multiple-values-assignment (cadr form) (caddr form)))))))
585
586(##sys#extend-macro-environment
587 'let-values '()
588 (##sys#er-transformer
589 (lambda (form r c)
590 (##sys#check-syntax 'let-values form '(_ list . _))
591 (let ((vbindings (cadr form))
592 (body (cddr form)))
593 (letrec ((append* (lambda (il l)
594 (if (not (pair? il))
595 (cons il l)
596 (cons (car il)
597 (append* (cdr il) l)))))
598 (map* (lambda (proc l)
599 (cond ((null? l) '())
600 ((not (pair? l)) (proc l))
601 (else (cons (proc (car l)) (map* proc (cdr l))))))))
602 (let* ([llists (map car vbindings)]
603 [vars (let loop ((llists llists) (acc '()))
604 (if (null? llists)
605 acc
606 (let* ((llist (car llists))
607 (new-acc
608 (cond ((list? llist) (append llist acc))
609 ((pair? llist) (append* llist acc))
610 (else (cons llist acc)))))
611 (loop (cdr llists) new-acc))))]
612 [aliases (map (lambda (v) (cons v (r (gensym v)))) vars)]
613 [lookup (lambda (v) (cdr (assq v aliases)))]
614 [llists2 (let loop ((llists llists) (acc '()))
615 (if (null? llists)
616 (reverse acc)
617 (let* ((llist (car llists))
618 (new-acc
619 (cond ((not (pair? llist)) (cons (lookup llist) acc))
620 (else (cons (map* lookup llist) acc)))))
621 (loop (cdr llists) new-acc))))])
622 (let fold ([llists llists]
623 [exps (map (lambda (x) (cadr x)) vbindings)]
624 [llists2 llists2] )
625 (cond ((null? llists)
626 `(##core#let
627 ,(map (lambda (v) (##sys#list v (lookup v))) vars)
628 ,@body) )
629 ((and (pair? (car llists2)) (null? (cdar llists2)))
630 `(##core#let
631 ((,(caar llists2) ,(car exps)))
632 ,(fold (cdr llists) (cdr exps) (cdr llists2)) ) )
633 (else
634 `(##sys#call-with-values
635 (##core#lambda () ,(car exps))
636 (##core#lambda
637 ,(car llists2)
638 ,(fold (cdr llists) (cdr exps) (cdr llists2))) ) ) ) ) ) ) ) ) ) )
639
640(##sys#extend-macro-environment
641 'let*-values '()
642 (##sys#er-transformer
643 (lambda (form r c)
644 (##sys#check-syntax 'let*-values form '(_ list . _))
645 (let ((vbindings (cadr form))
646 (body (cddr form))
647 (%let-values (r 'let-values)) )
648 (let fold ([vbindings vbindings])
649 (if (null? vbindings)
650 `(##core#let () ,@body)
651 `(,%let-values (,(car vbindings))
652 ,(fold (cdr vbindings))) ) ) ))))
653
654;;XXX do we need letrec*-values ?
655(##sys#extend-macro-environment
656 'letrec-values '()
657 (##sys#er-transformer
658 (lambda (form r c)
659 (##sys#check-syntax 'letrec-values form '(_ #((lambda-list . _) 0) . _))
660 (let ((vbindings (cadr form))
661 (body (cddr form)))
662 (let ((vars (map car vbindings))
663 (exprs (map cadr vbindings)))
664 `(##core#let
665 ,(map (lambda (v) (##sys#list v '(##core#undefined)))
666 (foldl (lambda (l v) ; flatten multi-value formals
667 (##sys#append l (##sys#decompose-lambda-list
668 v (lambda (a _ _) a))))
669 '()
670 vars))
671 ,@(map ##sys#expand-multiple-values-assignment vars exprs)
672 ,@body))))))
673
674(##sys#extend-macro-environment
675 'letrec*
676 '()
677 (##sys#er-transformer
678 (lambda (x r c)
679 (##sys#check-syntax 'letrec* x '(_ #((variable _) 0) . #(_ 1)))
680 (check-for-multiple-bindings (cadr x) x "letrec*")
681 `(##core#letrec* ,@(cdr x)))))
682
683(##sys#extend-macro-environment
684 'nth-value
685 `((list-ref . scheme#list-ref))
686 (##sys#er-transformer
687 (lambda (form r c)
688 (##sys#check-syntax 'nth-value form '(_ _ _))
689 (let ((v (r 'tmp)))
690 `(##sys#call-with-values
691 (##core#lambda () ,(caddr form))
692 (##core#lambda ,v (,(r 'list-ref) ,v ,(cadr form))))))))
693
694(##sys#extend-macro-environment
695 'define-inline '()
696 (##sys#er-transformer
697 (lambda (form r c)
698 (letrec ([quotify-proc
699 (lambda (xs id)
700 (##sys#check-syntax id xs '#(_ 1))
701 (let* ([head (car xs)]
702 [name (if (pair? head) (car head) head)]
703 [val (if (pair? head)
704 `(##core#lambda ,(cdr head) ,@(cdr xs))
705 (cadr xs) ) ] )
706 (when (or (not (pair? val))
707 (and (not (eq? '##core#lambda (car val)))
708 (not (c (r 'lambda) (car val)))))
709 (syntax-error
710 'define-inline "invalid substitution form - must be lambda"
711 name val) )
712 (list name val) ) ) ] )
713 `(##core#define-inline ,@(quotify-proc (cdr form) 'define-inline)))) ) )
714
715(##sys#extend-macro-environment
716 'and-let* '()
717 (##sys#er-transformer
718 (lambda (form r c)
719 (##sys#check-syntax 'and-let* form '(_ #(_ 0) . _))
720 (let ((bindings (cadr form))
721 (body (cddr form)))
722 (let fold ([bs bindings] [last #t])
723 (if (null? bs)
724 `(##core#begin ,last . ,body)
725 (let ([b (car bs)]
726 [bs2 (cdr bs)] )
727 (cond [(not (pair? b))
728 (##sys#check-syntax 'and-let* b 'variable)
729 (let ((var (r (gensym))))
730 `(##core#let ((,var ,b))
731 (##core#if ,var ,(fold bs2 var) #f)))]
732 [(null? (cdr b))
733 (let ((var (r (gensym))))
734 `(##core#let ((,var ,(car b)))
735 (##core#if ,var ,(fold bs2 var) #f)))]
736 [else
737 (##sys#check-syntax 'and-let* b '(variable _))
738 (let ((var (car b)))
739 `(##core#let ((,var ,(cadr b)))
740 (##core#if ,var ,(fold bs2 var) #f)))]))))))))
741
742
743
744;;; Optional argument handling:
745
746;;; Copyright (C) 1996 by Olin Shivers.
747;;;
748;;; This file defines three macros for parsing optional arguments to procs:
749;;; (LET-OPTIONALS arg-list ((var1 default1) ...) . body)
750;;; (LET-OPTIONALS* arg-list ((var1 default1) ...) . body)
751;;; (:OPTIONAL rest-arg default-exp)
752;;;
753;;; The LET-OPTIONALS macro is defined using the Clinger/Rees
754;;; explicit-renaming low-level macro system. You'll have to do some work to
755;;; port it to another macro system.
756;;;
757;;; The LET-OPTIONALS* and :OPTIONAL macros are defined with simple
758;;; high-level macros, and should be portable to any R4RS system.
759;;;
760;;; These macros are all careful to evaluate their default forms *only* if
761;;; their values are needed.
762;;;
763;;; The only non-R4RS dependencies in the macros are ERROR
764;;; and CALL-WITH-VALUES.
765;;; -Olin
766
767;;; (LET-OPTIONALS arg-list ((var1 default1) ...)
768;;; body
769;;; ...)
770;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
771;;; This form is for binding a procedure's optional arguments to either
772;;; the passed-in values or a default.
773;;;
774;;; The expression takes a rest list ARG-LIST and binds the VARi to
775;;; the elements of the rest list. When there are no more elements, then
776;;; the remaining VARi are bound to their corresponding DEFAULTi values.
777;;;
778;;; - The default expressions are *not* evaluated unless needed.
779;;;
780;;; - When evaluated, the default expressions are carried out in the *outer*
781;;; environment. That is, the DEFAULTi forms do *not* see any of the VARi
782;;; bindings.
783;;;
784;;; I originally wanted to have the DEFAULTi forms get eval'd in a LET*
785;;; style scope -- DEFAULT3 would see VAR1 and VAR2, etc. But this is
786;;; impossible to implement without side effects or redundant conditional
787;;; tests. If I drop this requirement, I can use the efficient expansion
788;;; shown below. If you need LET* scope, use the less-efficient
789;;; LET-OPTIONALS* form defined below.
790;;;
791;;; Example:
792;;; (define (read-string! str . maybe-args)
793;;; (let-optionals maybe-args ((port (current-input-port))
794;;; (start 0)
795;;; (end (string-length str)))
796;;; ...))
797;;;
798;;; expands to:
799;;;
800;;; (let* ((body (lambda (port start end) ...))
801;;; (end-def (lambda (%port %start) (body %port %start <end-default>)))
802;;; (start-def (lambda (%port) (end-def %port <start-default>)))
803;;; (port-def (lambda () (start-def <port-def>))))
804;;; (if (null? rest) (port-def)
805;;; (let ((%port (car rest))
806;;; (rest (cdr rest)))
807;;; (if (null? rest) (start-def %port)
808;;; (let ((%start (car rest))
809;;; (rest (cdr rest)))
810;;; (if (null? rest) (end-def %port %start)
811;;; (let ((%end (car rest))
812;;; (rest (cdr rest)))
813;;; (if (null? rest) (body %port %start %end)
814;;; (error ...)))))))))
815
816
817;;; (LET-OPTIONALS args ((var1 default1) ...) body1 ...)
818
819(##sys#extend-macro-environment
820 'let-optionals
821 `((null? . scheme#null?)
822 (car . scheme#car)
823 (cdr . scheme#cdr))
824 (##sys#er-transformer
825 (lambda (form r c)
826 (##sys#check-syntax 'let-optionals form '(_ _ . _))
827 (let ((arg-list (cadr form))
828 (var/defs (caddr form))
829 (body (cdddr form)))
830
831 ;; This guy makes the END-DEF, START-DEF, PORT-DEF definitions above.
832 ;; I wish I had a reasonable loop macro.
833
834 (define (make-default-procs vars body-proc defaulter-names defs rename)
835 (let recur ((vars (reverse vars))
836 (defaulter-names (reverse defaulter-names))
837 (defs (reverse defs))
838 (next-guy body-proc))
839 (if (null? vars) '()
840 (let ((vars (cdr vars)))
841 `((,(car defaulter-names)
842 (##core#lambda ,(reverse vars)
843 (,next-guy ,@(reverse vars) ,(car defs))))
844 . ,(recur vars
845 (cdr defaulter-names)
846 (cdr defs)
847 (car defaulter-names)))))))
848
849
850 ;; This guy makes the (IF (NULL? REST) (PORT-DEF) ...) tree above.
851
852 (define (make-if-tree vars defaulters body-proc rest rename)
853 (let recur ((vars vars) (defaulters defaulters) (non-defaults '()))
854 (if (null? vars)
855 `(,body-proc . ,(reverse non-defaults))
856 (let ((v (car vars)))
857 `(##core#if (,(r 'null?) ,rest)
858 (,(car defaulters) . ,(reverse non-defaults))
859 (##core#let ((,v (,(r 'car) ,rest)) ; we use car/cdr, because of rest-list optimization
860 (,rest (,(r 'cdr) ,rest)))
861 ,(recur (cdr vars)
862 (cdr defaulters)
863 (cons v non-defaults))))))))
864
865 (##sys#check-syntax 'let-optionals var/defs '#((variable _) 0))
866 (##sys#check-syntax 'let-optionals body '#(_ 1))
867 (let* ((vars (map car var/defs))
868 (prefix-sym (lambda (prefix sym)
869 (string->symbol (string-append prefix (symbol->string sym)))))
870
871 ;; Private vars, one for each user var.
872 ;; We prefix the % to help keep macro-expanded code from being
873 ;; too confusing.
874 (vars2 (map (lambda (v) (r (prefix-sym "%" v)))
875 vars))
876
877 (defs (map cadr var/defs))
878 (body-proc (r 'body))
879
880 ;; A private var, bound to the value of the ARG-LIST expression.
881 (rest-var (r '_%rest))
882
883 (defaulter-names (map (lambda (var) (r (prefix-sym "def-" var)))
884 vars))
885
886 (defaulters (make-default-procs vars2 body-proc
887 defaulter-names defs gensym))
888 (if-tree (make-if-tree vars2 defaulter-names body-proc
889 rest-var gensym)))
890
891 `(,(r 'let*) ((,rest-var ,arg-list)
892 (,body-proc (##core#lambda ,vars . ,body))
893 . ,defaulters)
894 ,if-tree) ) ))))
895
896
897;;; (optional rest-arg default-exp)
898;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
899;;; This form is for evaluating optional arguments and their defaults
900;;; in simple procedures that take a *single* optional argument. It is
901;;; a macro so that the default will not be computed unless it is needed.
902;;;
903;;; REST-ARG is a rest list from a lambda -- e.g., R in
904;;; (lambda (a b . r) ...)
905;;; - If REST-ARG has 0 elements, evaluate DEFAULT-EXP and return that.
906;;; - If REST-ARG has 1 element, return that element.
907
908(##sys#extend-macro-environment
909 'optional
910 `((null? . scheme#null?)
911 (car . scheme#car)
912 (cdr . scheme#cdr) )
913 (##sys#er-transformer
914 (lambda (form r c)
915 (##sys#check-syntax 'optional form '(_ _ . #(_ 0 1)))
916 (let ((var (r 'tmp)))
917 `(##core#let ((,var ,(cadr form)))
918 (##core#if (,(r 'null?) ,var)
919 ,(optional (cddr form) #f)
920 (,(r 'car) ,var)))))))
921
922
923;;; (LET-OPTIONALS* args ((var1 default1) ... [rest]) body1 ...)
924;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
925;;; This is just like LET-OPTIONALS, except that the DEFAULTi forms
926;;; are evaluated in a LET*-style environment. That is, DEFAULT3 is evaluated
927;;; within the scope of VAR1 and VAR2, and so forth.
928;;;
929;;; - If the last form in the ((var1 default1) ...) list is not a
930;;; (VARi DEFAULTi) pair, but a simple variable REST, then it is
931;;; bound to any left-over values. For example, if we have VAR1 through
932;;; VAR7, and ARGS has 9 values, then REST will be bound to the list of
933;;; the two values of ARGS. If ARGS is too short, causing defaults to
934;;; be used, then REST is bound to '().
935
936(##sys#extend-macro-environment
937 'let-optionals*
938 `((null? . scheme#null?)
939 (car . scheme#car)
940 (cdr . scheme#cdr))
941 (##sys#er-transformer
942 (lambda (form r c)
943 (##sys#check-syntax 'let-optionals* form '(_ _ list . _))
944 (let ((args (cadr form))
945 (var/defs (caddr form))
946 (body (cdddr form))
947 (%null? (r 'null?))
948 (%car (r 'car))
949 (%cdr (r 'cdr)))
950 (let ((rvar (r 'tmp)))
951 `(##core#let
952 ((,rvar ,args))
953 ,(let loop ((args rvar) (vardefs var/defs))
954 (if (null? vardefs)
955 `(##core#let () ,@body)
956 (let ((head (car vardefs)))
957 (if (pair? head)
958 (let ((rvar2 (r 'tmp2)))
959 `(##core#let ((,(car head) (##core#if (,%null? ,args)
960 ,(cadr head)
961 (,%car ,args)))
962 (,rvar2 (##core#if (,%null? ,args)
963 (##core#quote ())
964 (,%cdr ,args))) )
965 ,(loop rvar2 (cdr vardefs)) ) )
966 `(##core#let ((,head ,args)) ,@body) ) ) ) ) ) ) ))))
967
968
969;;; case-lambda (SRFI-16):
970
971(##sys#extend-macro-environment
972 'case-lambda
973 `((>= . scheme#>=)
974 (car . scheme#car)
975 (cdr . scheme#cdr)
976 (eq? . scheme#eq?)
977 (length . scheme#length))
978 (##sys#er-transformer
979 (lambda (form r c)
980 (##sys#check-syntax 'case-lambda form '(_ . _))
981 (define (genvars n)
982 (let loop ([i 0])
983 (if (fx>= i n)
984 '()
985 (cons (r (gensym)) (loop (fx+ i 1))) ) ) )
986 (let* ((mincount (apply min (map (lambda (c)
987 (##sys#decompose-lambda-list
988 (car c)
989 (lambda (vars argc rest) argc) ) )
990 (cdr form))))
991 (minvars (genvars mincount))
992 (rvar (r 'rvar))
993 (lvar (r 'lvar))
994 (%>= (r '>=))
995 (%eq? (r 'eq?))
996 (%car (r 'car))
997 (%cdr (r 'cdr))
998 (%length (r 'length)))
999 `(##core#lambda
1000 ,(append minvars rvar)
1001 (##core#let
1002 ((,lvar (,%length ,rvar)))
1003 ,(foldr
1004 (lambda (c body)
1005 (##sys#decompose-lambda-list
1006 (car c)
1007 (lambda (vars argc rest)
1008 (##sys#check-syntax 'case-lambda (car c) 'lambda-list)
1009 `(##core#if ,(let ((a2 (fx- argc mincount)))
1010 (if rest
1011 (if (zero? a2)
1012 #t
1013 `(,%>= ,lvar ,a2) )
1014 `(,%eq? ,lvar ,a2) ) )
1015 ,(receive (vars1 vars2)
1016 (split-at (take vars argc) mincount)
1017 (let ((bindings
1018 (let build ((vars2 vars2) (vrest rvar))
1019 (if (null? vars2)
1020 (cond (rest `(##core#let ((,rest ,vrest)) ,@(cdr c)))
1021 ((null? (cddr c)) (cadr c))
1022 (else `(##core#let () ,@(cdr c))) )
1023 (let ((vrest2 (r (gensym))))
1024 `(##core#let ((,(car vars2) (,%car ,vrest))
1025 (,vrest2 (,%cdr ,vrest)) )
1026 ,(if (pair? (cdr vars2))
1027 (build (cdr vars2) vrest2)
1028 (build '() vrest2) ) ) ) ) ) ) )
1029 (if (null? vars1)
1030 bindings
1031 `(##core#let ,(map list vars1 minvars) ,bindings) ) ) )
1032 ,body) ) ) )
1033 '(##core#check (##sys#error (##core#immutable (##core#quote "no matching clause in call to 'case-lambda' form"))))
1034 (cdr form))))))))
1035
1036
1037;;; Record printing:
1038
1039(##sys#extend-macro-environment
1040 'define-record-printer '() ;; DEPRECATED
1041 (##sys#er-transformer
1042 (lambda (form r c)
1043 (##sys#check-syntax 'define-record-printer form '(_ _ . _))
1044 (let ((head (cadr form))
1045 (body (cddr form))
1046 (%set-record-printer! (r 'chicken.base#set-record-printer!)))
1047 (cond [(pair? head)
1048 (##sys#check-syntax
1049 'define-record-printer (cons head body)
1050 '((variable variable variable) . #(_ 1)))
1051 (let* ((plain-name (strip-syntax (##sys#slot head 0)))
1052 (tag (if (##sys#current-module)
1053 (symbol-append
1054 (##sys#module-name (##sys#current-module))
1055 '|#| plain-name)
1056 plain-name)))
1057 `(,%set-record-printer!
1058 (##core#quote ,tag)
1059 (##core#lambda ,(##sys#slot head 1) ,@body)))]
1060 (else
1061 (##sys#check-syntax 'define-record-printer (cons head body) '(variable _))
1062 (let* ((plain-name (strip-syntax head))
1063 (tag (if (##sys#current-module)
1064 (symbol-append
1065 (##sys#module-name (##sys#current-module))
1066 '|#| plain-name)
1067 plain-name)))
1068 `(,%set-record-printer!
1069 (##core#quote ,tag) ,@body))))))))
1070
1071;;; SRFI-9:
1072
1073(##sys#extend-macro-environment
1074 'define-record-type
1075 `()
1076 (##sys#er-transformer
1077 (lambda (form r c)
1078 (##sys#check-syntax
1079 'define-record-type
1080 form
1081 '(_ variable #(variable 1) variable . _))
1082 (let* ((type-name (cadr form))
1083 (plain-name (strip-syntax type-name))
1084 (tag (if (##sys#current-module)
1085 (symbol-append
1086 (##sys#module-name (##sys#current-module))
1087 '|#| plain-name)
1088 plain-name))
1089 (conser (caddr form))
1090 (pred (cadddr form))
1091 (slots (cddddr form))
1092 (%define (r 'define))
1093 (%getter-with-setter (r 'chicken.base#getter-with-setter))
1094 (vars (cdr conser))
1095 (x (r 'x))
1096 (y (r 'y))
1097 (slotnames (map car slots)))
1098 ;; Check for inconsistencies in slot names vs constructor args
1099 (for-each (lambda (vname)
1100 (unless (memq vname slotnames)
1101 (syntax-error
1102 'define-record-type
1103 "unknown slot name in constructor definition"
1104 vname)))
1105 vars)
1106 `(##core#begin
1107 ;; TODO: Maybe wrap this in an opaque object?
1108 (,%define ,type-name (##core#quote ,tag))
1109 (,%define ,conser
1110 (##sys#make-structure
1111 (##core#quote ,tag)
1112 ,@(map (lambda (sname)
1113 (if (memq sname vars)
1114 sname
1115 '(##core#undefined) ) )
1116 slotnames) ) )
1117 (,%define (,pred ,x) (##sys#structure? ,x (##core#quote ,tag)))
1118 ,@(let loop ([slots slots] [i 1])
1119 (if (null? slots)
1120 '()
1121 (let* ((slot (car slots))
1122 (settable (pair? (cddr slot)))
1123 (setr (and settable (caddr slot)))
1124 (ssetter (and (pair? setr)
1125 (pair? (cdr setr))
1126 (c 'setter (car setr))
1127 (cadr setr)))
1128 (get `(##core#lambda
1129 (,x)
1130 (##core#check
1131 (##sys#check-structure
1132 ,x
1133 (##core#quote ,tag)
1134 (##core#quote ,(cadr slot))))
1135 (##sys#block-ref ,x ,i) ) )
1136 (set (and settable
1137 `(##core#lambda
1138 (,x ,y)
1139 (##core#check
1140 (##sys#check-structure
1141 ,x
1142 (##core#quote ,tag)
1143 (##core#quote ,ssetter)))
1144 (##sys#block-set! ,x ,i ,y)) )))
1145 `((,%define
1146 ,(cadr slot)
1147 ,(if (and ssetter (c ssetter (cadr slot)))
1148 `(,%getter-with-setter ,get ,set)
1149 get))
1150 ,@(if settable
1151 (if ssetter
1152 (if (not (c ssetter (cadr slot)))
1153 `(((##sys#setter ##sys#setter) ,ssetter ,set))
1154 '())
1155 `((,%define ,setr ,set)))
1156 '())
1157 ,@(loop (cdr slots) (add1 i)) ) ) ) ) ) ) ) ) )
1158
1159
1160;;; SRFI-26:
1161
1162(##sys#extend-macro-environment
1163 'cut
1164 `((apply . scheme#apply))
1165 (##sys#er-transformer
1166 (lambda (form r c)
1167 (let ((%<> (r '<>))
1168 (%<...> (r '<...>))
1169 (%apply (r 'apply)))
1170 (when (null? (cdr form))
1171 (syntax-error 'cut "you need to supply at least a procedure" form))
1172 (let loop ([xs (cdr form)] [vars '()] [vals '()] [rest #f])
1173 (if (null? xs)
1174 (let ([rvars (reverse vars)]
1175 [rvals (reverse vals)] )
1176 (if rest
1177 (let ([rv (r (gensym))])
1178 `(##core#lambda
1179 (,@rvars . ,rv)
1180 (,%apply ,(car rvals) ,@(cdr rvals) ,rv) ) )
1181 ;;XXX should we drop the begin?
1182 `(##core#lambda ,rvars ((##core#begin ,(car rvals)) ,@(cdr rvals)) ) ) )
1183 (cond ((c %<> (car xs))
1184 (let ([v (r (gensym))])
1185 (loop (cdr xs) (cons v vars) (cons v vals) #f) ) )
1186 ((c %<...> (car xs))
1187 (if (null? (cdr xs))
1188 (loop '() vars vals #t)
1189 (syntax-error
1190 'cut
1191 "tail patterns after <...> are not supported"
1192 form)))
1193 (else (loop (cdr xs) vars (cons (car xs) vals) #f)) ) ) ) ) )))
1194
1195(##sys#extend-macro-environment
1196 'cute
1197 `((apply . scheme#apply))
1198 (##sys#er-transformer
1199 (lambda (form r c)
1200 (let ((%apply (r 'apply))
1201 (%<> (r '<>))
1202 (%<...> (r '<...>)))
1203 (when (null? (cdr form))
1204 (syntax-error 'cute "you need to supply at least a procedure" form))
1205 (let loop ([xs (cdr form)] [vars '()] [bs '()] [vals '()] [rest #f])
1206 (if (null? xs)
1207 (let ([rvars (reverse vars)]
1208 [rvals (reverse vals)] )
1209 (if rest
1210 (let ([rv (r (gensym))])
1211 `(##core#let
1212 ,bs
1213 (##core#lambda (,@rvars . ,rv)
1214 (,%apply ,(car rvals) ,@(cdr rvals) ,rv) ) ) )
1215 `(##core#let ,bs
1216 (##core#lambda ,rvars (,(car rvals) ,@(cdr rvals)) ) ) ) )
1217 (cond ((c %<> (car xs))
1218 (let ([v (r (gensym))])
1219 (loop (cdr xs) (cons v vars) bs (cons v vals) #f) ) )
1220 ((c %<...> (car xs))
1221 (if (null? (cdr xs))
1222 (loop '() vars bs vals #t)
1223 (syntax-error
1224 'cute
1225 "tail patterns after <...> are not supported"
1226 form)))
1227 (else
1228 (let ([v (r (gensym))])
1229 (loop (cdr xs)
1230 vars
1231 (cons (list v (car xs)) bs)
1232 (cons v vals) #f) ) ))))))))
1233
1234
1235;;; SRFI-31
1236
1237(##sys#extend-macro-environment
1238 'rec '()
1239 (##sys#er-transformer
1240 (lambda (form r c)
1241 (##sys#check-syntax 'rec form '(_ _ . _))
1242 (let ((head (cadr form)))
1243 (if (pair? head)
1244 `(##core#letrec* ((,(car head)
1245 (##core#lambda ,(cdr head)
1246 ,@(cddr form))))
1247 ,(car head))
1248 `(##core#letrec* ((,head ,@(cddr form))) ,head))))))
1249
1250
1251;;; SRFI-55
1252
1253(##sys#extend-macro-environment
1254 'require-extension
1255 '()
1256 (##sys#er-transformer
1257 (lambda (x r c)
1258 `(,(r 'import) ,@(cdr x)))))
1259
1260
1261;;; Assertions
1262
1263(##sys#extend-macro-environment
1264 'assert '()
1265 (##sys#er-transformer
1266 (let ((string-append string-append))
1267 (lambda (form r c)
1268 (##sys#check-syntax 'assert form '#(_ 1))
1269 (let* ((exp (cadr form))
1270 (msg-and-args (cddr form))
1271 (msg (optional msg-and-args "assertion failed"))
1272 (tmp (r 'tmp)))
1273 (when (string? msg)
1274 (and-let* ((ln (get-line-number form)))
1275 (set! msg (string-append "(" ln ") " msg))))
1276 `(##core#let ((,tmp ,exp))
1277 (##core#if (##core#check ,tmp)
1278 ,tmp
1279 (##sys#error
1280 ,msg
1281 ,@(if (pair? msg-and-args)
1282 (cdr msg-and-args)
1283 `((##core#quote ,(strip-syntax exp))))))))))))
1284
1285(macro-subset me0 ##sys#default-macro-environment)))
1286
1287
1288;;; "time"
1289
1290(set! ##sys#chicken.time-macro-environment
1291 (let ((me0 (##sys#macro-environment)))
1292
1293(##sys#extend-macro-environment
1294 'time '()
1295 (##sys#er-transformer
1296 (lambda (form r c)
1297 (let ((rvar (r 't)))
1298 `(##core#begin
1299 (##sys#start-timer)
1300 (##sys#call-with-values
1301 (##core#lambda () ,@(cdr form))
1302 (##core#lambda
1303 ,rvar
1304 (##sys#display-times (##sys#stop-timer))
1305 (##sys#apply ##sys#values ,rvar))))))))
1306
1307(macro-subset me0 ##sys#default-macro-environment)))
1308
1309;; register features
1310
1311(register-feature! 'srfi-2 'srfi-8 'srfi-9 'srfi-11 'srfi-15 'srfi-16 'srfi-26 'srfi-31 'srfi-55)