From 052c19f46f24832958fbb554835b736d7fde7432 Mon Sep 17 00:00:00 2001 From: Jack Firth Date: Wed, 8 Jul 2026 01:20:19 -0700 Subject: [PATCH] Add rule flattening apply/append/map syntax templates Adds the `flatten-apply-append-syntax-template` rule, rewriting `(apply append (map syntax->list (syntax->list #'((a ...) ...))))` to the more direct `(syntax->list #'(a ... ...))`. To render the reconstructed template with `#'` shorthand instead of the `(syntax ...)` long form, the s-expression renderer now prints constructed `syntax` forms as `#'`, mirroring its existing `quote` -> `'` handling. Fixes #769 Co-Authored-By: Claude Opus 4.8 --- .../syntax-shortcuts-test.rkt | 14 ++++++++++++++ default-recommendations/syntax-shortcuts.rkt | 16 +++++++++++++++- private/syntax-replacement.rkt | 6 ++++-- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/default-recommendations/syntax-shortcuts-test.rkt b/default-recommendations/syntax-shortcuts-test.rkt index 147ffdd3..f71c38cb 100644 --- a/default-recommendations/syntax-shortcuts-test.rkt +++ b/default-recommendations/syntax-shortcuts-test.rkt @@ -53,3 +53,17 @@ test: "making a symbol with format from a keyword can be simplified to format-sy 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) + + +test: "flattening a nested ellipsis template can be simplified to a flat template" +------------------------------------------------------------------------------------------------------ +(define (f stx) + (with-syntax ([((a ...) ...) stx]) + (apply append + (map syntax->list (syntax->list #'((a ...) ...)))))) +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +(define (f stx) + (with-syntax ([((a ...) ...) stx]) + (syntax->list #'(a ... ...)))) +------------------------------------------------------------------------------------------------------ diff --git a/default-recommendations/syntax-shortcuts.rkt b/default-recommendations/syntax-shortcuts.rkt index 2ff8ce1e..c9bfbcd0 100644 --- a/default-recommendations/syntax-shortcuts.rkt +++ b/default-recommendations/syntax-shortcuts.rkt @@ -103,6 +103,20 @@ (format-symbol template (~replacement arg.simplified #:original arg) ...)) +(define-refactoring-rule flatten-apply-append-syntax-template + #:description + "Flattening a nested ellipsis syntax template with `apply`, `append`, and `map` can be expressed\ + more directly with a single flattened ellipsis template." + #:literals (apply append map syntax->list syntax) + + (apply append + (map syntax->list + (syntax->list (syntax ((elem (~datum ...)) (~datum ...)))))) + + (syntax->list #'(elem (... ...) (... ...)))) + + (define-refactoring-suite syntax-shortcuts - #:rules (format-string-to-format-symbol + #:rules (flatten-apply-append-syntax-template + format-string-to-format-symbol syntax-e-in-format-id-unnecessary)) diff --git a/private/syntax-replacement.rkt b/private/syntax-replacement.rkt index 6d084afc..b9dd455b 100644 --- a/private/syntax-replacement.rkt +++ b/private/syntax-replacement.rkt @@ -141,12 +141,14 @@ (define end (+ start (syntax-span stx))) (list (copied-string start end))) (syntax-parse stx - #:literals (quote) + #:literals (quote syntax) [(~or v:id v:boolean v:char v:keyword v:number v:regexp v:byte-regexp v:string v:bytes) (list (inserted-string (string->immutable-string (~s (syntax-e #'v)))))] - + [(quote datum) (cons (inserted-string "'") (pieces #'datum #:focused? focused?))] + + [(syntax datum) (cons (inserted-string "#'") (pieces #'datum #:focused? focused?))] [(subform ...) (define shape (syntax-property stx 'paren-shape))