~ chicken-core (master) /expand.scm


   1;;;; expand.scm - The HI/LO expander
   2;
   3; Copyright (c) 2008-2022, The CHICKEN Team
   4; All rights reserved.
   5;
   6; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
   7; conditions are met:
   8;
   9;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
  10;     disclaimer.
  11;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
  12;     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 promote
  14;     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 EXPRESS
  17; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  18; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
  19; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  23; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  24; POSSIBILITY OF SUCH DAMAGE.
  25
  26
  27;; this unit needs the "modules" unit, but must be initialized first, so it doesn't
  28;; declare "modules" as used - if you use "-explicit-use", take care of this.
  29
  30(declare
  31  (unit expand)
  32  (uses internal)
  33  (disable-interrupts)
  34  (fixnum)
  35  (not inline ##sys#syntax-error-hook ##sys#compiler-syntax-hook))
  36
  37(module chicken.syntax
  38  (expand
  39   expand1
  40   get-line-number
  41   read-with-source-info
  42   strip-syntax
  43   er-macro-transformer
  44   ir-macro-transformer)
  45
  46(import scheme
  47	chicken.base
  48	chicken.condition
  49	chicken.fixnum
  50	chicken.internal
  51	chicken.keyword
  52	chicken.platform
  53	chicken.string)
  54(import (only (scheme base) make-parameter open-output-string get-output-string))
  55
  56(include "common-declarations.scm")
  57(include "mini-srfi-1.scm")
  58
  59(define-syntax d (syntax-rules () ((_ . _) (void))))
  60;(define-syntax d (syntax-rules () ((_ args ...) (print args ...))))
  61
  62;; Macro to avoid "unused variable map-se" when "d" is disabled
  63(define-syntax map-se
  64  (syntax-rules ()
  65    ((_ ?se)
  66     (map (lambda (a)
  67	    (cons (car a) (if (symbol? (cdr a)) (cdr a) '<macro>)))
  68	  ?se))))
  69
  70(define-alias dd d)
  71(define-alias dm d)
  72(define-alias dx d)
  73
  74(define-inline (getp sym prop)
  75  (##core#inline "C_i_getprop" sym prop #f))
  76
  77(define-inline (putp sym prop val)
  78  (##core#inline_allocate ("C_a_i_putprop" 8) sym prop val))
  79
  80(define-inline (namespaced-symbol? sym)
  81  (##core#inline "C_u_i_namespaced_symbolp" sym))
  82
  83;;; Source file tracking
  84
  85(define ##sys#current-source-filename #f)
  86
  87;;; Syntactic environments
  88
  89(define ##sys#current-environment (make-parameter '()))
  90(define ##sys#current-meta-environment (make-parameter '()))
  91
  92(define (lookup id se)
  93  (cond ((##core#inline "C_u_i_assq" id se) => cdr)
  94	((getp id '##core#macro-alias))
  95	(else #f)))
  96
  97(define (macro-alias var se)
  98  (if (or (keyword? var) (namespaced-symbol? var))
  99      var
 100      (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) ) )
 110
 111(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)))))
 136
 137(define (##sys#extend-se se vars #!optional (aliases (map gensym vars)))
 138  (for-each
 139   (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 cons
 144
 145
 146;;; Macro handling
 147
 148(define ##sys#macro-environment (make-parameter '()))
 149
 150(define ##sys#scheme-macro-environment '()) ; reassigned below
 151;; These are all re-assigned by chicken-syntax.scm:
 152(define ##sys#chicken-ffi-macro-environment '()) ; used later in foreign.import.scm
 153(define ##sys#chicken.condition-macro-environment '()) ; used later in chicken.condition.import.scm
 154(define ##sys#chicken.time-macro-environment '()) ; used later in chicken.time.import.scm
 155(define ##sys#chicken.type-macro-environment '()) ; used later in chicken.type.import.scm
 156(define ##sys#chicken.syntax-macro-environment '()) ; used later in chicken.syntax.import.scm
 157(define ##sys#chicken.base-macro-environment '()) ; used later in chicken.base.import.scm
 158
 159(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)))
 163
 164(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	  (else
 173	   (let ((data (list se handler)))
 174	     (##sys#macro-environment
 175	      (cons (cons name data) me))
 176	     data)))))
 177
 178(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))))
 183
 184(define (##sys#undefine-macro! name)
 185  (##sys#macro-environment
 186    ;; 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))))))))
 191
 192;; The basic macro-expander
 193
 194(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 ex
 199	;; modify error message in condition object to include
 200	;; currently expanded macro-name
 201	(abort
 202	 (if (and (##sys#structure? ex 'condition)
 203		  (memv 'exn (##sys#slot ex 1)) )
 204	     (##sys#make-structure
 205	      'condition
 206	      (##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			  (cons
 216			   '(exn . message)
 217			   (cons (string-append
 218				  "during expansion of ("
 219				  (##sys#symbol->string/shared name)
 220				  " ...) - "
 221				  (car r) )
 222				 (cdr r) ) )
 223			  (copy r) ) ) ) ) )
 224	     ex) )
 225      (let ((exp2
 226	     (if cs
 227		 ;; compiler-syntax may "fall through"
 228		 (fluid-let ((chicken.internal.syntax-rules#syntax-rules-mismatch
 229			      (lambda (input) exp))) ; a bit of a hack
 230		   (handler exp se dse))
 231		 (handler exp se dse))) )
 232	(when (and (not cs) (eq? exp exp2))
 233	  (##sys#syntax-error
 234	   (string-append
 235	    "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	  ,head
 243	  ,(cond ((getp head '##core#macro-alias) =>
 244		  (lambda (a) (if (symbol? a) a '<macro>)) )
 245		 (else '_))
 246	  ,exp
 247	  ,(if (pair? mdef)
 248	       `(SE: ,@(map-se (car mdef)))
 249	       mdef)))
 250    (if (pair? mdef)
 251        (values
 252	 ;; 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 let
 271			      (##sys#check-syntax 'let body '(_ #((variable _) 0) . #(_ 1)) #f dse)
 272			      (let ([bs (cadr body)])
 273				(values
 274				 `(##core#app
 275				   (##core#letrec*
 276				    ([,bindings
 277				      (##core#loop-lambda
 278				       ,(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			       (else
 288				(when ##sys#compiler-syntax-hook
 289				  (##sys#compiler-syntax-hook head2 result))
 290				(loop result))))))
 291		    (else (expand head exp head2)) ) )
 292	    (values exp #f) ) )
 293      (values exp #f) ) ) )
 294
 295(define ##sys#compiler-syntax-hook #f)
 296(define ##sys#enable-runtime-macros #f)
 297(define expansion-result-hook (lambda (input output) output))
 298
 299
 300;;; User-level macroexpansion
 301
 302(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 m
 306	  (loop exp2)
 307	  exp2) ) ) )
 308
 309(define (expand1 exp #!optional (se (##sys#current-environment)) cs?)
 310  (nth-value 0 (##sys#expand-0 exp se cs?)) )
 311
 312
 313;;; Extended (DSSSL-style) lambda lists
 314;
 315; Assumptions:
 316;
 317; 1) #!rest must come before #!key
 318; 2) default values may refer to earlier variables
 319; 3) optional/key args may be either variable or (variable default)
 320; 4) an argument marker may not be specified more than once
 321; 5) no special handling of extra keywords (no error)
 322; 6) default value of optional/key args is #f
 323; 7) mixing with dotted list syntax is allowed
 324
 325(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))] ) ) ) )
 331
 332(define ##sys#expand-extended-lambda-list
 333  (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=4
 346		   [req '()]
 347		   [opt '()]
 348		   [key '()]
 349		   [llist llist0] )
 350	  (cond [(null? llist)
 351		 (values
 352		  (if rvar (##sys#append (reverse req) rvar) (reverse req))
 353		  (let ([body
 354			 (if (null? key)
 355			     body
 356			     `((,%let*
 357				,(map (lambda (k)
 358					(let ((s (car k)))
 359					  `(,s (##sys#get-keyword
 360						(##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			   `((,%let
 369			      ([,(caar opt) (,%opt ,rvar ,(cadar opt))])
 370			      ,@body) ) ]
 371			  [(and (not hasrest) (null? key))
 372			   `((,%let-optionals*
 373			      ,rvar ,(reverse opt) ,@body))]
 374			  [else
 375			   `((,%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		     (begin
 382		       (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		[else
 388		 (let* ((var (car llist))
 389			(x (or (and (symbol? var) (not (eq? 3 mode)) (lookup var se)) var))
 390			(r (cdr llist)))
 391		   (case x
 392		     [(#!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			      (begin
 401				(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		     [else
 412		      (cond [(symbol? var)
 413			     (case mode
 414			       [(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 mode
 420			       [(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")] ) ] ) ) ] ) ) ) ) ) )
 425
 426
 427;;; Error message for redefinition of currently used defining form
 428;
 429; (i.e.`"(define define ...)")
 430
 431(define (defjam-error form)
 432  (##sys#syntax-error
 433   "redefinition of currently used defining form" ; help me find something better
 434   form))
 435
 436;;; Expansion of multiple values assignments.
 437;
 438; Given a lambda list and a multi-valued expression, returns a form that
 439; will `set!` each variable to its corresponding value in order.
 440
 441(define (##sys#expand-multiple-values-assignment formals expr)
 442  (##sys#decompose-lambda-list
 443   formals
 444   (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-values
 448	 (##core#lambda () ,expr)
 449	 (##core#lambda
 450	  ,(append aliases rest-alias)
 451	  ,@(map (lambda (v a) `(##core#set! ,v ,a)) vars aliases)
 452	  ,@(cond
 453	      ((null? formals) '((##core#undefined)))
 454	      ((null? rest-alias) '())
 455	      (else `((##core#set! ,rest ,rest-alias))))))))))
 456
 457;;; Expansion of bodies (and internal definitions)
 458;
 459; This code is disgustingly complex.
 460
 461(define define-definition)
 462(define define-syntax-definition)
 463(define define-values-definition)
 464(define import-definition)
 465
 466(define ##sys#canonicalize-body
 467  (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		(cons
 495		 '##core#begin
 496		 (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 imports
 509			(if (comp-import (car x))
 510			    (loop rest (cons x exps))
 511			    (cons
 512			     '##core#begin
 513			     (##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 before
 517			      ;; we can continue with other forms, so hand
 518			      ;; control back to the compiler
 519			      (if (and (pair? x)
 520				       (symbol? (car x))
 521				       (or (comp '##core#module (car x))
 522					   (comp '##core#include (car x))))
 523				  `(##core#begin
 524				    ,@(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 compiler
 533	  ;; call us again for the remaining body by wrapping the
 534	  ;; remaining body forms in a ##core#let.
 535	  (let* ((result
 536		  `(##core#let
 537		    ,(##sys#map
 538		      (lambda (v) (##sys#list v '(##core#undefined)))
 539		      ;; vars are all normalised to lambda-lists: flatten them
 540		      (foldl (lambda (l v)
 541			       (##sys#append l (##sys#decompose-lambda-list
 542						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! for
 547			     ;; efficiency, but also because they must be
 548			     ;; 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      (fini
 560       vars vals mvars
 561       (let loop ((body body) (defs '()) (done #f))
 562	 (cond (done `((##core#letrec-syntax
 563			,(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 by
 571		  ;; 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.  As
 577    ;; soon as we encounter something else, finish up.
 578    (define (expand body)
 579      ;; Each #t in "mvars" indicates an MV-capable "var".  Non-MV
 580      ;; 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		  (cond
 592		   ((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 above
 599				  (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-syntax
 608				 'define x '(_ (_ . lambda-list) . #(_ 1)) #f se)
 609				(loop2
 610				 (chicken.syntax#expand-curried-define head (cddr x) se)))
 611			       (else
 612				(##sys#check-syntax
 613				 'define x
 614				 '(_ (variable . lambda-list) . #(_ 1)) #f se)
 615				(loop rest
 616				      (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		    (else
 629		     ;; Do not macro-expand local definitions we are
 630		     ;; 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) ) )
 638
 639
 640;;; A simple expression matcher
 641
 642;; Used by "quasiquote", below
 643(define chicken.syntax#match-expression
 644  (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) ) ) )
 658
 659
 660;;; Expand "curried" lambda-list syntax for `define'
 661
 662;; Used by "define", below
 663(define (chicken.syntax#expand-curried-define head body se)
 664  (let ((name #f))
 665    (define (loop head body)
 666      (if (symbol? (car head))
 667	  (begin
 668	    (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) ) ) )
 673
 674
 675;;; Line-number database management:
 676
 677(define ##sys#line-number-database #f)
 678
 679
 680;;; General syntax checking routine:
 681
 682(define ##sys#syntax-error-culprit #f)
 683(define ##sys#syntax-context '())
 684
 685(define (##sys#syntax-error-hook . args)
 686  (apply ##sys#signal-hook #:syntax-error
 687	 (strip-syntax args)))
 688
 689(define (##sys#syntax-error . args)
 690  (apply ##sys#syntax-error-hook args))
 691
 692(define ##sys#syntax-error/context
 693  (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 found
 707		   (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		  (else
 714		   (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				(outstr
 725				 (string-append
 726				  "  Suggesting: `(import "
 727				  (symbol->string (car us))
 728				  ")'"))
 729				(outstr
 730				 (string-append
 731				  "  Suggesting one of:\n"
 732				  (let loop ((lst us))
 733				    (if (null? lst)
 734					""
 735					(string-append
 736					 "\n      (import " (symbol->string (car lst)) ")'"
 737					 (loop (cdr lst)))))))))
 738			   (else (loop (cdr cx))))))))
 739	  (##sys#syntax-error-hook (get-output-string out))))))
 740
 741;;; Hook for source information
 742
 743(define (alist-weak-cons k v lst)
 744  (cons (##core#inline_allocate ("C_a_i_weak_cons" 3) k v) lst))
 745
 746(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 prev
 752		(##core#inline "C_bwpp" (caar lst)))
 753	   (set-cdr! prev (cdr lst))
 754	   (lp (cdr lst) prev))
 755	  (else (lp (cdr lst) lst)))))
 756
 757(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 values
 761      (hash-table-set!
 762       ##sys#line-number-database
 763       (car data)
 764       (alist-weak-cons
 765	data (conc (or ##sys#current-source-filename "<stdin>") ":" val)
 766	old-value ) )) )
 767  data)
 768
 769(define-constant line-number-database-size 997) ; Copied from core.scm
 770
 771(define (read-with-source-info #!optional (in ##sys#standard-input) fname)
 772  ;; Initialize line number db on first use
 773  (unless ##sys#line-number-database
 774    (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) ) )
 778
 779
 780(define (get-line-number sexp)
 781  (and ##sys#line-number-database
 782       (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))))))
 790
 791;; TODO: Needs a better name - it extracts the name(?) and the source expression
 792(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)) ) ) )
 798
 799(define (##sys#display-line-number-database)
 800  (hash-table-for-each
 801   (lambda (key val)
 802     (when val
 803       (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) )
 809
 810;;; Traverse expression and update line-number db with all contained calls:
 811
 812(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))
 828
 829
 830(define-constant +default-argument-count-limit+ 99999)
 831
 832(define ##sys#check-syntax
 833  (lambda (id exp pat #!optional culprit (se (##sys#current-environment)))
 834
 835    (define (test x pred msg)
 836      (unless (pred x) (err msg)) )
 837
 838    (define (err msg)
 839      (let* ([sexp ##sys#syntax-error-culprit]
 840	     [ln (get-line-number sexp)] )
 841	(##sys#syntax-error
 842	 (if ln
 843	     (string-append "(" ln ") in `" (symbol->string id) "' - " msg)
 844	     (string-append "in `" (symbol->string id) "' - " msg) )
 845	 exp) ) )
 846
 847    (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) ) ) ) )
 857
 858    (define (variable? v)
 859      (symbol? v))
 860
 861    (define (proper-list? x)
 862      (let loop ((x x))
 863	(cond ((eq? x '()))
 864	      ((pair? x) (loop (cdr x)))
 865	      (else #f) ) ) )
 866
 867    (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 p
 892	       ((_) #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	       (else
 901		(test
 902		 x
 903		 (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	    (else
 911	     (walk (car x) (car p))
 912	     (walk (cdr x) (cdr p)) ) ) ) ) )
 913
 914
 915;;; explicit/implicit-renaming transformer
 916
 917(define (make-er/ir-transformer handler explicit-renaming?)
 918  (##sys#make-structure
 919   'transformer
 920   (lambda (form se dse)
 921     (let ((renv '()))	  ; keep rename-environment for this expansion
 922       (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 name
 929			      (alist-weak-cons new ln cur))))
 930	 new)
 931       (assert (list? se) "not a list" se) ;XXX remove later
 932       (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	       (else
 943		(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 ((result
 949		(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	 (cond
 991	  ((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-numbers
 997		 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-syntax
1002		(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 still
1015                        ;; access symbols as entered by the user
1016			(else (let ((implicitly-renamed (rename sym)))
1017                                (dd "BUILTIN ALIAS: " sym " as " renamed
1018                                    " --> " implicitly-renamed)
1019                                implicitly-renamed)))))))
1020       (if explicit-renaming?
1021	   ;; Let the user handle renaming
1022	   (handler form rename compare)
1023	   ;; Implicit renaming:
1024	   ;; Rename everything in the input first, feed it to the transformer
1025	   ;; and then swap out all renamed identifiers by their non-renamed
1026	   ;; versions, and vice versa.  User can decide when to inject code
1027	   ;; unhygienically this way.
1028	   (mirror-rename (handler (rename form) rename compare)) ) ) )))
1029
1030(define (er-macro-transformer handler) (make-er/ir-transformer handler #t))
1031(define (ir-macro-transformer handler) (make-er/ir-transformer handler #f))
1032
1033(define ##sys#er-transformer er-macro-transformer)
1034(define ##sys#ir-transformer ir-macro-transformer)
1035
1036
1037;; Expose some internals for use in core.scm and chicken-syntax.scm:
1038
1039(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)
1043
1044) ; chicken.syntax module
1045
1046(import scheme chicken.base chicken.bytevector chicken.fixnum)
1047(import chicken.syntax chicken.internal chicken.platform)
1048(import (only (scheme base) make-parameter))
1049
1050;;; Macro definitions:
1051
1052(##sys#extend-macro-environment
1053 'import-syntax '()
1054 (##sys#er-transformer
1055  (cut ##sys#expand-import <> <> <>
1056       ##sys#current-environment ##sys#macro-environment
1057       #f #f 'import-syntax)))
1058
1059(##sys#extend-macro-environment
1060 'import-syntax-for-syntax '()
1061 (##sys#er-transformer
1062  (cut ##sys#expand-import <> <> <>
1063       ##sys#current-meta-environment ##sys#meta-macro-environment
1064       #t #f 'import-syntax-for-syntax)))
1065
1066(set! chicken.syntax#import-definition
1067  (##sys#extend-macro-environment
1068   'import '()
1069   (##sys#er-transformer
1070    (lambda (x r c)
1071      `(##core#begin
1072	,@(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-error
1077		      'import "cannot import from module currently being defined" name))
1078		   (if (not spec)
1079		       (##sys#syntax-error
1080			'import "cannot import from undefined module" name)
1081		       (##sys#import
1082			spec v s i
1083			##sys#current-environment ##sys#macro-environment #f #f 'import))
1084		   (if (not lib)
1085		       '(##core#undefined)
1086		       `(##core#require ,lib ,name))))
1087	       (cdr x)))))))
1088
1089(##sys#extend-macro-environment
1090 'import-for-syntax '()
1091 (##sys#er-transformer
1092  (lambda (x r c)
1093    (##sys#register-meta-expression `(,(r 'import) ,@(cdr x)))
1094    `(##core#elaborationtimeonly (,(r 'import) ,@(cdr x))))))
1095
1096(define (process-cond-expand clauses)
1097      (define (err x)
1098	(##sys#syntax-error "syntax error in `cond-expand' form"
1099		     x
1100		     (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	      (else
1117	       (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#apply
1142		##sys#error "no matching clause in `cond-expand' form"
1143		(map (lambda (x) (car x)) clauses)))
1144	      ((not (pair? cls)) (err cls))
1145	      (else
1146	       (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))))))))))
1158
1159(##sys#extend-macro-environment
1160 'cond-expand
1161 '()
1162 (##sys#er-transformer
1163  (lambda (form r c)
1164    (process-cond-expand (cdr form)))))
1165
1166;; The "initial" macro environment, containing only import forms and
1167;; cond-expand.  TODO: Eventually, cond-expand should move to the
1168;; (chicken base) module to match r7rs.  Keeping it in the initial env
1169;; makes it a whole lot easier to write portable CHICKEN 4 & 5 code.
1170(define ##sys#initial-macro-environment (##sys#macro-environment))
1171
1172(##sys#extend-macro-environment
1173 'module '()
1174 (##sys#er-transformer
1175  (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 comparison
1180      ;; to "=".  This is a tradeoff; either we do this, or we must
1181      ;; include a mapping of (= . scheme#=) in our syntax env.  In
1182      ;; the initial environment, = is bound to scheme#=, but when
1183      ;; using -explicit-use that's not the case.  Doing an unhygienic
1184      ;; 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		      ;; (begin
1194		      ;;   (module _NAME * BODY ...)
1195		      ;;   (module NAME = (FUNCTORNAME _NAME)))
1196		      ;;
1197		      ;; - the use of "_NAME" is a bit stupid, but it must be
1198		      ;;   externally visible to generate an import library from
1199		      ;;   and compiling "NAME" separately may need an import-lib
1200		      ;;   for stuff in "BODY" (say, syntax needed by syntax exported
1201		      ;;   from the functor, or something like this...)
1202		      (let ((mtmp (string->symbol
1203				   (##sys#string-append
1204				    "_"
1205				    (symbol->string name))))
1206			    (%module (r 'module)))
1207			`(##core#begin
1208			  (,%module ,mtmp * ,@(cddddr x))
1209			  (,%module ,name = (,app ,mtmp)))))
1210		     (else
1211		      (##sys#check-syntax
1212		       'module x '(_ _ _ (_ . #(_ 0))))
1213		      (##sys#instantiate-functor
1214		       name
1215		       (library-id (car app))
1216		       (cdr app)))))) ; functor arguments
1217	    (else
1218	     ;;XXX use module name in "loc" argument?
1219	     (let ((exports (##sys#validate-exports (strip-syntax (caddr x)) 'module)))
1220	       `(##core#module
1221		 ,name
1222		 ,(if (eq? '* exports)
1223		      #t
1224		      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))))))))))
1231
1232;;; R7RS define-library
1233
1234(##sys#extend-macro-environment
1235  'define-library '()
1236  (##sys#er-transformer
1237   (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-bindings
1243       '(begin
1244          cond-expand
1245          export
1246          import
1247          import-for-syntax
1248          include
1249          include-ci
1250          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                      (else
1265                        (##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#begin
1272           ,@(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-hook
1285                       (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-file
1290               filename
1291               ##sys#current-source-filename ci?
1292               (lambda (forms path) forms))))
1293       (define (process-include-decls fnames)
1294         (parse-decls
1295           (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-decls
1330                     `((##core#begin
1331                        ,(process-cond-expand (cdr spec))
1332                        ,@more))))
1333                  ((##core#begin)
1334                    (parse-decls (append (cdr spec) more)))
1335                  ((##core#undefined)	; residue from cond-expand
1336                    (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 exports
1344	 (##core#define-syntax ,dummy
1345	  (##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 declarations
1351	 ,(parse-decls decls))))))
1352
1353(##sys#extend-macro-environment
1354 'export '()
1355 (##sys#er-transformer
1356  (lambda (x r c)
1357    (let ((exps (##sys#validate-exports (strip-syntax (cdr x)) 'export))
1358	  (mod (##sys#current-module)))
1359      (when mod
1360	(##sys#add-to-export-list mod exps))
1361      '(##core#undefined)))))
1362
1363(##sys#extend-macro-environment
1364 'export/rename '()
1365 (##sys#er-transformer
1366  (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 mod
1379	(##sys#add-to-export/rename-list mod exps))
1380      '(##core#undefined)))))
1381
1382(##sys#extend-macro-environment
1383 'reexport '()
1384 (##sys#er-transformer
1385  (cut ##sys#expand-import <> <> <>
1386       ##sys#current-environment ##sys#macro-environment
1387       #f #t 'reexport)))
1388
1389;;; functor definition
1390
1391(##sys#extend-macro-environment
1392 'functor '()
1393 (##sys#er-transformer
1394  (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	   (registration
1403	    `(##sys#register-functor
1404	      (##core#quote ,(library-id name))
1405	      (##core#quote
1406	       ,(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	#t
1421	(import scheme chicken.syntax) ;; TODO: Is this correct?
1422	(begin-for-syntax ,registration))))))
1423
1424;;; interface definition
1425
1426(##sys#extend-macro-environment
1427 'define-interface '()
1428 (##sys#er-transformer
1429  (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-error
1434	 'define-interface "`*' is not allowed as a name for an interface"))
1435      `(##core#elaborationtimeonly
1436	(##sys#put/restore!
1437	 (##core#quote ,name)
1438	 (##core#quote ##core#interface)
1439	 (##core#quote
1440	  ,(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		   (else
1446		    (##sys#syntax-error
1447		     'define-interface "invalid exports" (caddr x))))))))))))
1448
1449(##sys#extend-macro-environment
1450 'current-module '()
1451 (##sys#er-transformer
1452  (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))))))
1456
1457;; The chicken.module syntax environment
1458(define ##sys#chicken.module-macro-environment (##sys#macro-environment))
1459
1460(set! ##sys#scheme-macro-environment
1461  (let ((me0 (##sys#macro-environment)))
1462
1463(##sys#extend-macro-environment
1464 'lambda
1465 '()
1466 (##sys#er-transformer
1467  (lambda (x r c)
1468    (##sys#check-syntax 'lambda x '(_ lambda-list . #(_ 1)))
1469    `(##core#lambda ,@(cdr x)))))
1470
1471(##sys#extend-macro-environment
1472 'quote
1473 '()
1474 (##sys#er-transformer
1475  (lambda (x r c)
1476    (##sys#check-syntax 'quote x '(_ _))
1477    `(##core#quote ,(cadr x)))))
1478
1479(##sys#extend-macro-environment
1480 'if
1481 '()
1482 (##sys#er-transformer
1483  (lambda (x r c)
1484    (##sys#check-syntax 'if x '(_ _ _ . #(_)))
1485    `(##core#if ,@(cdr x)))))
1486
1487(##sys#extend-macro-environment
1488 'begin
1489 '()
1490 (##sys#er-transformer
1491  (lambda (x r c)
1492    (##sys#check-syntax 'begin x '(_ . #(_ 0)))
1493    `(##core#begin ,@(cdr x)))))
1494
1495(set! chicken.syntax#define-definition
1496  (##sys#extend-macro-environment
1497   'define
1498   '()
1499   (##sys#er-transformer
1500    (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#begin
1512		    (##core#ensure-toplevel-definition ,head)
1513		    (##core#set!
1514		     ,head
1515		     ,(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 se
1519		(else
1520		 (##sys#check-syntax 'define form '(_ (variable . lambda-list) . #(_ 1)))
1521		 (loop (list (car x) (car head) `(##core#lambda ,(cdr head) ,@body)))))))))))
1522
1523(set! chicken.syntax#define-syntax-definition
1524  (##sys#extend-macro-environment
1525   'define-syntax
1526   '()
1527   (##sys#er-transformer
1528    (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))))))
1537
1538(##sys#extend-macro-environment
1539 'let
1540 '()
1541 (##sys#er-transformer
1542  (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	  (else
1547	   (##sys#check-syntax 'let x '(_ #((variable _) 0) . #(_ 1)))
1548           (check-for-multiple-bindings (cadr x) x "let")))
1549    `(##core#let ,@(cdr x)))))
1550
1551(##sys#extend-macro-environment
1552 'letrec
1553 '()
1554 (##sys#er-transformer
1555  (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)))))
1559
1560(##sys#extend-macro-environment
1561 'let-syntax
1562 '()
1563 (##sys#er-transformer
1564  (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)))))
1568
1569(##sys#extend-macro-environment
1570 'letrec-syntax
1571 '()
1572 (##sys#er-transformer
1573  (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)))))
1577
1578(##sys#extend-macro-environment
1579 'set!
1580 '()
1581 (##sys#er-transformer
1582  (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)))))))
1589
1590(##sys#extend-macro-environment
1591 'and
1592 '()
1593 (##sys#er-transformer
1594  (lambda (form r c)
1595    (let ((body (cdr form)))
1596      (if (null? body)
1597	  #t
1598	  (let ((rbody (cdr body))
1599		(hbody (car body)) )
1600	    (if (null? rbody)
1601		hbody
1602		`(##core#if ,hbody (,(r 'and) ,@rbody) #f) ) ) ) ) ) ) )
1603
1604(##sys#extend-macro-environment
1605 'or
1606 '()
1607 (##sys#er-transformer
1608  (lambda (form r c)
1609    (let ((body (cdr form)))
1610     (if (null? body)
1611	 #f
1612	 (let ((rbody (cdr body))
1613	       (hbody (car body)))
1614	   (if (null? rbody)
1615	       hbody
1616	       (let ((tmp (r 'tmp)))
1617		 `(##core#let ((,tmp ,hbody))
1618		    (##core#if ,tmp ,tmp (,(r 'or) ,@rbody)) ) ) ) ) ) ) ) ) )
1619
1620(##sys#extend-macro-environment
1621 'cond
1622 '()
1623 (##sys#er-transformer
1624  (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#warn
1637		      (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.scm
1644                         (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 ,tmp
1670					       (,(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-values
1676			 (##core#lambda () ,(car clause))
1677			 (##core#lambda
1678			  ,tmp
1679			  (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) ) ) ) ) ) ) ) ) ) )
1685
1686(##sys#extend-macro-environment
1687 'case
1688 '((eqv? . scheme#eqv?))
1689 (##sys#er-transformer
1690  (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#warn
1708			    "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				 (else
1720				  `(##core#begin ,@(cdr clause)))))
1721			  (else
1722			   `(##core#if (,%or ,@(##sys#map
1723						(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) ) ) ) ) ) ) ) ) ) ) ) )
1730
1731(##sys#extend-macro-environment
1732 'let*
1733 '()
1734 (##sys#er-transformer
1735  (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))) ) ) ) ) ) )
1743
1744(##sys#extend-macro-environment
1745 'do
1746 '()
1747 (##sys#er-transformer
1748  (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#let
1755	,dovar
1756	,(##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#begin
1763		    ,(if (eq? body '())
1764			 '(##core#undefined)
1765			 `(##core#let () ,@body) )
1766		    (##core#app
1767		     ,dovar ,@(##sys#map (lambda (b)
1768					   (if (eq? (cdr (cdr b)) '())
1769					       (car b)
1770					       (car (cdr (cdr b))) ) )
1771					 bindings) ) ) ) ) ) ) ) )
1772
1773(##sys#extend-macro-environment
1774 'quasiquote
1775 '()
1776 (##sys#er-transformer
1777  (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	      (else
1787	       (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                              (else
1803                               `(##sys#cons
1804                                 (##sys#cons (##core#quote ,%unquote-splicing)
1805                                             ,(walk (cdr head) (fx- n 1)) )
1806                                 ,(walk tail n)))))
1807		       (else
1808			`(##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) ) ) ) )
1824
1825(##sys#extend-macro-environment
1826 'delay
1827 '()
1828 (##sys#er-transformer
1829  (lambda (form r c)
1830    (##sys#check-syntax 'delay form '(_ _))
1831    `(,(r 'delay-force)
1832      (##sys#make-promise
1833       (##sys#call-with-values (##core#lambda () ,(cadr form)) ##sys#list))))))
1834
1835(##sys#extend-macro-environment
1836 'syntax-error
1837 '()
1838 (##sys#er-transformer
1839  (lambda (form r c)
1840    (##sys#check-syntax 'syntax-error form '(_ string . #(_ 0)))
1841    (apply ##sys#syntax-error (cadr form) (cddr form)))))
1842
1843;;; syntax-rules
1844
1845(include "synrules.scm")
1846
1847(macro-subset me0)))
1848
1849;;; the base macro environment (the old "scheme", essentially)
1850;;; TODO: Remove this
1851
1852(define ##sys#default-macro-environment
1853  (fixup-macro-environment (##sys#macro-environment)))
1854
1855(define ##sys#meta-macro-environment (make-parameter (##sys#macro-environment)))
1856
1857;; register features
1858
1859(register-feature! 'srfi-0 'srfi-46 'srfi-61 'srfi-87)
Trap