From 966ce9aad707e5430430aefe7196074474115e8f Mon Sep 17 00:00:00 2001 From: Jacqueline Firth Date: Wed, 18 Sep 2024 01:30:44 -0700 Subject: [PATCH] Add nested `for/or` and `for/and` rules (#303) Closes #176. --- .../for-loop-shortcuts-test.rkt | 30 ++++++++++++++ .../for-loop-shortcuts.rkt | 41 +++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/default-recommendations/for-loop-shortcuts-test.rkt b/default-recommendations/for-loop-shortcuts-test.rkt index 8228ce3..41fb1d6 100644 --- a/default-recommendations/for-loop-shortcuts-test.rkt +++ b/default-recommendations/for-loop-shortcuts-test.rkt @@ -385,6 +385,36 @@ test: "non-nested for form isn't replaced by a for* form" ------------------------------ +test: "nested for/or forms can be flattened to a for*/or form" +------------------------------ +(for/or ([x (in-range 0 5)]) + (for/or ([y (in-range 0 5)]) + (for/or ([z (in-range 0 5)]) + (>= (+ x y z) 5)))) +------------------------------ +------------------------------ +(for*/or ([x (in-range 0 5)] + [y (in-range 0 5)] + [z (in-range 0 5)]) + (>= (+ x y z) 5)) +------------------------------ + + +test: "nested for/and forms can be flattened to a for*/and form" +------------------------------ +(for/and ([x (in-range 0 5)]) + (for/and ([y (in-range 0 5)]) + (for/and ([z (in-range 0 5)]) + (<= (+ x y z) 5)))) +------------------------------ +------------------------------ +(for*/and ([x (in-range 0 5)] + [y (in-range 0 5)] + [z (in-range 0 5)]) + (<= (+ x y z) 5)) +------------------------------ + + test: "named let loop with conditional return over vector can be replaced by for/first" ------------------------------------------------------------ (define vec (vector 0 1 2 3 4 5)) diff --git a/default-recommendations/for-loop-shortcuts.rkt b/default-recommendations/for-loop-shortcuts.rkt index da2670f..4a4b6bc 100644 --- a/default-recommendations/for-loop-shortcuts.rkt +++ b/default-recommendations/for-loop-shortcuts.rkt @@ -12,7 +12,6 @@ (require (for-syntax racket/base) racket/list racket/set - rebellion/private/static-name resyntax/base resyntax/default-recommendations/private/boolean resyntax/default-recommendations/private/lambda-by-any-name @@ -22,8 +21,6 @@ resyntax/default-recommendations/private/syntax-identifier-sets resyntax/default-recommendations/private/syntax-lines resyntax/private/identifier-naming - resyntax/private/logger - resyntax/private/syntax-neighbors resyntax/private/syntax-traversal syntax/parse) @@ -181,6 +178,42 @@ function.body ...)) +(define-syntax-class nested-for/or + #:attributes ([clause 1] [body 1]) + #:literals (for/or) + + (pattern (for/or (outer-clause ...) nested:nested-for/or ~!) + #:attr [clause 1] (append (attribute outer-clause) (attribute nested.clause)) + #:attr [body 1] (attribute nested.body)) + + (pattern (for/or (clause ...) body ...))) + + +(define-syntax-class nested-for/and + #:attributes ([clause 1] [body 1]) + #:literals (for/and) + + (pattern (for/and (outer-clause ...) nested:nested-for/and ~!) + #:attr [clause 1] (append (attribute outer-clause) (attribute nested.clause)) + #:attr [body 1] (attribute nested.body)) + + (pattern (for/and (clause ...) body ...))) + + +(define-refactoring-rule nested-for/or-to-for*/or + #:description "Nested `for/or` loops can be replaced with a single `for*/loop`." + #:literals (for/or) + (for-id:for/or (clause ...) nested:nested-for/or) + ((~replacement for*/or #:original for-id) (clause ... nested.clause ...) nested.body ...)) + + +(define-refactoring-rule nested-for/and-to-for*/and + #:description "Nested `for/or` loops can be replaced with a single `for*/loop`." + #:literals (for/and) + (for-id:for/and (clause ...) nested:nested-for/and) + ((~replacement for*/and #:original for-id) (clause ... nested.clause ...) nested.body ...)) + + (define-syntax-class for-list-id #:attributes (set-id vector-id) #:literals (for/list for*/list) @@ -388,6 +421,8 @@ return just that result." named-let-loop-to-for/list named-let-loop-to-for/first-in-vector nested-for-to-for* + nested-for/and-to-for*/and + nested-for/or-to-for*/or or-in-for/and-to-filter-clause ormap-to-for/or unless-expression-in-for-loop-to-unless-keyword