#lang scheme/base
(require "../../base.ss")
(require "struct.ss")
(define-struct syntax-info
(id constructor transformer)
#:transparent)
(define make-syntax-hash
make-hasheq)
(define (syntax-hash? val)
(and (hash? val)
(hash-eq? val)))
(define (syntax-hash-ref hash id)
(let ([id (syntax->datum id)])
(hash-ref hash id (cut error "sql ~a: form not found" id))))
(define (syntax-hash-add! hash id constructor min-arity max-arity)
(let ([id (syntax->datum id)]
[raise-arity-error (lambda (stx)
(raise-syntax-error
#f
(cond [(equal? min-arity max-arity)
(format "sql ~a expects ~a arguments" id min-arity)]
[(not max-arity)
(format "sql ~a expects ~a or more arguments" id min-arity)]
[else
(format "sql ~a expects ~a to ~a arguments" id min-arity max-arity)])
stx))]
[transformer (lambda (stx expand-arg)
(syntax-case stx ()
[(_ arg ...)
(let* ([args (syntax->list #'(arg ...))]
[arity (length args)])
(cond [(< arity min-arity) (raise-arity-error stx)]
[(and max-arity (> arity max-arity)) (raise-arity-error stx)]
[else (with-syntax ([make constructor])
#`(make #,@(map expand-arg args)))]))]))])
(hash-set! hash id (make-syntax-info id constructor transformer))))
(define (syntax-hash-expand hash stx expand-arg)
(syntax-case stx ()
[(_ id arg ...)
((syntax-info-transformer (syntax-hash-ref hash #'id)) stx expand-arg)]))
(provide/contract
[struct syntax-info ([id symbol?]
[constructor syntax?]
[transformer (-> syntax? procedure? syntax?)])]
[make-syntax-hash (-> syntax-hash?)]
[syntax-hash? (-> any/c boolean?)]
[syntax-hash-ref (-> syntax-hash? identifier? syntax-info?)]
[syntax-hash-add! (-> syntax-hash?
identifier?
identifier?
natural-number/c
(or/c natural-number/c #f)
void?)]
[syntax-hash-expand (-> syntax-hash?
identifier?
(-> syntax? syntax?)
syntax?)])