Make captures able to express and-patterns.
This commit is contained in:
parent
3bd9b338b5
commit
6649689b8f
|
@ -18,7 +18,7 @@
|
||||||
?
|
?
|
||||||
wildcard?
|
wildcard?
|
||||||
?!
|
?!
|
||||||
capture?
|
(struct-out capture)
|
||||||
pretty-print-matcher
|
pretty-print-matcher
|
||||||
matcher-key-set
|
matcher-key-set
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
(define (event-handler descriptor)
|
(define (event-handler descriptor)
|
||||||
(handle-evt descriptor (lambda vs (send (event descriptor vs)))))
|
(handle-evt descriptor (lambda vs (send (event descriptor vs)))))
|
||||||
|
|
||||||
(define event-projection (compile-gestalt-projection (event ?! ?)))
|
(define event-projection (compile-gestalt-projection (event (?!) ?)))
|
||||||
|
|
||||||
(define (extract-active-events gestalt)
|
(define (extract-active-events gestalt)
|
||||||
(define es (matcher-key-set (gestalt-project gestalt 0 0 #f event-projection)))
|
(define es (matcher-key-set (gestalt-project gestalt 0 0 #f event-projection)))
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
(provide ?
|
(provide ?
|
||||||
wildcard?
|
wildcard?
|
||||||
?!
|
?!
|
||||||
capture?
|
(struct-out capture)
|
||||||
pattern->matcher
|
pattern->matcher
|
||||||
matcher? ;; expensive; see implementation
|
matcher? ;; expensive; see implementation
|
||||||
matcher-empty
|
matcher-empty
|
||||||
|
@ -54,7 +54,15 @@
|
||||||
(define-singleton-struct ? wildcard "★") ;; alternative printing: ¿
|
(define-singleton-struct ? wildcard "★") ;; alternative printing: ¿
|
||||||
|
|
||||||
;; When projecting a matcher, the capturing wildcard can be used.
|
;; When projecting a matcher, the capturing wildcard can be used.
|
||||||
(define-singleton-struct ?! capture "‽")
|
(struct capture (pattern) #:transparent)
|
||||||
|
|
||||||
|
;; Capture with default of wildcard.
|
||||||
|
(define (?! [pattern ?]) (capture pattern))
|
||||||
|
|
||||||
|
;; Compiled projections include start-of-capture and end-of-capture
|
||||||
|
;; elements.
|
||||||
|
(define-singleton-struct SOC start-of-capture "{{")
|
||||||
|
(define-singleton-struct EOC end-of-capture "}}")
|
||||||
|
|
||||||
;; A Matcher is either
|
;; A Matcher is either
|
||||||
;; - #f, indicating no further matches possible
|
;; - #f, indicating no further matches possible
|
||||||
|
@ -408,7 +416,7 @@
|
||||||
;; is how ?! is treated.
|
;; is how ?! is treated.
|
||||||
(let walk ((p p) (acc (cons EOS '())))
|
(let walk ((p p) (acc (cons EOS '())))
|
||||||
(match p
|
(match p
|
||||||
[(== ?!) (cons ?! acc)]
|
[(capture sub) (cons SOC (walk sub (cons EOC acc)))] ;; TODO: enforce non-nesting here
|
||||||
[(== ?) (cons ? acc)]
|
[(== ?) (cons ? acc)]
|
||||||
[(cons p1 p2) (cons SOP (walk p1 (walk p2 (cons EOS acc))))]
|
[(cons p1 p2) (cons SOP (walk p1 (walk p2 (cons EOS acc))))]
|
||||||
[(? vector? v) (cons SOV (vector-foldr walk (cons EOS acc) v))]
|
[(? vector? v) (cons SOV (vector-foldr walk (cons EOS acc) v))]
|
||||||
|
@ -425,82 +433,94 @@
|
||||||
;; The result matches a vector of length equal to the number of captures.
|
;; The result matches a vector of length equal to the number of captures.
|
||||||
;; The project-success function should return #f to signal "no success values".
|
;; The project-success function should return #f to signal "no success values".
|
||||||
(define matcher-project
|
(define matcher-project
|
||||||
;; TODO: skip-nested, capture-nested, and the ? and ?! cases in
|
;; TODO: skip-nested, capture-nested, and various cases in walk all
|
||||||
;; walk-out all share a suspicious amount of code. Refactor it away.
|
;; share a suspicious amount of code. Refactor it away.
|
||||||
(let ()
|
(let ()
|
||||||
(define (skip-nested m k)
|
(define (skip-nested m k)
|
||||||
(match m
|
(match m
|
||||||
[(wildcard-sequence mk) (k mk)]
|
[(wildcard-sequence mk) (k mk)]
|
||||||
[(? hash?)
|
[(? hash?)
|
||||||
(for/fold [(acc (skip-nested (rlookup m ?) k))] [((key mk) (in-hash m))]
|
(for/fold [(acc (skip-nested (rlookup m ?) k))] [((key mk) (in-hash m))]
|
||||||
(if (eq? key ?)
|
(if (eq? key ?)
|
||||||
acc
|
acc
|
||||||
(matcher-union acc (cond
|
(matcher-union acc (cond
|
||||||
[(key-open? key) (skip-nested mk (lambda (mk) (skip-nested mk k)))]
|
[(key-open? key)
|
||||||
[(key-close? key) (k mk)]
|
(skip-nested mk (lambda (mk) (skip-nested mk k)))]
|
||||||
[else (skip-nested mk k)]))))]
|
[(key-close? key) (k mk)]
|
||||||
[_ (matcher-empty)]))
|
[else (skip-nested mk k)]))))]
|
||||||
|
[_ (matcher-empty)]))
|
||||||
|
|
||||||
(define (capture-nested m k)
|
(define (capture-nested m k)
|
||||||
(match m
|
(match m
|
||||||
[(wildcard-sequence mk) (rwildseq (k mk))]
|
[(wildcard-sequence mk) (rwildseq (k mk))]
|
||||||
[(? hash?)
|
[(? hash?)
|
||||||
(for/fold [(acc (rwild (capture-nested (rlookup m ?) k)))] [((key mk) (in-hash m))]
|
(for/fold [(acc (rwild (capture-nested (rlookup m ?) k)))] [((key mk) (in-hash m))]
|
||||||
(if (eq? key ?)
|
(if (eq? key ?)
|
||||||
acc
|
acc
|
||||||
(cond
|
(cond
|
||||||
[(key-open? key)
|
[(key-open? key)
|
||||||
(rupdate acc key (capture-nested mk (lambda (mk) (capture-nested mk k))))]
|
(rupdate acc key (capture-nested mk (lambda (mk) (capture-nested mk k))))]
|
||||||
[(key-close? key) (rupdate acc key (k mk))]
|
[(key-close? key) (rupdate acc key (k mk))]
|
||||||
[else (rupdate acc key (capture-nested mk k))])))]
|
[else (rupdate acc key (capture-nested mk k))])))]
|
||||||
[_ (matcher-empty)]))
|
[_ (matcher-empty)]))
|
||||||
|
|
||||||
(lambda (m spec #:project-success [project-success values])
|
(lambda (m spec #:project-success [project-success values])
|
||||||
(define (walk-out m spec)
|
(define (walk capturing? m spec)
|
||||||
(match spec
|
(match spec
|
||||||
['()
|
['()
|
||||||
|
(when capturing? (error 'matcher-project "Bad specification: unclosed capture"))
|
||||||
(match m
|
(match m
|
||||||
[(success v) (rseq EOS (rseq EOS (rsuccess (project-success v))))]
|
[(success v) (rseq EOS (rseq EOS (rsuccess (project-success v))))]
|
||||||
[_ (matcher-empty)])]
|
[_ (matcher-empty)])]
|
||||||
|
|
||||||
|
[(cons (== EOC) k)
|
||||||
|
(when (not capturing?) (error 'matcher-project "Bad specification: unexpected EOC"))
|
||||||
|
(walk #f m k)]
|
||||||
|
|
||||||
|
[(cons (== SOC) k)
|
||||||
|
(when capturing? (error 'matcher-project "Bad specification: nested capture"))
|
||||||
|
(walk #t m k)]
|
||||||
|
|
||||||
[(cons (== ?) k)
|
[(cons (== ?) k)
|
||||||
(match m
|
(match m
|
||||||
[(wildcard-sequence _) (walk-out m k)]
|
[(wildcard-sequence _)
|
||||||
|
((if capturing? rwild values) (walk capturing? m k))]
|
||||||
[(? hash?)
|
[(? hash?)
|
||||||
(for/fold [(acc (walk-out (rlookup m ?) k))] [((key mk) (in-hash m))]
|
(if capturing?
|
||||||
(if (eq? key ?)
|
(for/fold [(acc (rwild (walk capturing? (rlookup m ?) k)))]
|
||||||
acc
|
[((key mk) (in-hash m))]
|
||||||
(matcher-union acc (cond
|
(if (eq? key ?)
|
||||||
[(key-open? key) (skip-nested mk (lambda (mk) (walk-out mk k)))]
|
acc
|
||||||
[(key-close? key) #f]
|
(cond
|
||||||
[else (walk-out mk k)]))))]
|
[(key-open? key)
|
||||||
[_ (matcher-empty)])]
|
(rupdate acc key (capture-nested mk (lambda (mk)
|
||||||
|
(walk capturing? mk k))))]
|
||||||
[(cons (== ?!) k)
|
[(key-close? key) acc]
|
||||||
(match m
|
[else (rupdate acc key (walk capturing? mk k))])))
|
||||||
[(wildcard-sequence _) (rwild (walk-out m k))]
|
(for/fold [(acc (walk capturing? (rlookup m ?) k))] [((key mk) (in-hash m))]
|
||||||
[(? hash?)
|
(if (eq? key ?)
|
||||||
(for/fold [(acc (rwild (walk-out (rlookup m ?) k)))] [((key mk) (in-hash m))]
|
acc
|
||||||
(if (eq? key ?)
|
(matcher-union acc (cond
|
||||||
acc
|
[(key-open? key)
|
||||||
(cond
|
(skip-nested mk (lambda (mk) (walk capturing? mk k)))]
|
||||||
[(key-open? key)
|
[(key-close? key) #f]
|
||||||
(rupdate acc key (capture-nested mk (lambda (mk) (walk-out mk k))))]
|
[else (walk capturing? mk k)])))))]
|
||||||
[(key-close? key) acc]
|
|
||||||
[else (rupdate acc key (walk-out mk k))])))]
|
|
||||||
[_ (matcher-empty)])]
|
[_ (matcher-empty)])]
|
||||||
|
|
||||||
[(cons sigma k)
|
[(cons sigma k)
|
||||||
(match m
|
((if capturing?
|
||||||
[(wildcard-sequence mk)
|
(lambda (m1) (rseq sigma m1))
|
||||||
(if (key-close? sigma)
|
values)
|
||||||
(walk-out mk k)
|
(match m
|
||||||
(walk-out m k))]
|
[(wildcard-sequence mk)
|
||||||
[(? hash?)
|
(if (key-close? sigma)
|
||||||
(matcher-union (walk-out (rlookup m sigma) k)
|
(walk capturing? mk k)
|
||||||
(walk-out (rlookup m ?) k))]
|
(walk capturing? m k))]
|
||||||
[_ (matcher-empty)])]))
|
[(? hash?)
|
||||||
(rseq SOV (walk-out m spec)))))
|
(matcher-union (walk capturing? (rlookup m sigma) k)
|
||||||
|
(walk capturing? (rlookup m ?) k))]
|
||||||
|
[_ (matcher-empty)]))]))
|
||||||
|
(rseq SOV (walk #f m spec)))))
|
||||||
|
|
||||||
;; Matcher → (Option (Setof Value))
|
;; Matcher → (Option (Setof Value))
|
||||||
;; Multiplies out unions. Returns #f if any dimension of m is infinite.
|
;; Multiplies out unions. Returns #f if any dimension of m is infinite.
|
||||||
|
@ -955,26 +975,26 @@
|
||||||
(module+ test
|
(module+ test
|
||||||
(check-equal? (compile-projection (list 'a 'b))
|
(check-equal? (compile-projection (list 'a 'b))
|
||||||
(list SOP 'a SOP 'b '() EOS EOS EOS))
|
(list SOP 'a SOP 'b '() EOS EOS EOS))
|
||||||
(check-equal? (compile-projection (list 'a ?!))
|
(check-equal? (compile-projection (list 'a (?!)))
|
||||||
(list SOP 'a SOP ?! '() EOS EOS EOS))
|
(list SOP 'a SOP SOC ? EOC '() EOS EOS EOS))
|
||||||
|
|
||||||
(check-equal? (matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
(check-equal? (matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
||||||
(pattern->matcher SB (list 'a 'b)))
|
(pattern->matcher SB (list 'a 'b)))
|
||||||
(compile-projection (list 'a ?!))
|
(compile-projection (list 'a (?!)))
|
||||||
#:project-success (lambda (v) #t))
|
#:project-success (lambda (v) #t))
|
||||||
(matcher-union (pattern->matcher #t (vector 'a))
|
(matcher-union (pattern->matcher #t (vector 'a))
|
||||||
(pattern->matcher #t (vector 'b))))
|
(pattern->matcher #t (vector 'b))))
|
||||||
|
|
||||||
(check-equal? (matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
(check-equal? (matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
||||||
(pattern->matcher SB (list 'a (vector 'b 'c 'd))))
|
(pattern->matcher SB (list 'a (vector 'b 'c 'd))))
|
||||||
(compile-projection (list 'a ?!))
|
(compile-projection (list 'a (?!)))
|
||||||
#:project-success (lambda (v) #t))
|
#:project-success (lambda (v) #t))
|
||||||
(matcher-union (pattern->matcher #t (vector 'a))
|
(matcher-union (pattern->matcher #t (vector 'a))
|
||||||
(pattern->matcher #t (vector (vector 'b 'c 'd)))))
|
(pattern->matcher #t (vector (vector 'b 'c 'd)))))
|
||||||
|
|
||||||
(check-equal? (matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
(check-equal? (matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
||||||
(pattern->matcher SB (list 'a (vector 'b ? 'd))))
|
(pattern->matcher SB (list 'a (vector 'b ? 'd))))
|
||||||
(compile-projection (list 'a ?!))
|
(compile-projection (list 'a (?!)))
|
||||||
#:project-success (lambda (v) #t))
|
#:project-success (lambda (v) #t))
|
||||||
(matcher-union (pattern->matcher #t (vector 'a))
|
(matcher-union (pattern->matcher #t (vector 'a))
|
||||||
(pattern->matcher #t (vector (vector 'b ? 'd)))))
|
(pattern->matcher #t (vector (vector 'b ? 'd)))))
|
||||||
|
@ -982,35 +1002,94 @@
|
||||||
(check-equal? (matcher-key-set
|
(check-equal? (matcher-key-set
|
||||||
(matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
(matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
||||||
(pattern->matcher SB (list 'a 'b)))
|
(pattern->matcher SB (list 'a 'b)))
|
||||||
(compile-projection (list 'a ?!))
|
(compile-projection (list 'a (?!)))
|
||||||
#:project-success (lambda (v) #t)))
|
#:project-success (lambda (v) #t)))
|
||||||
(set '#(a) '#(b)))
|
(set '#(a) '#(b)))
|
||||||
|
|
||||||
(check-equal? (matcher-key-set
|
(check-equal? (matcher-key-set
|
||||||
(matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
(matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
||||||
(pattern->matcher SB (list 'a (vector 'b 'c 'd))))
|
(pattern->matcher SB (list 'a (vector 'b 'c 'd))))
|
||||||
(compile-projection (list 'a ?!))
|
(compile-projection (list 'a (?!)))
|
||||||
#:project-success (lambda (v) #t)))
|
#:project-success (lambda (v) #t)))
|
||||||
(set '#(a) '#(#(b c d))))
|
(set '#(a) '#(#(b c d))))
|
||||||
|
|
||||||
(check-equal? (matcher-key-set
|
(check-equal? (matcher-key-set
|
||||||
(matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
(matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
||||||
(pattern->matcher SB (list 'a (vector 'b ? 'd))))
|
(pattern->matcher SB (list 'a (vector 'b ? 'd))))
|
||||||
(compile-projection (list 'a ?!))
|
(compile-projection (list 'a (?!)))
|
||||||
#:project-success (lambda (v) #t)))
|
#:project-success (lambda (v) #t)))
|
||||||
#f)
|
#f)
|
||||||
|
|
||||||
|
(check-equal? (matcher-key-set
|
||||||
|
(matcher-project (matcher-union (pattern->matcher SA (list 'a 'a))
|
||||||
|
(pattern->matcher SB (list 'a (vector 'b ? 'd))))
|
||||||
|
(compile-projection (list 'a (?! 'a)))
|
||||||
|
#:project-success (lambda (v) #t)))
|
||||||
|
(set '#(a)))
|
||||||
|
|
||||||
(check-equal? (matcher-project (matcher-union (pattern->matcher SA (cons 1 2))
|
(check-equal? (matcher-project (matcher-union (pattern->matcher SA (cons 1 2))
|
||||||
(pattern->matcher SB (cons 3 4)))
|
(pattern->matcher SB (cons 3 4)))
|
||||||
(compile-projection (cons ?! ?!))
|
(compile-projection (cons (?!) (?!)))
|
||||||
#:project-success (lambda (v) #t))
|
#:project-success (lambda (v) #t))
|
||||||
(matcher-union (pattern->matcher #t (vector 1 2))
|
(matcher-union (pattern->matcher #t (vector 1 2))
|
||||||
(pattern->matcher #t (vector 3 4))))
|
(pattern->matcher #t (vector 3 4))))
|
||||||
|
|
||||||
|
(check-equal? (matcher-project (foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher SA (cons 1 2))
|
||||||
|
(pattern->matcher SB (cons 1 4))
|
||||||
|
(pattern->matcher SC (cons 3 4))))
|
||||||
|
(compile-projection (cons (?!) (?!)))
|
||||||
|
#:project-success (lambda (v) #t))
|
||||||
|
(foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher #t (vector 1 2))
|
||||||
|
(pattern->matcher #t (vector 1 4))
|
||||||
|
(pattern->matcher #t (vector 3 4)))))
|
||||||
|
|
||||||
|
(check-equal? (matcher-project (foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher SA (cons 1 2))
|
||||||
|
(pattern->matcher SB (cons 1 4))
|
||||||
|
(pattern->matcher SC (cons 3 4))))
|
||||||
|
(compile-projection (?! (cons ? ?)))
|
||||||
|
#:project-success (lambda (v) #t))
|
||||||
|
(foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher #t (vector (cons 1 2)))
|
||||||
|
(pattern->matcher #t (vector (cons 1 4)))
|
||||||
|
(pattern->matcher #t (vector (cons 3 4))))))
|
||||||
|
|
||||||
|
(check-equal? (matcher-project (foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher SA (cons 1 2))
|
||||||
|
(pattern->matcher SB (cons 1 4))
|
||||||
|
(pattern->matcher SC (cons 3 4))))
|
||||||
|
(compile-projection (?! (cons 1 ?)))
|
||||||
|
#:project-success (lambda (v) #t))
|
||||||
|
(foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher #t (vector (cons 1 2)))
|
||||||
|
(pattern->matcher #t (vector (cons 1 4))))))
|
||||||
|
|
||||||
|
(check-equal? (matcher-project (foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher SA (cons 1 2))
|
||||||
|
(pattern->matcher SB (cons 1 4))
|
||||||
|
(pattern->matcher SC (cons 3 4))))
|
||||||
|
(compile-projection (cons (?! 1) (?!)))
|
||||||
|
#:project-success (lambda (v) #t))
|
||||||
|
(foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher #t (vector 1 2))
|
||||||
|
(pattern->matcher #t (vector 1 4)))))
|
||||||
|
|
||||||
|
(check-equal? (matcher-project (foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher SA (cons 1 2))
|
||||||
|
(pattern->matcher SB (cons 1 4))
|
||||||
|
(pattern->matcher SC (cons 3 4))))
|
||||||
|
(compile-projection (cons (?!) (?! 4)))
|
||||||
|
#:project-success (lambda (v) #t))
|
||||||
|
(foldr matcher-union (matcher-empty)
|
||||||
|
(list (pattern->matcher #t (vector 1 4))
|
||||||
|
(pattern->matcher #t (vector 3 4)))))
|
||||||
|
|
||||||
(check-equal? (matcher-key-set
|
(check-equal? (matcher-key-set
|
||||||
(matcher-project (matcher-union (pattern->matcher SA (cons 1 2))
|
(matcher-project (matcher-union (pattern->matcher SA (cons 1 2))
|
||||||
(pattern->matcher SB (cons 3 4)))
|
(pattern->matcher SB (cons 3 4)))
|
||||||
(compile-projection (cons ?! ?!))
|
(compile-projection (cons (?!) (?!)))
|
||||||
#:project-success (lambda (v) #t)))
|
#:project-success (lambda (v) #t)))
|
||||||
(set '#(1 2) '#(3 4)))
|
(set '#(1 2) '#(3 4)))
|
||||||
)
|
)
|
Loading…
Reference in New Issue