Skip to content

Commit 489181b

Browse files
authored
Add named-let-loop-to-for-in-range rule (#619)
1 parent 07ca7ac commit 489181b

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

default-recommendations/for-loop-shortcuts-test.rkt

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,31 @@ test: "nested for/and forms can be flattened to a for*/and form"
624624
------------------------------
625625

626626

627+
test: "named let loop over counter can be replaced by for in-range"
628+
------------------------------------------------------------
629+
(define (f x a b dx)
630+
(let loop ([x a])
631+
(when (< x b)
632+
(displayln x)
633+
(loop (+ x dx)))))
634+
============================================================
635+
(define (f x a b dx)
636+
(for ([x (in-range a b dx)])
637+
(displayln x)))
638+
------------------------------------------------------------
639+
640+
641+
no-change-test: "named let loop over counter not refactorable when loop function used elsewhere"
642+
------------------------------------------------------------
643+
(define (f x a b dx)
644+
(let loop ([x a])
645+
(when (< x b)
646+
(displayln x)
647+
(displayln loop)
648+
(loop (+ x dx)))))
649+
------------------------------------------------------------
650+
651+
627652
test: "named let loop with conditional return over vector can be replaced by for/first"
628653
------------------------------------------------------------
629654
(define vec (vector 0 1 2 3 4 5))
@@ -633,17 +658,15 @@ test: "named let loop with conditional return over vector can be replaced by for
633658
(if (> x 3)
634659
(+ x 42)
635660
(loop (add1 i))))))
636-
------------------------------------------------------------
637-
------------------------------------------------------------
661+
============================================================
638662
(define vec (vector 0 1 2 3 4 5))
639663
(let loop ([i 0])
640664
(and (< i (vector-length vec))
641665
(let ([x (vector-ref vec i)])
642666
(if (> x 3)
643667
(+ x 42)
644668
(loop (+ i 1))))))
645-
------------------------------------------------------------
646-
------------------------------------------------------------
669+
============================================================
647670
(define vec (vector 0 1 2 3 4 5))
648671
(for/first ([x (in-vector vec)]
649672
#:when (> x 3))

default-recommendations/for-loop-shortcuts.rkt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
resyntax/default-recommendations/private/lambda-by-any-name
1818
resyntax/default-recommendations/private/let-binding
1919
resyntax/default-recommendations/private/list-function
20+
resyntax/default-recommendations/private/literal-constant
2021
resyntax/default-recommendations/private/metafunction
2122
resyntax/default-recommendations/private/syntax-equivalence
2223
resyntax/default-recommendations/private/syntax-identifier-sets
@@ -436,6 +437,24 @@ return just that result."
436437
nested.body ...))
437438

438439

440+
(define-refactoring-rule named-let-loop-to-for-in-range
441+
#:description "This named `let` expression is equivalent to a `for` loop that uses `in-range`."
442+
#:literals (let when < +)
443+
(let loop:id ([x:id start:expr])
444+
(when (< x2:id (~or stop:id stop:literal-constant))
445+
body ...+
446+
(loop2:id (+ x3:id (~or step:id step:literal-constant)))))
447+
#:when (free-identifier=? (attribute x) (attribute x2))
448+
#:when (free-identifier=? (attribute x) (attribute x3))
449+
#:when (free-identifier=? (attribute loop) (attribute loop2))
450+
#:when (or (not (identifier? (attribute step)))
451+
(identifier-binding-unchanged-in-context? (attribute step) this-syntax))
452+
#:when (not (syntax-find-first #'(body ...) id:id
453+
#:when (free-identifier=? (attribute id) (attribute loop))))
454+
(for ([x (in-range start stop step)])
455+
body ...))
456+
457+
439458
(define-refactoring-rule named-let-loop-to-for/list
440459
#:description "This named `let` expression is equivalent to a `for/list` loop."
441460
#:literals (let cond else null? empty? null quote car first cdr rest cons)
@@ -654,6 +673,7 @@ return just that result."
654673
list->set-to-for/set
655674
list->vector-to-for/vector
656675
map-to-for
676+
named-let-loop-to-for-in-range
657677
named-let-loop-to-for/and
658678
named-let-loop-to-for/first-in-vector
659679
named-let-loop-to-for/list

0 commit comments

Comments
 (0)