195 lines
6.7 KiB
Racket
195 lines
6.7 KiB
Racket
#lang racket/base
|
|
(require racket/list
|
|
racket/match
|
|
racket/stxparam
|
|
net/url
|
|
web-server/dispatchers/dispatch
|
|
web-server/dispatch/http-expanders
|
|
web-server/dispatch/bidi-match
|
|
(for-syntax racket/base
|
|
syntax/parse
|
|
web-server/dispatch/pattern))
|
|
|
|
(define (default-else req)
|
|
(next-dispatcher))
|
|
|
|
(begin-for-syntax
|
|
(define default-method #'(or #f "get")))
|
|
|
|
(define (string-list->url strlist)
|
|
(url->string
|
|
(make-url #f #f #f #f #t
|
|
(if (empty? strlist)
|
|
(list (make-path/param "" empty))
|
|
(map (lambda (s) (make-path/param s empty))
|
|
strlist))
|
|
empty #f)))
|
|
|
|
(define-syntax (dispatch-case stx)
|
|
(syntax-parse
|
|
stx #:literals (else)
|
|
[(_ [(path-pat ...)
|
|
(~optional (~seq #:method method)
|
|
#:defaults ([method default-method]))
|
|
fun]
|
|
...
|
|
[else else-fun])
|
|
#:fail-unless
|
|
(for-each dispatch-pattern?
|
|
(syntax->list #'((path-pat ...) ...)))
|
|
"Not a dispatch pattern"
|
|
(with-syntax
|
|
([((path-pat/id ...) ...)
|
|
(map dispatch-pattern->dispatch-pattern/ids
|
|
(syntax->list #'((path-pat ...) ...)))])
|
|
(with-syntax
|
|
([((path-pat-id ...) ...)
|
|
(map (lambda (pp/is)
|
|
(map (lambda (bs)
|
|
(with-syntax ([(bidi-id arg ... id) bs])
|
|
#'id))
|
|
(filter (lambda (pp/i)
|
|
(syntax-case pp/i ()
|
|
[(bidi-id arg ... id) #t]
|
|
[_ #f]))
|
|
(syntax->list pp/is))))
|
|
(syntax->list #'((path-pat/id ...) ...)))])
|
|
(syntax/loc stx
|
|
(lambda (the-req)
|
|
(syntax-parameterize ([bidi-match-going-in? #t])
|
|
(match the-req
|
|
[(request/url method (url/paths path-pat/id ...))
|
|
(fun the-req path-pat-id ...)]
|
|
...
|
|
[_ (else-fun the-req)]))))))]
|
|
[(dc [(path-pat ...)
|
|
(~optional (~seq #:method method)
|
|
#:defaults ([method default-method]))
|
|
fun]
|
|
...)
|
|
(syntax/loc stx
|
|
(dc [(path-pat ...)
|
|
#:method method
|
|
fun]
|
|
...
|
|
[else default-else]))]))
|
|
|
|
(define-syntax (dispatch-url stx)
|
|
(syntax-parse
|
|
stx
|
|
[(_ [(path-pat ...) fun]
|
|
...)
|
|
(for-each dispatch-pattern?
|
|
(syntax->list #'((path-pat ...) ...)))
|
|
(with-syntax
|
|
([((path-pat/id ...) ...)
|
|
(map dispatch-pattern->dispatch-pattern/ids
|
|
(syntax->list #'((path-pat ...) ...)))])
|
|
(with-syntax
|
|
([((from-path-pat ...) ...)
|
|
(map (lambda (pp/is-pre)
|
|
(define pp/is (datum->syntax pp/is-pre (filter (compose not string-syntax?) (syntax->list pp/is-pre)) pp/is-pre))
|
|
(for/list ([pp/i (dispatch-pattern-not-... pp/is)]
|
|
[next-...? (dispatch-pattern-next-...? pp/is)])
|
|
(with-syntax ([pp pp/i]
|
|
[(bidi-id arg ... id) pp/i])
|
|
(if next-...?
|
|
(syntax/loc pp/i (list pp (... ...)))
|
|
pp/i))))
|
|
(syntax->list #'((path-pat/id ...) ...)))]
|
|
[((from-body ...) ...)
|
|
(map (lambda (pp/is)
|
|
(for/list ([pp/i (dispatch-pattern-not-... pp/is)]
|
|
[next-...? (dispatch-pattern-next-...? pp/is)])
|
|
(with-syntax ([pp pp/i])
|
|
(if (string-syntax? pp/i)
|
|
(syntax/loc pp/i (list pp))
|
|
(with-syntax ([(bidi-id arg ... id) pp/i])
|
|
(if next-...?
|
|
(syntax/loc pp/i id)
|
|
(syntax/loc pp/i (list id))))))))
|
|
(syntax->list #'((path-pat/id ...) ...)))])
|
|
(syntax/loc stx
|
|
(syntax-parameterize ([bidi-match-going-in? #f])
|
|
(match-lambda*
|
|
[(list (? (lambda (x) (eq? x fun))) from-path-pat ...)
|
|
(string-list->url (append from-body ...))]
|
|
...)))))]))
|
|
|
|
(define-syntax (dispatch-rules stx)
|
|
(syntax-parse
|
|
stx #:literals (else)
|
|
[(_ [(path-pat ...)
|
|
(~optional (~seq #:method method)
|
|
#:defaults ([method default-method]))
|
|
fun]
|
|
...
|
|
[else else-fun])
|
|
(for-each dispatch-pattern?
|
|
(syntax->list #'((path-pat ...) ...)))
|
|
(syntax/loc stx
|
|
(values
|
|
(dispatch-case [(path-pat ...)
|
|
#:method method
|
|
fun]
|
|
...
|
|
[else else-fun])
|
|
(dispatch-url [(path-pat ...) fun]
|
|
...)))]
|
|
[(dr [(path-pat ...)
|
|
(~optional (~seq #:method method)
|
|
#:defaults ([method default-method]))
|
|
fun]
|
|
...)
|
|
(syntax/loc stx
|
|
(dr [(path-pat ...)
|
|
#:method method
|
|
fun]
|
|
...
|
|
[else default-else]))]))
|
|
|
|
(define (dispatch-succ . _) #t)
|
|
(define (dispatch-fail . _) #f)
|
|
|
|
(define-syntax (dispatch-rules+applies stx)
|
|
(syntax-parse
|
|
stx #:literals (else)
|
|
[(_
|
|
[pat
|
|
(~optional (~seq #:method method)
|
|
#:defaults ([method default-method]))
|
|
fun]
|
|
...
|
|
[else else-fun])
|
|
(syntax/loc stx
|
|
(let-values ([(dispatch url)
|
|
(dispatch-rules
|
|
[pat #:method method fun]
|
|
...
|
|
[else else-fun])]
|
|
[(applies?)
|
|
(λ (req) #t)])
|
|
(values dispatch url applies?)))]
|
|
[(_
|
|
[pat
|
|
(~optional (~seq #:method method)
|
|
#:defaults ([method default-method]))
|
|
fun]
|
|
...)
|
|
(syntax/loc stx
|
|
(let-values ([(dispatch url)
|
|
(dispatch-rules
|
|
[pat #:method method fun]
|
|
...)]
|
|
[(applies?)
|
|
(dispatch-case
|
|
[pat #:method method dispatch-succ]
|
|
...
|
|
[else dispatch-fail])])
|
|
(values dispatch url applies?)))]))
|
|
|
|
(provide dispatch-case
|
|
dispatch-url
|
|
dispatch-rules
|
|
dispatch-rules+applies)
|