Skip to content

Commit d2935a5

Browse files
Copilotjackfirth
andcommitted
Add keep-sorted macro and refactoring rule for maintaining sorted lists
Co-authored-by: jackfirth <[email protected]>
1 parent 9a3981f commit d2935a5

File tree

4 files changed

+136
-0
lines changed

4 files changed

+136
-0
lines changed

default-recommendations.rkt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
resyntax/default-recommendations/function-definition-shortcuts
1919
resyntax/default-recommendations/function-shortcuts
2020
resyntax/default-recommendations/hash-shortcuts
21+
resyntax/default-recommendations/keep-sorted-suggestions
2122
resyntax/default-recommendations/legacy/define-simple-macro-migration
2223
resyntax/default-recommendations/legacy/legacy-contract-migrations
2324
resyntax/default-recommendations/legacy/legacy-struct-migrations
@@ -60,6 +61,7 @@
6061
resyntax/default-recommendations/function-definition-shortcuts
6162
resyntax/default-recommendations/function-shortcuts
6263
resyntax/default-recommendations/hash-shortcuts
64+
resyntax/default-recommendations/keep-sorted-suggestions
6365
resyntax/default-recommendations/legacy/define-simple-macro-migration
6466
resyntax/default-recommendations/legacy/legacy-contract-migrations
6567
resyntax/default-recommendations/legacy/legacy-struct-migrations
@@ -107,6 +109,7 @@
107109
function-definition-shortcuts
108110
function-shortcuts
109111
hash-shortcuts
112+
keep-sorted-suggestions
110113
legacy-contract-migrations
111114

112115
;; Excluded for lots of reasons. See the following github issues:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#lang resyntax/test
2+
3+
4+
require: resyntax/default-recommendations/keep-sorted-suggestions keep-sorted-suggestions
5+
6+
7+
header:
8+
--------------------
9+
#lang racket/base
10+
(require resyntax/keep-sorted)
11+
(define apple 'apple)
12+
(define banana 'banana)
13+
(define mango 'mango)
14+
(define orange 'orange)
15+
(define zebra 'zebra)
16+
--------------------
17+
18+
19+
test: "unsorted marked list should be resorted"
20+
------------------------------
21+
(void (keep-sorted (list apple orange banana)))
22+
==============================
23+
(void (keep-sorted (list apple banana orange)))
24+
------------------------------
25+
26+
27+
test: "unsorted marked set should be resorted"
28+
------------------------------
29+
(require racket/set)
30+
(void (keep-sorted (set orange apple banana)))
31+
==============================
32+
(require racket/set)
33+
(void (keep-sorted (set apple banana orange)))
34+
------------------------------
35+
36+
37+
test: "unsorted marked vector should be resorted"
38+
------------------------------
39+
(void (keep-sorted (vector zebra apple mango)))
40+
==============================
41+
(void (keep-sorted (vector apple mango zebra)))
42+
------------------------------
43+
44+
45+
no-change-test: "already sorted marked list should not be changed"
46+
------------------------------
47+
(void (keep-sorted (list apple banana orange)))
48+
------------------------------
49+
50+
51+
no-change-test: "unmarked unsorted list should not be changed"
52+
------------------------------
53+
(void (list orange apple banana))
54+
------------------------------
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#lang racket/base
2+
3+
4+
(require racket/contract/base)
5+
6+
7+
(provide
8+
(contract-out
9+
[keep-sorted-suggestions refactoring-suite?]))
10+
11+
12+
(require racket/list
13+
racket/sequence
14+
resyntax/base
15+
syntax/parse
16+
syntax/parse/define)
17+
18+
19+
;@----------------------------------------------------------------------------------------------------
20+
21+
22+
;; Check if a list of identifiers is sorted alphabetically by their symbol names
23+
(define (identifiers-sorted? ids)
24+
(define id-list (sequence->list ids))
25+
(define id-strings (map (λ (id) (symbol->string (syntax-e id))) id-list))
26+
(equal? id-strings (sort id-strings string<?)))
27+
28+
29+
;; Sort a list of syntax objects representing identifiers alphabetically
30+
(define (sort-identifiers ids)
31+
(sort (sequence->list ids)
32+
string<?
33+
#:key (λ (id) (symbol->string (syntax-e id)))))
34+
35+
36+
;; Syntax class for matching a list expression with identifier elements
37+
(define-syntax-class list-of-ids
38+
#:attributes (constructor [element 1] sorted?)
39+
(pattern (constructor:id element:id ...)
40+
#:attr sorted? (identifiers-sorted? (attribute element))))
41+
42+
43+
(define-refactoring-rule resort-keep-sorted-list
44+
#:description "This list is marked with `keep-sorted` but its elements are not in sorted order."
45+
body:list-of-ids
46+
#:when (syntax-property this-syntax 'keep-sorted)
47+
#:when (not (attribute body.sorted?))
48+
#:with (sorted-element ...) (sort-identifiers (attribute body.element))
49+
(body.constructor sorted-element ...))
50+
51+
52+
(define-refactoring-suite keep-sorted-suggestions
53+
#:rules (resort-keep-sorted-list))

keep-sorted.rkt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#lang racket/base
2+
3+
4+
(provide
5+
keep-sorted)
6+
7+
8+
(require (for-syntax racket/base
9+
syntax/parse))
10+
11+
12+
;@----------------------------------------------------------------------------------------------------
13+
14+
15+
;; The keep-sorted macro marks a collection as needing to be kept in sorted order.
16+
;; Resyntax refactoring rules can detect this syntax property and suggest reordering
17+
;; the elements when they're not sorted.
18+
19+
;; The macro expands to a syntax property on the inner expression that Resyntax can detect.
20+
;; The first form in the list is ignored (it's the collection constructor like list, set, vector).
21+
22+
23+
(define-syntax (keep-sorted stx)
24+
(syntax-parse stx
25+
[(_ body:expr)
26+
(syntax-property #'body 'keep-sorted #true)]))

0 commit comments

Comments
 (0)