#lang racket/base
(require (for-syntax racket/base
                     syntax/kerncase
                     syntax/context))

(provide finish-syntax-set)

;; Used in the expansion of `define-syntax-set' from "etc.rkt"
(define-syntax (finish-syntax-set stx)
  (syntax-case stx ()
    [(_ stx)
     (let ([stx (syntax stx)])
       (syntax-case stx ()
         [(_ (id ...) defn ...)
          ;; The ids have already been checked --------------------
          (let ([ids (syntax->list (syntax (id ...)))])
            (let ([internal-ids (map (lambda (id)
                                       (datum->syntax
                                        id
                                        (string->symbol (format "~a/proc" (syntax-e id)))
                                        id))
                                     ids)]
                  [expand-context (generate-expand-context)])
              ;; Check defns (requires expand) ---------
              (let* ([defns (let loop ([defns (syntax->list (syntax (defn ...)))])
                              (apply 
                               append
                               (map
                                (lambda (defn)
                                  (let ([defn (local-expand
                                               defn
                                               expand-context
                                               (kernel-form-identifier-list))])
                                    (syntax-case defn (define-values define-syntaxes begin)
                                      [(define-values (id ...) expr)
                                       (andmap identifier? (syntax->list (syntax (id ...))))
                                       (list defn)]
                                      [(define-values . _)
                                       (raise-syntax-error
                                        #f
                                        "bad definition"
                                        stx
                                        defn)]
                                      [(define-syntaxes (id ...) expr)
                                       (andmap identifier? (syntax->list (syntax (id ...))))
                                       (list defn)]
                                      [(define-syntaxes . _)
                                       (raise-syntax-error
                                        #f
                                        "bad definition"
                                        stx
                                        defn)]
                                      [(begin defn ...)
                                       (loop (syntax->list (syntax (defn ...))))]
                                      [(begin . _)
                                       (raise-syntax-error
                                        #f
                                        "bad `begin'"
                                        stx
                                        defn)]
                                      [else
                                       (raise-syntax-error
                                        #f
                                        "not a definition"
                                        stx
                                        defn)])))
                                defns)))]
                     
                     [def-ids (apply append (map (lambda (defn)
                                                   (syntax-case defn ()
                                                     [(_ (id ...) expr)
                                                      (syntax->list (syntax (id ...)))]))
                                                 defns))]
                     [val-ids (apply append (map (lambda (defn)
                                                   (syntax-case defn (define-values)
                                                     [(define-values (id ...) expr)
                                                      (syntax->list (syntax (id ...)))]
                                                     [_else null]))
                                                 defns))])
                (let ([dup (check-duplicate-identifier def-ids)])
                  (when dup
                    (raise-syntax-error
                     #f
                     "duplicate defined identifier"
                     stx
                     dup)))
                ;; Check that declared are defined ---------
                (for-each (lambda (id)
                            (unless (check-duplicate-identifier (cons id val-ids))
                              (raise-syntax-error
                               #f
                               "expected identifier is not defined"
                               stx
                               id)))
                          internal-ids)
                ;; Produce result ------------------------------
                (with-syntax ([(defn ...) defns]
                              [(internal-id ...) internal-ids])
                  (syntax/loc stx
                    (let ()
                      defn ...
                      (values internal-id ...)))))))]))]))
