~ 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))
 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  (##sys#read in read-with-source-info-hook) )
 777
 778
 779(define (get-line-number sexp)
 780  (and ##sys#line-number-database
 781       (pair? sexp)
 782       (let ([head (car sexp)])
 783	 (and (symbol? head)
 784	      (cond ((hash-table-ref ##sys#line-number-database head)
 785		     => (lambda (pl)
 786			  (let ((a (assq/drop-bwp! sexp pl)))
 787			    (and a (cdr a)))))
 788		    (else #f))))))
 789
 790;; TODO: Needs a better name - it extracts the name(?) and the source expression
 791(define (##sys#get-line-2 exp)
 792  (let* ((name (car exp))
 793	 (lst (hash-table-ref ##sys#line-number-database name)))
 794    (cond ((and lst (assq/drop-bwp! exp (cdr lst)))
 795	   => (lambda (a) (values (car lst) (cdr a))) )
 796	  (else (values name #f)) ) ) )
 797
 798(define (##sys#display-line-number-database)
 799  (hash-table-for-each
 800   (lambda (key val)
 801     (when val
 802       (let ((port (current-output-port)))
 803	 (##sys#print key #t port)
 804	 (##sys#print " " #f port)
 805	 (##sys#print (map cdr val) #t port)
 806	 (##sys#print "\n" #f port))) )
 807   ##sys#line-number-database) )
 808
 809;;; Traverse expression and update line-number db with all contained calls:
 810
 811(define (##sys#update-line-number-database! exp ln)
 812  (define (mapupdate xs)
 813    (let loop ((xs xs))
 814      (when (pair? xs)
 815        (walk (car xs))
 816        (loop (cdr xs)) ) ))
 817  (define (walk x)
 818    (cond ((not (pair? x)))
 819          ((symbol? (car x))
 820           (let* ((name (car x))
 821                  (old (or (hash-table-ref ##sys#line-number-database name) '())))
 822             (unless (assq x old)
 823               (hash-table-set! ##sys#line-number-database name (alist-cons x ln old)))
 824             (when (list? x) (mapupdate (cdr x)) )))
 825          (else (mapupdate x)) ) )
 826  (walk exp))
 827
 828
 829(define-constant +default-argument-count-limit+ 99999)
 830
 831(define ##sys#check-syntax
 832  (lambda (id exp pat #!optional culprit (se (##sys#current-environment)))
 833
 834    (define (test x pred msg)
 835      (unless (pred x) (err msg)) )
 836
 837    (define (err msg)
 838      (let* ([sexp ##sys#syntax-error-culprit]
 839	     [ln (get-line-number sexp)] )
 840	(##sys#syntax-error
 841	 (if ln
 842	     (string-append "(" ln ") in `" (symbol->string id) "' - " msg)
 843	     (string-append "in `" (symbol->string id) "' - " msg) )
 844	 exp) ) )
 845
 846    (define (lambda-list? x)
 847      (or (##sys#extended-lambda-list? x)
 848	  (let loop ((x x))
 849	    (cond ((null? x))
 850		  ((symbol? x))
 851		  ((pair? x)
 852		   (let ((s (car x)))
 853		     (and (symbol? s)
 854			  (loop (cdr x)) ) ) )
 855		  (else #f) ) ) ) )
 856
 857    (define (variable? v)
 858      (symbol? v))
 859
 860    (define (proper-list? x)
 861      (let loop ((x x))
 862	(cond ((eq? x '()))
 863	      ((pair? x) (loop (cdr x)))
 864	      (else #f) ) ) )
 865
 866    (when culprit (set! ##sys#syntax-error-culprit culprit))
 867    (let walk ((x exp) (p pat))
 868      (cond ((vector? p)
 869	     (let* ((p2 (vector-ref p 0))
 870		    (vlen (##sys#size p))
 871		    (min (if (fx> vlen 1)
 872			     (vector-ref p 1)
 873			     0) )
 874		    (max (cond ((eq? vlen 1) 1)
 875			       ((fx> vlen 2) (vector-ref p 2))
 876			       (else +default-argument-count-limit+) ) ) )
 877	       (do ((x x (cdr x))
 878		    (n 0 (fx+ n 1)) )
 879		   ((eq? x '())
 880		    (if (fx< n min)
 881			(err "not enough arguments") ) )
 882		 (cond ((fx>= n max)
 883			(err "too many arguments") )
 884		       ((not (pair? x))
 885			(err "not a proper list") )
 886		       (else (walk (car x) p2) ) ) ) ) )
 887	    ((##sys#immediate? p)
 888	     (if (not (eq? p x)) (err "unexpected object")) )
 889	    ((symbol? p)
 890	     (case p
 891	       ((_) #t)
 892	       ((pair) (test x pair? "pair expected"))
 893	       ((variable) (test x variable? "identifier expected"))
 894	       ((symbol) (test x symbol? "symbol expected"))
 895	       ((list) (test x proper-list? "proper list expected"))
 896	       ((number) (test x number? "number expected"))
 897	       ((string) (test x string? "string expected"))
 898	       ((lambda-list) (test x lambda-list? "lambda-list expected"))
 899	       (else
 900		(test
 901		 x
 902		 (lambda (y)
 903		   (let ((y2 (and (symbol? y) (lookup y se))))
 904		     (eq? (if (symbol? y2) y2 y) p)))
 905		 "missing keyword")) ) )
 906	    ((not (pair? p))
 907	     (err "incomplete form") )
 908	    ((not (pair? x)) (err "pair expected"))
 909	    (else
 910	     (walk (car x) (car p))
 911	     (walk (cdr x) (cdr p)) ) ) ) ) )
 912
 913
 914;;; explicit/implicit-renaming transformer
 915
 916(define (make-er/ir-transformer handler explicit-renaming?)
 917  (##sys#make-structure
 918   'transformer
 919   (lambda (form se dse)
 920     (let ((renv '()))	  ; keep rename-environment for this expansion
 921       (define (inherit-pair-line-numbers old new)
 922	 (and-let* ((name (car new))
 923		    ((symbol? name))
 924		    (ln (get-line-number old))
 925		    (cur (or (hash-table-ref ##sys#line-number-database name) '())) )
 926	   (unless (assq new cur)
 927	     (hash-table-set! ##sys#line-number-database name
 928			      (alist-weak-cons new ln cur))))
 929	 new)
 930       (assert (list? se) "not a list" se) ;XXX remove later
 931       (define (rename sym)
 932	 (cond ((pair? sym)
 933		(inherit-pair-line-numbers sym (cons (rename (car sym)) (rename (cdr sym)))))
 934	       ((vector? sym)
 935		(list->vector (rename (vector->list sym))))
 936	       ((not (symbol? sym)) sym)
 937	       ((assq sym renv) =>
 938		(lambda (a)
 939		  (dd `(RENAME/RENV: ,sym --> ,(cdr a)))
 940		  (cdr a)))
 941	       (else
 942		(let ((a (macro-alias sym se)))
 943		  (dd `(RENAME: ,sym --> ,a))
 944		  (set! renv (cons (cons sym a) renv))
 945		  a))))
 946       (define (compare s1 s2)
 947	 (let ((result
 948		(cond ((pair? s1)
 949		       (and (pair? s2)
 950			    (compare (car s1) (car s2))
 951			    (compare (cdr s1) (cdr s2))))
 952		      ((vector? s1)
 953		       (and (vector? s2)
 954			    (let ((len (vector-length s1)))
 955			      (and (fx= len (vector-length s2))
 956				   (do ((i 0 (fx+ i 1))
 957					(f #t (compare (vector-ref s1 i) (vector-ref s2 i))))
 958				       ((or (fx>= i len) (not f)) f))))))
 959		      ((and (symbol? s1)
 960			    (symbol? s2))
 961		       (let ((ss1 (or (getp s1 '##core#macro-alias)
 962				      (lookup2 1 s1 dse)
 963				      s1) )
 964			     (ss2 (or (getp s2 '##core#macro-alias)
 965				      (lookup2 2 s2 dse)
 966				      s2) ) )
 967			 (cond ((symbol? ss1)
 968				(cond ((symbol? ss2) (eq? ss1 ss2))
 969				      ((assq ss1 (##sys#macro-environment)) =>
 970				       (lambda (a) (eq? (cdr a) ss2)))
 971				      (else #f) ) )
 972			       ((symbol? ss2)
 973				(cond ((assq ss2 (##sys#macro-environment)) =>
 974				       (lambda (a) (eq? ss1 (cdr a))))
 975				      (else #f)))
 976			       (else (eq? ss1 ss2)))))
 977		      (else (eq? s1 s2))) ) )
 978	   (dd `(COMPARE: ,s1 ,s2 --> ,result))
 979	   result))
 980       (define (lookup2 n sym dse)
 981	 (let ((r (lookup sym dse)))
 982	   (dd "  (lookup/DSE " (list n) ": " sym " --> "
 983	       (if (and r (pair? r))
 984		   '<macro>
 985		   r)
 986	       ")")
 987	   r))
 988       (define (assq-reverse s l)
 989	 (cond
 990	  ((null? l) #f)
 991	  ((eq? (cdar l) s) (car l))
 992	  (else (assq-reverse s (cdr l)))))
 993       (define (mirror-rename sym)
 994	 (cond ((pair? sym)
 995		(inherit-pair-line-numbers
 996		 sym (cons (mirror-rename (car sym)) (mirror-rename (cdr sym)))))
 997	       ((vector? sym)
 998		(list->vector (mirror-rename (vector->list sym))))
 999	       ((not (symbol? sym)) sym)
 1000	       (else		 ; Code stolen from strip-syntax
1001		(let ((renamed (lookup sym se) ) )
1002		  (cond ((assq-reverse sym renv) =>
1003			 (lambda (a)
1004			   (dd "REVERSING RENAME: " sym " --> " (car a)) (car a)))
1005			((not renamed)
1006			 (dd "IMPLICITLY RENAMED: " sym) (rename sym))
1007			((pair? renamed)
1008			 (dd "MACRO: " sym) (rename sym))
1009			((getp sym '##core#real-name) =>
1010			 (lambda (name)
1011			   (dd "STRIP SYNTAX ON " sym " ---> " name)
1012			   name))
1013                        ;; Rename builtin aliases so strip-syntax can still
1014                        ;; access symbols as entered by the user
1015			(else (let ((implicitly-renamed (rename sym)))
1016                                (dd "BUILTIN ALIAS: " sym " as " renamed
1017                                    " --> " implicitly-renamed)
1018                                implicitly-renamed)))))))
1019       (if explicit-renaming?
1020	   ;; Let the user handle renaming
1021	   (handler form rename compare)
1022	   ;; Implicit renaming:
1023	   ;; Rename everything in the input first, feed it to the transformer
1024	   ;; and then swap out all renamed identifiers by their non-renamed
1025	   ;; versions, and vice versa.  User can decide when to inject code
1026	   ;; unhygienically this way.
1027	   (mirror-rename (handler (rename form) rename compare)) ) ) )))
1028
1029(define (er-macro-transformer handler) (make-er/ir-transformer handler #t))
1030(define (ir-macro-transformer handler) (make-er/ir-transformer handler #f))
1031
1032(define ##sys#er-transformer er-macro-transformer)
1033(define ##sys#ir-transformer ir-macro-transformer)
1034
1035
1036;; Expose some internals for use in core.scm and chicken-syntax.scm:
1037
1038(define chicken.syntax#define-definition define-definition)
1039(define chicken.syntax#define-syntax-definition define-syntax-definition)
1040(define chicken.syntax#define-values-definition define-values-definition)
1041(define chicken.syntax#expansion-result-hook expansion-result-hook)
1042
1043) ; chicken.syntax module
1044
1045(import scheme chicken.base chicken.bytevector chicken.fixnum)
1046(import chicken.syntax chicken.internal chicken.platform)
1047(import (only (scheme base) make-parameter))
1048
1049;;; Macro definitions:
1050
1051(##sys#extend-macro-environment
1052 'import-syntax '()
1053 (##sys#er-transformer
1054  (cut ##sys#expand-import <> <> <>
1055       ##sys#current-environment ##sys#macro-environment
1056       #f #f 'import-syntax)))
1057
1058(##sys#extend-macro-environment
1059 'import-syntax-for-syntax '()
1060 (##sys#er-transformer
1061  (cut ##sys#expand-import <> <> <>
1062       ##sys#current-meta-environment ##sys#meta-macro-environment
1063       #t #f 'import-syntax-for-syntax)))
1064
1065(set! chicken.syntax#import-definition
1066  (##sys#extend-macro-environment
1067   'import '()
1068   (##sys#er-transformer
1069    (lambda (x r c)
1070      `(##core#begin
1071	,@(map (lambda (x)
1072		 (let-values (((name lib spec v s i) (##sys#decompose-import x r c 'import))
1073			      ((mod) (##sys#current-module)))
1074		   (when (and mod (eq? name (##sys#module-name mod)))
1075		     (##sys#syntax-error
1076		      'import "cannot import from module currently being defined" name))
1077		   (if (not spec)
1078		       (##sys#syntax-error
1079			'import "cannot import from undefined module" name)
1080		       (##sys#import
1081			spec v s i
1082			##sys#current-environment ##sys#macro-environment #f #f 'import))
1083		   (if (not lib)
1084		       '(##core#undefined)
1085		       `(##core#require ,lib ,name))))
1086	       (cdr x)))))))
1087
1088(##sys#extend-macro-environment
1089 'import-for-syntax '()
1090 (##sys#er-transformer
1091  (lambda (x r c)
1092    (##sys#register-meta-expression `(,(r 'import) ,@(cdr x)))
1093    `(##core#elaborationtimeonly (,(r 'import) ,@(cdr x))))))
1094
1095(define (process-cond-expand clauses)
1096      (define (err x)
1097	(##sys#syntax-error "syntax error in `cond-expand' form"
1098		     x
1099		     (cons 'cond-expand clauses)))
1100      (define (file-exists? fname)
1101        (##sys#file-exists? fname #f #f 'cond-expand))
1102      (define (locate-library name)
1103        (let* ((name2 (library-id name))
1104               (sname2 (symbol->string name2)))
1105          (or (##sys#find-module name2 #f)
1106              (let loop ((rp (repository-path)))
1107                (and (pair? rp)
1108                     (let ((p (car rp)))
1109                       (or (file-exists? (string-append p "/" sname2 ".import.so"))
1110                           (file-exists? (string-append p "/" sname2 ".import.scm"))
1111                           (loop (cdr rp)))))))))
1112      (define (test fx)
1113	(cond ((symbol? fx) (feature? (strip-syntax fx)))
1114	      ((not (pair? fx)) (err fx))
1115	      (else
1116	       (let ((head (car fx))
1117		     (rest (cdr fx)))
1118		 (case (strip-syntax head)
1119		   ((and)
1120		    (or (eq? rest '())
1121			(if (pair? rest)
1122			    (and (test (car rest))
1123				 (test `(and ,@(cdr rest))))
1124			    (err fx))))
1125		   ((or)
1126		    (and (not (eq? rest '()))
1127			 (if (pair? rest)
1128			     (or (test (car rest))
1129				 (test `(or ,@(cdr rest))))
1130			     (err fx))))
1131		   ((not) (not (test (cadr fx))))
1132                   ((library)
1133                    (if (and (pair? rest)
1134                             (null? (cdr rest)))
1135                        (locate-library (strip-syntax (car rest)))
1136                        (err fx)))
1137		   (else (err fx)))))))
1138      (let expand ((cls clauses))
1139	(cond ((eq? cls '())
1140	       (##sys#apply
1141		##sys#error "no matching clause in `cond-expand' form"
1142		(map (lambda (x) (car x)) clauses)))
1143	      ((not (pair? cls)) (err cls))
1144	      (else
1145	       (let ((clause (car cls))
1146		    (rclauses (cdr cls)))
1147		 (if (not (pair? clause))
1148		     (err clause)
1149		     (let ((id (car clause)))
1150		       (cond ((eq? (strip-syntax id) 'else)
1151			      (let ((rest (cdr clause)))
1152				(if (eq? rest '())
1153				    '(##core#undefined)
1154				    `(##core#begin ,@rest))))
1155			     ((test id) `(##core#begin ,@(cdr clause)))
1156			     (else (expand rclauses))))))))))
1157
1158(##sys#extend-macro-environment
1159 'cond-expand
1160 '()
1161 (##sys#er-transformer
1162  (lambda (form r c)
1163    (process-cond-expand (cdr form)))))
1164
1165;; The "initial" macro environment, containing only import forms and
1166;; cond-expand.  TODO: Eventually, cond-expand should move to the
1167;; (chicken base) module to match r7rs.  Keeping it in the initial env
1168;; makes it a whole lot easier to write portable CHICKEN 4 & 5 code.
1169(define ##sys#initial-macro-environment (##sys#macro-environment))
1170
1171(##sys#extend-macro-environment
1172 'module '()
1173 (##sys#er-transformer
1174  (lambda (x r c)
1175    (##sys#check-syntax 'module x '(_ _ _ . #(_ 0)))
1176    (let ((len (length x))
1177	  (name (library-id (cadr x))))
1178      ;; We strip syntax here instead of doing a hygienic comparison
1179      ;; to "=".  This is a tradeoff; either we do this, or we must
1180      ;; include a mapping of (= . scheme#=) in our syntax env.  In
1181      ;; the initial environment, = is bound to scheme#=, but when
1182      ;; using -explicit-use that's not the case.  Doing an unhygienic
1183      ;; comparison ensures module will work in both cases.
1184      (cond ((and (fx>= len 4) (eq? '= (strip-syntax (caddr x))))
1185	     (let* ((x (strip-syntax x))
1186		    (app (cadddr x)))
1187	       (cond ((fx> len 4)
1188		      ;; feature suggested by syn:
1189		      ;;
1190		      ;; (module NAME = FUNCTORNAME BODY ...)
1191		      ;; ~>
1192		      ;; (begin
1193		      ;;   (module _NAME * BODY ...)
1194		      ;;   (module NAME = (FUNCTORNAME _NAME)))
1195		      ;;
1196		      ;; - the use of "_NAME" is a bit stupid, but it must be
1197		      ;;   externally visible to generate an import library from
1198		      ;;   and compiling "NAME" separately may need an import-lib
1199		      ;;   for stuff in "BODY" (say, syntax needed by syntax exported
1200		      ;;   from the functor, or something like this...)
1201		      (let ((mtmp (string->symbol
1202				   (##sys#string-append
1203				    "_"
1204				    (symbol->string name))))
1205			    (%module (r 'module)))
1206			`(##core#begin
1207			  (,%module ,mtmp * ,@(cddddr x))
1208			  (,%module ,name = (,app ,mtmp)))))
1209		     (else
1210		      (##sys#check-syntax
1211		       'module x '(_ _ _ (_ . #(_ 0))))
1212		      (##sys#instantiate-functor
1213		       name
1214		       (library-id (car app))
1215		       (cdr app)))))) ; functor arguments
1216	    (else
1217	     ;;XXX use module name in "loc" argument?
1218	     (let ((exports (##sys#validate-exports (strip-syntax (caddr x)) 'module)))
1219	       `(##core#module
1220		 ,name
1221		 ,(if (eq? '* exports)
1222		      #t
1223		      exports)
1224		 ,@(let ((body (cdddr x)))
1225		     (if (and (pair? body)
1226			      (null? (cdr body))
1227			      (string? (car body)))
1228			 `((##core#include ,(car body) ,##sys#current-source-filename))
1229			 body))))))))))
1230
1231;;; R7RS define-library
1232
1233(##sys#extend-macro-environment
1234  'define-library '()
1235  (##sys#er-transformer
1236   (lambda (x r c)
1237     (define (register-r7rs-module name)
1238       (let ((dummy (string->symbol (string-append (string #\x04) "r7rs" (symbol->string name)))))
1239         (##sys#put! name '##r7rs#module dummy)
1240         dummy))
1241     (define implicit-r7rs-library-bindings
1242       '(begin
1243          cond-expand
1244          export
1245          import
1246          import-for-syntax
1247          include
1248          include-ci
1249          syntax-rules))
1250     (##sys#check-syntax 'define-library x '(_ . #(_ 0)))
1251     (let* ((x (strip-syntax x))
1252            (name (cadr x))
1253            (real-name (library-id name))
1254            (decls (cddr x))
1255            (dummy (register-r7rs-module real-name)))
1256       (define (parse-exports specs)
1257	 (map (lambda (spec)
1258                (cond ((and (list? spec)
1259                            (= 3 (length spec))
1260                            (eq? 'rename (car spec)))
1261                       `(export/rename ,(cdr spec)))
1262                      ((symbol? spec) `(export ,spec))
1263                      (else
1264                        (##sys#syntax-error 'define-library "invalid export specifier" spec name))))
1265            specs))
1266       (define (parse-imports specs)
1267         ;; XXX TODO: Should be import-for-syntax'ed as well?
1268         `(import ,@specs))
1269       (define (process-includes fnames ci?)
1270         `(##core#begin
1271           ,@(map (lambda (fname)
1272                    (if (string? fname)
1273                        `(##core#begin ,@(read-forms fname ci?))
1274                        (##sys#syntax-error 'include "invalid filename"
1275                          fname)))
1276                  fnames)))
1277       (define (expand/begin e)
1278         (let ((e2 (expand e '())))
1279           (if (and (pair? e2) (eq? '##core#begin (car e2)))
1280               (cons '##core#begin (map expand/begin (cdr e2)))
1281               e2)))
1282       (define (read-forms filename ci?)
1283         (fluid-let ((##sys#default-read-info-hook
1284                       (let ((name 'chicken.compiler.support#read-info-hook))
1285                         (and (feature? 'compiling)
1286                              (##sys#symbol-has-toplevel-binding? name)
1287                              (##sys#slot name 0)))))
1288           (##sys#include-forms-from-file
1289               filename
1290               ##sys#current-source-filename ci?
1291               (lambda (forms path) forms))))
1292       (define (process-include-decls fnames)
1293         (parse-decls
1294           (let loop ((fnames fnames) (all '()))
1295             (if (null? fnames)
1296                 (reverse all)
1297                 (let ((forms (read-forms (car fnames) #t)))
1298                   (loop (cdr fnames)
1299                         (append (reverse forms) all)))))))
1300       (define (fail spec)
1301         (##sys#syntax-error 'define-library "invalid library declaration" spec))
1302       (define (parse-decls decls)
1303         (cond ((null? decls) '(##core#begin))
1304               ((and (pair? decls) (pair? (car decls)))
1305                (let ((spec (car decls))
1306                      (more (cdr decls)))
1307                 (case (car spec)
1308                  ((export)
1309                   (##sys#check-syntax 'export spec '(_ . #(_ 0)))
1310                   `(##core#begin ,@(parse-exports (cdr spec))
1311                                  ,(parse-decls more)))
1312                  ((import)
1313                   (##sys#check-syntax 'import spec '(_ . #(_ 0)))
1314                   `(##core#begin ,(parse-imports (cdr spec))
1315                                  ,(parse-decls more)))
1316                  ((include)
1317                   (##sys#check-syntax 'include spec '(_ . #(_ 0)))
1318                   `(##core#begin ,(process-includes (cdr spec) #f)
1319                                  ,(parse-decls more)))
1320                  ((include-ci)
1321                   (##sys#check-syntax 'include-ci spec '(_ . #(_ 0)))
1322                   `(##core#begin ,(process-includes (cdr spec) #t)
1323                                  ,(parse-decls more)))
1324                  ((include-library-declarations)
1325                   `(##core#begin ,(process-include-decls (cdr spec))
1326                                  ,(parse-decls more)))
1327                  ((cond-expand)
1328                   (parse-decls (append (list (process-cond-expand (cdr spec)))
1329                                        more)))
1330                  ((##core#begin)
1331                    (parse-decls (cdr spec)))
1332                  ((begin)
1333                   `(##core#begin ,@(cdr spec)
1334                                  ,(parse-decls more)))
1335                  (else (fail spec)))))
1336                (else (fail (car decls)))))
1337       `(##core#module ,real-name ((,dummy))
1338	 ;; gruesome hack: we add a dummy export for adding indirect exports
1339	 (##core#define-syntax ,dummy
1340	  (##sys#er-transformer (##core#lambda (x r c) (##core#undefined))))
1341	 ;; Set up an R7RS environment for the module's body.
1342	 (import-for-syntax (only scheme.base ,@implicit-r7rs-library-bindings))
1343	 (import (only scheme.base ,@implicit-r7rs-library-bindings)
1344            (only chicken.module export/rename))
1345	 ;; Now process all toplevel library declarations
1346	 ,(parse-decls decls))))))
1347
1348(##sys#extend-macro-environment
1349 'export '()
1350 (##sys#er-transformer
1351  (lambda (x r c)
1352    (let ((exps (##sys#validate-exports (strip-syntax (cdr x)) 'export))
1353	  (mod (##sys#current-module)))
1354      (when mod
1355	(##sys#add-to-export-list mod exps))
1356      '(##core#undefined)))))
1357
1358(##sys#extend-macro-environment
1359 'export/rename '()
1360 (##sys#er-transformer
1361  (lambda (x r c)
1362    (let ((exps (map (lambda (ren)
1363                       (if (and (pair? ren)
1364                                (symbol? (car ren))
1365                                (pair? (cdr ren))
1366                                (symbol? (cadr ren))
1367                                (null? (cddr ren)))
1368                           (cons (car ren) (cadr ren))
1369                           (##sys#syntax-error "invalid item in export rename list"
1370                                                    ren)))
1371                  (strip-syntax (cdr x))))
1372          (mod (##sys#current-module)))
1373      (when mod
1374	(##sys#add-to-export/rename-list mod exps))
1375      '(##core#undefined)))))
1376
1377(##sys#extend-macro-environment
1378 'reexport '()
1379 (##sys#er-transformer
1380  (cut ##sys#expand-import <> <> <>
1381       ##sys#current-environment ##sys#macro-environment
1382       #f #t 'reexport)))
1383
1384;;; functor definition
1385
1386(##sys#extend-macro-environment
1387 'functor '()
1388 (##sys#er-transformer
1389  (lambda (x r c)
1390    (##sys#check-syntax 'functor x '(_ (_ . #((_ _) 0)) _ . _))
1391    (let* ((x (strip-syntax x))
1392	   (head (cadr x))
1393	   (name (car head))
1394	   (args (cdr head))
1395	   (exps (caddr x))
1396	   (body (cdddr x))
1397	   (registration
1398	    `(##sys#register-functor
1399	      (##core#quote ,(library-id name))
1400	      (##core#quote
1401	       ,(map (lambda (arg)
1402		       (let ((argname (car arg))
1403			     (exps (##sys#validate-exports (cadr arg) 'functor)))
1404			 (unless (or (symbol? argname)
1405				     (and (list? argname)
1406					  (= 2 (length argname))
1407					  (symbol? (car argname))
1408					  (valid-library-specifier? (cadr argname))))
1409			   (##sys#syntax-error "invalid functor argument" name arg))
1410			 (cons argname exps)))
1411		     args))
1412	      (##core#quote ,(##sys#validate-exports exps 'functor))
1413	      (##core#quote ,body))))
1414      `(##core#module ,(library-id name)
1415	#t
1416	(import scheme chicken.syntax) ;; TODO: Is this correct?
1417	(begin-for-syntax ,registration))))))
1418
1419;;; interface definition
1420
1421(##sys#extend-macro-environment
1422 'define-interface '()
1423 (##sys#er-transformer
1424  (lambda (x r c)
1425    (##sys#check-syntax 'define-interface x '(_ variable _))
1426    (let ((name (strip-syntax (cadr x))))
1427      (when (eq? '* name)
1428	(##sys#syntax-error
1429	 'define-interface "`*' is not allowed as a name for an interface"))
1430      `(##core#elaborationtimeonly
1431	(##sys#put/restore!
1432	 (##core#quote ,name)
1433	 (##core#quote ##core#interface)
1434	 (##core#quote
1435	  ,(let ((exps (strip-syntax (caddr x))))
1436	     (cond ((eq? '* exps) '*)
1437		   ((symbol? exps) `(#:interface ,exps))
1438		   ((list? exps)
1439		    (##sys#validate-exports exps 'define-interface))
1440		   (else
1441		    (##sys#syntax-error
1442		     'define-interface "invalid exports" (caddr x))))))))))))
1443
1444(##sys#extend-macro-environment
1445 'current-module '()
1446 (##sys#er-transformer
1447  (lambda (x r c)
1448    (##sys#check-syntax 'current-module x '(_))
1449    (and-let* ((mod (##sys#current-module)))
1450      `(##core#quote ,(##sys#module-name mod))))))
1451
1452;; The chicken.module syntax environment
1453(define ##sys#chicken.module-macro-environment (##sys#macro-environment))
1454
1455(set! ##sys#scheme-macro-environment
1456  (let ((me0 (##sys#macro-environment)))
1457
1458(##sys#extend-macro-environment
1459 'lambda
1460 '()
1461 (##sys#er-transformer
1462  (lambda (x r c)
1463    (##sys#check-syntax 'lambda x '(_ lambda-list . #(_ 1)))
1464    `(##core#lambda ,@(cdr x)))))
1465
1466(##sys#extend-macro-environment
1467 'quote
1468 '()
1469 (##sys#er-transformer
1470  (lambda (x r c)
1471    (##sys#check-syntax 'quote x '(_ _))
1472    `(##core#quote ,(cadr x)))))
1473
1474(##sys#extend-macro-environment
1475 'if
1476 '()
1477 (##sys#er-transformer
1478  (lambda (x r c)
1479    (##sys#check-syntax 'if x '(_ _ _ . #(_)))
1480    `(##core#if ,@(cdr x)))))
1481
1482(##sys#extend-macro-environment
1483 'begin
1484 '()
1485 (##sys#er-transformer
1486  (lambda (x r c)
1487    (##sys#check-syntax 'begin x '(_ . #(_ 0)))
1488    `(##core#begin ,@(cdr x)))))
1489
1490(set! chicken.syntax#define-definition
1491  (##sys#extend-macro-environment
1492   'define
1493   '()
1494   (##sys#er-transformer
1495    (lambda (x r c)
1496      (##sys#check-syntax 'define x '(_ . #(_ 1)))
1497      (let loop ((form x))
1498	(let ((head (cadr form))
1499	      (body (cddr form)) )
1500	  (cond ((not (pair? head))
1501		 (##sys#check-syntax 'define form '(_ variable . #(_ 0 1)))
1502                 (let ((name (or (getp head '##core#macro-alias) head)))
1503                   (##sys#register-export name (##sys#current-module)))
1504		 (when (c (r 'define) head)
1505		   (chicken.syntax#defjam-error x))
1506		 `(##core#begin
1507		    (##core#ensure-toplevel-definition ,head)
1508		    (##core#set!
1509		     ,head
1510		     ,(if (pair? body) (car body) '(##core#undefined)))))
1511		((pair? (car head))
1512		 (##sys#check-syntax 'define form '(_ (_ . lambda-list) . #(_ 1)))
1513		 (loop (chicken.syntax#expand-curried-define head body '()))) ;XXX '() should be se
1514		(else
1515		 (##sys#check-syntax 'define form '(_ (variable . lambda-list) . #(_ 1)))
1516		 (loop (list (car x) (car head) `(##core#lambda ,(cdr head) ,@body)))))))))))
1517
1518(set! chicken.syntax#define-syntax-definition
1519  (##sys#extend-macro-environment
1520   'define-syntax
1521   '()
1522   (##sys#er-transformer
1523    (lambda (form r c)
1524      (##sys#check-syntax 'define-syntax form '(_ variable _))
1525      (let ((head (cadr form))
1526	    (body (caddr form)))
1527	(let ((name (or (getp head '##core#macro-alias) head)))
1528	  (##sys#register-export name (##sys#current-module)))
1529	(when (c (r 'define-syntax) head)
1530	  (chicken.syntax#defjam-error form))
1531	`(##core#define-syntax ,head ,body))))))
1532
1533(##sys#extend-macro-environment
1534 'let
1535 '()
1536 (##sys#er-transformer
1537  (lambda (x r c)
1538    (cond ((and (pair? (cdr x)) (symbol? (cadr x)))
1539	   (##sys#check-syntax 'let x '(_ variable #((variable _) 0) . #(_ 1)))
1540           (check-for-multiple-bindings (caddr x) x "let"))
1541	  (else
1542	   (##sys#check-syntax 'let x '(_ #((variable _) 0) . #(_ 1)))
1543           (check-for-multiple-bindings (cadr x) x "let")))
1544    `(##core#let ,@(cdr x)))))
1545
1546(##sys#extend-macro-environment
1547 'letrec
1548 '()
1549 (##sys#er-transformer
1550  (lambda (x r c)
1551    (##sys#check-syntax 'letrec x '(_ #((variable _) 0) . #(_ 1)))
1552    (check-for-multiple-bindings (cadr x) x "letrec")
1553    `(##core#letrec ,@(cdr x)))))
1554
1555(##sys#extend-macro-environment
1556 'let-syntax
1557 '()
1558 (##sys#er-transformer
1559  (lambda (x r c)
1560    (##sys#check-syntax 'let-syntax x '(_ #((variable _) 0) . #(_ 1)))
1561    (check-for-multiple-bindings (cadr x) x "let-syntax")
1562    `(##core#let-syntax ,@(cdr x)))))
1563
1564(##sys#extend-macro-environment
1565 'letrec-syntax
1566 '()
1567 (##sys#er-transformer
1568  (lambda (x r c)
1569    (##sys#check-syntax 'letrec-syntax x '(_ #((variable _) 0) . #(_ 1)))
1570    (check-for-multiple-bindings (cadr x) x "letrec-syntax")
1571    `(##core#letrec-syntax ,@(cdr x)))))
1572
1573(##sys#extend-macro-environment
1574 'set!
1575 '()
1576 (##sys#er-transformer
1577  (lambda (x r c)
1578    (##sys#check-syntax 'set! x '(_ _ _))
1579    (let ((dest (cadr x))
1580	  (val (caddr x)))
1581      (cond ((pair? dest)
1582	     `((##sys#setter ,(car dest)) ,@(cdr dest) ,val))
1583	    (else `(##core#set! ,dest ,val)))))))
1584
1585(##sys#extend-macro-environment
1586 'and
1587 '()
1588 (##sys#er-transformer
1589  (lambda (form r c)
1590    (let ((body (cdr form)))
1591      (if (null? body)
1592	  #t
1593	  (let ((rbody (cdr body))
1594		(hbody (car body)) )
1595	    (if (null? rbody)
1596		hbody
1597		`(##core#if ,hbody (,(r 'and) ,@rbody) #f) ) ) ) ) ) ) )
1598
1599(##sys#extend-macro-environment
1600 'or
1601 '()
1602 (##sys#er-transformer
1603  (lambda (form r c)
1604    (let ((body (cdr form)))
1605     (if (null? body)
1606	 #f
1607	 (let ((rbody (cdr body))
1608	       (hbody (car body)))
1609	   (if (null? rbody)
1610	       hbody
1611	       (let ((tmp (r 'tmp)))
1612		 `(##core#let ((,tmp ,hbody))
1613		    (##core#if ,tmp ,tmp (,(r 'or) ,@rbody)) ) ) ) ) ) ) ) ) )
1614
1615(##sys#extend-macro-environment
1616 'cond
1617 '()
1618 (##sys#er-transformer
1619  (lambda (form r c)
1620    (let ((body (cdr form))
1621	  (%=> (r '=>))
1622	  (%or (r 'or))
1623	  (%else (r 'else)))
1624      (let expand ((clauses body) (else? #f))
1625	(if (not (pair? clauses))
1626	    '(##core#undefined)
1627	    (let ((clause (car clauses))
1628		  (rclauses (cdr clauses)) )
1629	      (##sys#check-syntax 'cond clause '#(_ 1))
1630	      (cond (else?
1631		     (##sys#warn
1632		      (chicken.format#sprintf "clause following `~S' clause in `cond'" else?)
1633		      (strip-syntax clause))
1634		     (expand rclauses else?)
1635		     '(##core#begin))
1636		    ((or (c %else (car clause))
1637                         (eq? #t (car clause))
1638                         ;; Like "constant?" from support.scm
1639                         (number? (car clause))
1640                         (char? (car clause))
1641                         (string? (car clause))
1642                         (eof-object? (car clause))
1643                         (bytevector? (car clause))
1644                         (bwp-object? (car clause))
1645                         (vector? (car clause))
1646                         (##sys#srfi-4-vector? (car clause))
1647                         (and (pair? (car clause))
1648                              (c (r 'quote) (caar clause))))
1649		     (expand rclauses (strip-syntax (car clause)))
1650		     (cond ((and (fx= (length clause) 3)
1651				 (c %=> (cadr clause)))
1652			    `(,(caddr clause) ,(car clause)))
1653			   ((pair? (cdr clause))
1654			    `(##core#begin ,@(cdr clause)))
1655			   ((c %else (car clause))
1656			    `(##core#undefined))
1657			   (else (car clause))))
1658		    ((null? (cdr clause))
1659		     `(,%or ,(car clause) ,(expand rclauses #f)))
1660		    ((and (fx= (length clause) 3)
1661			  (c %=> (cadr clause)))
1662		     (let ((tmp (r 'tmp)))
1663		       `(##core#let ((,tmp ,(car clause)))
1664				    (##core#if ,tmp
1665					       (,(caddr clause) ,tmp)
1666					       ,(expand rclauses #f) ) ) ) )
1667		    ((and (fx= (length clause) 4)
1668			  (c %=> (caddr clause)))
1669		     (let ((tmp (r 'tmp)))
1670		       `(##sys#call-with-values
1671			 (##core#lambda () ,(car clause))
1672			 (##core#lambda
1673			  ,tmp
1674			  (if (##sys#apply ,(cadr clause) ,tmp)
1675			      (##sys#apply ,(cadddr clause) ,tmp)
1676			      ,(expand rclauses #f) ) ) ) ) )
1677		    (else `(##core#if ,(car clause)
1678				      (##core#begin ,@(cdr clause))
1679				      ,(expand rclauses #f) ) ) ) ) ) ) ) ) ) )
1680
1681(##sys#extend-macro-environment
1682 'case
1683 '((eqv? . scheme#eqv?))
1684 (##sys#er-transformer
1685  (lambda (form r c)
1686    (##sys#check-syntax 'case form '(_ _ . #(_ 0)))
1687    (let ((exp (cadr form))
1688	  (body (cddr form)) )
1689      (let ((tmp (r 'tmp))
1690	    (%or (r 'or))
1691	    (%=> (r '=>))
1692	    (%eqv? (r 'eqv?))
1693	    (%else (r 'else)))
1694	`(let ((,tmp ,exp))
1695	   ,(let expand ((clauses body) (else? #f))
1696	      (if (not (pair? clauses))
1697		  '(##core#undefined)
1698		  (let ((clause (car clauses))
1699			(rclauses (cdr clauses)) )
1700		    (##sys#check-syntax 'case clause '#(_ 1))
1701		    (cond (else?
1702			   (##sys#warn
1703			    "clause following `else' clause in `case'"
1704			    (strip-syntax clause))
1705			   (expand rclauses #t)
1706			   '(##core#begin))
1707			  ((c %else (car clause))
1708			   (expand rclauses #t)
1709			   (cond ((null? (cdr clause))
1710				  `(##core#undefined))
1711				 ((and (fx= (length clause) 3) ; (else => expr)
1712				       (c %=> (cadr clause)))
1713				  `(,(caddr clause) ,tmp))
1714				 (else
1715				  `(##core#begin ,@(cdr clause)))))
1716			  (else
1717			   `(##core#if (,%or ,@(##sys#map
1718						(lambda (x) `(,%eqv? ,tmp ',x))
1719						(car clause)))
1720				       ,(if (and (fx= (length clause) 3) ; ((...) => expr)
1721						 (c %=> (cadr clause)))
1722					    `(,(caddr clause) ,tmp)
1723					    `(##core#begin ,@(cdr clause)))
1724				       ,(expand rclauses #f) ) ) ) ) ) ) ) ) ) ) ) )
1725
1726(##sys#extend-macro-environment
1727 'let*
1728 '()
1729 (##sys#er-transformer
1730  (lambda (form r c)
1731    (##sys#check-syntax 'let* form '(_ #((variable _) 0) . #(_ 1)))
1732    (let ((bindings (cadr form))
1733	  (body (cddr form)) )
1734      (let expand ((bs bindings))
1735	(if (eq? bs '())
1736	    `(##core#let () ,@body)
1737	    `(##core#let (,(car bs)) ,(expand (cdr bs))) ) ) ) ) ) )
1738
1739(##sys#extend-macro-environment
1740 'do
1741 '()
1742 (##sys#er-transformer
1743  (lambda (form r c)
1744    (##sys#check-syntax 'do form '(_ #((variable _ . #(_)) 0) . #(_ 1)))
1745    (let ((bindings (cadr form))
1746	  (test (caddr form))
1747	  (body (cdddr form))
1748	  (dovar (r 'doloop)))
1749      `(##core#let
1750	,dovar
1751	,(##sys#map (lambda (b) (list (car b) (car (cdr b)))) bindings)
1752	(##core#if ,(car test)
1753		   ,(let ((tbody (cdr test)))
1754		      (if (eq? tbody '())
1755			  '(##core#undefined)
1756			  `(##core#begin ,@tbody) ) )
1757		   (##core#begin
1758		    ,(if (eq? body '())
1759			 '(##core#undefined)
1760			 `(##core#let () ,@body) )
1761		    (##core#app
1762		     ,dovar ,@(##sys#map (lambda (b)
1763					   (if (eq? (cdr (cdr b)) '())
1764					       (car b)
1765					       (car (cdr (cdr b))) ) )
1766					 bindings) ) ) ) ) ) ) ) )
1767
1768(##sys#extend-macro-environment
1769 'quasiquote
1770 '()
1771 (##sys#er-transformer
1772  (lambda (form r c)
1773    (let ((%quasiquote (r 'quasiquote))
1774	  (%unquote (r 'unquote))
1775	  (%unquote-splicing (r 'unquote-splicing)))
1776      (define (walk x n) (simplify (walk1 x n)))
1777      (define (walk1 x n)
1778	(cond ((vector? x)
1779	       `(##sys#list->vector ,(walk (vector->list x) n)) )
1780	      ((not (pair? x)) `(##core#quote ,x))
1781	      (else
1782	       (let ((head (car x))
1783		     (tail (cdr x)))
1784		 (cond ((c %unquote head)
1785                        (cond ((eq? n 0)
1786                               (##sys#check-syntax 'unquote x '(_ _))
1787                               (car tail))
1788                              (else (list '##sys#cons `(##core#quote ,%unquote)
1789                                          (walk tail (fx- n 1)) ) )))
1790		       ((c %quasiquote head)
1791			(list '##sys#cons `(##core#quote ,%quasiquote)
1792                              (walk tail (fx+ n 1)) ) )
1793		       ((and (pair? head) (c %unquote-splicing (car head)))
1794                        (cond ((eq? n 0)
1795                               (##sys#check-syntax 'unquote-splicing head '(_ _))
1796                               `(##sys#append ,(cadr head) ,(walk tail n)))
1797                              (else
1798                               `(##sys#cons
1799                                 (##sys#cons (##core#quote ,%unquote-splicing)
1800                                             ,(walk (cdr head) (fx- n 1)) )
1801                                 ,(walk tail n)))))
1802		       (else
1803			`(##sys#cons ,(walk head n) ,(walk tail n)) ) ) ) ) ) )
1804      (define (simplify x)
1805	(cond ((chicken.syntax#match-expression x '(##sys#cons a (##core#quote ())) '(a))
1806	       => (lambda (env) (simplify `(##sys#list ,(cdr (assq 'a env))))) )
1807	      ((chicken.syntax#match-expression x '(##sys#cons a (##sys#list . b)) '(a b))
1808	       => (lambda (env)
1809		    (let ((bxs (assq 'b env)))
1810		      (if (fx< (length bxs) 32)
1811			  (simplify `(##sys#list ,(cdr (assq 'a env))
1812						 ,@(cdr bxs) ) )
1813			  x) ) ) )
1814	      ((chicken.syntax#match-expression x '(##sys#append a (##core#quote ())) '(a))
1815	       => (lambda (env) (cdr (assq 'a env))) )
1816	      (else x) ) )
1817      (##sys#check-syntax 'quasiquote form '(_ _))
1818      (walk (cadr form) 0) ) ) ) )
1819
1820(##sys#extend-macro-environment
1821 'delay
1822 '()
1823 (##sys#er-transformer
1824  (lambda (form r c)
1825    (##sys#check-syntax 'delay form '(_ _))
1826    `(,(r 'delay-force)
1827      (##sys#make-promise
1828       (##sys#call-with-values (##core#lambda () ,(cadr form)) ##sys#list))))))
1829
1830(##sys#extend-macro-environment
1831 'syntax-error
1832 '()
1833 (##sys#er-transformer
1834  (lambda (form r c)
1835    (##sys#check-syntax 'syntax-error form '(_ string . #(_ 0)))
1836    (apply ##sys#syntax-error (cadr form) (cddr form)))))
1837
1838;;; syntax-rules
1839
1840(include "synrules.scm")
1841
1842(macro-subset me0)))
1843
1844;;; the base macro environment (the old "scheme", essentially)
1845;;; TODO: Remove this
1846
1847(define ##sys#default-macro-environment
1848  (fixup-macro-environment (##sys#macro-environment)))
1849
1850(define ##sys#meta-macro-environment (make-parameter (##sys#macro-environment)))
1851
1852;; register features
1853
1854(register-feature! 'srfi-0 'srfi-46 'srfi-61 'srfi-87)
Trap