~ chicken-core (chicken-5) /chicken-syntax.scm
Trap1;;;; chicken-syntax.scm - non-standard syntax extensions2;3; Copyright (c) 2008-2022, The CHICKEN Team4; Copyright (c) 2000-2007, Felix L. Winkelmann5; All rights reserved.6;7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following8; conditions are met:9;10; Redistributions of source code must retain the above copyright notice, this list of conditions and the following11; disclaimer.12; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following13; 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 promote15; 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 EXPRESS18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE25; POSSIBILITY OF SUCH DAMAGE.262728(declare29 (unit chicken-syntax)30 (uses expand internal)31 (disable-interrupts)32 (fixnum) )3334;; IMPORTANT: These macros expand directly into fully qualified names35;; from the scrutinizer and support modules.3637#+(not debugbuild)38(declare39 (no-bound-checks)40 (no-procedure-checks))4142(import (scheme)43 (chicken base)44 (chicken fixnum)45 (chicken syntax)46 (chicken internal)47 (chicken platform))4849(include "common-declarations.scm")50(include "mini-srfi-1.scm")5152;;; Exceptions:53(set! ##sys#chicken.condition-macro-environment54 (let ((me0 (##sys#macro-environment)))5556(##sys#extend-macro-environment57 'handle-exceptions58 `((call-with-current-continuation . scheme#call-with-current-continuation))59 (##sys#er-transformer60 (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#lambda66 (,k)67 (chicken.condition#with-exception-handler68 (##core#lambda (,(cadr form)) (,k (##core#lambda () ,(caddr form))))69 (##core#lambda70 ()71 (##sys#call-with-values72 (##core#lambda () ,@(cdddr form))73 (##core#lambda74 ,args75 (,k (##core#lambda () (##sys#apply ##sys#values ,args))))))))))))))7677(##sys#extend-macro-environment78 'condition-case79 `((memv . scheme#memv))80 (##sys#er-transformer81 (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 var92 `(##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) ,exvar100 (##core#let ((,kvar (,%and (##sys#structure? ,exvar101 (##core#quote condition))102 (##sys#slot ,exvar 1))))103 ,(let ((clauses (map parse-clause (cddr form))))104 `(,(r 'cond)105 ,@clauses106 ,@(if (assq %else clauses)107 `() ; Don't generate two else clauses108 `((,%else (chicken.condition#signal ,exvar)))))))109 ,(cadr form))))))110111(macro-subset me0 ##sys#default-macro-environment)))112113114;;; type-related syntax115116(set! ##sys#chicken.type-macro-environment117 (let ((me0 (##sys#macro-environment)))118119(##sys#extend-macro-environment120 ': '()121 (##sys#er-transformer122 (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 using129 ;; "chicken.compiler.scrutinizer#check-and-validate-type"130 (let-values (((type pred pure)131 (chicken.compiler.scrutinizer#validate-type132 type1133 (strip-syntax name1))))134 (cond ((not type)135 (syntax-error ': "invalid type syntax" name1 type1))136 (else137 `(##core#declare138 (type (,name1 ,type1 ,@(cdddr x)))139 ,@(if pure `((pure ,name1)) '())140 ,@(if pred `((predicate (,name1 ,pred))) '()))))))))))141142(##sys#extend-macro-environment143 'the '()144 (##sys#er-transformer145 (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 #t151 ,(caddr x))))))152153(##sys#extend-macro-environment154 'assume '()155 (syntax-rules ()156 ((_ ((var type) ...) body ...)157 (let ((var (the type var)) ...) body ...))))158159(##sys#extend-macro-environment160 'define-specialization '()161 (##sys#er-transformer162 (lambda (x r c)163 (cond ((not (memq #:compiling ##sys#features)) '(##core#undefined))164 (else165 (##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 (spec178 `(,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#begin184 (##core#local-specialization185 ,name186 ,alias187 ,(cons atypes188 (if (and rtypes (pair? rtypes))189 (list190 (map (cut chicken.compiler.scrutinizer#check-and-validate-type191 <>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 (else203 (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 (loop208 (cdr args)209 (cons (car arg) anames)210 (cons211 (chicken.compiler.scrutinizer#check-and-validate-type212 (cadr arg)213 'define-specialization)214 atypes)))215 (else (syntax-error216 'define-specialization217 "invalid argument syntax" arg head)))))))))))))218219(##sys#extend-macro-environment220 'compiler-typecase '()221 (##sys#er-transformer222 (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#typecase229 ,ln230 ,var ; must be variable (see: CPS transform)231 ,@(map (lambda (clause)232 (let ((hd (strip-syntax (car clause))))233 (list234 (if (eq? hd 'else)235 'else236 (if val237 (chicken.compiler.scrutinizer#check-and-validate-type238 hd239 'compiler-typecase)240 hd))241 `(##core#begin ,@(cdr clause)))))242 (cddr x))))))))243244(##sys#extend-macro-environment245 'define-type '()246 (##sys#er-transformer247 (lambda (x r c)248 (##sys#check-syntax 'define-type x '(_ variable _))249 (cond ((not (memq #:compiling ##sys#features)) '(##core#undefined))250 (else251 (let ((name (strip-syntax (cadr x)))252 (%quote (r 'quote))253 (t0 (strip-syntax (caddr x))))254 `(##core#elaborationtimeonly255 (##sys#put/restore!256 (,%quote ,name)257 (,%quote ##compiler#type-abbreviation)258 (,%quote259 ,(chicken.compiler.scrutinizer#check-and-validate-type260 t0 'define-type name))))))))))261262(macro-subset me0 ##sys#default-macro-environment)))263264;;; Syntax-related syntax (for use in macro transformers)265266(set! ##sys#chicken.syntax-macro-environment267 (let ((me0 (##sys#macro-environment)))268269(##sys#extend-macro-environment270 'syntax271 '()272 (##sys#er-transformer273 (lambda (x r c)274 (##sys#check-syntax 'syntax x '(_ _))275 `(##core#syntax ,(cadr x)))))276277(##sys#extend-macro-environment278 'begin-for-syntax '()279 (##sys#er-transformer280 (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))))))284285(##sys#extend-macro-environment286 'define-for-syntax '()287 (##sys#er-transformer288 (lambda (form r c)289 (##sys#check-syntax 'define-for-syntax form '(_ _ . _))290 `(,(r 'begin-for-syntax)291 (,(r 'define) ,@(cdr form))))))292293294;;; Compiler syntax295296(##sys#extend-macro-environment297 '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))))303304(##sys#extend-macro-environment305 'let-compiler-syntax '()306 (syntax-rules ()307 ((_ (binding ...) body ...)308 (##core#let-compiler-syntax (binding ...) body ...))))309310(macro-subset me0 ##sys#default-macro-environment)))311312313;;; Non-standard macros that provide core/"base" functionality:314315(set! ##sys#chicken.base-macro-environment316 (let ((me0 (##sys#macro-environment)))317318(##sys#extend-macro-environment319 'define-constant320 '()321 (##sys#er-transformer322 (lambda (form r c)323 (##sys#check-syntax 'define-constant form '(_ variable _))324 `(##core#define-constant ,@(cdr form)))))325326(##sys#extend-macro-environment327 'define-record '()328 (##sys#er-transformer329 (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-append336 (##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 (slotnames343 (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 (else352 (syntax-error353 'define-record "invalid slot specification" slot))))354 slots)))355 `(##core#begin356 (,%define ,type-name (##core#quote ,tag))357 (,%define358 ,(string->symbol (string-append "make-" prefix))359 (##core#lambda360 ,slotnames361 (##sys#make-structure (##core#quote ,tag) ,@slotnames)))362 (,%define363 ,(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 slots368 (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 (setrcode374 `(##core#lambda375 (x val)376 (##core#check (##sys#check-structure x (##core#quote ,tag)))377 (##sys#block-set! x ,i val) ) ))378 (cons379 `(##core#begin380 ,@(if has-setter381 '()382 `((,%define ,setr ,setrcode)))383 (,%define384 ,getr385 ,(if has-setter386 `(,%getter-with-setter387 (##core#lambda388 (x)389 (##core#check (##sys#check-structure x (##core#quote ,tag)))390 (##sys#block-ref x ,i) )391 ,setrcode)392 `(##core#lambda393 (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)) ) ) ) ) ) ) ) ) )397398(##sys#extend-macro-environment399 'receive400 '()401 (##sys#er-transformer402 (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 (else407 (##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-values414 (##core#lambda () ,exp)415 (##core#lambda ,vars ,@rest)) ) ) ) ) )))416417(##sys#extend-macro-environment418 'declare '()419 (##sys#er-transformer420 (lambda (form r c)421 `(##core#declare ,@(cdr form)))))422423(##sys#extend-macro-environment424 'delay-force425 '()426 (##sys#er-transformer427 (lambda (form r c)428 (##sys#check-syntax 'delay-force form '(_ _))429 `(##sys#make-promise (##core#lambda () ,(cadr form))))))430431(##sys#extend-macro-environment432 'include '()433 (##sys#er-transformer434 (lambda (form r c)435 (##sys#check-syntax 'include form '(_ string))436 `(##core#include ,(cadr form) #f))))437438(##sys#extend-macro-environment439 'include-relative '()440 (##sys#er-transformer441 (lambda (form r c)442 (##sys#check-syntax 'include-relative form '(_ string))443 `(##core#include ,(cadr form) ,##sys#current-source-filename))))444445(##sys#extend-macro-environment446 'fluid-let '()447 (##sys#er-transformer448 (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#let456 (,@(map ##sys#list new-tmps (##sys#map cadr clauses))457 ,@(map ##sys#list old-tmps458 (let loop ((n (length clauses)))459 (if (eq? n 0)460 '()461 (cons #f (loop (fx- n 1))) ) ) ) )462 (##sys#dynamic-wind463 (##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) ) ) ) ) )))476477(##sys#extend-macro-environment478 'parameterize '()479 (##sys#er-transformer480 (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#let495 ,(map ##sys#list param-aliases params) ; These may be expressions496 (##core#let497 ,(map ##sys#list saveds vals)498 (##core#let499 ;; Inner names are actually set. This hides the exact500 ;; ordering of the let if any call/cc is used in the501 ;; value expressions (see first example in #1336).502 ,(map ##sys#list saveds saveds)503 (##core#let504 ((,convert? (##core#the boolean #t #t))) ; Convert only first time extent is entered!505 (##sys#dynamic-wind506 (##core#lambda ()507 (##core#let508 ;; 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 later513 ,@(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#let522 ;; 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))))))))))))530531(##sys#extend-macro-environment532 'require-library533 '()534 (##sys#er-transformer535 (lambda (x r c)536 `(##core#begin537 ,@(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))))))543544(##sys#extend-macro-environment545 'when '()546 (##sys#er-transformer547 (lambda (form r c)548 (##sys#check-syntax 'when form '#(_ 2))549 `(##core#if ,(cadr form)550 (##core#begin ,@(cddr form))))))551552(##sys#extend-macro-environment553 'unless '()554 (##sys#er-transformer555 (lambda (form r c)556 (##sys#check-syntax 'unless form '#(_ 2))557 `(##core#if ,(cadr form)558 (##core#undefined)559 (##core#begin ,@(cddr form))))))560561(##sys#extend-macro-environment562 'set!-values '()563 (##sys#er-transformer564 (lambda (form r c)565 (##sys#check-syntax 'set!-values form '(_ lambda-list _))566 (##sys#expand-multiple-values-assignment (cadr form) (caddr form)))))567568(set! chicken.syntax#define-values-definition569 (##sys#extend-macro-environment570 'define-values '()571 (##sys#er-transformer572 (lambda (form r c)573 (##sys#check-syntax 'define-values form '(_ lambda-list _))574 `(##core#begin575 ,@(##sys#decompose-lambda-list576 (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)))))))585586(##sys#extend-macro-environment587 'let-values '()588 (##sys#er-transformer589 (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 acc606 (let* ((llist (car llists))607 (new-acc608 (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-acc619 (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#let627 ,(map (lambda (v) (##sys#list v (lookup v))) vars)628 ,@body) )629 ((and (pair? (car llists2)) (null? (cdar llists2)))630 `(##core#let631 ((,(caar llists2) ,(car exps)))632 ,(fold (cdr llists) (cdr exps) (cdr llists2)) ) )633 (else634 `(##sys#call-with-values635 (##core#lambda () ,(car exps))636 (##core#lambda637 ,(car llists2)638 ,(fold (cdr llists) (cdr exps) (cdr llists2))) ) ) ) ) ) ) ) ) ) )639640(##sys#extend-macro-environment641 'let*-values '()642 (##sys#er-transformer643 (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))) ) ) ))))653654;;XXX do we need letrec*-values ?655(##sys#extend-macro-environment656 'letrec-values '()657 (##sys#er-transformer658 (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#let665 ,(map (lambda (v) (##sys#list v '(##core#undefined)))666 (foldl (lambda (l v) ; flatten multi-value formals667 (##sys#append l (##sys#decompose-lambda-list668 v (lambda (a _ _) a))))669 '()670 vars))671 ,@(map ##sys#expand-multiple-values-assignment vars exprs)672 ,@body))))))673674(##sys#extend-macro-environment675 'letrec*676 '()677 (##sys#er-transformer678 (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)))))682683(##sys#extend-macro-environment684 'nth-value685 `((list-ref . scheme#list-ref))686 (##sys#er-transformer687 (lambda (form r c)688 (##sys#check-syntax 'nth-value form '(_ _ _))689 (let ((v (r 'tmp)))690 `(##sys#call-with-values691 (##core#lambda () ,(caddr form))692 (##core#lambda ,v (,(r 'list-ref) ,v ,(cadr form))))))))693694(##sys#extend-macro-environment695 'define-inline '()696 (##sys#er-transformer697 (lambda (form r c)698 (letrec ([quotify-proc699 (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-error710 '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)))) ) )714715(##sys#extend-macro-environment716 'and-let* '()717 (##sys#er-transformer718 (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 [else737 (##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)))]))))))))741742743744;;; Optional argument handling:745746;;; 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/Rees754;;; explicit-renaming low-level macro system. You'll have to do some work to755;;; port it to another macro system.756;;;757;;; The LET-OPTIONALS* and :OPTIONAL macros are defined with simple758;;; high-level macros, and should be portable to any R4RS system.759;;;760;;; These macros are all careful to evaluate their default forms *only* if761;;; their values are needed.762;;;763;;; The only non-R4RS dependencies in the macros are ERROR764;;; and CALL-WITH-VALUES.765;;; -Olin766767;;; (LET-OPTIONALS arg-list ((var1 default1) ...)768;;; body769;;; ...)770;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;771;;; This form is for binding a procedure's optional arguments to either772;;; the passed-in values or a default.773;;;774;;; The expression takes a rest list ARG-LIST and binds the VARi to775;;; the elements of the rest list. When there are no more elements, then776;;; 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 VARi782;;; 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 is786;;; impossible to implement without side effects or redundant conditional787;;; tests. If I drop this requirement, I can use the efficient expansion788;;; shown below. If you need LET* scope, use the less-efficient789;;; 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 ...)))))))))815816817;;; (LET-OPTIONALS args ((var1 default1) ...) body1 ...)818819(##sys#extend-macro-environment820 'let-optionals821 `((null? . scheme#null?)822 (car . scheme#car)823 (cdr . scheme#cdr))824 (##sys#er-transformer825 (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)))830831 ;; This guy makes the END-DEF, START-DEF, PORT-DEF definitions above.832 ;; I wish I had a reasonable loop macro.833834 (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 vars845 (cdr defaulter-names)846 (cdr defs)847 (car defaulter-names)))))))848849850 ;; This guy makes the (IF (NULL? REST) (PORT-DEF) ...) tree above.851852 (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 optimization860 (,rest (,(r 'cdr) ,rest)))861 ,(recur (cdr vars)862 (cdr defaulters)863 (cons v non-defaults))))))))864865 (##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)))))870871 ;; Private vars, one for each user var.872 ;; We prefix the % to help keep macro-expanded code from being873 ;; too confusing.874 (vars2 (map (lambda (v) (r (prefix-sym "%" v)))875 vars))876877 (defs (map cadr var/defs))878 (body-proc (r 'body))879880 ;; A private var, bound to the value of the ARG-LIST expression.881 (rest-var (r '_%rest))882883 (defaulter-names (map (lambda (var) (r (prefix-sym "def-" var)))884 vars))885886 (defaulters (make-default-procs vars2 body-proc887 defaulter-names defs gensym))888 (if-tree (make-if-tree vars2 defaulter-names body-proc889 rest-var gensym)))890891 `(,(r 'let*) ((,rest-var ,arg-list)892 (,body-proc (##core#lambda ,vars . ,body))893 . ,defaulters)894 ,if-tree) ) ))))895896897;;; (optional rest-arg default-exp)898;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;899;;; This form is for evaluating optional arguments and their defaults900;;; in simple procedures that take a *single* optional argument. It is901;;; 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 in904;;; (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.907908(##sys#extend-macro-environment909 'optional910 `((null? . scheme#null?)911 (car . scheme#car)912 (cdr . scheme#cdr) )913 (##sys#er-transformer914 (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)))))))921922923;;; (LET-OPTIONALS* args ((var1 default1) ... [rest]) body1 ...)924;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;925;;; This is just like LET-OPTIONALS, except that the DEFAULTi forms926;;; are evaluated in a LET*-style environment. That is, DEFAULT3 is evaluated927;;; within the scope of VAR1 and VAR2, and so forth.928;;;929;;; - If the last form in the ((var1 default1) ...) list is not a930;;; (VARi DEFAULTi) pair, but a simple variable REST, then it is931;;; bound to any left-over values. For example, if we have VAR1 through932;;; VAR7, and ARGS has 9 values, then REST will be bound to the list of933;;; the two values of ARGS. If ARGS is too short, causing defaults to934;;; be used, then REST is bound to '().935936(##sys#extend-macro-environment937 'let-optionals*938 `((null? . scheme#null?)939 (car . scheme#car)940 (cdr . scheme#cdr))941 (##sys#er-transformer942 (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#let952 ((,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) ) ) ) ) ) ) ))))967968969;;; case-lambda (SRFI-16):970971(##sys#extend-macro-environment972 'case-lambda973 `((>= . scheme#>=)974 (car . scheme#car)975 (cdr . scheme#cdr)976 (eq? . scheme#eq?)977 (length . scheme#length))978 (##sys#er-transformer979 (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-list988 (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#lambda1000 ,(append minvars rvar)1001 (##core#let1002 ((,lvar (,%length ,rvar)))1003 ,(foldr1004 (lambda (c body)1005 (##sys#decompose-lambda-list1006 (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 rest1011 (if (zero? a2)1012 #t1013 `(,%>= ,lvar ,a2) )1014 `(,%eq? ,lvar ,a2) ) )1015 ,(receive (vars1 vars2)1016 (split-at (take vars argc) mincount)1017 (let ((bindings1018 (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 bindings1031 `(##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))))))))103510361037;;; Record printing:10381039(##sys#extend-macro-environment1040 'define-record-printer '() ;; DEPRECATED1041 (##sys#er-transformer1042 (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-syntax1049 '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-append1054 (##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 (else1061 (##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-append1065 (##sys#module-name (##sys#current-module))1066 '|#| plain-name)1067 plain-name)))1068 `(,%set-record-printer!1069 (##core#quote ,tag) ,@body))))))))10701071;;; SRFI-9:10721073(##sys#extend-macro-environment1074 'define-record-type1075 `()1076 (##sys#er-transformer1077 (lambda (form r c)1078 (##sys#check-syntax1079 'define-record-type1080 form1081 '(_ 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-append1086 (##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 args1099 (for-each (lambda (vname)1100 (unless (memq vname slotnames)1101 (syntax-error1102 'define-record-type1103 "unknown slot name in constructor definition"1104 vname)))1105 vars)1106 `(##core#begin1107 ;; TODO: Maybe wrap this in an opaque object?1108 (,%define ,type-name (##core#quote ,tag))1109 (,%define ,conser1110 (##sys#make-structure1111 (##core#quote ,tag)1112 ,@(map (lambda (sname)1113 (if (memq sname vars)1114 sname1115 '(##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#lambda1129 (,x)1130 (##core#check1131 (##sys#check-structure1132 ,x1133 (##core#quote ,tag)1134 (##core#quote ,(cadr slot))))1135 (##sys#block-ref ,x ,i) ) )1136 (set (and settable1137 `(##core#lambda1138 (,x ,y)1139 (##core#check1140 (##sys#check-structure1141 ,x1142 (##core#quote ,tag)1143 (##core#quote ,ssetter)))1144 (##sys#block-set! ,x ,i ,y)) )))1145 `((,%define1146 ,(cadr slot)1147 ,(if (and ssetter (c ssetter (cadr slot)))1148 `(,%getter-with-setter ,get ,set)1149 get))1150 ,@(if settable1151 (if ssetter1152 (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)) ) ) ) ) ) ) ) ) )115811591160;;; SRFI-26:11611162(##sys#extend-macro-environment1163 'cut1164 `((apply . scheme#apply))1165 (##sys#er-transformer1166 (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 rest1177 (let ([rv (r (gensym))])1178 `(##core#lambda1179 (,@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-error1190 'cut1191 "tail patterns after <...> are not supported"1192 form)))1193 (else (loop (cdr xs) vars (cons (car xs) vals) #f)) ) ) ) ) )))11941195(##sys#extend-macro-environment1196 'cute1197 `((apply . scheme#apply))1198 (##sys#er-transformer1199 (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 rest1210 (let ([rv (r (gensym))])1211 `(##core#let1212 ,bs1213 (##core#lambda (,@rvars . ,rv)1214 (,%apply ,(car rvals) ,@(cdr rvals) ,rv) ) ) )1215 `(##core#let ,bs1216 (##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-error1224 'cute1225 "tail patterns after <...> are not supported"1226 form)))1227 (else1228 (let ([v (r (gensym))])1229 (loop (cdr xs)1230 vars1231 (cons (list v (car xs)) bs)1232 (cons v vals) #f) ) ))))))))123312341235;;; SRFI-3112361237(##sys#extend-macro-environment1238 'rec '()1239 (##sys#er-transformer1240 (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))))))124912501251;;; SRFI-5512521253(##sys#extend-macro-environment1254 'require-extension1255 '()1256 (##sys#er-transformer1257 (lambda (x r c)1258 `(,(r 'import) ,@(cdr x)))))125912601261;;; Assertions12621263(##sys#extend-macro-environment1264 'assert '()1265 (##sys#er-transformer1266 (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 ,tmp1279 (##sys#error1280 ,msg1281 ,@(if (pair? msg-and-args)1282 (cdr msg-and-args)1283 `((##core#quote ,(strip-syntax exp))))))))))))12841285(macro-subset me0 ##sys#default-macro-environment)))128612871288;;; "time"12891290(set! ##sys#chicken.time-macro-environment1291 (let ((me0 (##sys#macro-environment)))12921293(##sys#extend-macro-environment1294 'time '()1295 (##sys#er-transformer1296 (lambda (form r c)1297 (let ((rvar (r 't)))1298 `(##core#begin1299 (##sys#start-timer)1300 (##sys#call-with-values1301 (##core#lambda () ,@(cdr form))1302 (##core#lambda1303 ,rvar1304 (##sys#display-times (##sys#stop-timer))1305 (##sys#apply ##sys#values ,rvar))))))))13061307(macro-subset me0 ##sys#default-macro-environment)))13081309;; register features13101311(register-feature! 'srfi-2 'srfi-8 'srfi-9 'srfi-11 'srfi-15 'srfi-16 'srfi-26 'srfi-31 'srfi-55)