~ chicken-core (master) /expand.scm
Trap1;;;; expand.scm - The HI/LO expander2;3; Copyright (c) 2008-2022, The CHICKEN Team4; All rights reserved.5;6; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following7; conditions are met:8;9; Redistributions of source code must retain the above copyright notice, this list of conditions and the following10; disclaimer.11; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following12; disclaimer in the documentation and/or other materials provided with the distribution.13; Neither the name of the author nor the names of its contributors may be used to endorse or promote14; products derived from this software without specific prior written permission.15;16; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS17; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY18; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR19; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR20; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR21; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY22; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR23; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE24; POSSIBILITY OF SUCH DAMAGE.252627;; this unit needs the "modules" unit, but must be initialized first, so it doesn't28;; declare "modules" as used - if you use "-explicit-use", take care of this.2930(declare31 (unit expand)32 (uses internal)33 (disable-interrupts)34 (fixnum)35 (not inline ##sys#syntax-error-hook ##sys#compiler-syntax-hook))3637(module chicken.syntax38 (expand39 expand140 get-line-number41 read-with-source-info42 strip-syntax43 er-macro-transformer44 ir-macro-transformer)4546(import scheme47 chicken.base48 chicken.condition49 chicken.fixnum50 chicken.internal51 chicken.keyword52 chicken.platform53 chicken.string)54(import (only (scheme base) make-parameter open-output-string get-output-string))5556(include "common-declarations.scm")57(include "mini-srfi-1.scm")5859(define-syntax d (syntax-rules () ((_ . _) (void))))60;(define-syntax d (syntax-rules () ((_ args ...) (print args ...))))6162;; Macro to avoid "unused variable map-se" when "d" is disabled63(define-syntax map-se64 (syntax-rules ()65 ((_ ?se)66 (map (lambda (a)67 (cons (car a) (if (symbol? (cdr a)) (cdr a) '<macro>)))68 ?se))))6970(define-alias dd d)71(define-alias dm d)72(define-alias dx d)7374(define-inline (getp sym prop)75 (##core#inline "C_i_getprop" sym prop #f))7677(define-inline (putp sym prop val)78 (##core#inline_allocate ("C_a_i_putprop" 8) sym prop val))7980(define-inline (namespaced-symbol? sym)81 (##core#inline "C_u_i_namespaced_symbolp" sym))8283;;; Source file tracking8485(define ##sys#current-source-filename #f)8687;;; Syntactic environments8889(define ##sys#current-environment (make-parameter '()))90(define ##sys#current-meta-environment (make-parameter '()))9192(define (lookup id se)93 (cond ((##core#inline "C_u_i_assq" id se) => cdr)94 ((getp id '##core#macro-alias))95 (else #f)))9697(define (macro-alias var se)98 (if (or (keyword? var) (namespaced-symbol? var))99 var100 (let* ((alias (gensym var))101 (ua (or (lookup var se) var))102 (rn (or (getp var '##core#real-name) var)))103 (putp alias '##core#macro-alias ua)104 (putp alias '##core#real-name rn)105 (dd "aliasing " alias " (real: " var ") to "106 (if (pair? ua)107 '<macro>108 ua))109 alias) ) )110111(define (strip-syntax exp)112 (let ((seen '()))113 (let walk ((x exp))114 (cond ((assq x seen) => cdr)115 ((keyword? x) x)116 ((symbol? x)117 (let ((x2 (getp x '##core#macro-alias) ) )118 (cond ((getp x '##core#real-name))119 ((not x2) x)120 ((pair? x2) x)121 (else x2))))122 ((pair? x)123 (let ((cell (cons #f #f)))124 (set! seen (cons (cons x cell) seen))125 (set-car! cell (walk (car x)))126 (set-cdr! cell (walk (cdr x)))127 cell))128 ((vector? x)129 (let* ((len (##sys#size x))130 (vec (make-vector len)))131 (set! seen (cons (cons x vec) seen))132 (do ((i 0 (fx+ i 1)))133 ((fx>= i len) vec)134 (##sys#setslot vec i (walk (##sys#slot x i))))))135 (else x)))))136137(define (##sys#extend-se se vars #!optional (aliases (map gensym vars)))138 (for-each139 (lambda (alias sym)140 (let ((original-real-name (getp sym '##core#real-name)))141 (putp alias '##core#real-name (or original-real-name sym))))142 aliases vars)143 (append (map (lambda (x y) (cons x y)) vars aliases) se)) ; inline cons144145146;;; Macro handling147148(define ##sys#macro-environment (make-parameter '()))149150(define ##sys#scheme-macro-environment '()) ; reassigned below151;; These are all re-assigned by chicken-syntax.scm:152(define ##sys#chicken-ffi-macro-environment '()) ; used later in foreign.import.scm153(define ##sys#chicken.condition-macro-environment '()) ; used later in chicken.condition.import.scm154(define ##sys#chicken.time-macro-environment '()) ; used later in chicken.time.import.scm155(define ##sys#chicken.type-macro-environment '()) ; used later in chicken.type.import.scm156(define ##sys#chicken.syntax-macro-environment '()) ; used later in chicken.syntax.import.scm157(define ##sys#chicken.base-macro-environment '()) ; used later in chicken.base.import.scm158159(define (##sys#ensure-transformer t #!optional loc)160 (if (##sys#structure? t 'transformer)161 (##sys#slot t 1)162 (##sys#error loc "expected syntax-transformer, but got" t)))163164(define (##sys#extend-macro-environment name se transformer)165 (let ((me (##sys#macro-environment))166 (handler (##sys#ensure-transformer transformer name)))167 (cond ((lookup name me) =>168 (lambda (a)169 (set-car! a se)170 (set-car! (cdr a) handler)171 a))172 (else173 (let ((data (list se handler)))174 (##sys#macro-environment175 (cons (cons name data) me))176 data)))))177178(define (##sys#macro? sym #!optional (senv (##sys#current-environment)))179 (or (let ((l (lookup sym senv)))180 (pair? l))181 (and-let* ((l (lookup sym (##sys#macro-environment))))182 (pair? l))))183184(define (##sys#undefine-macro! name)185 (##sys#macro-environment186 ;; this builds up stack, but isn't used often anyway...187 (let loop ((me (##sys#macro-environment)))188 (cond ((null? me) '())189 ((eq? name (caar me)) (cdr me))190 (else (cons (car me) (loop (cdr me))))))))191192;; The basic macro-expander193194(define (##sys#expand-0 exp dse cs?)195 (define (call-handler name handler exp se cs)196 (dd "invoking macro: " name)197 (dd `(STATIC-SE: ,@(map-se se)))198 (handle-exceptions ex199 ;; modify error message in condition object to include200 ;; currently expanded macro-name201 (abort202 (if (and (##sys#structure? ex 'condition)203 (memv 'exn (##sys#slot ex 1)) )204 (##sys#make-structure205 'condition206 (##sys#slot ex 1)207 (let copy ([ps (##sys#slot ex 2)])208 (if (null? ps)209 '()210 (let ([p (car ps)]211 [r (cdr ps)])212 (if (and (equal? '(exn . message) p)213 (pair? r)214 (string? (car r)) )215 (cons216 '(exn . message)217 (cons (string-append218 "during expansion of ("219 (##sys#symbol->string/shared name)220 " ...) - "221 (car r) )222 (cdr r) ) )223 (copy r) ) ) ) ) )224 ex) )225 (let ((exp2226 (if cs227 ;; compiler-syntax may "fall through"228 (fluid-let ((chicken.internal.syntax-rules#syntax-rules-mismatch229 (lambda (input) exp))) ; a bit of a hack230 (handler exp se dse))231 (handler exp se dse))) )232 (when (and (not cs) (eq? exp exp2))233 (##sys#syntax-error234 (string-append235 "syntax transformer for `" (##sys#symbol->string/shared name)236 "' returns original form, which would result in endless expansion")237 exp))238 (dx `(,name ~~> ,exp2))239 (expansion-result-hook exp exp2) ) ) )240 (define (expand head exp mdef)241 (dd `(EXPAND:242 ,head243 ,(cond ((getp head '##core#macro-alias) =>244 (lambda (a) (if (symbol? a) a '<macro>)) )245 (else '_))246 ,exp247 ,(if (pair? mdef)248 `(SE: ,@(map-se (car mdef)))249 mdef)))250 (if (pair? mdef)251 (values252 ;; force ref. opaqueness by passing dynamic se [what does this comment mean? I forgot ...]253 (call-handler head (cadr mdef) exp (car mdef) #f)254 #t)255 (values exp #f)) )256 (let loop ((exp exp))257 (if (pair? exp)258 (let ((head (car exp))259 (body (cdr exp)) )260 (if (symbol? head)261 (let ((head2 (or (lookup head dse) head)))262 (unless (pair? head2)263 (set! head2 (or (lookup head2 (##sys#macro-environment)) head2)) )264 (cond ((and (pair? head2)265 (eq? (##sys#get head '##sys#override) 'value))266 (values exp #f))267 ((eq? head2 '##core#let)268 (##sys#check-syntax 'let body '#(_ 2) #f dse)269 (let ((bindings (car body)))270 (cond ((symbol? bindings) ; expand named let271 (##sys#check-syntax 'let body '(_ #((variable _) 0) . #(_ 1)) #f dse)272 (let ([bs (cadr body)])273 (values274 `(##core#app275 (##core#letrec*276 ([,bindings277 (##core#loop-lambda278 ,(map (lambda (b) (car b)) bs) ,@(cddr body))])279 ,bindings)280 ,@(##sys#map cadr bs) )281 #t) ) )282 (else (values exp #f)) ) ) )283 ((and cs? (symbol? head2) (getp head2 '##compiler#compiler-syntax)) =>284 (lambda (cs)285 (let ((result (call-handler head (car cs) exp (cdr cs) #t)))286 (cond ((eq? result exp) (expand head exp head2))287 (else288 (when ##sys#compiler-syntax-hook289 (##sys#compiler-syntax-hook head2 result))290 (loop result))))))291 (else (expand head exp head2)) ) )292 (values exp #f) ) )293 (values exp #f) ) ) )294295(define ##sys#compiler-syntax-hook #f)296(define ##sys#enable-runtime-macros #f)297(define expansion-result-hook (lambda (input output) output))298299300;;; User-level macroexpansion301302(define (expand exp #!optional (se (##sys#current-environment)) cs?)303 (let loop ((exp exp))304 (let-values (((exp2 m) (##sys#expand-0 exp se cs?)))305 (if m306 (loop exp2)307 exp2) ) ) )308309(define (expand1 exp #!optional (se (##sys#current-environment)) cs?)310 (nth-value 0 (##sys#expand-0 exp se cs?)) )311312313;;; Extended (DSSSL-style) lambda lists314;315; Assumptions:316;317; 1) #!rest must come before #!key318; 2) default values may refer to earlier variables319; 3) optional/key args may be either variable or (variable default)320; 4) an argument marker may not be specified more than once321; 5) no special handling of extra keywords (no error)322; 6) default value of optional/key args is #f323; 7) mixing with dotted list syntax is allowed324325(define (##sys#extended-lambda-list? llist)326 (let loop ([llist llist])327 (and (pair? llist)328 (case (##sys#slot llist 0)329 [(#!rest #!optional #!key) #t]330 [else (loop (cdr llist))] ) ) ) )331332(define ##sys#expand-extended-lambda-list333 (let ((reverse reverse))334 (lambda (llist0 body errh se)335 (define (err msg) (errh msg llist0))336 (define (->keyword s) (string->keyword (##sys#symbol->string/shared s)))337 (let ((rvar #f)338 (hasrest #f)339 ;; These might not exist in se, use default or chicken env:340 (%let* (macro-alias 'let* ##sys#default-macro-environment))341 (%lambda '##core#lambda)342 (%opt (macro-alias 'optional ##sys#chicken.base-macro-environment))343 (%let-optionals* (macro-alias 'let-optionals* ##sys#chicken.base-macro-environment))344 (%let '##core#let))345 (let loop ([mode 0] ; req=0, opt=1, rest=2, key=3, end=4346 [req '()]347 [opt '()]348 [key '()]349 [llist llist0] )350 (cond [(null? llist)351 (values352 (if rvar (##sys#append (reverse req) rvar) (reverse req))353 (let ([body354 (if (null? key)355 body356 `((,%let*357 ,(map (lambda (k)358 (let ((s (car k)))359 `(,s (##sys#get-keyword360 (##core#quote ,(->keyword (strip-syntax s))) ,(or hasrest rvar)361 ,@(if (pair? (cdr k))362 `((,%lambda () ,@(cdr k)))363 '())))))364 (reverse key) )365 ,@body) ) ) ] )366 (cond [(null? opt) body]367 [(and (not hasrest) (null? key) (null? (cdr opt)))368 `((,%let369 ([,(caar opt) (,%opt ,rvar ,(cadar opt))])370 ,@body) ) ]371 [(and (not hasrest) (null? key))372 `((,%let-optionals*373 ,rvar ,(reverse opt) ,@body))]374 [else375 `((,%let-optionals*376 ,rvar ,(##sys#append (reverse opt) (list (or hasrest rvar)))377 ,@body))] ) ) ) ]378 [(symbol? llist)379 (if (fx> mode 2)380 (err "rest argument list specified more than once")381 (begin382 (unless rvar (set! rvar llist))383 (set! hasrest llist)384 (loop 4 req opt '() '()) ) ) ]385 [(not (pair? llist))386 (err "invalid lambda list syntax") ]387 [else388 (let* ((var (car llist))389 (x (or (and (symbol? var) (not (eq? 3 mode)) (lookup var se)) var))390 (r (cdr llist)))391 (case x392 [(#!optional)393 (unless rvar (set! rvar (macro-alias 'rest se)))394 (if (eq? mode 0)395 (loop 1 req '() '() r)396 (err "`#!optional' argument marker in wrong context") ) ]397 [(#!rest)398 (if (fx<= mode 1)399 (if (and (pair? r) (symbol? (car r)))400 (begin401 (if (not rvar) (set! rvar (car r)))402 (set! hasrest (car r))403 (loop 2 req opt '() (cdr r)) )404 (err "invalid syntax of `#!rest' argument") )405 (err "`#!rest' argument marker in wrong context") ) ]406 [(#!key)407 (if (not rvar) (set! rvar (macro-alias 'rest se)))408 (if (fx<= mode 2)409 (loop 3 req opt '() r)410 (err "`#!key' argument marker in wrong context") ) ]411 [else412 (cond [(symbol? var)413 (case mode414 [(0) (loop 0 (cons var req) '() '() r)]415 [(1) (loop 1 req (cons (list var #f) opt) '() r)]416 [(2) (err "invalid lambda list syntax after `#!rest' marker")]417 [else (loop 3 req opt (cons (list var) key) r)] ) ]418 [(and (list? var) (eq? 2 (length var)) (symbol? (car var)))419 (case mode420 [(0) (err "invalid required argument syntax")]421 [(1) (loop 1 req (cons var opt) '() r)]422 [(2) (err "invalid lambda list syntax after `#!rest' marker")]423 [else (loop 3 req opt (cons var key) r)] ) ]424 [else (err "invalid lambda list syntax")] ) ] ) ) ] ) ) ) ) ) )425426427;;; Error message for redefinition of currently used defining form428;429; (i.e.`"(define define ...)")430431(define (defjam-error form)432 (##sys#syntax-error433 "redefinition of currently used defining form" ; help me find something better434 form))435436;;; Expansion of multiple values assignments.437;438; Given a lambda list and a multi-valued expression, returns a form that439; will `set!` each variable to its corresponding value in order.440441(define (##sys#expand-multiple-values-assignment formals expr)442 (##sys#decompose-lambda-list443 formals444 (lambda (vars argc rest)445 (let ((aliases (if (symbol? formals) '() (map gensym formals)))446 (rest-alias (if (not rest) '() (gensym rest))))447 `(##sys#call-with-values448 (##core#lambda () ,expr)449 (##core#lambda450 ,(append aliases rest-alias)451 ,@(map (lambda (v a) `(##core#set! ,v ,a)) vars aliases)452 ,@(cond453 ((null? formals) '((##core#undefined)))454 ((null? rest-alias) '())455 (else `((##core#set! ,rest ,rest-alias))))))))))456457;;; Expansion of bodies (and internal definitions)458;459; This code is disgustingly complex.460461(define define-definition)462(define define-syntax-definition)463(define define-values-definition)464(define import-definition)465466(define ##sys#canonicalize-body467 (lambda (body #!optional (se (##sys#current-environment)) cs?)468 (define (comp s id)469 (let ((f (or (lookup id se)470 (lookup id (##sys#macro-environment)))))471 (and (or (not (symbol? f))472 (not (eq? (##sys#get id '##sys#override) 'value)))473 (or (eq? f s) (eq? s id)))))474 (define (comp-def def)475 (lambda (id)476 (let repeat ((id id))477 (let ((f (or (lookup id se)478 (lookup id (##sys#macro-environment)))))479 (and (or (not (symbol? f))480 (not (eq? (##sys#get id '##sys#override) 'value)))481 (or (eq? f def)482 (and (symbol? f)483 (not (eq? f id))484 (repeat f))))))))485 (define comp-define (comp-def define-definition))486 (define comp-define-syntax (comp-def define-syntax-definition))487 (define comp-define-values (comp-def define-values-definition))488 (define comp-import (comp-def import-definition))489 (define (fini vars vals mvars body)490 (if (and (null? vars) (null? mvars))491 ;; Macro-expand body, and restart when defines are found.492 (let loop ((body body) (exps '()))493 (if (not (pair? body))494 (cons495 '##core#begin496 (reverse exps)) ; no more defines, otherwise we would have called `expand'497 (let loop2 ((body body))498 (let ((x (car body))499 (rest (cdr body)))500 (if (and (pair? x)501 (let ((d (car x)))502 (and (symbol? d)503 (or (comp '##core#begin d)504 (comp-define d)505 (comp-define-values d)506 (comp-define-syntax d)507 (comp-import d)))))508 ;; Stupid hack to avoid expanding imports509 (if (comp-import (car x))510 (loop rest (cons x exps))511 (cons512 '##core#begin513 (##sys#append (reverse exps) (list (expand body)))))514 (let ((x2 (##sys#expand-0 x se cs?)))515 (if (eq? x x2)516 ;; Modules and includes must be processed before517 ;; we can continue with other forms, so hand518 ;; control back to the compiler519 (if (and (pair? x)520 (symbol? (car x))521 (or (comp '##core#module (car x))522 (comp '##core#include (car x))))523 `(##core#begin524 ,@(reverse exps)525 ,@(if (comp '##core#module (car x))526 (if (null? rest)527 `(,x)528 `(,x (##core#let () ,@rest)))529 `((##core#include ,@(cdr x) ,rest))))530 (loop rest (cons x exps)))531 (loop2 (cons x2 rest)) )) ))) ))532 ;; We saw defines. Translate to letrec, and let compiler533 ;; call us again for the remaining body by wrapping the534 ;; remaining body forms in a ##core#let.535 (let* ((result536 `(##core#let537 ,(##sys#map538 (lambda (v) (##sys#list v '(##core#undefined)))539 ;; vars are all normalised to lambda-lists: flatten them540 (foldl (lambda (l v)541 (##sys#append l (##sys#decompose-lambda-list542 v (lambda (a _ _) a))))543 '()544 (reverse vars))) ; not strictly necessary...545 ,@(map (lambda (var val is-mvar?)546 ;; Non-mvars should expand to set! for547 ;; efficiency, but also because they must be548 ;; implicit multi-value continuations.549 (if is-mvar?550 (##sys#expand-multiple-values-assignment var val)551 `(##core#set! ,(car var) ,val)))552 (reverse vars)553 (reverse vals)554 (reverse mvars))555 ,@body) ) )556 (dd `(BODY: ,result))557 result)))558 (define (fini/syntax vars vals mvars body)559 (fini560 vars vals mvars561 (let loop ((body body) (defs '()) (done #f))562 (cond (done `((##core#letrec-syntax563 ,(map cdr (reverse defs)) ,@body) ))564 ((not (pair? body)) (loop body defs #t))565 ((and (list? (car body))566 (>= 3 (length (car body)))567 (symbol? (caar body))568 (comp-define-syntax (caar body)))569 (let ((def (car body)))570 ;; This check is insufficient, if introduced by571 ;; different expansions, but better than nothing:572 (when (eq? (car def) (cadr def))573 (defjam-error def))574 (loop (cdr body) (cons def defs) #f)))575 (else (loop body defs #t))))))576 ;; Expand a run of defines or define-syntaxes into letrec. As577 ;; soon as we encounter something else, finish up.578 (define (expand body)579 ;; Each #t in "mvars" indicates an MV-capable "var". Non-MV580 ;; vars (#f in mvars) are 1-element lambda-lists for simplicity.581 (let loop ((body body) (vars '()) (vals '()) (mvars '()))582 (d "BODY: " body)583 (if (not (pair? body))584 (fini vars vals mvars body)585 (let* ((x (car body))586 (rest (cdr body))587 (exp1 (and (pair? x) (car x)))588 (head (and exp1 (symbol? exp1) exp1)))589 (if (not (symbol? head))590 (fini vars vals mvars body)591 (cond592 ((comp-define head)593 (##sys#check-syntax 'define x '(_ _ . #(_ 0)) #f se)594 (let loop2 ((x x))595 (let ((head (cadr x)))596 (cond ((not (pair? head))597 (##sys#check-syntax 'define x '(_ variable . #(_ 0)) #f se)598 (when (eq? (car x) head) ; see above599 (defjam-error x))600 (loop rest (cons (list head) vars)601 (cons (if (pair? (cddr x))602 (caddr x)603 '(##core#undefined) )604 vals)605 (cons #f mvars)))606 ((pair? (car head))607 (##sys#check-syntax608 'define x '(_ (_ . lambda-list) . #(_ 1)) #f se)609 (loop2610 (chicken.syntax#expand-curried-define head (cddr x) se)))611 (else612 (##sys#check-syntax613 'define x614 '(_ (variable . lambda-list) . #(_ 1)) #f se)615 (loop rest616 (cons (list (car head)) vars)617 (cons `(##core#lambda ,(cdr head) ,@(cddr x)) vals)618 (cons #f mvars)))))))619 ((comp-define-syntax head)620 (##sys#check-syntax 'define-syntax x '(_ _ . #(_ 1)) se)621 (fini/syntax vars vals mvars body))622 ((comp-define-values head)623 ;;XXX check for any of the variables being `define-values'624 (##sys#check-syntax 'define-values x '(_ lambda-list _) #f se)625 (loop rest (cons (cadr x) vars) (cons (caddr x) vals) (cons #t mvars)))626 ((comp '##core#begin head)627 (loop (##sys#append (cdr x) rest) vars vals mvars))628 (else629 ;; Do not macro-expand local definitions we are630 ;; in the process of introducing.631 (if (member (list head) vars)632 (fini vars vals mvars body)633 (let ((x2 (##sys#expand-0 x se cs?)))634 (if (eq? x x2)635 (fini vars vals mvars body)636 (loop (cons x2 rest) vars vals mvars)))))))))))637 (expand body) ) )638639640;;; A simple expression matcher641642;; Used by "quasiquote", below643(define chicken.syntax#match-expression644 (lambda (exp pat vars)645 (let ((env '()))646 (define (mwalk x p)647 (cond ((not (pair? p))648 (cond ((assq p env) => (lambda (a) (equal? x (cdr a))))649 ((memq p vars)650 (set! env (cons (cons p x) env))651 #t)652 (else (eq? x p)) ) )653 ((pair? x)654 (and (mwalk (car x) (car p))655 (mwalk (cdr x) (cdr p)) ) )656 (else #f) ) )657 (and (mwalk exp pat) env) ) ) )658659660;;; Expand "curried" lambda-list syntax for `define'661662;; Used by "define", below663(define (chicken.syntax#expand-curried-define head body se)664 (let ((name #f))665 (define (loop head body)666 (if (symbol? (car head))667 (begin668 (set! name (car head))669 `(##core#lambda ,(cdr head) ,@body) )670 (loop (car head) `((##core#lambda ,(cdr head) ,@body)) ) ))671 (let ([exp (loop head body)])672 (list 'define name exp) ) ) )673674675;;; Line-number database management:676677(define ##sys#line-number-database #f)678679680;;; General syntax checking routine:681682(define ##sys#syntax-error-culprit #f)683(define ##sys#syntax-context '())684685(define (##sys#syntax-error-hook . args)686 (apply ##sys#signal-hook #:syntax-error687 (strip-syntax args)))688689(define (##sys#syntax-error . args)690 (apply ##sys#syntax-error-hook args))691692(define ##sys#syntax-error/context693 (lambda (msg arg)694 (define (syntax-imports sym)695 (let loop ((defs (or (##sys#get (strip-syntax sym) '##core#db) '())))696 (cond ((null? defs) '())697 ((eq? 'syntax (caar defs))698 (cons (cadar defs) (loop (cdr defs))))699 (else (loop (cdr defs))))))700 (if (null? ##sys#syntax-context)701 (##sys#syntax-error-hook msg arg)702 (let ((out (open-output-string)))703 (define (outstr str)704 (##sys#print str #f out))705 (let loop ((cx ##sys#syntax-context))706 (cond ((null? cx) ; no unimported syntax found707 (outstr msg)708 (outstr ": ")709 (##sys#print arg #t out)710 (outstr "\ninside expression `(")711 (##sys#print (strip-syntax (car ##sys#syntax-context)) #t out)712 (outstr " ...)'"))713 (else714 (let* ((sym (strip-syntax (car cx)))715 (us (syntax-imports sym)))716 (cond ((pair? us)717 (outstr msg)718 (outstr ": ")719 (##sys#print arg #t out)720 (outstr "\n\n Perhaps you intended to use the syntax `(")721 (##sys#print sym #t out)722 (outstr " ...)' without importing it first.\n")723 (if (fx= 1 (length us))724 (outstr725 (string-append726 " Suggesting: `(import "727 (symbol->string (car us))728 ")'"))729 (outstr730 (string-append731 " Suggesting one of:\n"732 (let loop ((lst us))733 (if (null? lst)734 ""735 (string-append736 "\n (import " (symbol->string (car lst)) ")'"737 (loop (cdr lst)))))))))738 (else (loop (cdr cx))))))))739 (##sys#syntax-error-hook (get-output-string out))))))740741;;; Hook for source information742743(define (alist-weak-cons k v lst)744 (cons (##core#inline_allocate ("C_a_i_weak_cons" 3) k v) lst))745746(define (assq/drop-bwp! x lst)747 (let lp ((lst lst)748 (prev #f))749 (cond ((null? lst) #f)750 ((eq? x (caar lst)) (car lst))751 ((and prev752 (##core#inline "C_bwpp" (caar lst)))753 (set-cdr! prev (cdr lst))754 (lp (cdr lst) prev))755 (else (lp (cdr lst) lst)))))756757(define (read-with-source-info-hook class data val)758 (when (and (eq? 'list-info class) (symbol? (car data)))759 (let ((old-value (or (hash-table-ref ##sys#line-number-database (car data)) '())))760 (assq/drop-bwp! (car data) old-value) ;; Hack to clean out garbage values761 (hash-table-set!762 ##sys#line-number-database763 (car data)764 (alist-weak-cons765 data (conc (or ##sys#current-source-filename "<stdin>") ":" val)766 old-value ) )) )767 data)768769(define-constant line-number-database-size 997) ; Copied from core.scm770771(define (read-with-source-info #!optional (in ##sys#standard-input) fname)772 ;; Initialize line number db on first use773 (unless ##sys#line-number-database774 (set! ##sys#line-number-database (make-vector line-number-database-size '())))775 (##sys#check-input-port in #t 'read-with-source-info)776 (fluid-let ((##sys#current-source-filename (or fname ##sys#current-source-filename)))777 (##sys#read in read-with-source-info-hook) ) )778779780(define (get-line-number sexp)781 (and ##sys#line-number-database782 (pair? sexp)783 (let ([head (car sexp)])784 (and (symbol? head)785 (cond ((hash-table-ref ##sys#line-number-database head)786 => (lambda (pl)787 (let ((a (assq/drop-bwp! sexp pl)))788 (and a (cdr a)))))789 (else #f))))))790791;; TODO: Needs a better name - it extracts the name(?) and the source expression792(define (##sys#get-line-2 exp)793 (let* ((name (car exp))794 (lst (hash-table-ref ##sys#line-number-database name)))795 (cond ((and lst (assq/drop-bwp! exp (cdr lst)))796 => (lambda (a) (values (car lst) (cdr a))) )797 (else (values name #f)) ) ) )798799(define (##sys#display-line-number-database)800 (hash-table-for-each801 (lambda (key val)802 (when val803 (let ((port (current-output-port)))804 (##sys#print key #t port)805 (##sys#print " " #f port)806 (##sys#print (map cdr val) #t port)807 (##sys#print "\n" #f port))) )808 ##sys#line-number-database) )809810;;; Traverse expression and update line-number db with all contained calls:811812(define (##sys#update-line-number-database! exp ln)813 (define (mapupdate xs)814 (let loop ((xs xs))815 (when (pair? xs)816 (walk (car xs))817 (loop (cdr xs)) ) ))818 (define (walk x)819 (cond ((not (pair? x)))820 ((symbol? (car x))821 (let* ((name (car x))822 (old (or (hash-table-ref ##sys#line-number-database name) '())))823 (unless (assq x old)824 (hash-table-set! ##sys#line-number-database name (alist-cons x ln old)))825 (when (list? x) (mapupdate (cdr x)) )))826 (else (mapupdate x)) ) )827 (walk exp))828829830(define-constant +default-argument-count-limit+ 99999)831832(define ##sys#check-syntax833 (lambda (id exp pat #!optional culprit (se (##sys#current-environment)))834835 (define (test x pred msg)836 (unless (pred x) (err msg)) )837838 (define (err msg)839 (let* ([sexp ##sys#syntax-error-culprit]840 [ln (get-line-number sexp)] )841 (##sys#syntax-error842 (if ln843 (string-append "(" ln ") in `" (symbol->string id) "' - " msg)844 (string-append "in `" (symbol->string id) "' - " msg) )845 exp) ) )846847 (define (lambda-list? x)848 (or (##sys#extended-lambda-list? x)849 (let loop ((x x))850 (cond ((null? x))851 ((symbol? x))852 ((pair? x)853 (let ((s (car x)))854 (and (symbol? s)855 (loop (cdr x)) ) ) )856 (else #f) ) ) ) )857858 (define (variable? v)859 (symbol? v))860861 (define (proper-list? x)862 (let loop ((x x))863 (cond ((eq? x '()))864 ((pair? x) (loop (cdr x)))865 (else #f) ) ) )866867 (when culprit (set! ##sys#syntax-error-culprit culprit))868 (let walk ((x exp) (p pat))869 (cond ((vector? p)870 (let* ((p2 (vector-ref p 0))871 (vlen (##sys#size p))872 (min (if (fx> vlen 1)873 (vector-ref p 1)874 0) )875 (max (cond ((eq? vlen 1) 1)876 ((fx> vlen 2) (vector-ref p 2))877 (else +default-argument-count-limit+) ) ) )878 (do ((x x (cdr x))879 (n 0 (fx+ n 1)) )880 ((eq? x '())881 (if (fx< n min)882 (err "not enough arguments") ) )883 (cond ((fx>= n max)884 (err "too many arguments") )885 ((not (pair? x))886 (err "not a proper list") )887 (else (walk (car x) p2) ) ) ) ) )888 ((##sys#immediate? p)889 (if (not (eq? p x)) (err "unexpected object")) )890 ((symbol? p)891 (case p892 ((_) #t)893 ((pair) (test x pair? "pair expected"))894 ((variable) (test x variable? "identifier expected"))895 ((symbol) (test x symbol? "symbol expected"))896 ((list) (test x proper-list? "proper list expected"))897 ((number) (test x number? "number expected"))898 ((string) (test x string? "string expected"))899 ((lambda-list) (test x lambda-list? "lambda-list expected"))900 (else901 (test902 x903 (lambda (y)904 (let ((y2 (and (symbol? y) (lookup y se))))905 (eq? (if (symbol? y2) y2 y) p)))906 "missing keyword")) ) )907 ((not (pair? p))908 (err "incomplete form") )909 ((not (pair? x)) (err "pair expected"))910 (else911 (walk (car x) (car p))912 (walk (cdr x) (cdr p)) ) ) ) ) )913914915;;; explicit/implicit-renaming transformer916917(define (make-er/ir-transformer handler explicit-renaming?)918 (##sys#make-structure919 'transformer920 (lambda (form se dse)921 (let ((renv '())) ; keep rename-environment for this expansion922 (define (inherit-pair-line-numbers old new)923 (and-let* ((name (car new))924 ((symbol? name))925 (ln (get-line-number old))926 (cur (or (hash-table-ref ##sys#line-number-database name) '())) )927 (unless (assq new cur)928 (hash-table-set! ##sys#line-number-database name929 (alist-weak-cons new ln cur))))930 new)931 (assert (list? se) "not a list" se) ;XXX remove later932 (define (rename sym)933 (cond ((pair? sym)934 (inherit-pair-line-numbers sym (cons (rename (car sym)) (rename (cdr sym)))))935 ((vector? sym)936 (list->vector (rename (vector->list sym))))937 ((not (symbol? sym)) sym)938 ((assq sym renv) =>939 (lambda (a)940 (dd `(RENAME/RENV: ,sym --> ,(cdr a)))941 (cdr a)))942 (else943 (let ((a (macro-alias sym se)))944 (dd `(RENAME: ,sym --> ,a))945 (set! renv (cons (cons sym a) renv))946 a))))947 (define (compare s1 s2)948 (let ((result949 (cond ((pair? s1)950 (and (pair? s2)951 (compare (car s1) (car s2))952 (compare (cdr s1) (cdr s2))))953 ((vector? s1)954 (and (vector? s2)955 (let ((len (vector-length s1)))956 (and (fx= len (vector-length s2))957 (do ((i 0 (fx+ i 1))958 (f #t (compare (vector-ref s1 i) (vector-ref s2 i))))959 ((or (fx>= i len) (not f)) f))))))960 ((and (symbol? s1)961 (symbol? s2))962 (let ((ss1 (or (getp s1 '##core#macro-alias)963 (lookup2 1 s1 dse)964 s1) )965 (ss2 (or (getp s2 '##core#macro-alias)966 (lookup2 2 s2 dse)967 s2) ) )968 (cond ((symbol? ss1)969 (cond ((symbol? ss2) (eq? ss1 ss2))970 ((assq ss1 (##sys#macro-environment)) =>971 (lambda (a) (eq? (cdr a) ss2)))972 (else #f) ) )973 ((symbol? ss2)974 (cond ((assq ss2 (##sys#macro-environment)) =>975 (lambda (a) (eq? ss1 (cdr a))))976 (else #f)))977 (else (eq? ss1 ss2)))))978 (else (eq? s1 s2))) ) )979 (dd `(COMPARE: ,s1 ,s2 --> ,result))980 result))981 (define (lookup2 n sym dse)982 (let ((r (lookup sym dse)))983 (dd " (lookup/DSE " (list n) ": " sym " --> "984 (if (and r (pair? r))985 '<macro>986 r)987 ")")988 r))989 (define (assq-reverse s l)990 (cond991 ((null? l) #f)992 ((eq? (cdar l) s) (car l))993 (else (assq-reverse s (cdr l)))))994 (define (mirror-rename sym)995 (cond ((pair? sym)996 (inherit-pair-line-numbers997 sym (cons (mirror-rename (car sym)) (mirror-rename (cdr sym)))))998 ((vector? sym)999 (list->vector (mirror-rename (vector->list sym))))1000 ((not (symbol? sym)) sym)1001 (else ; Code stolen from strip-syntax1002 (let ((renamed (lookup sym se) ) )1003 (cond ((assq-reverse sym renv) =>1004 (lambda (a)1005 (dd "REVERSING RENAME: " sym " --> " (car a)) (car a)))1006 ((not renamed)1007 (dd "IMPLICITLY RENAMED: " sym) (rename sym))1008 ((pair? renamed)1009 (dd "MACRO: " sym) (rename sym))1010 ((getp sym '##core#real-name) =>1011 (lambda (name)1012 (dd "STRIP SYNTAX ON " sym " ---> " name)1013 name))1014 ;; Rename builtin aliases so strip-syntax can still1015 ;; access symbols as entered by the user1016 (else (let ((implicitly-renamed (rename sym)))1017 (dd "BUILTIN ALIAS: " sym " as " renamed1018 " --> " implicitly-renamed)1019 implicitly-renamed)))))))1020 (if explicit-renaming?1021 ;; Let the user handle renaming1022 (handler form rename compare)1023 ;; Implicit renaming:1024 ;; Rename everything in the input first, feed it to the transformer1025 ;; and then swap out all renamed identifiers by their non-renamed1026 ;; versions, and vice versa. User can decide when to inject code1027 ;; unhygienically this way.1028 (mirror-rename (handler (rename form) rename compare)) ) ) )))10291030(define (er-macro-transformer handler) (make-er/ir-transformer handler #t))1031(define (ir-macro-transformer handler) (make-er/ir-transformer handler #f))10321033(define ##sys#er-transformer er-macro-transformer)1034(define ##sys#ir-transformer ir-macro-transformer)103510361037;; Expose some internals for use in core.scm and chicken-syntax.scm:10381039(define chicken.syntax#define-definition define-definition)1040(define chicken.syntax#define-syntax-definition define-syntax-definition)1041(define chicken.syntax#define-values-definition define-values-definition)1042(define chicken.syntax#expansion-result-hook expansion-result-hook)10431044) ; chicken.syntax module10451046(import scheme chicken.base chicken.bytevector chicken.fixnum)1047(import chicken.syntax chicken.internal chicken.platform)1048(import (only (scheme base) make-parameter))10491050;;; Macro definitions:10511052(##sys#extend-macro-environment1053 'import-syntax '()1054 (##sys#er-transformer1055 (cut ##sys#expand-import <> <> <>1056 ##sys#current-environment ##sys#macro-environment1057 #f #f 'import-syntax)))10581059(##sys#extend-macro-environment1060 'import-syntax-for-syntax '()1061 (##sys#er-transformer1062 (cut ##sys#expand-import <> <> <>1063 ##sys#current-meta-environment ##sys#meta-macro-environment1064 #t #f 'import-syntax-for-syntax)))10651066(set! chicken.syntax#import-definition1067 (##sys#extend-macro-environment1068 'import '()1069 (##sys#er-transformer1070 (lambda (x r c)1071 `(##core#begin1072 ,@(map (lambda (x)1073 (let-values (((name lib spec v s i) (##sys#decompose-import x r c 'import))1074 ((mod) (##sys#current-module)))1075 (when (and mod (eq? name (##sys#module-name mod)))1076 (##sys#syntax-error1077 'import "cannot import from module currently being defined" name))1078 (if (not spec)1079 (##sys#syntax-error1080 'import "cannot import from undefined module" name)1081 (##sys#import1082 spec v s i1083 ##sys#current-environment ##sys#macro-environment #f #f 'import))1084 (if (not lib)1085 '(##core#undefined)1086 `(##core#require ,lib ,name))))1087 (cdr x)))))))10881089(##sys#extend-macro-environment1090 'import-for-syntax '()1091 (##sys#er-transformer1092 (lambda (x r c)1093 (##sys#register-meta-expression `(,(r 'import) ,@(cdr x)))1094 `(##core#elaborationtimeonly (,(r 'import) ,@(cdr x))))))10951096(define (process-cond-expand clauses)1097 (define (err x)1098 (##sys#syntax-error "syntax error in `cond-expand' form"1099 x1100 (cons 'cond-expand clauses)))1101 (define (file-exists? fname)1102 (##sys#file-exists? fname #f #f 'cond-expand))1103 (define (locate-library name)1104 (let* ((name2 (library-id name))1105 (sname2 (symbol->string name2)))1106 (or (##sys#find-module name2 #f)1107 (let loop ((rp (repository-path)))1108 (and (pair? rp)1109 (let ((p (car rp)))1110 (or (file-exists? (string-append p "/" sname2 ".import.so"))1111 (file-exists? (string-append p "/" sname2 ".import.scm"))1112 (loop (cdr rp)))))))))1113 (define (test fx)1114 (cond ((symbol? fx) (feature? (strip-syntax fx)))1115 ((not (pair? fx)) (err fx))1116 (else1117 (let ((head (car fx))1118 (rest (cdr fx)))1119 (case (strip-syntax head)1120 ((and)1121 (or (eq? rest '())1122 (if (pair? rest)1123 (and (test (car rest))1124 (test `(and ,@(cdr rest))))1125 (err fx))))1126 ((or)1127 (and (not (eq? rest '()))1128 (if (pair? rest)1129 (or (test (car rest))1130 (test `(or ,@(cdr rest))))1131 (err fx))))1132 ((not) (not (test (cadr fx))))1133 ((library)1134 (if (and (pair? rest)1135 (null? (cdr rest)))1136 (locate-library (strip-syntax (car rest)))1137 (err fx)))1138 (else (err fx)))))))1139 (let expand ((cls clauses))1140 (cond ((eq? cls '())1141 (##sys#apply1142 ##sys#error "no matching clause in `cond-expand' form"1143 (map (lambda (x) (car x)) clauses)))1144 ((not (pair? cls)) (err cls))1145 (else1146 (let ((clause (car cls))1147 (rclauses (cdr cls)))1148 (if (not (pair? clause))1149 (err clause)1150 (let ((id (car clause)))1151 (cond ((eq? (strip-syntax id) 'else)1152 (let ((rest (cdr clause)))1153 (if (eq? rest '())1154 '(##core#undefined)1155 `(##core#begin ,@rest))))1156 ((test id) `(##core#begin ,@(cdr clause)))1157 (else (expand rclauses))))))))))11581159(##sys#extend-macro-environment1160 'cond-expand1161 '()1162 (##sys#er-transformer1163 (lambda (form r c)1164 (process-cond-expand (cdr form)))))11651166;; The "initial" macro environment, containing only import forms and1167;; cond-expand. TODO: Eventually, cond-expand should move to the1168;; (chicken base) module to match r7rs. Keeping it in the initial env1169;; makes it a whole lot easier to write portable CHICKEN 4 & 5 code.1170(define ##sys#initial-macro-environment (##sys#macro-environment))11711172(##sys#extend-macro-environment1173 'module '()1174 (##sys#er-transformer1175 (lambda (x r c)1176 (##sys#check-syntax 'module x '(_ _ _ . #(_ 0)))1177 (let ((len (length x))1178 (name (library-id (cadr x))))1179 ;; We strip syntax here instead of doing a hygienic comparison1180 ;; to "=". This is a tradeoff; either we do this, or we must1181 ;; include a mapping of (= . scheme#=) in our syntax env. In1182 ;; the initial environment, = is bound to scheme#=, but when1183 ;; using -explicit-use that's not the case. Doing an unhygienic1184 ;; comparison ensures module will work in both cases.1185 (cond ((and (fx>= len 4) (eq? '= (strip-syntax (caddr x))))1186 (let* ((x (strip-syntax x))1187 (app (cadddr x)))1188 (cond ((fx> len 4)1189 ;; feature suggested by syn:1190 ;;1191 ;; (module NAME = FUNCTORNAME BODY ...)1192 ;; ~>1193 ;; (begin1194 ;; (module _NAME * BODY ...)1195 ;; (module NAME = (FUNCTORNAME _NAME)))1196 ;;1197 ;; - the use of "_NAME" is a bit stupid, but it must be1198 ;; externally visible to generate an import library from1199 ;; and compiling "NAME" separately may need an import-lib1200 ;; for stuff in "BODY" (say, syntax needed by syntax exported1201 ;; from the functor, or something like this...)1202 (let ((mtmp (string->symbol1203 (##sys#string-append1204 "_"1205 (symbol->string name))))1206 (%module (r 'module)))1207 `(##core#begin1208 (,%module ,mtmp * ,@(cddddr x))1209 (,%module ,name = (,app ,mtmp)))))1210 (else1211 (##sys#check-syntax1212 'module x '(_ _ _ (_ . #(_ 0))))1213 (##sys#instantiate-functor1214 name1215 (library-id (car app))1216 (cdr app)))))) ; functor arguments1217 (else1218 ;;XXX use module name in "loc" argument?1219 (let ((exports (##sys#validate-exports (strip-syntax (caddr x)) 'module)))1220 `(##core#module1221 ,name1222 ,(if (eq? '* exports)1223 #t1224 exports)1225 ,@(let ((body (cdddr x)))1226 (if (and (pair? body)1227 (null? (cdr body))1228 (string? (car body)))1229 `((##core#include ,(car body) ,##sys#current-source-filename))1230 body))))))))))12311232;;; R7RS define-library12331234(##sys#extend-macro-environment1235 'define-library '()1236 (##sys#er-transformer1237 (lambda (x r c)1238 (define (register-r7rs-module name)1239 (let ((dummy (string->symbol (string-append (string #\x04) "r7rs" (symbol->string name)))))1240 (##sys#put! name '##r7rs#module dummy)1241 dummy))1242 (define implicit-r7rs-library-bindings1243 '(begin1244 cond-expand1245 export1246 import1247 import-for-syntax1248 include1249 include-ci1250 syntax-rules))1251 (##sys#check-syntax 'define-library x '(_ . #(_ 0)))1252 (let* ((x (strip-syntax x))1253 (name (cadr x))1254 (real-name (library-id name))1255 (decls (cddr x))1256 (dummy (register-r7rs-module real-name)))1257 (define (parse-exports specs)1258 (map (lambda (spec)1259 (cond ((and (list? spec)1260 (= 3 (length spec))1261 (eq? 'rename (car spec)))1262 `(export/rename ,(cdr spec)))1263 ((symbol? spec) `(export ,spec))1264 (else1265 (##sys#syntax-error 'define-library "invalid export specifier" spec name))))1266 specs))1267 (define (parse-imports specs)1268 ;; XXX TODO: Should be import-for-syntax'ed as well?1269 `(import ,@specs))1270 (define (process-includes fnames ci?)1271 `(##core#begin1272 ,@(map (lambda (fname)1273 (if (string? fname)1274 `(##core#begin ,@(read-forms fname ci?))1275 (##sys#syntax-error 'include "invalid filename"1276 fname)))1277 fnames)))1278 (define (expand/begin e)1279 (let ((e2 (expand e '())))1280 (if (and (pair? e2) (eq? '##core#begin (car e2)))1281 (cons '##core#begin (map expand/begin (cdr e2)))1282 e2)))1283 (define (read-forms filename ci?)1284 (fluid-let ((##sys#default-read-info-hook1285 (let ((name 'chicken.compiler.support#read-info-hook))1286 (and (feature? 'compiling)1287 (##sys#symbol-has-toplevel-binding? name)1288 (##sys#slot name 0)))))1289 (##sys#include-forms-from-file1290 filename1291 ##sys#current-source-filename ci?1292 (lambda (forms path) forms))))1293 (define (process-include-decls fnames)1294 (parse-decls1295 (let loop ((fnames fnames) (all '()))1296 (if (null? fnames)1297 (reverse all)1298 (let ((forms (read-forms (car fnames) #t)))1299 (loop (cdr fnames)1300 (append (reverse forms) all)))))))1301 (define (fail spec)1302 (##sys#syntax-error 'define-library "invalid library declaration" spec))1303 (define (parse-decls decls)1304 (cond ((null? decls) '(##core#begin))1305 ((and (pair? decls) (pair? (car decls)))1306 (let ((spec (car decls))1307 (more (cdr decls)))1308 (case (car spec)1309 ((export)1310 (##sys#check-syntax 'export spec '(_ . #(_ 0)))1311 `(##core#begin ,@(parse-exports (cdr spec))1312 ,(parse-decls more)))1313 ((import)1314 (##sys#check-syntax 'import spec '(_ . #(_ 0)))1315 `(##core#begin ,(parse-imports (cdr spec))1316 ,(parse-decls more)))1317 ((include)1318 (##sys#check-syntax 'include spec '(_ . #(_ 0)))1319 `(##core#begin ,(process-includes (cdr spec) #f)1320 ,(parse-decls more)))1321 ((include-ci)1322 (##sys#check-syntax 'include-ci spec '(_ . #(_ 0)))1323 `(##core#begin ,(process-includes (cdr spec) #t)1324 ,(parse-decls more)))1325 ((include-library-declarations)1326 `(##core#begin ,(process-include-decls (cdr spec))1327 ,(parse-decls more)))1328 ((cond-expand)1329 (parse-decls1330 `((##core#begin1331 ,(process-cond-expand (cdr spec))1332 ,@more))))1333 ((##core#begin)1334 (parse-decls (append (cdr spec) more)))1335 ((##core#undefined) ; residue from cond-expand1336 (parse-decls more))1337 ((begin)1338 `(##core#begin ,@(cdr spec)1339 ,(parse-decls more)))1340 (else (fail spec)))))1341 (else (fail (car decls)))))1342 `(##core#module ,real-name ((,dummy))1343 ;; gruesome hack: we add a dummy export for adding indirect exports1344 (##core#define-syntax ,dummy1345 (##sys#er-transformer (##core#lambda (x r c) (##core#undefined))))1346 ;; Set up an R7RS environment for the module's body.1347 (import-for-syntax (only scheme.base ,@implicit-r7rs-library-bindings))1348 (import (only scheme.base ,@implicit-r7rs-library-bindings)1349 (only chicken.module export/rename))1350 ;; Now process all toplevel library declarations1351 ,(parse-decls decls))))))13521353(##sys#extend-macro-environment1354 'export '()1355 (##sys#er-transformer1356 (lambda (x r c)1357 (let ((exps (##sys#validate-exports (strip-syntax (cdr x)) 'export))1358 (mod (##sys#current-module)))1359 (when mod1360 (##sys#add-to-export-list mod exps))1361 '(##core#undefined)))))13621363(##sys#extend-macro-environment1364 'export/rename '()1365 (##sys#er-transformer1366 (lambda (x r c)1367 (let ((exps (map (lambda (ren)1368 (if (and (pair? ren)1369 (symbol? (car ren))1370 (pair? (cdr ren))1371 (symbol? (cadr ren))1372 (null? (cddr ren)))1373 (cons (car ren) (cadr ren))1374 (##sys#syntax-error "invalid item in export rename list"1375 ren)))1376 (strip-syntax (cdr x))))1377 (mod (##sys#current-module)))1378 (when mod1379 (##sys#add-to-export/rename-list mod exps))1380 '(##core#undefined)))))13811382(##sys#extend-macro-environment1383 'reexport '()1384 (##sys#er-transformer1385 (cut ##sys#expand-import <> <> <>1386 ##sys#current-environment ##sys#macro-environment1387 #f #t 'reexport)))13881389;;; functor definition13901391(##sys#extend-macro-environment1392 'functor '()1393 (##sys#er-transformer1394 (lambda (x r c)1395 (##sys#check-syntax 'functor x '(_ (_ . #((_ _) 0)) _ . _))1396 (let* ((x (strip-syntax x))1397 (head (cadr x))1398 (name (car head))1399 (args (cdr head))1400 (exps (caddr x))1401 (body (cdddr x))1402 (registration1403 `(##sys#register-functor1404 (##core#quote ,(library-id name))1405 (##core#quote1406 ,(map (lambda (arg)1407 (let ((argname (car arg))1408 (exps (##sys#validate-exports (cadr arg) 'functor)))1409 (unless (or (symbol? argname)1410 (and (list? argname)1411 (= 2 (length argname))1412 (symbol? (car argname))1413 (valid-library-specifier? (cadr argname))))1414 (##sys#syntax-error "invalid functor argument" name arg))1415 (cons argname exps)))1416 args))1417 (##core#quote ,(##sys#validate-exports exps 'functor))1418 (##core#quote ,body))))1419 `(##core#module ,(library-id name)1420 #t1421 (import scheme chicken.syntax) ;; TODO: Is this correct?1422 (begin-for-syntax ,registration))))))14231424;;; interface definition14251426(##sys#extend-macro-environment1427 'define-interface '()1428 (##sys#er-transformer1429 (lambda (x r c)1430 (##sys#check-syntax 'define-interface x '(_ variable _))1431 (let ((name (strip-syntax (cadr x))))1432 (when (eq? '* name)1433 (##sys#syntax-error1434 'define-interface "`*' is not allowed as a name for an interface"))1435 `(##core#elaborationtimeonly1436 (##sys#put/restore!1437 (##core#quote ,name)1438 (##core#quote ##core#interface)1439 (##core#quote1440 ,(let ((exps (strip-syntax (caddr x))))1441 (cond ((eq? '* exps) '*)1442 ((symbol? exps) `(#:interface ,exps))1443 ((list? exps)1444 (##sys#validate-exports exps 'define-interface))1445 (else1446 (##sys#syntax-error1447 'define-interface "invalid exports" (caddr x))))))))))))14481449(##sys#extend-macro-environment1450 'current-module '()1451 (##sys#er-transformer1452 (lambda (x r c)1453 (##sys#check-syntax 'current-module x '(_))1454 (and-let* ((mod (##sys#current-module)))1455 `(##core#quote ,(##sys#module-name mod))))))14561457;; The chicken.module syntax environment1458(define ##sys#chicken.module-macro-environment (##sys#macro-environment))14591460(set! ##sys#scheme-macro-environment1461 (let ((me0 (##sys#macro-environment)))14621463(##sys#extend-macro-environment1464 'lambda1465 '()1466 (##sys#er-transformer1467 (lambda (x r c)1468 (##sys#check-syntax 'lambda x '(_ lambda-list . #(_ 1)))1469 `(##core#lambda ,@(cdr x)))))14701471(##sys#extend-macro-environment1472 'quote1473 '()1474 (##sys#er-transformer1475 (lambda (x r c)1476 (##sys#check-syntax 'quote x '(_ _))1477 `(##core#quote ,(cadr x)))))14781479(##sys#extend-macro-environment1480 'if1481 '()1482 (##sys#er-transformer1483 (lambda (x r c)1484 (##sys#check-syntax 'if x '(_ _ _ . #(_)))1485 `(##core#if ,@(cdr x)))))14861487(##sys#extend-macro-environment1488 'begin1489 '()1490 (##sys#er-transformer1491 (lambda (x r c)1492 (##sys#check-syntax 'begin x '(_ . #(_ 0)))1493 `(##core#begin ,@(cdr x)))))14941495(set! chicken.syntax#define-definition1496 (##sys#extend-macro-environment1497 'define1498 '()1499 (##sys#er-transformer1500 (lambda (x r c)1501 (##sys#check-syntax 'define x '(_ . #(_ 1)))1502 (let loop ((form x))1503 (let ((head (cadr form))1504 (body (cddr form)) )1505 (cond ((not (pair? head))1506 (##sys#check-syntax 'define form '(_ variable . #(_ 0 1)))1507 (let ((name (or (getp head '##core#macro-alias) head)))1508 (##sys#register-export name (##sys#current-module)))1509 (when (c (r 'define) head)1510 (chicken.syntax#defjam-error x))1511 `(##core#begin1512 (##core#ensure-toplevel-definition ,head)1513 (##core#set!1514 ,head1515 ,(if (pair? body) (car body) '(##core#undefined)))))1516 ((pair? (car head))1517 (##sys#check-syntax 'define form '(_ (_ . lambda-list) . #(_ 1)))1518 (loop (chicken.syntax#expand-curried-define head body '()))) ;XXX '() should be se1519 (else1520 (##sys#check-syntax 'define form '(_ (variable . lambda-list) . #(_ 1)))1521 (loop (list (car x) (car head) `(##core#lambda ,(cdr head) ,@body)))))))))))15221523(set! chicken.syntax#define-syntax-definition1524 (##sys#extend-macro-environment1525 'define-syntax1526 '()1527 (##sys#er-transformer1528 (lambda (form r c)1529 (##sys#check-syntax 'define-syntax form '(_ variable _))1530 (let ((head (cadr form))1531 (body (caddr form)))1532 (let ((name (or (getp head '##core#macro-alias) head)))1533 (##sys#register-export name (##sys#current-module)))1534 (when (c (r 'define-syntax) head)1535 (chicken.syntax#defjam-error form))1536 `(##core#define-syntax ,head ,body))))))15371538(##sys#extend-macro-environment1539 'let1540 '()1541 (##sys#er-transformer1542 (lambda (x r c)1543 (cond ((and (pair? (cdr x)) (symbol? (cadr x)))1544 (##sys#check-syntax 'let x '(_ variable #((variable _) 0) . #(_ 1)))1545 (check-for-multiple-bindings (caddr x) x "let"))1546 (else1547 (##sys#check-syntax 'let x '(_ #((variable _) 0) . #(_ 1)))1548 (check-for-multiple-bindings (cadr x) x "let")))1549 `(##core#let ,@(cdr x)))))15501551(##sys#extend-macro-environment1552 'letrec1553 '()1554 (##sys#er-transformer1555 (lambda (x r c)1556 (##sys#check-syntax 'letrec x '(_ #((variable _) 0) . #(_ 1)))1557 (check-for-multiple-bindings (cadr x) x "letrec")1558 `(##core#letrec ,@(cdr x)))))15591560(##sys#extend-macro-environment1561 'let-syntax1562 '()1563 (##sys#er-transformer1564 (lambda (x r c)1565 (##sys#check-syntax 'let-syntax x '(_ #((variable _) 0) . #(_ 1)))1566 (check-for-multiple-bindings (cadr x) x "let-syntax")1567 `(##core#let-syntax ,@(cdr x)))))15681569(##sys#extend-macro-environment1570 'letrec-syntax1571 '()1572 (##sys#er-transformer1573 (lambda (x r c)1574 (##sys#check-syntax 'letrec-syntax x '(_ #((variable _) 0) . #(_ 1)))1575 (check-for-multiple-bindings (cadr x) x "letrec-syntax")1576 `(##core#letrec-syntax ,@(cdr x)))))15771578(##sys#extend-macro-environment1579 'set!1580 '()1581 (##sys#er-transformer1582 (lambda (x r c)1583 (##sys#check-syntax 'set! x '(_ _ _))1584 (let ((dest (cadr x))1585 (val (caddr x)))1586 (cond ((pair? dest)1587 `((##sys#setter ,(car dest)) ,@(cdr dest) ,val))1588 (else `(##core#set! ,dest ,val)))))))15891590(##sys#extend-macro-environment1591 'and1592 '()1593 (##sys#er-transformer1594 (lambda (form r c)1595 (let ((body (cdr form)))1596 (if (null? body)1597 #t1598 (let ((rbody (cdr body))1599 (hbody (car body)) )1600 (if (null? rbody)1601 hbody1602 `(##core#if ,hbody (,(r 'and) ,@rbody) #f) ) ) ) ) ) ) )16031604(##sys#extend-macro-environment1605 'or1606 '()1607 (##sys#er-transformer1608 (lambda (form r c)1609 (let ((body (cdr form)))1610 (if (null? body)1611 #f1612 (let ((rbody (cdr body))1613 (hbody (car body)))1614 (if (null? rbody)1615 hbody1616 (let ((tmp (r 'tmp)))1617 `(##core#let ((,tmp ,hbody))1618 (##core#if ,tmp ,tmp (,(r 'or) ,@rbody)) ) ) ) ) ) ) ) ) )16191620(##sys#extend-macro-environment1621 'cond1622 '()1623 (##sys#er-transformer1624 (lambda (form r c)1625 (let ((body (cdr form))1626 (%=> (r '=>))1627 (%or (r 'or))1628 (%else (r 'else)))1629 (let expand ((clauses body) (else? #f))1630 (if (not (pair? clauses))1631 '(##core#undefined)1632 (let ((clause (car clauses))1633 (rclauses (cdr clauses)) )1634 (##sys#check-syntax 'cond clause '#(_ 1))1635 (cond (else?1636 (##sys#warn1637 (chicken.format#sprintf "clause following `~S' clause in `cond'" else?)1638 (strip-syntax clause))1639 (expand rclauses else?)1640 '(##core#begin))1641 ((or (c %else (car clause))1642 (eq? #t (car clause))1643 ;; Like "constant?" from support.scm1644 (number? (car clause))1645 (char? (car clause))1646 (string? (car clause))1647 (eof-object? (car clause))1648 (bytevector? (car clause))1649 (bwp-object? (car clause))1650 (vector? (car clause))1651 (##sys#srfi-4-vector? (car clause))1652 (and (pair? (car clause))1653 (c (r 'quote) (caar clause))))1654 (expand rclauses (strip-syntax (car clause)))1655 (cond ((and (fx= (length clause) 3)1656 (c %=> (cadr clause)))1657 `(,(caddr clause) ,(car clause)))1658 ((pair? (cdr clause))1659 `(##core#begin ,@(cdr clause)))1660 ((c %else (car clause))1661 `(##core#undefined))1662 (else (car clause))))1663 ((null? (cdr clause))1664 `(,%or ,(car clause) ,(expand rclauses #f)))1665 ((and (fx= (length clause) 3)1666 (c %=> (cadr clause)))1667 (let ((tmp (r 'tmp)))1668 `(##core#let ((,tmp ,(car clause)))1669 (##core#if ,tmp1670 (,(caddr clause) ,tmp)1671 ,(expand rclauses #f) ) ) ) )1672 ((and (fx= (length clause) 4)1673 (c %=> (caddr clause)))1674 (let ((tmp (r 'tmp)))1675 `(##sys#call-with-values1676 (##core#lambda () ,(car clause))1677 (##core#lambda1678 ,tmp1679 (if (##sys#apply ,(cadr clause) ,tmp)1680 (##sys#apply ,(cadddr clause) ,tmp)1681 ,(expand rclauses #f) ) ) ) ) )1682 (else `(##core#if ,(car clause)1683 (##core#begin ,@(cdr clause))1684 ,(expand rclauses #f) ) ) ) ) ) ) ) ) ) )16851686(##sys#extend-macro-environment1687 'case1688 '((eqv? . scheme#eqv?))1689 (##sys#er-transformer1690 (lambda (form r c)1691 (##sys#check-syntax 'case form '(_ _ . #(_ 0)))1692 (let ((exp (cadr form))1693 (body (cddr form)) )1694 (let ((tmp (r 'tmp))1695 (%or (r 'or))1696 (%=> (r '=>))1697 (%eqv? (r 'eqv?))1698 (%else (r 'else)))1699 `(let ((,tmp ,exp))1700 ,(let expand ((clauses body) (else? #f))1701 (if (not (pair? clauses))1702 '(##core#undefined)1703 (let ((clause (car clauses))1704 (rclauses (cdr clauses)) )1705 (##sys#check-syntax 'case clause '#(_ 1))1706 (cond (else?1707 (##sys#warn1708 "clause following `else' clause in `case'"1709 (strip-syntax clause))1710 (expand rclauses #t)1711 '(##core#begin))1712 ((c %else (car clause))1713 (expand rclauses #t)1714 (cond ((null? (cdr clause))1715 `(##core#undefined))1716 ((and (fx= (length clause) 3) ; (else => expr)1717 (c %=> (cadr clause)))1718 `(,(caddr clause) ,tmp))1719 (else1720 `(##core#begin ,@(cdr clause)))))1721 (else1722 `(##core#if (,%or ,@(##sys#map1723 (lambda (x) `(,%eqv? ,tmp ',x))1724 (car clause)))1725 ,(if (and (fx= (length clause) 3) ; ((...) => expr)1726 (c %=> (cadr clause)))1727 `(,(caddr clause) ,tmp)1728 `(##core#begin ,@(cdr clause)))1729 ,(expand rclauses #f) ) ) ) ) ) ) ) ) ) ) ) )17301731(##sys#extend-macro-environment1732 'let*1733 '()1734 (##sys#er-transformer1735 (lambda (form r c)1736 (##sys#check-syntax 'let* form '(_ #((variable _) 0) . #(_ 1)))1737 (let ((bindings (cadr form))1738 (body (cddr form)) )1739 (let expand ((bs bindings))1740 (if (eq? bs '())1741 `(##core#let () ,@body)1742 `(##core#let (,(car bs)) ,(expand (cdr bs))) ) ) ) ) ) )17431744(##sys#extend-macro-environment1745 'do1746 '()1747 (##sys#er-transformer1748 (lambda (form r c)1749 (##sys#check-syntax 'do form '(_ #((variable _ . #(_)) 0) . #(_ 1)))1750 (let ((bindings (cadr form))1751 (test (caddr form))1752 (body (cdddr form))1753 (dovar (r 'doloop)))1754 `(##core#let1755 ,dovar1756 ,(##sys#map (lambda (b) (list (car b) (car (cdr b)))) bindings)1757 (##core#if ,(car test)1758 ,(let ((tbody (cdr test)))1759 (if (eq? tbody '())1760 '(##core#undefined)1761 `(##core#begin ,@tbody) ) )1762 (##core#begin1763 ,(if (eq? body '())1764 '(##core#undefined)1765 `(##core#let () ,@body) )1766 (##core#app1767 ,dovar ,@(##sys#map (lambda (b)1768 (if (eq? (cdr (cdr b)) '())1769 (car b)1770 (car (cdr (cdr b))) ) )1771 bindings) ) ) ) ) ) ) ) )17721773(##sys#extend-macro-environment1774 'quasiquote1775 '()1776 (##sys#er-transformer1777 (lambda (form r c)1778 (let ((%quasiquote (r 'quasiquote))1779 (%unquote (r 'unquote))1780 (%unquote-splicing (r 'unquote-splicing)))1781 (define (walk x n) (simplify (walk1 x n)))1782 (define (walk1 x n)1783 (cond ((vector? x)1784 `(##sys#list->vector ,(walk (vector->list x) n)) )1785 ((not (pair? x)) `(##core#quote ,x))1786 (else1787 (let ((head (car x))1788 (tail (cdr x)))1789 (cond ((c %unquote head)1790 (cond ((eq? n 0)1791 (##sys#check-syntax 'unquote x '(_ _))1792 (car tail))1793 (else (list '##sys#cons `(##core#quote ,%unquote)1794 (walk tail (fx- n 1)) ) )))1795 ((c %quasiquote head)1796 (list '##sys#cons `(##core#quote ,%quasiquote)1797 (walk tail (fx+ n 1)) ) )1798 ((and (pair? head) (c %unquote-splicing (car head)))1799 (cond ((eq? n 0)1800 (##sys#check-syntax 'unquote-splicing head '(_ _))1801 `(##sys#append ,(cadr head) ,(walk tail n)))1802 (else1803 `(##sys#cons1804 (##sys#cons (##core#quote ,%unquote-splicing)1805 ,(walk (cdr head) (fx- n 1)) )1806 ,(walk tail n)))))1807 (else1808 `(##sys#cons ,(walk head n) ,(walk tail n)) ) ) ) ) ) )1809 (define (simplify x)1810 (cond ((chicken.syntax#match-expression x '(##sys#cons a (##core#quote ())) '(a))1811 => (lambda (env) (simplify `(##sys#list ,(cdr (assq 'a env))))) )1812 ((chicken.syntax#match-expression x '(##sys#cons a (##sys#list . b)) '(a b))1813 => (lambda (env)1814 (let ((bxs (assq 'b env)))1815 (if (fx< (length bxs) 32)1816 (simplify `(##sys#list ,(cdr (assq 'a env))1817 ,@(cdr bxs) ) )1818 x) ) ) )1819 ((chicken.syntax#match-expression x '(##sys#append a (##core#quote ())) '(a))1820 => (lambda (env) (cdr (assq 'a env))) )1821 (else x) ) )1822 (##sys#check-syntax 'quasiquote form '(_ _))1823 (walk (cadr form) 0) ) ) ) )18241825(##sys#extend-macro-environment1826 'delay1827 '()1828 (##sys#er-transformer1829 (lambda (form r c)1830 (##sys#check-syntax 'delay form '(_ _))1831 `(,(r 'delay-force)1832 (##sys#make-promise1833 (##sys#call-with-values (##core#lambda () ,(cadr form)) ##sys#list))))))18341835(##sys#extend-macro-environment1836 'syntax-error1837 '()1838 (##sys#er-transformer1839 (lambda (form r c)1840 (##sys#check-syntax 'syntax-error form '(_ string . #(_ 0)))1841 (apply ##sys#syntax-error (cadr form) (cddr form)))))18421843;;; syntax-rules18441845(include "synrules.scm")18461847(macro-subset me0)))18481849;;; the base macro environment (the old "scheme", essentially)1850;;; TODO: Remove this18511852(define ##sys#default-macro-environment1853 (fixup-macro-environment (##sys#macro-environment)))18541855(define ##sys#meta-macro-environment (make-parameter (##sys#macro-environment)))18561857;; register features18581859(register-feature! 'srfi-0 'srfi-46 'srfi-61 'srfi-87)