Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions default-recommendations/match-shortcuts-test.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ test: "match patterns using ? with a lambda cannot be simplified when under elli
[_ 'no-match]))
------------------------------


test: "match patterns using ? with a commented lambda can be simplified with #:when clauses"
------------------------------
(define (foo x)
Expand Down Expand Up @@ -198,3 +199,102 @@ test: "match patterns using ? with a commented lambda can be simplified with #:w
(foo 100)
------------------------------


test: "match patterns with if conditionals can be simplified using #:when clauses"
------------------------------
(define (f pt)
(match pt
[(list x y)
(if (> x y)
(list y x)
pt)]
[(list) '()]))
------------------------------
------------------------------
(define (f pt)
(match pt
[(list x y)
#:when (> x y)
(list y x)]
[(list x y) pt]
[(list) '()]))
------------------------------


test: "match patterns with cond conditionals can be simplified using #:when clauses"
------------------------------
(define (f pt)
(match pt
[(list x y)
(cond
[(> x y) (list y x)]
[else pt])]
[(list) '()]))
------------------------------
------------------------------
(define (f pt)
(match pt
[(list x y)
#:when (> x y)
(list y x)]
[(list x y) pt]
[(list) '()]))
------------------------------


test: "match patterns with multi-body cond conditionals can be simplified using #:when clauses"
------------------------------
(define (f pt)
(match pt
[(list x y)
(cond
[(> x y)
(displayln "true case")
(list y x)]
[else
(displayln "false case")
pt])]
[(list) '()]))
------------------------------
------------------------------
(define (f pt)
(match pt
[(list x y)
#:when (> x y)
(displayln "true case")
(list y x)]
[(list x y)
(displayln "false case")
pt]
[(list) '()]))
------------------------------


test: "single-clause match with if conditional should be refactored to match-define instead of #:when"
------------------------------
(define (f pt)
(match pt
[(list x y)
(if (> x y)
(list y x)
pt)]))
------------------------------
------------------------------
(define (f pt)
(match-define (list x y) pt)
(if (> x y)
(list y x)
pt))
------------------------------


test: "match with if conditional and long pattern should not be refactored to use #:when"
------------------------------
(define (f data)
(match data
[(list x y _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _)
(if (> x y)
(list y x)
data)]
[_ 'no-match]))
------------------------------
39 changes: 38 additions & 1 deletion default-recommendations/match-shortcuts.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
resyntax/base
resyntax/default-recommendations/private/lambda-by-any-name
resyntax/default-recommendations/private/syntax-identifier-sets
resyntax/default-recommendations/private/syntax-lines
resyntax/private/syntax-traversal
syntax/parse
syntax/strip-context)
Expand Down Expand Up @@ -156,6 +157,42 @@
clause-after ...))


(define-syntax-class conditional-body
#:description "conditional expression in match clause body"
#:attributes (condition [then-expr 1] [else-expr 1])
#:literals (if cond else)
(pattern (if condition only-then-expr only-else-expr)
#:attr [then-expr 1] (list (attribute only-then-expr))
#:attr [else-expr 1] (list (attribute only-else-expr)))
(pattern (cond [condition then-expr ...] [else else-expr ...])))


(define-refactoring-rule match-conditional-to-when
#:description "This conditional in a `match` clause can be simplified using `#:when`."
#:literals (match)

(match subject
clause-before ...
(~and [pattern conditional:conditional-body] clause-to-replace)
clause-after ...+)

#:when (positive? (+ (length (attribute clause-before)) (length (attribute clause-after))))

; Duplicating a long or complex match pattern isn't worth the reduction in nesting from
; refactoring the code to use #:when, so we don't bother if the pattern is multiple lines or if
; it's a fairly long line.
#:when (oneline-syntax? (attribute pattern))
#:when (<= (syntax-span (attribute pattern)) 60)

(match subject
clause-before ...
(~@ . (~splicing-replacement ([pattern #:when conditional.condition conditional.then-expr ...]
[pattern conditional.else-expr ...])
#:original pattern))
clause-after ...))


(define-refactoring-suite match-shortcuts
#:rules (predicate-pattern-with-lambda-to-when
#:rules (match-conditional-to-when
predicate-pattern-with-lambda-to-when
single-clause-match-to-match-define))