; Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees. See file COPYING.

; package -> template

(define (compile-package package)
  (let ((template (compile-forms ((get-optimizer
				     (package-optimizer-names package))
				    (expand-package package)
				    package)
				 (package-name package))))
    (link! template package #t)		; #t means warn about undefined variables
    template))

; First we map down the FORMS+FILES, adding the filenames to ENV and
; scanning the forms.  Then we walk down the list of scanned forms and
; expand all the macros.
;
; All of the reversing in the second step makes it so that we process the
; forms in there original order, to keep any errors or warnings in as
; appropriate an order as possible, and then return them in their original
; order.

(define (expand-package package)
  (let ((env (package->environment package)))
    (call-with-values
     (lambda ()
       (package-source package))
     (lambda (forms+files transforms needs-primitives?)
       (for-each (lambda (name)
		   (define-usual-transform env name))
		 transforms)
       (let ((scanned+envs
	      (map (lambda (forms+file)
		     (let ((filename (car forms+file))
			   (forms (cdr forms+file)))
		       (let ((env (bind-source-file-name filename env)))
			 (cons env
			       (scan-forms forms env)))))
		   (if needs-primitives?
		       `((#f . ,(define-primitives env))
			 . ,forms+files)
		       forms+files))))
	 (reverse 
	  (fold (lambda (scanned+env expanded)
		  (let ((env (car scanned+env)))
		    (fold (lambda (form expanded)
			    (cons (delay (expand-scanned-form form env))
				  expanded))
			  (cdr scanned+env)
			  expanded)))
		scanned+envs
		'())))))))
		       
; NAME is the name of one of the usual Scheme macros (AND, OR, COND, and so
; forth).  This adds the appropriate transform to ENV.

(define (define-usual-transform env name)
  (environment-define! env
		       name
		       syntax-type
		       (make-transform (usual-transform name)
				       (extract-package-from-environment env)
				       syntax-type
				       `(usual-transform ',name)
				       name)))

; This adds definitions of all operators to ENV and returns a list of forms
; that define the closed-compiled versions of those operators that have such.

(define (define-primitives env)
  (let ((procs '()))
    (table-walk (lambda (name op)
		  (let ((type (operator-type op)))
		    (if (not (eq? (operator-type op) 'leaf))
			(environment-define! env name (operator-type op) op))))
		operators-table)
    (walk-primops (lambda (name type primop)
		    (environment-define! env name type primop)
		    (set! procs
			  (cons (make-define-primitive-node name env)
				procs))))
    procs))

(define (make-define-primitive-node name env)
  (make-node operator/define
	     `(define ,(expand name env)
		,(make-node operator/primitive-procedure
			    `(primitive-procedure ,name)))))

;----------------
(define operator/define	             (get-operator 'define syntax-type))
(define operator/primitive-procedure (get-operator 'primitive-procedure syntax-type))