Skip to content

Commit

Permalink
Tweak refactoring rule definition macros
Browse files Browse the repository at this point in the history
The new API no longer requires brackets.
  • Loading branch information
jackfirth committed Sep 2, 2024
1 parent 2e88986 commit 8e4b387
Show file tree
Hide file tree
Showing 23 changed files with 460 additions and 449 deletions.
46 changes: 22 additions & 24 deletions default-recommendations/boolean-shortcuts.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -26,46 +26,44 @@

(define-refactoring-rule nested-or-to-flat-or
#:description "Nested `or` expressions can be flattened into a single, equivalent `or` expression."
[or-tree
#:declare or-tree (syntax-tree #'or)
;; Restricted to single-line expressions for now because the syntax-tree operations don't preserve
;; any formatting between adjacent leaves.
#:when (oneline-syntax? #'or-tree)
#:when (>= (attribute or-tree.rank) 2)
(or or-tree.leaf ...)])
(~var or-tree (syntax-tree #'or))
;; Restricted to single-line expressions for now because the syntax-tree operations don't preserve
;; any formatting between adjacent leaves.
#:when (oneline-syntax? #'or-tree)
#:when (>= (attribute or-tree.rank) 2)
(or or-tree.leaf ...))


(define-refactoring-rule nested-and-to-flat-and
#:description
"Nested `and` expressions can be flattened into a single, equivalent `and` expression."
[and-tree
#:declare and-tree (syntax-tree #'and)
;; Restricted to single-line expressions for now because the syntax-tree operations don't preserve
;; any formatting between adjacent leaves.
#:when (oneline-syntax? #'and-tree)
#:when (>= (attribute and-tree.rank) 2)
(and and-tree.leaf ...)])
(~var and-tree (syntax-tree #'and))
;; Restricted to single-line expressions for now because the syntax-tree operations don't preserve
;; any formatting between adjacent leaves.
#:when (oneline-syntax? #'and-tree)
#:when (>= (attribute and-tree.rank) 2)
(and and-tree.leaf ...))


(define-refactoring-rule if-then-true-else-false-to-condition
#:description "The condition of this `if` expression is already a boolean and can be used directly."
#:literals (if)
[(if condition:likely-boolean #true #false)
condition])
(if condition:likely-boolean #true #false)
condition)


(define-refactoring-rule if-then-false-else-true-to-not
#:description "This `if` expression can be refactored to an equivalent expression using `not`."
#:literals (if)
[(if condition #false #true)
(not condition)])
(if condition #false #true)
(not condition))


(define-refactoring-rule if-else-false-to-and
#:description "This `if` expression can be refactored to an equivalent expression using `and`."
#:literals (if)
[(if condition then #false)
(and condition then)])
(if condition then #false)
(and condition then))


(define-syntax-class negated-condition
Expand All @@ -78,15 +76,15 @@
(define-refactoring-rule inverted-when
#:description "This negated `when` expression can be replaced by an `unless` expression."
#:literals (when)
[(when-id:when negated:negated-condition body ...)
((~replacement unless #:original when-id) negated.flipped body ...)])
(when-id:when negated:negated-condition body ...)
((~replacement unless #:original when-id) negated.flipped body ...))


(define-refactoring-rule inverted-unless
#:description "This negated `unless` expression can be replaced by a `when` expression."
#:literals (unless)
[(unless-id:unless negated:negated-condition body ...)
((~replacement when #:original unless-id) negated.flipped body ...)])
(unless-id:unless negated:negated-condition body ...)
((~replacement when #:original unless-id) negated.flipped body ...))


(define boolean-shortcuts
Expand Down
12 changes: 6 additions & 6 deletions default-recommendations/comparison-shortcuts.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@

(define-refactoring-rule comparison-of-difference-and-zero-to-direct-comparison
#:description "This comparison can be replaced with a simpler, more direct comparison."
[comparison:comparison-of-difference-and-zero
comparison.direct-comparison])
comparison:comparison-of-difference-and-zero
comparison.direct-comparison)


(define-syntax-class two-exclusive-comparisons
Expand Down Expand Up @@ -99,15 +99,15 @@
(define-refactoring-rule two-exclusive-comparisons-to-triple-comparison
#:description
"Comparison functions like `<` accept multiple arguments, so this condition can be simplified."
[comparison:two-exclusive-comparisons
(< comparison.lower-bound comparison.x comparison.upper-bound)])
comparison:two-exclusive-comparisons
(< comparison.lower-bound comparison.x comparison.upper-bound))


(define-refactoring-rule two-inclusive-comparisons-to-triple-comparison
#:description
"Comparison functions like `<=` accept multiple arguments, so this condition can be simplified."
[comparison:two-inclusive-comparisons
(<= comparison.lower-bound comparison.x comparison.upper-bound)])
comparison:two-inclusive-comparisons
(<= comparison.lower-bound comparison.x comparison.upper-bound))


(define comparison-shortcuts
Expand Down
107 changes: 52 additions & 55 deletions default-recommendations/conditional-shortcuts.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
(define-refactoring-rule nested-if-to-cond
#:description "This `if`-`else` chain can be converted to a `cond` expression."
#:literals (cond)
[nested:nested-if-else
#:when (> (attribute nested.branches-size) 2)
(cond nested.branch ...)])
nested:nested-if-else
#:when (> (attribute nested.branches-size) 2)
(cond nested.branch ...))


(define equivalent-conditional-description
Expand All @@ -56,16 +56,16 @@
(define-refactoring-rule if-else-false-to-and
#:description equivalent-conditional-description
#:literals (if)
[(if condition then-branch #false)
(and condition then-branch)])
(if condition then-branch #false)
(and condition then-branch))


(define-refactoring-rule if-x-else-x-to-and
#:description equivalent-conditional-description
#:literals (if)
[(if x:id then-branch:expr y:id)
#:when (free-identifier=? #'x #'y)
(and x then-branch)])
(if x:id then-branch:expr y:id)
#:when (free-identifier=? #'x #'y)
(and x then-branch))


(define-syntax-class block-expression
Expand All @@ -88,9 +88,8 @@

(define-refactoring-rule if-void-to-when-or-unless
#:description equivalent-conditional-description
[conditional:when-or-unless-equivalent-conditional
((~if conditional.negated? unless when)
conditional.condition conditional.body ...)])
conditional:when-or-unless-equivalent-conditional
((~if conditional.negated? unless when) conditional.condition conditional.body ...))


(define-syntax-class always-throwing-if-expression
Expand All @@ -111,10 +110,10 @@
(define-definition-context-refactoring-rule always-throwing-if-to-when
#:description
"Using `when` and `unless` is simpler than a conditional with an always-throwing branch."
[(~seq body-before ... throwing-if:always-throwing-if-expression)
(body-before ...
throwing-if.equivalent-guard-expression
throwing-if.success-expression)])
(~seq body-before ... throwing-if:always-throwing-if-expression)
(body-before ...
throwing-if.equivalent-guard-expression
throwing-if.success-expression))


(define-syntax-class always-throwing-cond-expression
Expand All @@ -130,22 +129,22 @@
(define-definition-context-refactoring-rule always-throwing-cond-to-when
#:description
"Using `when` and `unless` is simpler than a conditional with an always-throwing branch."
[(~seq body-before ... throwing-cond:always-throwing-cond-expression)
(body-before ...
throwing-cond.guard-expression ...
throwing-cond.body ...)])
(~seq body-before ... throwing-cond:always-throwing-cond-expression)
(body-before ...
throwing-cond.guard-expression ...
throwing-cond.body ...))


(define-refactoring-rule cond-else-cond-to-cond
#:description
"The `else` clause of this `cond` expression is another `cond` expression and can be flattened."
#:literals (cond else)
[((~and outer-cond-id cond)
clause ... last-non-else-clause
(~and outer-else-clause [else (cond nested-clause ...)]))
(outer-cond-id clause ... last-non-else-clause
(ORIGINAL-GAP last-non-else-clause outer-else-clause)
nested-clause ...)])
((~and outer-cond-id cond)
clause ... last-non-else-clause
(~and outer-else-clause [else (cond nested-clause ...)]))
(outer-cond-id clause ... last-non-else-clause
(ORIGINAL-GAP last-non-else-clause outer-else-clause)
nested-clause ...))


(define-syntax-class let-refactorable-cond-clause
Expand All @@ -170,8 +169,8 @@
#:description
"Internal definitions are recommended instead of `let` expressions, to reduce nesting."
#:literals (cond)
[(cond-id:cond clause-before ... clause:let-refactorable-cond-clause clause-after ...)
(cond-id clause-before ... clause.refactored clause-after ...)])
(cond-id:cond clause-before ... clause:let-refactorable-cond-clause clause-after ...)
(cond-id clause-before ... clause.refactored clause-after ...))


(define-syntax-class if-arm
Expand All @@ -193,40 +192,38 @@
(define-refactoring-rule if-begin-to-cond
#:description "Using `cond` instead of `if` here makes `begin` unnecessary"
#:literals (if void)
[(if condition
(~and then-expr:if-arm (~not (void)))
(~and else-expr:if-arm (~not (void))))
#:when (or (attribute then-expr.uses-begin?) (attribute else-expr.uses-begin?))
#:with (true-branch ...)
(if (attribute then-expr.uses-begin?)
#'([condition (ORIGINAL-GAP condition then-expr) then-expr.refactored ...])
#'([condition then-expr.refactored ...]))
#:with (false-branch ...)
(if (attribute else-expr.uses-begin?)
#'([else (ORIGINAL-GAP then-expr else-expr) else-expr.refactored ...])
#'((ORIGINAL-GAP then-expr else-expr) [else else-expr.refactored ...]))
(cond true-branch ... false-branch ...)])
(if condition
(~and then-expr:if-arm (~not (void)))
(~and else-expr:if-arm (~not (void))))
#:when (or (attribute then-expr.uses-begin?) (attribute else-expr.uses-begin?))
#:with (true-branch ...)
(if (attribute then-expr.uses-begin?)
#'([condition (ORIGINAL-GAP condition then-expr) then-expr.refactored ...])
#'([condition then-expr.refactored ...]))
#:with (false-branch ...)
(if (attribute else-expr.uses-begin?)
#'([else (ORIGINAL-GAP then-expr else-expr) else-expr.refactored ...])
#'((ORIGINAL-GAP then-expr else-expr) [else else-expr.refactored ...]))
(cond true-branch ... false-branch ...))


(define-refactoring-rule if-let-to-cond
#:description
"`cond` with internal definitions is preferred over `if` with `let`, to reduce nesting"
#:literals (if void)
[(if condition
(~and then-expr:if-arm (~not (void)))
(~and else-expr:if-arm (~not (void))))
#:when (or (attribute then-expr.uses-let?) (attribute else-expr.uses-let?))
#:with (true-branch ...)
(if (attribute then-expr.uses-let?)
#'([condition (ORIGINAL-GAP condition then-expr) then-expr.refactored ...])
#'([condition then-expr.refactored ...]))
#:with (false-branch ...)
(if (attribute else-expr.uses-let?)
#'([else (ORIGINAL-GAP then-expr else-expr) else-expr.refactored ...])
#'((ORIGINAL-GAP then-expr else-expr) [else else-expr.refactored ...]))
(cond
true-branch ...
false-branch ...)])
(if condition
(~and then-expr:if-arm (~not (void)))
(~and else-expr:if-arm (~not (void))))
#:when (or (attribute then-expr.uses-let?) (attribute else-expr.uses-let?))
#:with (true-branch ...)
(if (attribute then-expr.uses-let?)
#'([condition (ORIGINAL-GAP condition then-expr) then-expr.refactored ...])
#'([condition then-expr.refactored ...]))
#:with (false-branch ...)
(if (attribute else-expr.uses-let?)
#'([else (ORIGINAL-GAP then-expr else-expr) else-expr.refactored ...])
#'((ORIGINAL-GAP then-expr else-expr) [else else-expr.refactored ...]))
(cond true-branch ... false-branch ...))


(define conditional-shortcuts
Expand Down
44 changes: 21 additions & 23 deletions default-recommendations/contract-shortcuts.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -24,43 +24,41 @@

(define-refactoring-rule nested-or/c-to-flat-or/c
#:description "Nested `or/c` contracts can be flattened to a single, equivalent `or/c` contract."
[or-tree
#:declare or-tree (syntax-tree #'or/c)
;; Restricted to single-line expressions for now because the syntax-tree operations don't preserve
;; any formatting between adjacent leaves.
#:when (oneline-syntax? #'or-tree)
#:when (>= (attribute or-tree.rank) 2)
(or/c or-tree.leaf ...)])
(~var or-tree (syntax-tree #'or/c))
;; Restricted to single-line expressions for now because the syntax-tree operations don't preserve
;; any formatting between adjacent leaves.
#:when (oneline-syntax? #'or-tree)
#:when (>= (attribute or-tree.rank) 2)
(or/c or-tree.leaf ...))


(define-refactoring-rule nested-and/c-to-flat-and/c
#:description "Nested `and/c` contracts can be flattened to a single, equivalent `and/c` contract."
[and-tree
#:declare and-tree (syntax-tree #'and/c)
;; Restricted to single-line expressions for now because the syntax-tree operations don't preserve
;; any formatting between adjacent leaves.
#:when (oneline-syntax? #'and-tree)
#:when (>= (attribute and-tree.rank) 2)
(and/c and-tree.leaf ...)])
(~var and-tree (syntax-tree #'and/c))
;; Restricted to single-line expressions for now because the syntax-tree operations don't preserve
;; any formatting between adjacent leaves.
#:when (oneline-syntax? #'and-tree)
#:when (>= (attribute and-tree.rank) 2)
(and/c and-tree.leaf ...))


(define-refactoring-rule explicit-path-string?-to-path-string?
#:description "This contract is equivalent to the `path-string?` predicate."
#:literals (or/c path? string?)
[(~or (or/c path? string?) (or/c string? path?)) path-string?])
(~or (or/c path? string?) (or/c string? path?))
path-string?)


(define-refactoring-rule arrow-contract-with-rest-to-arrow-contract-with-ellipses
#:description "This `->*` contract can be rewritten using `->` with ellipses."
#:literals (->* listof)
[(->*
(arg-contract ...)
(~optional ())
#:rest (~and rest-list (listof rest-contract))
result-contract)
(-> arg-contract ...
rest-contract (... ...)
result-contract)])
(->* (arg-contract ...)
(~optional ())
#:rest (~and rest-list (listof rest-contract))
result-contract)
(-> arg-contract ...
rest-contract (... ...)
result-contract))


(define contract-shortcuts
Expand Down
14 changes: 7 additions & 7 deletions default-recommendations/definition-shortcuts.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@
(define-definition-context-refactoring-rule define-values-values-to-define
#:description "This use of `define-values` is unnecessary."
#:literals (define-values values)
[(~seq body-before ...
(define-values (id:id ...) (values expr:expr ...))
body-after ...)
(body-before ... (define id expr) ... body-after ...)])
(~seq body-before ...
(define-values (id:id ...) (values expr:expr ...))
body-after ...)
(body-before ... (define id expr) ... body-after ...))


(define-definition-context-refactoring-rule inline-unnecessary-define
#:description "This variable is returned immediately and can be inlined."
#:literals (define)
[(~seq body-before ... (define id1:id expr) id2)
#:when (free-identifier=? #'id1 #'id2)
(body-before ... expr)])
(~seq body-before ... (define id1:id expr) id2)
#:when (free-identifier=? #'id1 #'id2)
(body-before ... expr))


(define definition-shortcuts
Expand Down
Loading

0 comments on commit 8e4b387

Please sign in to comment.