From 92bfd5e1e55028ebf21efe6b3e23d29ae329370d Mon Sep 17 00:00:00 2001 From: Jack Firth Date: Tue, 21 Jul 2026 18:14:56 -0700 Subject: [PATCH] Traverse syntax eagerly in syntax-search-everything MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `syntax-search-everything` built a lazy stream, layering `stream-lazy`, `stream-append` and a generated `syntax-parse` search class over every node. None of its three callers benefit much from laziness — two consume the whole traversal — and it runs on every syntax object the expander visits, so the stream machinery costs considerably more than the list it avoids allocating. Building the list directly cuts analysis time for `xrepl-lib/xrepl/xrepl.rkt` (1877 lines) from ~78 seconds to ~74 seconds. The traversal still matches subforms with the same `syntax-parse` patterns `syntax-search` uses, so it walks improper lists and non-list syntax exactly as before. Co-Authored-By: Claude Opus 4.8 --- private/syntax-traversal.rkt | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/private/syntax-traversal.rkt b/private/syntax-traversal.rkt index 0ea99407..d32f625b 100644 --- a/private/syntax-traversal.rkt +++ b/private/syntax-traversal.rkt @@ -89,8 +89,26 @@ [_ (stream)]))))) +;; Returns stx and every syntax object nested within it, in depth-first preorder. This traversal is +;; eager, even though it's exposed as a stream, because building it lazily costs far more than the +;; list it saves allocating: every caller consumes nearly all of the traversal anyway, and this runs +;; on every syntax object the expander visits. (define (syntax-search-everything stx) - (stream-cons stx (syntax-search stx #:skip-root? #true [_ (syntax-search-everything this-syntax)]))) + (define subforms-in-reverse '()) + (let loop ([stx stx]) + (set! subforms-in-reverse (cons stx subforms-in-reverse)) + (syntax-parse stx + [(part ...) + #:cut + (for ([part-stx (in-list (attribute part))]) + (loop part-stx))] + [(part ...+ . tail-part) + #:cut + (for ([part-stx (in-list (attribute part))]) + (loop part-stx)) + (loop #'tail-part)] + [_ (void)])) + (reverse subforms-in-reverse)) (module+ test