Skip to content
Draft
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
3 changes: 3 additions & 0 deletions default-recommendations.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
resyntax/default-recommendations/function-definition-shortcuts
resyntax/default-recommendations/function-shortcuts
resyntax/default-recommendations/hash-shortcuts
resyntax/default-recommendations/keep-sorted-suggestions
resyntax/default-recommendations/legacy/define-simple-macro-migration
resyntax/default-recommendations/legacy/legacy-contract-migrations
resyntax/default-recommendations/legacy/legacy-struct-migrations
Expand Down Expand Up @@ -60,6 +61,7 @@
resyntax/default-recommendations/function-definition-shortcuts
resyntax/default-recommendations/function-shortcuts
resyntax/default-recommendations/hash-shortcuts
resyntax/default-recommendations/keep-sorted-suggestions
resyntax/default-recommendations/legacy/define-simple-macro-migration
resyntax/default-recommendations/legacy/legacy-contract-migrations
resyntax/default-recommendations/legacy/legacy-struct-migrations
Expand Down Expand Up @@ -107,6 +109,7 @@
function-definition-shortcuts
function-shortcuts
hash-shortcuts
keep-sorted-suggestions
legacy-contract-migrations

;; Excluded for lots of reasons. See the following github issues:
Expand Down
54 changes: 54 additions & 0 deletions default-recommendations/keep-sorted-suggestions-test.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#lang resyntax/test


require: resyntax/default-recommendations/keep-sorted-suggestions keep-sorted-suggestions


header:
--------------------
#lang racket/base
(require resyntax/keep-sorted)
(define apple 'apple)
(define banana 'banana)
(define mango 'mango)
(define orange 'orange)
(define zebra 'zebra)
--------------------


test: "unsorted marked list should be resorted"
------------------------------
(void (keep-sorted (list apple orange banana)))
==============================
(void (keep-sorted (list apple banana orange)))
------------------------------


test: "unsorted marked set should be resorted"
------------------------------
(require racket/set)
(void (keep-sorted (set orange apple banana)))
==============================
(require racket/set)
(void (keep-sorted (set apple banana orange)))
------------------------------


test: "unsorted marked vector should be resorted"
------------------------------
(void (keep-sorted (vector zebra apple mango)))
==============================
(void (keep-sorted (vector apple mango zebra)))
------------------------------


no-change-test: "already sorted marked list should not be changed"
------------------------------
(void (keep-sorted (list apple banana orange)))
------------------------------


no-change-test: "unmarked unsorted list should not be changed"
------------------------------
(void (list orange apple banana))
------------------------------
54 changes: 54 additions & 0 deletions default-recommendations/keep-sorted-suggestions.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#lang racket/base


(require racket/contract/base)


(provide
(contract-out
[keep-sorted-suggestions refactoring-suite?]))


(require racket/list
resyntax/base
syntax/parse
syntax/parse/define)


;@----------------------------------------------------------------------------------------------------


;; Convert an identifier syntax object to its string representation
(define (identifier->string id)
(symbol->string (syntax-e id)))


;; Check if a list of identifiers is sorted alphabetically by their symbol names
(define (identifiers-sorted? ids)
(define id-strings (map identifier->string ids))
(equal? id-strings (sort id-strings string<?)))


;; Sort a list of syntax objects representing identifiers alphabetically
(define (sort-identifiers ids)
(sort ids string<? #:key identifier->string))


;; Syntax class for matching a list expression with identifier elements
(define-syntax-class list-of-ids
#:attributes (constructor [element 1] sorted?)
(pattern (constructor:id element:id ...)
#:attr sorted? (identifiers-sorted? (attribute element))))


(define-refactoring-rule resort-keep-sorted-list
#:description "This list is marked with `keep-sorted` but its elements are not in sorted order."
body:list-of-ids
#:when (syntax-property this-syntax 'keep-sorted)
#:when (not (attribute body.sorted?))
#:with (sorted-element ...) (sort-identifiers (attribute body.element))
(body.constructor sorted-element ...))


(define-refactoring-suite keep-sorted-suggestions
#:rules (resort-keep-sorted-list))
26 changes: 26 additions & 0 deletions keep-sorted.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#lang racket/base


(provide
keep-sorted)


(require (for-syntax racket/base
syntax/parse))


;@----------------------------------------------------------------------------------------------------


;; The keep-sorted macro marks a collection as needing to be kept in sorted order.
;; Resyntax refactoring rules can detect this syntax property and suggest reordering
;; the elements when they're not sorted.

;; The macro expands to a syntax property on the inner expression that Resyntax can detect.
;; The first form in the list is ignored (it's the collection constructor like list, set, vector).


(define-syntax (keep-sorted stx)
(syntax-parse stx
[(_ body:expr)
(syntax-property #'body 'keep-sorted #true)]))