#lang racket/base
(require (for-syntax racket/base) racket/stxparam racket/splicing)
(provide splicing-syntax-parameterize
         define-syntax-parameters
         define-language-variables
         define-language-variable
         inject-language-variables
         (rename-out [br:define-syntax-parameter define-syntax-parameter]))

(define-syntax (br:define-syntax-parameter stx)
  (syntax-case stx ()
    [(_ ID STX) #'(define-syntax-parameter ID STX)]
    [(_ [ID VAL]) #'(define-syntax-parameter ID (λ (stx) #'VAL))]
    [(_ ID) #'(define-syntax-parameter ID
                (λ (stx) (raise-syntax-error (syntax-e stx) "parameter not set")))]))

(define-syntax-rule (define-syntax-parameters ID ...)
  (begin (br:define-syntax-parameter ID) ...))

(define-syntax-rule (define-language-variable ID VAL)
  (br:define-syntax-parameter [ID VAL]))

(define-syntax-rule (define-language-variables [ID VAL] ...)
  (begin (define-language-variable ID VAL) ...))

(define-syntax (inject-language-variables stx)
  (syntax-case stx ()
    [(_ (VAR-PARAM ...) LANG-CODE ...)
     (with-syntax ([(HOLDS-ORIG-PARAM-VALUE ...) (generate-temporaries #'(VAR-PARAM ...))]
                   [(INTERNAL-NAME ...) (generate-temporaries #'(VAR-PARAM ...))])
       ;; need to use splicing expressions in a module-begin to compose with requires etc. that might be in lang code
       #'(splicing-let ([HOLDS-ORIG-PARAM-VALUE VAR-PARAM] ...)
           (splicing-syntax-parameterize 
               ([VAR-PARAM (make-rename-transformer #'INTERNAL-NAME)] ...)
             (define INTERNAL-NAME HOLDS-ORIG-PARAM-VALUE) ...
             (provide (rename-out [INTERNAL-NAME VAR-PARAM] ...))
             LANG-CODE ...)))]))