~ 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   get-line-number
  40   read-with-source-info
  41   strip-syntax
  42   er-macro-transformer
  43   ir-macro-transformer)
  44
  45(import scheme
  46	chicken.base
  47	chicken.condition
  48	chicken.fixnum
  49	chicken.internal
  50	chicken.keyword
  51	chicken.platform
  52	chicken.string)
  53(import (only (scheme base) make-parameter open-output-string get-output-string))
  54
  55(include "common-declarations.scm")
  56(include "mini-srfi-1.scm")
  57
  58(define-syntax d (syntax-rules () ((_ . _) (void))))
  59;(define-syntax d (syntax-rules () ((_ args ...) (print args ...))))
  60
  61;; Macro to avoid "unused variable map-se" when "d" is disabled
  62(define-syntax map-se
  63  (syntax-rules ()
  64    ((_ ?se)
  65     (map (lambda (a)
  66	    (cons (car a) (if (symbol? (cdr a)) (cdr a) '<macro>)))
  67	  ?se))))
  68
  69(define-alias dd d)
  70(define-alias dm d)
  71(define-alias dx d)
  72
  73(define-inline (getp sym prop)
  74  (##core#inline "C_i_getprop" sym prop #f))
  75
  76(define-inline (putp sym prop val)
  77  (##core#inline_allocate ("C_a_i_putprop" 8) sym prop val))
  78
  79(define-inline (namespaced-symbol? sym)
  80  (##core#inline "C_u_i_namespaced_symbolp" sym))
  81
  82;;; Source file tracking
  83
  84(define ##sys#current-source-filename #f)
  85
  86;;; Syntactic environments
  87
  88(define ##sys#current-environment (make-parameter '()))
  89(define ##sys#current-meta-environment (make-parameter '()))
  90
  91(define (lookup id se)
  92  (cond ((##core#inline "C_u_i_assq" id se) => cdr)
  93	((getp id '##core#macro-alias))
  94	(else #f)))
  95
  96(define (macro-alias var se)
  97  (if (or (keyword? var) (namespaced-symbol? var))
  98      var
  99      (let* ((alias (gensym var))
 100	     (ua (or (lookup var se) var))
 101             (rn (or (getp var '##core#real-name) var)))
 102	(putp alias '##core#macro-alias ua)
 103	(putp alias '##core#real-name rn)
 104	(dd "aliasing " alias " (real: " var ") to "
 105	    (if (pair? ua)
 106		'<macro>
 107		ua))
 108	alias) ) )
 109
 110(define (strip-syntax exp)
 111 (let ((seen '()))
 112   (let walk ((x exp))
 113     (cond ((assq x seen) => cdr)
 114	   ((keyword? x) x)
 115           ((symbol? x)
 116            (let ((x2 (getp x '##core#macro-alias) ) )
 117              (cond ((getp x '##core#real-name))
 118                    ((not x2) x)
 119                    ((pair? x2) x)
 120                    (else x2))))
 121           ((pair? x)
 122            (let ((cell (cons #f #f)))
 123              (set! seen (cons (cons x cell) seen))
 124              (set-car! cell (walk (car x)))
 125              (set-cdr! cell (walk (cdr x)))
 126              cell))
 127           ((vector? x)
 128            (let* ((len (##sys#size x))
 129		   (vec (make-vector len)))
 130              (set! seen (cons (cons x vec) seen))
 131              (do ((i 0 (fx+ i 1)))
 132                  ((fx>= i len) vec)
 133                (##sys#setslot vec i (walk (##sys#slot x i))))))
 134           (else x)))))
 135
 136(define (##sys#extend-se se vars #!optional (aliases (map gensym vars)))
 137  (for-each
 138   (lambda (alias sym)
 139     (let ((original-real-name (getp sym '##core#real-name)))
 140       (putp alias '##core#real-name (or original-real-name sym))))
 141   aliases vars)
 142  (append (map (lambda (x y) (cons x y)) vars aliases) se)) ; inline cons
 143
 144
 145;;; Macro handling
 146
 147(define ##sys#macro-environment (make-parameter '()))
 148
 149(define ##sys#scheme-macro-environment '()) ; reassigned below
 150;; These are all re-assigned by chicken-syntax.scm:
 151(define ##sys#chicken-ffi-macro-environment '()) ; used later in foreign.import.scm
 152(define ##sys#chicken.condition-macro-environment '()) ; used later in chicken.condition.import.scm
 153(define ##sys#chicken.time-macro-environment '()) ; used later in chicken.time.import.scm
 154(define ##sys#chicken.type-macro-environment '()) ; used later in chicken.type.import.scm
 155(define ##sys#chicken.syntax-macro-environment '()) ; used later in chicken.syntax.import.scm
 156(define ##sys#chicken.base-macro-environment '()) ; used later in chicken.base.import.scm
 157
 158(define (##sys#ensure-transformer t #!optional loc)
 159  (if (##sys#structure? t 'transformer)
 160      (##sys#slot t 1)
 161      (##sys#error loc "expected syntax-transformer, but got" t)))
 162
 163(define (##sys#extend-macro-environment name se transformer)
 164  (let ((me (##sys#macro-environment))
 165	(handler (##sys#ensure-transformer transformer name)))
 166    (cond ((lookup name me) =>
 167	   (lambda (a)
 168	     (set-car! a se)
 169	     (set-car! (cdr a) handler)
 170	     a))
 171	  (else
 172	   (let ((data (list se handler)))
 173	     (##sys#macro-environment
 174	      (cons (cons name data) me))
 175	     data)))))
 176
 177(define (##sys#macro? sym #!optional (senv (##sys#current-environment)))
 178  (or (let ((l (lookup sym senv)))
 179	(pair? l))
 180      (and-let* ((l (lookup sym (##sys#macro-environment))))
 181	(pair? l))))
 182
 183(define (##sys#undefine-macro! name)
 184  (##sys#macro-environment
 185    ;; this builds up stack, but isn't used often anyway...
 186    (let loop ((me (##sys#macro-environment)))
 187      (cond ((null? me) '())
 188	    ((eq? name (caar me)) (cdr me))
 189	    (else (cons (car me) (loop (cdr me))))))))
 190
 191;; The basic macro-expander
 192
 193(define (##sys#expand-0 exp dse cs?)
 194  (define (call-handler name handler exp se cs)
 195    (dd "invoking macro: " name)
 196    (dd `(STATIC-SE: ,@(map-se se)))
 197    (handle-exceptions ex
 198	;; modify error message in condition object to include
 199	;; currently expanded macro-name
 200	(abort
 201	 (if (and (##sys#structure? ex 'condition)
 202		  (memv 'exn (##sys#slot ex 1)) )
 203	     (##sys#make-structure
 204	      'condition
 205	      (##sys#slot ex 1)
 206	      (let copy ([ps (##sys#slot ex 2)])
 207		(if (null? ps)
 208		    '()
 209		    (let ([p (car ps)]
 210			  [r (cdr ps)])
 211		      (if (and (equal? '(exn . message) p)
 212			       (pair? r)
 213			       (string? (car r)) )
 214			  (cons
 215			   '(exn . message)
 216			   (cons (string-append
 217				  "during expansion of ("
 218				  (##sys#symbol->string/shared name)
 219				  " ...) - "
 220				  (car r) )
 221				 (cdr r) ) )
 222			  (copy r) ) ) ) ) )
 223	     ex) )
 224      (let ((exp2
 225	     (if cs
 226		 ;; compiler-syntax may "fall through"
 227		 (fluid-let ((chicken.internal.syntax-rules#syntax-rules-mismatch
 228			      (lambda (input) exp))) ; a bit of a hack
 229		   (handler exp se dse))
 230		 (handler exp se dse))) )
 231	(when (and (not cs) (eq? exp exp2))
 232	  (##sys#syntax-error
 233	   (string-append
 234	    "syntax transformer for `" (##sys#symbol->string/shared name)
 235	    "' returns original form, which would result in endless expansion")
 236	   exp))
 237	(dx `(,name ~~> ,exp2))
 238	(expansion-result-hook exp exp2) ) ) )
 239  (define (expand head exp mdef)
 240    (dd `(EXPAND:
 241	  ,head
 242	  ,(cond ((getp head '##core#macro-alias) =>
 243		  (lambda (a) (if (symbol? a) a '<macro>)) )
 244		 (else '_))
 245	  ,exp
 246	  ,(if (pair? mdef)
 247	       `(SE: ,@(map-se (car mdef)))
 248	       mdef)))
 249    (if (pair? mdef)
 250        (values
 251	 ;; force ref. opaqueness by passing dynamic se [what does this comment mean? I forgot ...]
 252           (call-handler head (cadr mdef) exp (car mdef) #f)
 253           #t)
 254	(values exp #f)) )
 255  (let loop ((exp exp))
 256    (if (pair? exp)
 257      (let ((head (car exp))
 258	    (body (cdr exp)) )
 259	(if (symbol? head)
 260	    (let ((head2 (or (lookup head dse) head)))
 261	      (unless (pair? head2)
 262		(set! head2 (or (lookup head2 (##sys#macro-environment)) head2)) )
 263	      (cond ((and (pair? head2)
 264                          (eq? (##sys#get head '##sys#override) 'value))
 265                     (values exp #f))
 266                    ((eq? head2 '##core#let)
 267		     (##sys#check-syntax 'let body '#(_ 2) #f dse)
 268		     (let ((bindings (car body)))
 269		       (cond ((symbol? bindings) ; expand named let
 270			      (##sys#check-syntax 'let body '(_ #((variable _) 0) . #(_ 1)) #f dse)
 271			      (let ([bs (cadr body)])
 272				(values
 273				 `(##core#app
 274				   (##core#letrec*
 275				    ([,bindings
 276				      (##core#loop-lambda
 277				       ,(map (lambda (b) (car b)) bs) ,@(cddr body))])
 278				    ,bindings)
 279				   ,@(##sys#map cadr bs) )
 280				 #t) ) )
 281			     (else (values exp #f)) ) ) )
 282		    ((and cs? (symbol? head2) (getp head2 '##compiler#compiler-syntax)) =>
 283		     (lambda (cs)
 284		       (let ((result (call-handler head (car cs) exp (cdr cs) #t)))
 285			 (cond ((eq? result exp) (expand head exp head2))
 286			       (else
 287				(when ##sys#compiler-syntax-hook
 288				  (##sys#compiler-syntax-hook head2 result))
 289				(loop result))))))
 290		    (else (expand head exp head2)) ) )
 291	    (values exp #f) ) )
 292      (values exp #f) ) ) )
 293
 294(define ##sys#compiler-syntax-hook #f)
 295(define ##sys#enable-runtime-macros #f)
 296(define expansion-result-hook (lambda (input output) output))
 297
 298
 299;;; User-level macroexpansion
 300
 301(define (expand exp #!optional (se (##sys#current-environment)) cs?)
 302  (let loop ((exp exp))
 303    (let-values (((exp2 m) (##sys#expand-0 exp se cs?)))
 304      (if m
 305	  (loop exp2)
 306	  exp2) ) ) )
 307
 308
 309;;; Extended (DSSSL-style) lambda lists
 310;
 311; Assumptions:
 312;
 313; 1) #!rest must come before #!key
 314; 2) default values may refer to earlier variables
 315; 3) optional/key args may be either variable or (variable default)
 316; 4) an argument marker may not be specified more than once
 317; 5) no special handling of extra keywords (no error)
 318; 6) default value of optional/key args is #f
 319; 7) mixing with dotted list syntax is allowed
 320
 321(define (##sys#extended-lambda-list? llist)
 322  (let loop ([llist llist])
 323    (and (pair? llist)
 324	 (case (##sys#slot llist 0)
 325	   [(#!rest #!optional #!key) #t]
 326	   [else (loop (cdr llist))] ) ) ) )
 327
 328(define ##sys#expand-extended-lambda-list
 329  (let ((reverse reverse))
 330    (lambda (llist0 body errh se)
 331      (define (err msg) (errh msg llist0))
 332      (define (->keyword s) (string->keyword (##sys#symbol->string/shared s)))
 333      (let ((rvar #f)
 334	    (hasrest #f)
 335	    ;; These might not exist in se, use default or chicken env:
 336	    (%let* (macro-alias 'let* ##sys#default-macro-environment))
 337	    (%lambda '##core#lambda)
 338	    (%opt (macro-alias 'optional ##sys#chicken.base-macro-environment))
 339	    (%let-optionals* (macro-alias 'let-optionals* ##sys#chicken.base-macro-environment))
 340	    (%let '##core#let))
 341	(let loop ([mode 0]		; req=0, opt=1, rest=2, key=3, end=4
 342		   [req '()]
 343		   [opt '()]
 344		   [key '()]
 345		   [llist llist0] )
 346	  (cond [(null? llist)
 347		 (values
 348		  (if rvar (##sys#append (reverse req) rvar) (reverse req))
 349		  (let ([body
 350			 (if (null? key)
 351			     body
 352			     `((,%let*
 353				,(map (lambda (k)
 354					(let ((s (car k)))
 355					  `(,s (##sys#get-keyword
 356						(##core#quote ,(->keyword (strip-syntax s))) ,(or hasrest rvar)
 357						,@(if (pair? (cdr k))
 358						      `((,%lambda () ,@(cdr k)))
 359						      '())))))
 360				      (reverse key) )
 361				,@body) ) ) ] )
 362		    (cond [(null? opt) body]
 363			  [(and (not hasrest) (null? key) (null? (cdr opt)))
 364			   `((,%let
 365			      ([,(caar opt) (,%opt ,rvar ,(cadar opt))])
 366			      ,@body) ) ]
 367			  [(and (not hasrest) (null? key))
 368			   `((,%let-optionals*
 369			      ,rvar ,(reverse opt) ,@body))]
 370			  [else
 371			   `((,%let-optionals*
 372			      ,rvar ,(##sys#append (reverse opt) (list (or hasrest rvar)))
 373			      ,@body))] ) ) ) ]
 374		[(symbol? llist)
 375		 (if (fx> mode 2)
 376		     (err "rest argument list specified more than once")
 377		     (begin
 378		       (unless rvar (set! rvar llist))
 379		       (set! hasrest llist)
 380		       (loop 4 req opt '() '()) ) ) ]
 381		[(not (pair? llist))
 382		 (err "invalid lambda list syntax") ]
 383		[else
 384		 (let* ((var (car llist))
 385			(x (or (and (symbol? var) (not (eq? 3 mode)) (lookup var se)) var))
 386			(r (cdr llist)))
 387		   (case x
 388		     [(#!optional)
 389		      (unless rvar (set! rvar (macro-alias 'rest se)))
 390		      (if (eq? mode 0)
 391			  (loop 1 req '() '() r)
 392			  (err "`#!optional' argument marker in wrong context") ) ]
 393		     [(#!rest)
 394		      (if (fx<= mode 1)
 395			  (if (and (pair? r) (symbol? (car r)))
 396			      (begin
 397				(if (not rvar) (set! rvar (car r)))
 398				(set! hasrest (car r))
 399				(loop 2 req opt '() (cdr r)) )
 400			      (err "invalid syntax of `#!rest' argument") )
 401			  (err "`#!rest' argument marker in wrong context") ) ]
 402		     [(#!key)
 403		      (if (not rvar) (set! rvar (macro-alias 'rest se)))
 404		      (if (fx<= mode 2)
 405			  (loop 3 req opt '() r)
 406			  (err "`#!key' argument marker in wrong context") ) ]
 407		     [else
 408		      (cond [(symbol? var)
 409			     (case mode
 410			       [(0) (loop 0 (cons var req) '() '() r)]
 411			       [(1) (loop 1 req (cons (list var #f) opt) '() r)]
 412			       [(2) (err "invalid lambda list syntax after `#!rest' marker")]
 413			       [else (loop 3 req opt (cons (list var) key) r)] ) ]
 414			    [(and (list? var) (eq? 2 (length var)) (symbol? (car var)))
 415			     (case mode
 416			       [(0) (err "invalid required argument syntax")]
 417			       [(1) (loop 1 req (cons var opt) '() r)]
 418			       [(2) (err "invalid lambda list syntax after `#!rest' marker")]
 419			       [else (loop 3 req opt (cons var key) r)] ) ]
 420			    [else (err "invalid lambda list syntax")] ) ] ) ) ] ) ) ) ) ) )
 421
 422
 423;;; Error message for redefinition of currently used defining form
 424;
 425; (i.e.`"(define define ...)")
 426
 427(define (defjam-error form)
 428  (##sys#syntax-error
 429   "redefinition of currently used defining form" ; help me find something better
 430   form))
 431
 432;;; Expansion of multiple values assignments.
 433;
 434; Given a lambda list and a multi-valued expression, returns a form that
 435; will `set!` each variable to its corresponding value in order.
 436
 437(define (##sys#expand-multiple-values-assignment formals expr)
 438  (##sys#decompose-lambda-list
 439   formals
 440   (lambda (vars argc rest)
 441     (let ((aliases    (if (symbol? formals) '() (map gensym formals)))
 442	   (rest-alias (if (not rest) '() (gensym rest))))
 443       `(##sys#call-with-values
 444	 (##core#lambda () ,expr)
 445	 (##core#lambda
 446	  ,(append aliases rest-alias)
 447	  ,@(map (lambda (v a) `(##core#set! ,v ,a)) vars aliases)
 448	  ,@(cond
 449	      ((null? formals) '((##core#undefined)))
 450	      ((null? rest-alias) '())
 451	      (else `((##core#set! ,rest ,rest-alias))))))))))
 452
 453;;; Expansion of bodies (and internal definitions)
 454;
 455; This code is disgustingly complex.
 456
 457(define define-definition)
 458(define define-syntax-definition)
 459(define define-values-definition)
 460(define import-definition)
 461
 462(define ##sys#canonicalize-body
 463  (lambda (body #!optional (se (##sys#current-environment)) cs?)
 464    (define (comp s id)
 465      (let ((f (or (lookup id se)
 466                   (lookup id (##sys#macro-environment)))))
 467        (and (or (not (symbol? f))
 468                 (not (eq? (##sys#get id '##sys#override) 'value)))
 469             (or (eq? f s) (eq? s id)))))
 470    (define (comp-def def)
 471      (lambda (id)
 472        (let repeat ((id id))
 473          (let ((f (or (lookup id se)
 474                       (lookup id (##sys#macro-environment)))))
 475            (and (or (not (symbol? f))
 476                     (not (eq? (##sys#get id '##sys#override) 'value)))
 477                 (or (eq? f def)
 478                     (and (symbol? f)
 479                          (not (eq? f id))
 480                          (repeat f))))))))
 481    (define comp-define (comp-def define-definition))
 482    (define comp-define-syntax (comp-def define-syntax-definition))
 483    (define comp-define-values (comp-def define-values-definition))
 484    (define comp-import (comp-def import-definition))
 485    (define (fini vars vals mvars body)
 486      (if (and (null? vars) (null? mvars))
 487	  ;; Macro-expand body, and restart when defines are found.
 488	  (let loop ((body body) (exps '()))
 489	    (if (not (pair? body))
 490		(cons
 491		 '##core#begin
 492		 (reverse exps)) ; no more defines, otherwise we would have called `expand'
 493		(let loop2 ((body body))
 494		  (let ((x (car body))
 495			(rest (cdr body)))
 496		    (if (and (pair? x)
 497			     (let ((d (car x)))
 498			       (and (symbol? d)
 499				    (or (comp '##core#begin d)
 500                                        (comp-define d)
 501					(comp-define-values d)
 502					(comp-define-syntax d)
 503					(comp-import d)))))
 504			;; Stupid hack to avoid expanding imports
 505			(if (comp-import (car x))
 506			    (loop rest (cons x exps))
 507			    (cons
 508			     '##core#begin
 509			     (##sys#append (reverse exps) (list (expand body)))))
 510			(let ((x2 (##sys#expand-0 x se cs?)))
 511			  (if (eq? x x2)
 512			      ;; Modules and includes must be processed before
 513			      ;; we can continue with other forms, so hand
 514			      ;; control back to the compiler
 515			      (if (and (pair? x)
 516				       (symbol? (car x))
 517				       (or (comp '##core#module (car x))
 518					   (comp '##core#include (car x))))
 519				  `(##core#begin
 520				    ,@(reverse exps)
 521				    ,@(if (comp '##core#module (car x))
 522					  (if (null? rest)
 523					      `(,x)
 524					      `(,x (##core#let () ,@rest)))
 525					  `((##core#include ,@(cdr x) ,rest))))
 526				  (loop rest (cons x exps)))
 527			      (loop2 (cons x2 rest)) )) ))) ))
 528	  ;; We saw defines.  Translate to letrec, and let compiler
 529	  ;; call us again for the remaining body by wrapping the
 530	  ;; remaining body forms in a ##core#let.
 531	  (let* ((result
 532		  `(##core#let
 533		    ,(##sys#map
 534		      (lambda (v) (##sys#list v '(##core#undefined)))
 535		      ;; vars are all normalised to lambda-lists: flatten them
 536		      (foldl (lambda (l v)
 537			       (##sys#append l (##sys#decompose-lambda-list
 538						v (lambda (a _ _) a))))
 539			     '()
 540			     (reverse vars))) ; not strictly necessary...
 541		    ,@(map (lambda (var val is-mvar?)
 542			     ;; Non-mvars should expand to set! for
 543			     ;; efficiency, but also because they must be
 544			     ;; implicit multi-value continuations.
 545			     (if is-mvar?
 546				 (##sys#expand-multiple-values-assignment var val)
 547				 `(##core#set! ,(car var) ,val)))
 548			   (reverse vars)
 549			   (reverse vals)
 550			   (reverse mvars))
 551		    ,@body) ) )
 552	    (dd `(BODY: ,result))
 553	    result)))
 554    (define (fini/syntax vars vals mvars body)
 555      (fini
 556       vars vals mvars
 557       (let loop ((body body) (defs '()) (done #f))
 558	 (cond (done `((##core#letrec-syntax
 559			,(map cdr (reverse defs)) ,@body) ))
 560	       ((not (pair? body)) (loop body defs #t))
 561	       ((and (list? (car body))
 562		     (>= 3 (length (car body)))
 563		     (symbol? (caar body))
 564		     (comp-define-syntax (caar body)))
 565		(let ((def (car body)))
 566		  ;; This check is insufficient, if introduced by
 567		  ;; different expansions, but better than nothing:
 568		  (when (eq? (car def) (cadr def))
 569		    (defjam-error def))
 570		  (loop (cdr body) (cons def defs) #f)))
 571	       (else (loop body defs #t))))))
 572    ;; Expand a run of defines or define-syntaxes into letrec.  As
 573    ;; soon as we encounter something else, finish up.
 574    (define (expand body)
 575      ;; Each #t in "mvars" indicates an MV-capable "var".  Non-MV
 576      ;; vars (#f in mvars) are 1-element lambda-lists for simplicity.
 577      (let loop ((body body) (vars '()) (vals '()) (mvars '()))
 578        (d "BODY: " body)
 579	(if (not (pair? body))
 580	    (fini vars vals mvars body)
 581	    (let* ((x (car body))
 582		   (rest (cdr body))
 583		   (exp1 (and (pair? x) (car x)))
 584		   (head (and exp1 (symbol? exp1) exp1)))
 585	      (if (not (symbol? head))
 586		  (fini vars vals mvars body)
 587		  (cond
 588		   ((comp-define head)
 589		     (##sys#check-syntax 'define x '(_ _ . #(_ 0)) #f se)
 590		     (let loop2 ((x x))
 591		       (let ((head (cadr x)))
 592			 (cond ((not (pair? head))
 593				(##sys#check-syntax 'define x '(_ variable . #(_ 0)) #f se)
 594				(when (eq? (car x) head) ; see above
 595				  (defjam-error x))
 596				(loop rest (cons (list head) vars)
 597				      (cons (if (pair? (cddr x))
 598						(caddr x)
 599						'(##core#undefined) )
 600					    vals)
 601				      (cons #f mvars)))
 602			       ((pair? (car head))
 603				(##sys#check-syntax
 604				 'define x '(_ (_ . lambda-list) . #(_ 1)) #f se)
 605				(loop2
 606				 (chicken.syntax#expand-curried-define head (cddr x) se)))
 607			       (else
 608				(##sys#check-syntax
 609				 'define x
 610				 '(_ (variable . lambda-list) . #(_ 1)) #f se)
 611				(loop rest
 612				      (cons (list (car head)) vars)
 613				      (cons `(##core#lambda ,(cdr head) ,@(cddr x)) vals)
 614				      (cons #f mvars)))))))
 615		    ((comp-define-syntax head)
 616		     (##sys#check-syntax 'define-syntax x '(_ _ . #(_ 1)) se)
 617		     (fini/syntax vars vals mvars body))
 618		    ((comp-define-values head)
 619		     ;;XXX check for any of the variables being `define-values'
 620		     (##sys#check-syntax 'define-values x '(_ lambda-list _) #f se)
 621		     (loop rest (cons (cadr x) vars) (cons (caddr x) vals) (cons #t mvars)))
 622		    ((comp '##core#begin head)
 623		     (loop (##sys#append (cdr x) rest) vars vals mvars))
 624		    (else
 625		     ;; Do not macro-expand local definitions we are
 626		     ;; in the process of introducing.
 627		     (if (member (list head) vars)
 628			 (fini vars vals mvars body)
 629			 (let ((x2 (##sys#expand-0 x se cs?)))
 630			   (if (eq? x x2)
 631			       (fini vars vals mvars body)
 632			       (loop (cons x2 rest) vars vals mvars)))))))))))
 633    (expand body) ) )
 634
 635
 636;;; A simple expression matcher
 637
 638;; Used by "quasiquote", below
 639(define chicken.syntax#match-expression
 640  (lambda (exp pat vars)
 641    (let ((env '()))
 642      (define (mwalk x p)
 643	(cond ((not (pair? p))
 644	       (cond ((assq p env) => (lambda (a) (equal? x (cdr a))))
 645		     ((memq p vars)
 646		      (set! env (cons (cons p x) env))
 647		      #t)
 648		     (else (eq? x p)) ) )
 649	      ((pair? x)
 650	       (and (mwalk (car x) (car p))
 651		    (mwalk (cdr x) (cdr p)) ) )
 652	      (else #f) ) )
 653      (and (mwalk exp pat) env) ) ) )
 654
 655
 656;;; Expand "curried" lambda-list syntax for `define'
 657
 658;; Used by "define", below
 659(define (chicken.syntax#expand-curried-define head body se)
 660  (let ((name #f))
 661    (define (loop head body)
 662      (if (symbol? (car head))
 663	  (begin
 664	    (set! name (car head))
 665	    `(##core#lambda ,(cdr head) ,@body) )
 666	  (loop (car head) `((##core#lambda ,(cdr head) ,@body)) ) ))
 667    (let ([exp (loop head body)])
 668      (list 'define name exp) ) ) )
 669
 670
 671;;; Line-number database management:
 672
 673(define ##sys#line-number-database #f)
 674
 675
 676;;; General syntax checking routine:
 677
 678(define ##sys#syntax-error-culprit #f)
 679(define ##sys#syntax-context '())
 680
 681(define (##sys#syntax-error-hook . args)
 682  (apply ##sys#signal-hook #:syntax-error
 683	 (strip-syntax args)))
 684
 685(define (##sys#syntax-error . args)
 686  (apply ##sys#syntax-error-hook args))
 687
 688(define ##sys#syntax-error/context
 689  (lambda (msg arg)
 690    (define (syntax-imports sym)
 691      (let loop ((defs (or (##sys#get (strip-syntax sym) '##core#db) '())))
 692	(cond ((null? defs) '())
 693	      ((eq? 'syntax (caar defs))
 694	       (cons (cadar defs) (loop (cdr defs))))
 695	      (else (loop (cdr defs))))))
 696    (if (null? ##sys#syntax-context)
 697	(##sys#syntax-error-hook msg arg)
 698	(let ((out (open-output-string)))
 699	  (define (outstr str)
 700	    (##sys#print str #f out))
 701	  (let loop ((cx ##sys#syntax-context))
 702	    (cond ((null? cx)		; no unimported syntax found
 703		   (outstr msg)
 704		   (outstr ": ")
 705		   (##sys#print arg #t out)
 706		   (outstr "\ninside expression `(")
 707		   (##sys#print (strip-syntax (car ##sys#syntax-context)) #t out)
 708		   (outstr " ...)'"))
 709		  (else
 710		   (let* ((sym (strip-syntax (car cx)))
 711			  (us (syntax-imports sym)))
 712		     (cond ((pair? us)
 713			    (outstr msg)
 714			    (outstr ": ")
 715			    (##sys#print arg #t out)
 716			    (outstr "\n\n  Perhaps you intended to use the syntax `(")
 717			    (##sys#print sym #t out)
 718			    (outstr " ...)' without importing it first.\n")
 719			    (if (fx= 1 (length us))
 720				(outstr
 721				 (string-append
 722				  "  Suggesting: `(import "
 723				  (symbol->string (car us))
 724				  ")'"))
 725				(outstr
 726				 (string-append
 727				  "  Suggesting one of:\n"
 728				  (let loop ((lst us))
 729				    (if (null? lst)
 730					""
 731					(string-append
 732					 "\n      (import " (symbol->string (car lst)) ")'"
 733					 (loop (cdr lst)))))))))
 734			   (else (loop (cdr cx))))))))
 735	  (##sys#syntax-error-hook (get-output-string out))))))
 736
 737;;; Hook for source information
 738
 739(define (alist-weak-cons k v lst)
 740  (cons (##core#inline_allocate ("C_a_i_weak_cons" 3) k v) lst))
 741
 742(define (assq/drop-bwp! x lst)
 743  (let lp ((lst lst)
 744	   (prev #f))
 745    (cond ((null? lst) #f)
 746	  ((eq? x (caar lst)) (car lst))
 747	  ((and prev
 748		(##core#inline "C_bwpp" (caar lst)))
 749	   (set-cdr! prev (cdr lst))
 750	   (lp (cdr lst) prev))
 751	  (else (lp (cdr lst) lst)))))
 752
 753(define (read-with-source-info-hook class data val)
 754  (when (and (eq? 'list-info class) (symbol? (car data)))
 755    (let ((old-value (or (hash-table-ref ##sys#line-number-database (car data)) '())))
 756      (assq/drop-bwp! (car data) old-value) ;; Hack to clean out garbage values
 757      (hash-table-set!
 758       ##sys#line-number-database
 759       (car data)
 760       (alist-weak-cons
 761	data (conc (or ##sys#current-source-filename "<stdin>") ":" val)
 762	old-value ) )) )
 763  data)
 764
 765(define-constant line-number-database-size 997) ; Copied from core.scm
 766
 767(define (read-with-source-info #!optional (in ##sys#standard-input))
 768  ;; Initialize line number db on first use
 769  (unless ##sys#line-number-database
 770    (set! ##sys#line-number-database (make-vector line-number-database-size '())))
 771  (##sys#check-input-port in #t 'read-with-source-info)
 772  (##sys#read in read-with-source-info-hook) )
 773
 774
 775(define (get-line-number sexp)
 776  (and ##sys#line-number-database
 777       (pair? sexp)
 778       (let ([head (car sexp)])
 779	 (and (symbol? head)
 780	      (cond ((hash-table-ref ##sys#line-number-database head)
 781		     => (lambda (pl)
 782			  (let ((a (assq/drop-bwp! sexp pl)))
 783			    (and a (cdr a)))))
 784		    (else #f))))))
 785
 786;; TODO: Needs a better name - it extracts the name(?) and the source expression
 787(define (##sys#get-line-2 exp)
 788  (let* ((name (car exp))
 789	 (lst (hash-table-ref ##sys#line-number-database name)))
 790    (cond ((and lst (assq/drop-bwp! exp (cdr lst)))
 791	   => (lambda (a) (values (car lst) (cdr a))) )
 792	  (else (values name #f)) ) ) )
 793
 794(define (##sys#display-line-number-database)
 795  (hash-table-for-each
 796   (lambda (key val)
 797     (when val
 798       (let ((port (current-output-port)))
 799	 (##sys#print key #t port)
 800	 (##sys#print " " #f port)
 801	 (##sys#print (map cdr val) #t port)
 802	 (##sys#print "\n" #f port))) )
 803   ##sys#line-number-database) )
 804
 805;;; Traverse expression and update line-number db with all contained calls:
 806
 807(define (##sys#update-line-number-database! exp ln)
 808  (define (mapupdate xs)
 809    (let loop ((xs xs))
 810      (when (pair? xs)
 811        (walk (car xs))
 812        (loop (cdr xs)) ) ))
 813  (define (walk x)
 814    (cond ((not (pair? x)))
 815          ((symbol? (car x))
 816           (let* ((name (car x))
 817                  (old (or (hash-table-ref ##sys#line-number-database name) '())))
 818             (unless (assq x old)
 819               (hash-table-set! ##sys#line-number-database name (alist-cons x ln old)))
 820             (when (list? x) (mapupdate (cdr x)) )))
 821          (else (mapupdate x)) ) )
 822  (walk exp))
 823
 824
 825(define-constant +default-argument-count-limit+ 99999)
 826
 827(define ##sys#check-syntax
 828  (lambda (id exp pat #!optional culprit (se (##sys#current-environment)))
 829
 830    (define (test x pred msg)
 831      (unless (pred x) (err msg)) )
 832
 833    (define (err msg)
 834      (let* ([sexp ##sys#syntax-error-culprit]
 835	     [ln (get-line-number sexp)] )
 836	(##sys#syntax-error
 837	 (if ln
 838	     (string-append "(" ln ") in `" (symbol->string id) "' - " msg)
 839	     (string-append "in `" (symbol->string id) "' - " msg) )
 840	 exp) ) )
 841
 842    (define (lambda-list? x)
 843      (or (##sys#extended-lambda-list? x)
 844	  (let loop ((x x))
 845	    (cond ((null? x))
 846		  ((symbol? x))
 847		  ((pair? x)
 848		   (let ((s (car x)))
 849		     (and (symbol? s)
 850			  (loop (cdr x)) ) ) )
 851		  (else #f) ) ) ) )
 852
 853    (define (variable? v)
 854      (symbol? v))
 855
 856    (define (proper-list? x)
 857      (let loop ((x x))
 858	(cond ((eq? x '()))
 859	      ((pair? x) (loop (cdr x)))
 860	      (else #f) ) ) )
 861
 862    (when culprit (set! ##sys#syntax-error-culprit culprit))
 863    (let walk ((x exp) (p pat))
 864      (cond ((vector? p)
 865	     (let* ((p2 (vector-ref p 0))
 866		    (vlen (##sys#size p))
 867		    (min (if (fx> vlen 1)
 868			     (vector-ref p 1)
 869			     0) )
 870		    (max (cond ((eq? vlen 1) 1)
 871			       ((fx> vlen 2) (vector-ref p 2))
 872			       (else +default-argument-count-limit+) ) ) )
 873	       (do ((x x (cdr x))
 874		    (n 0 (fx+ n 1)) )
 875		   ((eq? x '())
 876		    (if (fx< n min)
 877			(err "not enough arguments") ) )
 878		 (cond ((fx>= n max)
 879			(err "too many arguments") )
 880		       ((not (pair? x))
 881			(err "not a proper list") )
 882		       (else (walk (car x) p2) ) ) ) ) )
 883	    ((##sys#immediate? p)
 884	     (if (not (eq? p x)) (err "unexpected object")) )
 885	    ((symbol? p)
 886	     (case p
 887	       ((_) #t)
 888	       ((pair) (test x pair? "pair expected"))
 889	       ((variable) (test x variable? "identifier expected"))
 890	       ((symbol) (test x symbol? "symbol expected"))
 891	       ((list) (test x proper-list? "proper list expected"))
 892	       ((number) (test x number? "number expected"))
 893	       ((string) (test x string? "string expected"))
 894	       ((lambda-list) (test x lambda-list? "lambda-list expected"))
 895	       (else
 896		(test
 897		 x
 898		 (lambda (y)
 899		   (let ((y2 (and (symbol? y) (lookup y se))))
 900		     (eq? (if (symbol? y2) y2 y) p)))
 901		 "missing keyword")) ) )
 902	    ((not (pair? p))
 903	     (err "incomplete form") )
 904	    ((not (pair? x)) (err "pair expected"))
 905	    (else
 906	     (walk (car x) (car p))
 907	     (walk (cdr x) (cdr p)) ) ) ) ) )
 908
 909
 910;;; explicit/implicit-renaming transformer
 911
 912(define (make-er/ir-transformer handler explicit-renaming?)
 913  (##sys#make-structure
 914   'transformer
 915   (lambda (form se dse)
 916     (let ((renv '()))	  ; keep rename-environment for this expansion
 917       (define (inherit-pair-line-numbers old new)
 918	 (and-let* ((name (car new))
 919		    ((symbol? name))
 920		    (ln (get-line-number old))
 921		    (cur (or (hash-table-ref ##sys#line-number-database name) '())) )
 922	   (unless (assq new cur)
 923	     (hash-table-set! ##sys#line-number-database name
 924			      (alist-weak-cons new ln cur))))
 925	 new)
 926       (assert (list? se) "not a list" se) ;XXX remove later
 927       (define (rename sym)
 928	 (cond ((pair? sym)
 929		(inherit-pair-line-numbers sym (cons (rename (car sym)) (rename (cdr sym)))))
 930	       ((vector? sym)
 931		(list->vector (rename (vector->list sym))))
 932	       ((not (symbol? sym)) sym)
 933	       ((assq sym renv) =>
 934		(lambda (a)
 935		  (dd `(RENAME/RENV: ,sym --> ,(cdr a)))
 936		  (cdr a)))
 937	       (else
 938		(let ((a (macro-alias sym se)))
 939		  (dd `(RENAME: ,sym --> ,a))
 940		  (set! renv (cons (cons sym a) renv))
 941		  a))))
 942       (define (compare s1 s2)
 943	 (let ((result
 944		(cond ((pair? s1)
 945		       (and (pair? s2)
 946			    (compare (car s1) (car s2))
 947			    (compare (cdr s1) (cdr s2))))
 948		      ((vector? s1)
 949		       (and (vector? s2)
 950			    (let ((len (vector-length s1)))
 951			      (and (fx= len (vector-length s2))
 952				   (do ((i 0 (fx+ i 1))
 953					(f #t (compare (vector-ref s1 i) (vector-ref s2 i))))
 954				       ((or (fx>= i len) (not f)) f))))))
 955		      ((and (symbol? s1)
 956			    (symbol? s2))
 957		       (let ((ss1 (or (getp s1 '##core#macro-alias)
 958				      (lookup2 1 s1 dse)
 959				      s1) )
 960			     (ss2 (or (getp s2 '##core#macro-alias)
 961				      (lookup2 2 s2 dse)
 962				      s2) ) )
 963			 (cond ((symbol? ss1)
 964				(cond ((symbol? ss2) (eq? ss1 ss2))
 965				      ((assq ss1 (##sys#macro-environment)) =>
 966				       (lambda (a) (eq? (cdr a) ss2)))
 967				      (else #f) ) )
 968			       ((symbol? ss2)
 969				(cond ((assq ss2 (##sys#macro-environment)) =>
 970				       (lambda (a) (eq? ss1 (cdr a))))
 971				      (else #f)))
 972			       (else (eq? ss1 ss2)))))
 973		      (else (eq? s1 s2))) ) )
 974	   (dd `(COMPARE: ,s1 ,s2 --> ,result))
 975	   result))
 976       (define (lookup2 n sym dse)
 977	 (let ((r (lookup sym dse)))
 978	   (dd "  (lookup/DSE " (list n) ": " sym " --> "
 979	       (if (and r (pair? r))
 980		   '<macro>
 981		   r)
 982	       ")")
 983	   r))
 984       (define (assq-reverse s l)
 985	 (cond
 986	  ((null? l) #f)
 987	  ((eq? (cdar l) s) (car l))
 988	  (else (assq-reverse s (cdr l)))))
 989       (define (mirror-rename sym)
 990	 (cond ((pair? sym)
 991		(inherit-pair-line-numbers
 992		 sym (cons (mirror-rename (car sym)) (mirror-rename (cdr sym)))))
 993	       ((vector? sym)
 994		(list->vector (mirror-rename (vector->list sym))))
 995	       ((not (symbol? sym)) sym)
 996	       (else		 ; Code stolen from strip-syntax
 997		(let ((renamed (lookup sym se) ) )
 998		  (cond ((assq-reverse sym renv) =>
 999			 (lambda (a)
 1000			   (dd "REVERSING RENAME: " sym " --> " (car a)) (car a)))
1001			((not renamed)
1002			 (dd "IMPLICITLY RENAMED: " sym) (rename sym))
1003			((pair? renamed)
1004			 (dd "MACRO: " sym) (rename sym))
1005			((getp sym '##core#real-name) =>
1006			 (lambda (name)
1007			   (dd "STRIP SYNTAX ON " sym " ---> " name)
1008			   name))
1009                        ;; Rename builtin aliases so strip-syntax can still
1010                        ;; access symbols as entered by the user
1011			(else (let ((implicitly-renamed (rename sym)))
1012                                (dd "BUILTIN ALIAS: " sym " as " renamed
1013                                    " --> " implicitly-renamed)
1014                                implicitly-renamed)))))))
1015       (if explicit-renaming?
1016	   ;; Let the user handle renaming
1017	   (handler form rename compare)
1018	   ;; Implicit renaming:
1019	   ;; Rename everything in the input first, feed it to the transformer
1020	   ;; and then swap out all renamed identifiers by their non-renamed
1021	   ;; versions, and vice versa.  User can decide when to inject code
1022	   ;; unhygienically this way.
1023	   (mirror-rename (handler (rename form) rename compare)) ) ) )))
1024
1025(define (er-macro-transformer handler) (make-er/ir-transformer handler #t))
1026(define (ir-macro-transformer handler) (make-er/ir-transformer handler #f))
1027
1028(define ##sys#er-transformer er-macro-transformer)
1029(define ##sys#ir-transformer ir-macro-transformer)
1030
1031
1032;; Expose some internals for use in core.scm and chicken-syntax.scm:
1033
1034(define chicken.syntax#define-definition define-definition)
1035(define chicken.syntax#define-syntax-definition define-syntax-definition)
1036(define chicken.syntax#define-values-definition define-values-definition)
1037(define chicken.syntax#expansion-result-hook expansion-result-hook)
1038
1039) ; chicken.syntax module
1040
1041(import scheme chicken.base chicken.bytevector chicken.fixnum)
1042(import chicken.syntax chicken.internal chicken.platform)
1043(import (only (scheme base) make-parameter))
1044
1045;;; Macro definitions:
1046
1047(##sys#extend-macro-environment
1048 'import-syntax '()
1049 (##sys#er-transformer
1050  (cut ##sys#expand-import <> <> <>
1051       ##sys#current-environment ##sys#macro-environment
1052       #f #f 'import-syntax)))
1053
1054(##sys#extend-macro-environment
1055 'import-syntax-for-syntax '()
1056 (##sys#er-transformer
1057  (cut ##sys#expand-import <> <> <>
1058       ##sys#current-meta-environment ##sys#meta-macro-environment
1059       #t #f 'import-syntax-for-syntax)))
1060
1061(set! chicken.syntax#import-definition
1062  (##sys#extend-macro-environment
1063   'import '()
1064   (##sys#er-transformer
1065    (lambda (x r c)
1066      `(##core#begin
1067	,@(map (lambda (x)
1068		 (let-values (((name lib spec v s i) (##sys#decompose-import x r c 'import))
1069			      ((mod) (##sys#current-module)))
1070		   (when (and mod (eq? name (##sys#module-name mod)))
1071		     (##sys#syntax-error
1072		      'import "cannot import from module currently being defined" name))
1073		   (if (not spec)
1074		       (##sys#syntax-error
1075			'import "cannot import from undefined module" name)
1076		       (##sys#import
1077			spec v s i
1078			##sys#current-environment ##sys#macro-environment #f #f 'import))
1079		   (if (not lib)
1080		       '(##core#undefined)
1081		       `(##core#require ,lib ,name))))
1082	       (cdr x)))))))
1083
1084(##sys#extend-macro-environment
1085 'import-for-syntax '()
1086 (##sys#er-transformer
1087  (lambda (x r c)
1088    (##sys#register-meta-expression `(,(r 'import) ,@(cdr x)))
1089    `(##core#elaborationtimeonly (,(r 'import) ,@(cdr x))))))
1090
1091(define (process-cond-expand clauses)
1092      (define (err x)
1093	(##sys#syntax-error "syntax error in `cond-expand' form"
1094		     x
1095		     (cons 'cond-expand clauses)))
1096      (define (file-exists? fname)
1097        (##sys#file-exists? fname #f #f 'cond-expand))
1098      (define (locate-library name)
1099        (let* ((name2 (library-id name))
1100               (sname2 (symbol->string name2)))
1101          (or (##sys#find-module name2 #f)
1102              (let loop ((rp (repository-path)))
1103                (and (pair? rp)
1104                     (let ((p (car rp)))
1105                       (or (file-exists? (string-append p "/" sname2 ".import.so"))
1106                           (file-exists? (string-append p "/" sname2 ".import.scm"))
1107                           (loop (cdr rp)))))))))
1108      (define (test fx)
1109	(cond ((symbol? fx) (feature? (strip-syntax fx)))
1110	      ((not (pair? fx)) (err fx))
1111	      (else
1112	       (let ((head (car fx))
1113		     (rest (cdr fx)))
1114		 (case (strip-syntax head)
1115		   ((and)
1116		    (or (eq? rest '())
1117			(if (pair? rest)
1118			    (and (test (car rest))
1119				 (test `(and ,@(cdr rest))))
1120			    (err fx))))
1121		   ((or)
1122		    (and (not (eq? rest '()))
1123			 (if (pair? rest)
1124			     (or (test (car rest))
1125				 (test `(or ,@(cdr rest))))
1126			     (err fx))))
1127		   ((not) (not (test (cadr fx))))
1128                   ((library)
1129                    (if (and (pair? rest)
1130                             (null? (cdr rest)))
1131                        (locate-library (strip-syntax (car rest)))
1132                        (err fx)))
1133		   (else (err fx)))))))
1134      (let expand ((cls clauses))
1135	(cond ((eq? cls '())
1136	       (##sys#apply
1137		##sys#error "no matching clause in `cond-expand' form"
1138		(map (lambda (x) (car x)) clauses)))
1139	      ((not (pair? cls)) (err cls))
1140	      (else
1141	       (let ((clause (car cls))
1142		    (rclauses (cdr cls)))
1143		 (if (not (pair? clause))
1144		     (err clause)
1145		     (let ((id (car clause)))
1146		       (cond ((eq? (strip-syntax id) 'else)
1147			      (let ((rest (cdr clause)))
1148				(if (eq? rest '())
1149				    '(##core#undefined)
1150				    `(##core#begin ,@rest))))
1151			     ((test id) `(##core#begin ,@(cdr clause)))
1152			     (else (expand rclauses))))))))))
1153
1154(##sys#extend-macro-environment
1155 'cond-expand
1156 '()
1157 (##sys#er-transformer
1158  (lambda (form r c)
1159    (process-cond-expand (cdr form)))))
1160
1161;; The "initial" macro environment, containing only import forms and
1162;; cond-expand.  TODO: Eventually, cond-expand should move to the
1163;; (chicken base) module to match r7rs.  Keeping it in the initial env
1164;; makes it a whole lot easier to write portable CHICKEN 4 & 5 code.
1165(define ##sys#initial-macro-environment (##sys#macro-environment))
1166
1167(##sys#extend-macro-environment
1168 'module '()
1169 (##sys#er-transformer
1170  (lambda (x r c)
1171    (##sys#check-syntax 'module x '(_ _ _ . #(_ 0)))
1172    (let ((len (length x))
1173	  (name (library-id (cadr x))))
1174      ;; We strip syntax here instead of doing a hygienic comparison
1175      ;; to "=".  This is a tradeoff; either we do this, or we must
1176      ;; include a mapping of (= . scheme#=) in our syntax env.  In
1177      ;; the initial environment, = is bound to scheme#=, but when
1178      ;; using -explicit-use that's not the case.  Doing an unhygienic
1179      ;; comparison ensures module will work in both cases.
1180      (cond ((and (fx>= len 4) (eq? '= (strip-syntax (caddr x))))
1181	     (let* ((x (strip-syntax x))
1182		    (app (cadddr x)))
1183	       (cond ((fx> len 4)
1184		      ;; feature suggested by syn:
1185		      ;;
1186		      ;; (module NAME = FUNCTORNAME BODY ...)
1187		      ;; ~>
1188		      ;; (begin
1189		      ;;   (module _NAME * BODY ...)
1190		      ;;   (module NAME = (FUNCTORNAME _NAME)))
1191		      ;;
1192		      ;; - the use of "_NAME" is a bit stupid, but it must be
1193		      ;;   externally visible to generate an import library from
1194		      ;;   and compiling "NAME" separately may need an import-lib
1195		      ;;   for stuff in "BODY" (say, syntax needed by syntax exported
1196		      ;;   from the functor, or something like this...)
1197		      (let ((mtmp (string->symbol
1198				   (##sys#string-append
1199				    "_"
1200				    (symbol->string name))))
1201			    (%module (r 'module)))
1202			`(##core#begin
1203			  (,%module ,mtmp * ,@(cddddr x))
1204			  (,%module ,name = (,app ,mtmp)))))
1205		     (else
1206		      (##sys#check-syntax
1207		       'module x '(_ _ _ (_ . #(_ 0))))
1208		      (##sys#instantiate-functor
1209		       name
1210		       (library-id (car app))
1211		       (cdr app)))))) ; functor arguments
1212	    (else
1213	     ;;XXX use module name in "loc" argument?
1214	     (let ((exports (##sys#validate-exports (strip-syntax (caddr x)) 'module)))
1215	       `(##core#module
1216		 ,name
1217		 ,(if (eq? '* exports)
1218		      #t
1219		      exports)
1220		 ,@(let ((body (cdddr x)))
1221		     (if (and (pair? body)
1222			      (null? (cdr body))
1223			      (string? (car body)))
1224			 `((##core#include ,(car body) ,##sys#current-source-filename))
1225			 body))))))))))
1226
1227;;; R7RS define-library
1228
1229(##sys#extend-macro-environment
1230  'define-library '()
1231  (##sys#er-transformer
1232   (lambda (x r c)
1233     (define (register-r7rs-module name)
1234       (let ((dummy (string->symbol (string-append (string #\x04) "r7rs" (symbol->string name)))))
1235         (##sys#put! name '##r7rs#module dummy)
1236         dummy))
1237     (define implicit-r7rs-library-bindings
1238       '(begin
1239          cond-expand
1240          export
1241          import
1242          import-for-syntax
1243          include
1244          include-ci
1245          syntax-rules))
1246     (##sys#check-syntax 'define-library x '(_ . #(_ 0)))
1247     (let* ((x (strip-syntax x))
1248            (name (cadr x))
1249            (real-name (library-id name))
1250            (decls (cddr x))
1251            (dummy (register-r7rs-module real-name)))
1252       (define (parse-exports specs)
1253	 (map (lambda (spec)
1254                (cond ((and (list? spec)
1255                            (= 3 (length spec))
1256                            (eq? 'rename (car spec)))
1257                       `(export/rename ,(cdr spec)))
1258                      ((symbol? spec) `(export ,spec))
1259                      (else
1260                        (##sys#syntax-error 'define-library "invalid export specifier" spec name))))
1261            specs))
1262       (define (parse-imports specs)
1263	 ;; XXX TODO: Should be import-for-syntax'ed as well?
1264	 `(import ,@specs))
1265       (define (process-includes fnames ci?)
1266	 `(##core#begin
1267	   ,@(map (lambda (fname)
1268                    (if (string? fname)
1269                        `(##core#begin ,@(read-forms fname ci?)))
1270		    (fname (##sys#syntax-error 'include "invalid include-filename" fname)))
1271		  fnames)))
1272       (define (expand/begin e)
1273         (let ((e2 (expand e '())))
1274           (if (and (pair? e2) (eq? '##core#begin (car e2)))
1275               (cons '##core#begin (map expand/begin (cdr e2)))
1276               e2)))
1277       (define (read-forms filename ci? #!optional (proc (lambda (x) (map expand/begin x))))
1278         (fluid-let ((##sys#default-read-info-hook
1279                       (let ((name 'chicken.compiler.support#read-info-hook))
1280                         (and (feature? 'compiling)
1281                              (##sys#symbol-has-toplevel-binding? name)
1282                              (##sys#slot name 0)))))
1283           (##sys#include-forms-from-file
1284               filename
1285               ##sys#current-source-filename ci?
1286               (lambda (forms path) (proc forms)))))
1287       (define (process-include-decls fnames)
1288         (parse-decls
1289           (let loop ((fnames fnames) (all '()))
1290             (if (null? fnames)
1291                 (reverse all)
1292                 (let ((forms (read-forms (car fnames) #t (lambda (x) x))))
1293                   (loop (cdr fnames)
1294                         (append (reverse forms) all)))))))
1295       (define (fail spec)
1296         (##sys#syntax-error 'define-library "invalid library declaration" spec))
1297       (define (parse-decls decls)
1298         (cond ((null? decls) '(##core#begin))
1299               ((and (pair? decls) (pair? (car decls)))
1300                (let ((spec (car decls))
1301                      (more (cdr decls)))
1302                 (case (car spec)
1303                  ((export)
1304                   (##sys#check-syntax 'export spec '(_ . #(_ 0)))
1305                   `(##core#begin ,@(parse-exports (cdr spec))
1306                                  ,(parse-decls more)))
1307                  ((import)
1308                   (##sys#check-syntax 'import spec '(_ . #(_ 0)))
1309                   `(##core#begin ,(parse-imports (cdr spec))
1310                                  ,(parse-decls more)))
1311                  ((include)
1312                   (##sys#check-syntax 'include spec '(_ . #(_ 0)))
1313                   `(##core#begin ,(process-includes (cdr spec) #f)
1314                                  ,(parse-decls more)))
1315                  ((include-ci)
1316                   (##sys#check-syntax 'include-ci spec '(_ . #(_ 0)))
1317                   `(##core#begin ,(process-includes (cdr spec) #t)
1318                                  ,(parse-decls more)))
1319                  ((include-library-declarations)
1320                   `(##core#begin ,(process-include-decls (cdr spec))
1321                                  ,(parse-decls more)))
1322                  ((cond-expand)
1323                   (parse-decls (append (list (process-cond-expand (cdr spec)))
1324                                        more)))
1325                  ((##core#begin)
1326                    (parse-decls (cdr spec)))
1327                  ((begin)
1328                   `(##core#begin ,@(cdr spec)
1329                                  ,(parse-decls more)))
1330                  (else (fail spec)))))
1331                (else (fail (car decls)))))
1332       `(##core#module ,real-name ((,dummy))
1333	 ;; gruesome hack: we add a dummy export for adding indirect exports
1334	 (##core#define-syntax ,dummy
1335	  (##sys#er-transformer (##core#lambda (x r c) (##core#undefined))))
1336	 ;; Set up an R7RS environment for the module's body.
1337	 (import-for-syntax (only scheme.base ,@implicit-r7rs-library-bindings))
1338	 (import (only scheme.base ,@implicit-r7rs-library-bindings)
1339            (only chicken.module export/rename))
1340	 ;; Now process all toplevel library declarations
1341	 ,(parse-decls decls))))))
1342
1343(##sys#extend-macro-environment
1344 'export '()
1345 (##sys#er-transformer
1346  (lambda (x r c)
1347    (let ((exps (##sys#validate-exports (strip-syntax (cdr x)) 'export))
1348	  (mod (##sys#current-module)))
1349      (when mod
1350	(##sys#add-to-export-list mod exps))
1351      '(##core#undefined)))))
1352
1353(##sys#extend-macro-environment
1354 'export/rename '()
1355 (##sys#er-transformer
1356  (lambda (x r c)
1357    (let ((exps (map (lambda (ren)
1358                       (if (and (pair? ren)
1359                                (symbol? (car ren))
1360                                (pair? (cdr ren))
1361                                (symbol? (cadr ren))
1362                                (null? (cddr ren)))
1363                           (cons (car ren) (cadr ren))
1364                           (##sys#syntax-error "invalid item in export rename list"
1365                                                    ren)))
1366                  (strip-syntax (cdr x))))
1367          (mod (##sys#current-module)))
1368      (when mod
1369	(##sys#add-to-export/rename-list mod exps))
1370      '(##core#undefined)))))
1371
1372(##sys#extend-macro-environment
1373 'reexport '()
1374 (##sys#er-transformer
1375  (cut ##sys#expand-import <> <> <>
1376       ##sys#current-environment ##sys#macro-environment
1377       #f #t 'reexport)))
1378
1379;;; functor definition
1380
1381(##sys#extend-macro-environment
1382 'functor '()
1383 (##sys#er-transformer
1384  (lambda (x r c)
1385    (##sys#check-syntax 'functor x '(_ (_ . #((_ _) 0)) _ . _))
1386    (let* ((x (strip-syntax x))
1387	   (head (cadr x))
1388	   (name (car head))
1389	   (args (cdr head))
1390	   (exps (caddr x))
1391	   (body (cdddr x))
1392	   (registration
1393	    `(##sys#register-functor
1394	      (##core#quote ,(library-id name))
1395	      (##core#quote
1396	       ,(map (lambda (arg)
1397		       (let ((argname (car arg))
1398			     (exps (##sys#validate-exports (cadr arg) 'functor)))
1399			 (unless (or (symbol? argname)
1400				     (and (list? argname)
1401					  (= 2 (length argname))
1402					  (symbol? (car argname))
1403					  (valid-library-specifier? (cadr argname))))
1404			   (##sys#syntax-error "invalid functor argument" name arg))
1405			 (cons argname exps)))
1406		     args))
1407	      (##core#quote ,(##sys#validate-exports exps 'functor))
1408	      (##core#quote ,body))))
1409      `(##core#module ,(library-id name)
1410	#t
1411	(import scheme chicken.syntax) ;; TODO: Is this correct?
1412	(begin-for-syntax ,registration))))))
1413
1414;;; interface definition
1415
1416(##sys#extend-macro-environment
1417 'define-interface '()
1418 (##sys#er-transformer
1419  (lambda (x r c)
1420    (##sys#check-syntax 'define-interface x '(_ variable _))
1421    (let ((name (strip-syntax (cadr x))))
1422      (when (eq? '* name)
1423	(##sys#syntax-error
1424	 'define-interface "`*' is not allowed as a name for an interface"))
1425      `(##core#elaborationtimeonly
1426	(##sys#put/restore!
1427	 (##core#quote ,name)
1428	 (##core#quote ##core#interface)
1429	 (##core#quote
1430	  ,(let ((exps (strip-syntax (caddr x))))
1431	     (cond ((eq? '* exps) '*)
1432		   ((symbol? exps) `(#:interface ,exps))
1433		   ((list? exps)
1434		    (##sys#validate-exports exps 'define-interface))
1435		   (else
1436		    (##sys#syntax-error
1437		     'define-interface "invalid exports" (caddr x))))))))))))
1438
1439(##sys#extend-macro-environment
1440 'current-module '()
1441 (##sys#er-transformer
1442  (lambda (x r c)
1443    (##sys#check-syntax 'current-module x '(_))
1444    (and-let* ((mod (##sys#current-module)))
1445      `(##core#quote ,(##sys#module-name mod))))))
1446
1447;; The chicken.module syntax environment
1448(define ##sys#chicken.module-macro-environment (##sys#macro-environment))
1449
1450(set! ##sys#scheme-macro-environment
1451  (let ((me0 (##sys#macro-environment)))
1452
1453(##sys#extend-macro-environment
1454 'lambda
1455 '()
1456 (##sys#er-transformer
1457  (lambda (x r c)
1458    (##sys#check-syntax 'lambda x '(_ lambda-list . #(_ 1)))
1459    `(##core#lambda ,@(cdr x)))))
1460
1461(##sys#extend-macro-environment
1462 'quote
1463 '()
1464 (##sys#er-transformer
1465  (lambda (x r c)
1466    (##sys#check-syntax 'quote x '(_ _))
1467    `(##core#quote ,(cadr x)))))
1468
1469(##sys#extend-macro-environment
1470 'if
1471 '()
1472 (##sys#er-transformer
1473  (lambda (x r c)
1474    (##sys#check-syntax 'if x '(_ _ _ . #(_)))
1475    `(##core#if ,@(cdr x)))))
1476
1477(##sys#extend-macro-environment
1478 'begin
1479 '()
1480 (##sys#er-transformer
1481  (lambda (x r c)
1482    (##sys#check-syntax 'begin x '(_ . #(_ 0)))
1483    `(##core#begin ,@(cdr x)))))
1484
1485(set! chicken.syntax#define-definition
1486  (##sys#extend-macro-environment
1487   'define
1488   '()
1489   (##sys#er-transformer
1490    (lambda (x r c)
1491      (##sys#check-syntax 'define x '(_ . #(_ 1)))
1492      (let loop ((form x))
1493	(let ((head (cadr form))
1494	      (body (cddr form)) )
1495	  (cond ((not (pair? head))
1496		 (##sys#check-syntax 'define form '(_ variable . #(_ 0 1)))
1497                 (let ((name (or (getp head '##core#macro-alias) head)))
1498                   (##sys#register-export name (##sys#current-module)))
1499		 (when (c (r 'define) head)
1500		   (chicken.syntax#defjam-error x))
1501		 `(##core#begin
1502		    (##core#ensure-toplevel-definition ,head)
1503		    (##core#set!
1504		     ,head
1505		     ,(if (pair? body) (car body) '(##core#undefined)))))
1506		((pair? (car head))
1507		 (##sys#check-syntax 'define form '(_ (_ . lambda-list) . #(_ 1)))
1508		 (loop (chicken.syntax#expand-curried-define head body '()))) ;XXX '() should be se
1509		(else
1510		 (##sys#check-syntax 'define form '(_ (variable . lambda-list) . #(_ 1)))
1511		 (loop (list (car x) (car head) `(##core#lambda ,(cdr head) ,@body)))))))))))
1512
1513(set! chicken.syntax#define-syntax-definition
1514  (##sys#extend-macro-environment
1515   'define-syntax
1516   '()
1517   (##sys#er-transformer
1518    (lambda (form r c)
1519      (##sys#check-syntax 'define-syntax form '(_ variable _))
1520      (let ((head (cadr form))
1521	    (body (caddr form)))
1522	(let ((name (or (getp head '##core#macro-alias) head)))
1523	  (##sys#register-export name (##sys#current-module)))
1524	(when (c (r 'define-syntax) head)
1525	  (chicken.syntax#defjam-error form))
1526	`(##core#define-syntax ,head ,body))))))
1527
1528(##sys#extend-macro-environment
1529 'let
1530 '()
1531 (##sys#er-transformer
1532  (lambda (x r c)
1533    (cond ((and (pair? (cdr x)) (symbol? (cadr x)))
1534	   (##sys#check-syntax 'let x '(_ variable #((variable _) 0) . #(_ 1)))
1535           (check-for-multiple-bindings (caddr x) x "let"))
1536	  (else
1537	   (##sys#check-syntax 'let x '(_ #((variable _) 0) . #(_ 1)))
1538           (check-for-multiple-bindings (cadr x) x "let")))
1539    `(##core#let ,@(cdr x)))))
1540
1541(##sys#extend-macro-environment
1542 'letrec
1543 '()
1544 (##sys#er-transformer
1545  (lambda (x r c)
1546    (##sys#check-syntax 'letrec x '(_ #((variable _) 0) . #(_ 1)))
1547    (check-for-multiple-bindings (cadr x) x "letrec")
1548    `(##core#letrec ,@(cdr x)))))
1549
1550(##sys#extend-macro-environment
1551 'let-syntax
1552 '()
1553 (##sys#er-transformer
1554  (lambda (x r c)
1555    (##sys#check-syntax 'let-syntax x '(_ #((variable _) 0) . #(_ 1)))
1556    (check-for-multiple-bindings (cadr x) x "let-syntax")
1557    `(##core#let-syntax ,@(cdr x)))))
1558
1559(##sys#extend-macro-environment
1560 'letrec-syntax
1561 '()
1562 (##sys#er-transformer
1563  (lambda (x r c)
1564    (##sys#check-syntax 'letrec-syntax x '(_ #((variable _) 0) . #(_ 1)))
1565    (check-for-multiple-bindings (cadr x) x "letrec-syntax")
1566    `(##core#letrec-syntax ,@(cdr x)))))
1567
1568(##sys#extend-macro-environment
1569 'set!
1570 '()
1571 (##sys#er-transformer
1572  (lambda (x r c)
1573    (##sys#check-syntax 'set! x '(_ _ _))
1574    (let ((dest (cadr x))
1575	  (val (caddr x)))
1576      (cond ((pair? dest)
1577	     `((##sys#setter ,(car dest)) ,@(cdr dest) ,val))
1578	    (else `(##core#set! ,dest ,val)))))))
1579
1580(##sys#extend-macro-environment
1581 'and
1582 '()
1583 (##sys#er-transformer
1584  (lambda (form r c)
1585    (let ((body (cdr form)))
1586      (if (null? body)
1587	  #t
1588	  (let ((rbody (cdr body))
1589		(hbody (car body)) )
1590	    (if (null? rbody)
1591		hbody
1592		`(##core#if ,hbody (,(r 'and) ,@rbody) #f) ) ) ) ) ) ) )
1593
1594(##sys#extend-macro-environment
1595 'or
1596 '()
1597 (##sys#er-transformer
1598  (lambda (form r c)
1599    (let ((body (cdr form)))
1600     (if (null? body)
1601	 #f
1602	 (let ((rbody (cdr body))
1603	       (hbody (car body)))
1604	   (if (null? rbody)
1605	       hbody
1606	       (let ((tmp (r 'tmp)))
1607		 `(##core#let ((,tmp ,hbody))
1608		    (##core#if ,tmp ,tmp (,(r 'or) ,@rbody)) ) ) ) ) ) ) ) ) )
1609
1610(##sys#extend-macro-environment
1611 'cond
1612 '()
1613 (##sys#er-transformer
1614  (lambda (form r c)
1615    (let ((body (cdr form))
1616	  (%=> (r '=>))
1617	  (%or (r 'or))
1618	  (%else (r 'else)))
1619      (let expand ((clauses body) (else? #f))
1620	(if (not (pair? clauses))
1621	    '(##core#undefined)
1622	    (let ((clause (car clauses))
1623		  (rclauses (cdr clauses)) )
1624	      (##sys#check-syntax 'cond clause '#(_ 1))
1625	      (cond (else?
1626		     (##sys#warn
1627		      (chicken.format#sprintf "clause following `~S' clause in `cond'" else?)
1628		      (strip-syntax clause))
1629		     (expand rclauses else?)
1630		     '(##core#begin))
1631		    ((or (c %else (car clause))
1632                         (eq? #t (car clause))
1633                         ;; Like "constant?" from support.scm
1634                         (number? (car clause))
1635                         (char? (car clause))
1636                         (string? (car clause))
1637                         (eof-object? (car clause))
1638                         (bytevector? (car clause))
1639                         (bwp-object? (car clause))
1640                         (vector? (car clause))
1641                         (##sys#srfi-4-vector? (car clause))
1642                         (and (pair? (car clause))
1643                              (c (r 'quote) (caar clause))))
1644		     (expand rclauses (strip-syntax (car clause)))
1645		     (cond ((and (fx= (length clause) 3)
1646				 (c %=> (cadr clause)))
1647			    `(,(caddr clause) ,(car clause)))
1648			   ((pair? (cdr clause))
1649			    `(##core#begin ,@(cdr clause)))
1650			   ((c %else (car clause))
1651			    `(##core#undefined))
1652			   (else (car clause))))
1653		    ((null? (cdr clause))
1654		     `(,%or ,(car clause) ,(expand rclauses #f)))
1655		    ((and (fx= (length clause) 3)
1656			  (c %=> (cadr clause)))
1657		     (let ((tmp (r 'tmp)))
1658		       `(##core#let ((,tmp ,(car clause)))
1659				    (##core#if ,tmp
1660					       (,(caddr clause) ,tmp)
1661					       ,(expand rclauses #f) ) ) ) )
1662		    ((and (fx= (length clause) 4)
1663			  (c %=> (caddr clause)))
1664		     (let ((tmp (r 'tmp)))
1665		       `(##sys#call-with-values
1666			 (##core#lambda () ,(car clause))
1667			 (##core#lambda
1668			  ,tmp
1669			  (if (##sys#apply ,(cadr clause) ,tmp)
1670			      (##sys#apply ,(cadddr clause) ,tmp)
1671			      ,(expand rclauses #f) ) ) ) ) )
1672		    (else `(##core#if ,(car clause)
1673				      (##core#begin ,@(cdr clause))
1674				      ,(expand rclauses #f) ) ) ) ) ) ) ) ) ) )
1675
1676(##sys#extend-macro-environment
1677 'case
1678 '((eqv? . scheme#eqv?))
1679 (##sys#er-transformer
1680  (lambda (form r c)
1681    (##sys#check-syntax 'case form '(_ _ . #(_ 0)))
1682    (let ((exp (cadr form))
1683	  (body (cddr form)) )
1684      (let ((tmp (r 'tmp))
1685	    (%or (r 'or))
1686	    (%=> (r '=>))
1687	    (%eqv? (r 'eqv?))
1688	    (%else (r 'else)))
1689	`(let ((,tmp ,exp))
1690	   ,(let expand ((clauses body) (else? #f))
1691	      (if (not (pair? clauses))
1692		  '(##core#undefined)
1693		  (let ((clause (car clauses))
1694			(rclauses (cdr clauses)) )
1695		    (##sys#check-syntax 'case clause '#(_ 1))
1696		    (cond (else?
1697			   (##sys#warn
1698			    "clause following `else' clause in `case'"
1699			    (strip-syntax clause))
1700			   (expand rclauses #t)
1701			   '(##core#begin))
1702			  ((c %else (car clause))
1703			   (expand rclauses #t)
1704			   (cond ((null? (cdr clause))
1705				  `(##core#undefined))
1706				 ((and (fx= (length clause) 3) ; (else => expr)
1707				       (c %=> (cadr clause)))
1708				  `(,(caddr clause) ,tmp))
1709				 (else
1710				  `(##core#begin ,@(cdr clause)))))
1711			  (else
1712			   `(##core#if (,%or ,@(##sys#map
1713						(lambda (x) `(,%eqv? ,tmp ',x))
1714						(car clause)))
1715				       ,(if (and (fx= (length clause) 3) ; ((...) => expr)
1716						 (c %=> (cadr clause)))
1717					    `(,(caddr clause) ,tmp)
1718					    `(##core#begin ,@(cdr clause)))
1719				       ,(expand rclauses #f) ) ) ) ) ) ) ) ) ) ) ) )
1720
1721(##sys#extend-macro-environment
1722 'let*
1723 '()
1724 (##sys#er-transformer
1725  (lambda (form r c)
1726    (##sys#check-syntax 'let* form '(_ #((variable _) 0) . #(_ 1)))
1727    (let ((bindings (cadr form))
1728	  (body (cddr form)) )
1729      (let expand ((bs bindings))
1730	(if (eq? bs '())
1731	    `(##core#let () ,@body)
1732	    `(##core#let (,(car bs)) ,(expand (cdr bs))) ) ) ) ) ) )
1733
1734(##sys#extend-macro-environment
1735 'do
1736 '()
1737 (##sys#er-transformer
1738  (lambda (form r c)
1739    (##sys#check-syntax 'do form '(_ #((variable _ . #(_)) 0) . #(_ 1)))
1740    (let ((bindings (cadr form))
1741	  (test (caddr form))
1742	  (body (cdddr form))
1743	  (dovar (r 'doloop)))
1744      `(##core#let
1745	,dovar
1746	,(##sys#map (lambda (b) (list (car b) (car (cdr b)))) bindings)
1747	(##core#if ,(car test)
1748		   ,(let ((tbody (cdr test)))
1749		      (if (eq? tbody '())
1750			  '(##core#undefined)
1751			  `(##core#begin ,@tbody) ) )
1752		   (##core#begin
1753		    ,(if (eq? body '())
1754			 '(##core#undefined)
1755			 `(##core#let () ,@body) )
1756		    (##core#app
1757		     ,dovar ,@(##sys#map (lambda (b)
1758					   (if (eq? (cdr (cdr b)) '())
1759					       (car b)
1760					       (car (cdr (cdr b))) ) )
1761					 bindings) ) ) ) ) ) ) ) )
1762
1763(##sys#extend-macro-environment
1764 'quasiquote
1765 '()
1766 (##sys#er-transformer
1767  (lambda (form r c)
1768    (let ((%quasiquote (r 'quasiquote))
1769	  (%unquote (r 'unquote))
1770	  (%unquote-splicing (r 'unquote-splicing)))
1771      (define (walk x n) (simplify (walk1 x n)))
1772      (define (walk1 x n)
1773	(cond ((vector? x)
1774	       `(##sys#list->vector ,(walk (vector->list x) n)) )
1775	      ((not (pair? x)) `(##core#quote ,x))
1776	      (else
1777	       (let ((head (car x))
1778		     (tail (cdr x)))
1779		 (cond ((c %unquote head)
1780                        (cond ((eq? n 0)
1781                               (##sys#check-syntax 'unquote x '(_ _))
1782                               (car tail))
1783                              (else (list '##sys#cons `(##core#quote ,%unquote)
1784                                          (walk tail (fx- n 1)) ) )))
1785		       ((c %quasiquote head)
1786			(list '##sys#cons `(##core#quote ,%quasiquote)
1787                              (walk tail (fx+ n 1)) ) )
1788		       ((and (pair? head) (c %unquote-splicing (car head)))
1789                        (cond ((eq? n 0)
1790                               (##sys#check-syntax 'unquote-splicing head '(_ _))
1791                               `(##sys#append ,(cadr head) ,(walk tail n)))
1792                              (else
1793                               `(##sys#cons
1794                                 (##sys#cons (##core#quote ,%unquote-splicing)
1795                                             ,(walk (cdr head) (fx- n 1)) )
1796                                 ,(walk tail n)))))
1797		       (else
1798			`(##sys#cons ,(walk head n) ,(walk tail n)) ) ) ) ) ) )
1799      (define (simplify x)
1800	(cond ((chicken.syntax#match-expression x '(##sys#cons a (##core#quote ())) '(a))
1801	       => (lambda (env) (simplify `(##sys#list ,(cdr (assq 'a env))))) )
1802	      ((chicken.syntax#match-expression x '(##sys#cons a (##sys#list . b)) '(a b))
1803	       => (lambda (env)
1804		    (let ((bxs (assq 'b env)))
1805		      (if (fx< (length bxs) 32)
1806			  (simplify `(##sys#list ,(cdr (assq 'a env))
1807						 ,@(cdr bxs) ) )
1808			  x) ) ) )
1809	      ((chicken.syntax#match-expression x '(##sys#append a (##core#quote ())) '(a))
1810	       => (lambda (env) (cdr (assq 'a env))) )
1811	      (else x) ) )
1812      (##sys#check-syntax 'quasiquote form '(_ _))
1813      (walk (cadr form) 0) ) ) ) )
1814
1815(##sys#extend-macro-environment
1816 'delay
1817 '()
1818 (##sys#er-transformer
1819  (lambda (form r c)
1820    (##sys#check-syntax 'delay form '(_ _))
1821    `(,(r 'delay-force)
1822      (##sys#make-promise
1823       (##sys#call-with-values (##core#lambda () ,(cadr form)) ##sys#list))))))
1824
1825(##sys#extend-macro-environment
1826 'syntax-error
1827 '()
1828 (##sys#er-transformer
1829  (lambda (form r c)
1830    (##sys#check-syntax 'syntax-error form '(_ string . #(_ 0)))
1831    (apply ##sys#syntax-error (cadr form) (cddr form)))))
1832
1833;;; syntax-rules
1834
1835(include "synrules.scm")
1836
1837(macro-subset me0)))
1838
1839;;; the base macro environment (the old "scheme", essentially)
1840;;; TODO: Remove this
1841
1842(define ##sys#default-macro-environment
1843  (fixup-macro-environment (##sys#macro-environment)))
1844
1845(define ##sys#meta-macro-environment (make-parameter (##sys#macro-environment)))
1846
1847;; register features
1848
1849(register-feature! 'srfi-0 'srfi-46 'srfi-61 'srfi-87)
Trap