Skip to content
Merged
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
25 changes: 25 additions & 0 deletions default-recommendations/syntax-shortcuts-test.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,28 @@ test: "syntax-e on a single format-id argument is removable"

test: "format-id call without any syntax-e unwrapped arguments not refactorable"
- (format-id #'foo "~a.~a.~a" #'bar #'baz #'blah)


test: "making a symbol with format can be simplified to format-symbol"
- (string->symbol (format "make-~a" "foo"))
- (format-symbol "make-~a" "foo")


test: "making a symbol with format from a symbol can be simplified to format-symbol"
- (string->symbol (format "make-~a" (symbol->string 'foo)))
- (format-symbol "make-~a" 'foo)


test: "making a symbol with format from an identifier can be simplified to format-symbol"
- (string->symbol (format "make-~a" (symbol->string (syntax-e #'foo))))
- (format-symbol "make-~a" #'foo)


test: "making a symbol with format from a keyword can be simplified to format-symbol"
- (string->symbol (format "make-~a" (keyword->string '#:foo)))
- (format-symbol "make-~a" '#:foo)


test: "making a symbol with format from a keyword syntax object can be simplified to format-symbol"
- (string->symbol (format "make-~a" (keyword->string (syntax-e #'#:foo))))
- (format-symbol "make-~a" #'#:foo)
65 changes: 63 additions & 2 deletions default-recommendations/syntax-shortcuts.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
[syntax-shortcuts refactoring-suite?]))


(require racket/syntax
(require racket/string
racket/syntax
rebellion/private/static-name
resyntax/base
syntax/parse)
Expand Down Expand Up @@ -43,5 +44,65 @@
(format-id lctx fmt arg.simplified ...))


(define-syntax-class format-symbol-argument
#:attributes (simplified)
#:literals (syntax-e keyword->string symbol->string)

(pattern (syntax-e inner:format-symbol-argument) #:attr simplified (attribute inner.simplified))

(pattern (keyword->string inner:format-symbol-argument)
#:attr simplified (attribute inner.simplified))

(pattern (symbol->string inner:format-symbol-argument)
#:attr simplified (attribute inner.simplified))

(pattern simplified:expr))


;; The format-symbol function only allows ~a placeholders. Rather a fancy generic utilty that finds
;; all placeholders, we just explicitly list out all the other ones and check one-by-one whether any
;; of them are contained in the template string. That's easier to implement and the performance
;; doesn't matter at all since template strings are almost always short.
(define disallowed-format-symbol-placeholders
(list "~n"
"~%"
"~s"
"~S"
"~v"
"~V"
"~.a"
"~.A"
"~.s"
"~.S"
"~.v"
"~.V"
"~e"
"~E"
"~c"
"~C"
"~b"
"~B"
"~o"
"~O"
"~x"
"~X"
"~ "
"~\n"
"~\t"))


(define-refactoring-rule format-string-to-format-symbol
#:description
"This `format` expression can be simplified to an equivalent `format-symbol` expression."
#:literals (format string->symbol)

(string->symbol (format template:str arg:format-symbol-argument ...))
#:when (for/and ([disallowed (in-list disallowed-format-symbol-placeholders)])
(not (string-contains? (syntax-e #'template) disallowed)))

(format-symbol template (~replacement arg.simplified #:original arg) ...))


(define-refactoring-suite syntax-shortcuts
#:rules (syntax-e-in-format-id-unnecessary))
#:rules (format-string-to-format-symbol
syntax-e-in-format-id-unnecessary))