|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
#lang racket/base
|
|
|
|
|
(require "syntax-flatten.rkt")
|
|
|
|
|
(provide all-...-follow-wildcards generate-literals)
|
|
|
|
|
(require "syntax-flatten.rkt" racket/list)
|
|
|
|
|
(provide all-...-follow-wildcards generate-literals generate-bound-and-unbound-literals)
|
|
|
|
|
|
|
|
|
|
(define (literal-identifier? pat-datum)
|
|
|
|
|
(and (symbol? pat-datum)
|
|
|
|
@ -19,36 +19,45 @@
|
|
|
|
|
(for*/list ([pat-arg (in-list (syntax-flatten pats))]
|
|
|
|
|
[pat-datum (in-value (syntax->datum pat-arg))]
|
|
|
|
|
#:when (literal-identifier? pat-datum))
|
|
|
|
|
pat-arg))
|
|
|
|
|
pat-arg))
|
|
|
|
|
|
|
|
|
|
(define (generate-bound-and-unbound-literals pats #:treat-as-bound [bound-id #f])
|
|
|
|
|
(define-values (bound-literals unbound-literals)
|
|
|
|
|
(partition identifier-binding (for/list ([pat (in-list (generate-literals pats))]
|
|
|
|
|
#:unless (and bound-id (bound-identifier=? pat bound-id)))
|
|
|
|
|
pat)))
|
|
|
|
|
;; return as list of two lists so it's easy to match them in syntax pattern
|
|
|
|
|
(list (if bound-id (cons bound-id bound-literals) bound-literals)
|
|
|
|
|
unbound-literals))
|
|
|
|
|
|
|
|
|
|
(define (all-...-follow-wildcards pats)
|
|
|
|
|
(define prev-datum (box #f))
|
|
|
|
|
(and
|
|
|
|
|
(for*/and ([pat-arg (in-list (syntax-flatten pats))]
|
|
|
|
|
[pat-datum (in-value (syntax->datum pat-arg))])
|
|
|
|
|
;; OK if there's no previous datum,
|
|
|
|
|
(and
|
|
|
|
|
(when (eq? pat-datum '...)
|
|
|
|
|
(wildcard-identifier? (unbox prev-datum)))
|
|
|
|
|
(set-box! prev-datum pat-datum)))
|
|
|
|
|
#true))
|
|
|
|
|
(for*/and ([pat-arg (in-list (syntax-flatten pats))]
|
|
|
|
|
[pat-datum (in-value (syntax->datum pat-arg))])
|
|
|
|
|
;; OK if there's no previous datum,
|
|
|
|
|
(and
|
|
|
|
|
(when (eq? pat-datum '...)
|
|
|
|
|
(wildcard-identifier? (unbox prev-datum)))
|
|
|
|
|
(set-box! prev-datum pat-datum)))
|
|
|
|
|
#true))
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|
(require rackunit)
|
|
|
|
|
(check-equal? (map syntax->datum (generate-literals #'(foo 42 BAR _ (... ...) bar <=> 3Bar 3bar))) '(foo bar <=> 3Bar 3bar))
|
|
|
|
|
|
|
|
|
|
(test-case "wildcard-identifier?"
|
|
|
|
|
(check-true (wildcard-identifier? 'FOO))
|
|
|
|
|
(check-true (wildcard-identifier? 'TOPPING))
|
|
|
|
|
(check-true (wildcard-identifier? 'FOO))
|
|
|
|
|
(check-true (wildcard-identifier? 'TOPPING))
|
|
|
|
|
|
|
|
|
|
(check-false (wildcard-identifier? 'piZZa))
|
|
|
|
|
(check-false (wildcard-identifier? 'please)))
|
|
|
|
|
(check-false (wildcard-identifier? 'piZZa))
|
|
|
|
|
(check-false (wildcard-identifier? 'please)))
|
|
|
|
|
|
|
|
|
|
(test-case "all-...-follow-wildcards"
|
|
|
|
|
(check-true (all-...-follow-wildcards #'()))
|
|
|
|
|
(check-true (all-...-follow-wildcards (datum->syntax #f '(a b))))
|
|
|
|
|
(check-true (all-...-follow-wildcards (datum->syntax #f '(a b C ...))))
|
|
|
|
|
(check-true (all-...-follow-wildcards #'()))
|
|
|
|
|
(check-true (all-...-follow-wildcards (datum->syntax #f '(a b))))
|
|
|
|
|
(check-true (all-...-follow-wildcards (datum->syntax #f '(a b C ...))))
|
|
|
|
|
|
|
|
|
|
(check-false (all-...-follow-wildcards (datum->syntax #f '(...))))
|
|
|
|
|
(check-false (all-...-follow-wildcards (datum->syntax #f '(a ...))))
|
|
|
|
|
(check-false (all-...-follow-wildcards (datum->syntax #f '(A ... b ...))))))
|
|
|
|
|
(check-false (all-...-follow-wildcards (datum->syntax #f '(...))))
|
|
|
|
|
(check-false (all-...-follow-wildcards (datum->syntax #f '(a ...))))
|
|
|
|
|
(check-false (all-...-follow-wildcards (datum->syntax #f '(A ... b ...))))))
|
|
|
|
|