Commit73e3e4faRecorded3 Mar 2026Repositorysigil-format
Optimize formatter analysis phase: move indent checks into lparen branch
Message
Move check-indent-decrease and check-indent-mismatch inside the lparen case branch instead of calling them on every token. Compute form-type once per lparen and pass to both helpers. Inline content-token? check with direct eq? comparisons. Use direct vector-ref for token fields.
Analysis phase: ~2.6s -> ~1.3s on build.sgl. Total: 4.5s -> 2.5s.
Changed
src/sigil/format.sgl | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------
1 file changed, 63 insertions(+), 74 deletions(-)Diff
src/sigil/format.sglmodified
@@ -510,27 +510,19 @@
510
511
;; Helper: check if a form appears at unexpectedly deep indent 512
;; This suggests a previous form was closed prematurely−513
(define (check-indent-mismatch state tok next-tokens chars)−514
(let ((tok-type (token-type tok))−515
(tok-indent (token-indent tok))−516
(tok-line (token-line tok))+513
;; Called only for lparen/lbracket at line start with pre-computed form-type+514
(define (check-indent-mismatch state tok form-type)+515
(let ((tok-indent (vector-ref tok 5)) 516
(current-depth (analysis-state-depth state)))−518
;; Only check opening parens at start of line (column should be indent+1)−519
(if (and (memq tok-type '(lparen lbracket))−520
(= (token-column tok) (+ tok-indent 1)))−521
(let ((expected-indent (expected-indent-for-depth current-depth))−522
(form-type (get-form-type next-tokens chars)))−523
;; If indent is deeper than expected for current depth−524
;; AND it looks like a major form (define, let, etc.), warn−525
;; This catches cases like begin closing too early−526
(if (and form-type−527
(memq form-type '(define define-syntax define-library define-struct−528
let let* letrec begin))−529
(> tok-indent expected-indent)) ; Deeper than expected+517
(if (and form-type+518
(memq form-type '(define define-syntax define-library define-struct+519
let let* letrec begin)))+520
(let ((expected-indent (* current-depth 2)))+521
(if (> tok-indent expected-indent) 522
(set-analysis-state-warnings! state 523
(cons (format-warning−532
line: tok-line−533
column: (token-column tok)+524
line: (vector-ref tok 3)+525
column: (vector-ref tok 4) 526
message: (format "~a at column ~a is deeper than expected ~a for nesting depth ~a - check if previous form closed too early" 527
form-type (+ tok-indent 1) (+ expected-indent 1) current-depth) 528
code: "W001")@@ -550,41 +542,34 @@
542
;; Helper: check if we should infer closing parens 543
;; Trigger when we see a form (like define) at the same indentation 544
;; as an unclosed form of the same type in the stack−553
;; prev-tok is the last non-whitespace/newline token seen−554
(define (check-indent-decrease state tok next-tokens prev-content-line chars)−555
(let ((tok-type (token-type tok))−556
(tok-indent (token-indent tok))−557
(tok-line (token-line tok)))−558
;; Only check when we see an opening paren at the start of a line−559
(if (and (memq tok-type '(lparen lbracket))−560
(= (token-column tok) (+ tok-indent 1))) ; first token on line−561
(let ((form-type (get-form-type next-tokens chars)))−562
;; Check if there's an unclosed form of the same type at same indent−563
(if (and form-type−564
(memq form-type '(define define-syntax define-struct let let* letrec)))−565
(let ((match-count (find-matching-form-in-stack state form-type tok-indent)))−566
(if match-count−567
;; Close all parens up to and including the matching one−568
;; Use prev-content-line so ) goes at end of previous content−569
(let ((close-at-line (or prev-content-line tok-line)))−570
(let loop ((to-close (+ match-count 1)))−571
(if (and (> to-close 0) (not (null? (analysis-state-paren-stack state))))−572
(let ((top (car (analysis-state-paren-stack state))))−573
(set-analysis-state-inferences! state−574
(cons (paren-inference−575
line: close-at-line−576
column: 9999 ; End of line marker−577
type: 'close−578
confidence: 'high−579
reason: (format "New ~a at same level - ~a from line ~a should close"−580
form-type−581
(if (eq? (paren-info-type top) 'lparen) "(" "[")−582
(paren-info-line top)))−583
(analysis-state-inferences state)))−584
(set-analysis-state-paren-stack! state (cdr (analysis-state-paren-stack state)))−585
(set-analysis-state-depth! state (- (analysis-state-depth state) 1))−586
(loop (- to-close 1))))))))))))−587
#f)+545
;; Called only for lparen/lbracket at line start with pre-computed form-type+546
(define (check-indent-decrease state tok form-type prev-content-line)+547
(if (and form-type+548
(memq form-type '(define define-syntax define-struct let let* letrec)))+549
(let ((tok-indent (vector-ref tok 5))+550
(tok-line (vector-ref tok 3)))+551
(let ((match-count (find-matching-form-in-stack state form-type tok-indent)))+552
(if match-count+553
;; Close all parens up to and including the matching one+554
;; Use prev-content-line so ) goes at end of previous content+555
(let ((close-at-line (or prev-content-line tok-line)))+556
(let loop ((to-close (+ match-count 1)))+557
(if (and (> to-close 0) (not (null? (analysis-state-paren-stack state))))+558
(let ((top (car (analysis-state-paren-stack state))))+559
(set-analysis-state-inferences! state+560
(cons (paren-inference+561
line: close-at-line+562
column: 9999 ; End of line marker+563
type: 'close+564
confidence: 'high+565
reason: (format "New ~a at same level - ~a from line ~a should close"+566
form-type+567
(if (eq? (paren-info-type top) 'lparen) "(" "[")+568
(paren-info-line top)))+569
(analysis-state-inferences state)))+570
(set-analysis-state-paren-stack! state (cdr (analysis-state-paren-stack state)))+571
(set-analysis-state-depth! state (- (analysis-state-depth state) 1))+572
(loop (- to-close 1))))))))))) 573
574
;; Helper: check if a token is content (not whitespace/newline/comment) 575
(define (content-token? tok)@@ -626,33 +611,36 @@
611
(reverse (analysis-state-errors state)) 612
(reverse (analysis-state-warnings state)))) 613
−629
(let ((tok (car ts))−630
(rest (cdr ts)))−631
;; Check for indent-based inference−632
(check-indent-decrease state tok rest prev-content-line chars)−633
;; Check for indent mismatch (suggests premature closing)−634
(check-indent-mismatch state tok rest chars)+614
(let* ((tok (car ts))+615
(rest (cdr ts))+616
(ttype (vector-ref tok 0))) 617
618
;; Process token−637
(case (token-type tok)+619
(case ttype 620
((lparen)−639
(set-analysis-state-paren-stack! state−640
(cons (paren-info−641
type: 'lparen−642
line: (token-line tok)−643
column: (token-column tok)−644
indent: (token-indent tok)−645
form-type: (get-form-type rest chars))−646
(analysis-state-paren-stack state)))−647
(set-analysis-state-depth! state (+ (analysis-state-depth state) 1)))+621
;; Compute form-type once; check indent only at line start+622
(let* ((at-line-start (= (vector-ref tok 4) (+ (vector-ref tok 5) 1)))+623
(form-type (get-form-type rest chars)))+624
(when at-line-start+625
(check-indent-decrease state tok form-type prev-content-line)+626
(check-indent-mismatch state tok form-type))+627
(set-analysis-state-paren-stack! state+628
(cons (paren-info+629
type: 'lparen+630
line: (vector-ref tok 3)+631
column: (vector-ref tok 4)+632
indent: (vector-ref tok 5)+633
form-type: form-type)+634
(analysis-state-paren-stack state)))+635
(set-analysis-state-depth! state (+ (analysis-state-depth state) 1)))) 636
637
((lbracket) 638
(set-analysis-state-paren-stack! state 639
(cons (paren-info 640
type: 'lbracket−653
line: (token-line tok)−654
column: (token-column tok)−655
indent: (token-indent tok)+641
line: (vector-ref tok 3)+642
column: (vector-ref tok 4)+643
indent: (vector-ref tok 5) 644
form-type: #f) 645
(analysis-state-paren-stack state))) 646
(set-analysis-state-depth! state (+ (analysis-state-depth state) 1)))@@ -760,8 +748,9 @@
748
749
;; Update prev-content-line if this is a content token 750
(loop rest tok−763
(if (content-token? tok)−764
(token-line tok)+751
(if (not (or (eq? ttype 'whitespace) (eq? ttype 'newline)+752
(eq? ttype 'comment) (eq? ttype 'eof)))+753
(vector-ref tok 3) 754
prev-content-line))))))) 755
756
;; ============================================================