forked from soegaard/remacs
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmatch-paren.rkt
144 lines (127 loc) · 5.36 KB
/
match-paren.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#lang racket
(provide %-point a-paren-pair)
(require "core.rkt" "common-utils.rkt" "Scope.rkt")
(module+ test (require rackunit))
(define (get-paren-pair char)
(match char
[(or #\( #\)) (cons #\( #\))]
[(or #\{ #\}) (cons #\{ #\})]
[(or #\[ #\]) (cons #\[ #\])]
[_ (error 'missing-case (~v char))]))
(define (line-match-forwards paren-pair line counter)
(for/fold ([l-counter counter]
[col- 0])
([col (in-naturals)]
[c line]
#:when (or (equal? c (car paren-pair)) (equal? c (cdr paren-pair)))
#:break (= l-counter 0)) ; todo start from p
(define local-counter
(cond
[(equal? c (car paren-pair))
(add1 l-counter)]
[else (sub1 l-counter)]))
(values local-counter col)))
(define (string-reverse x)
(list->string (reverse (string->list x))))
(define (line-match-backwards paren-pair line counter)
(for/fold ([l-counter counter]
[col- (sub1 (string-length line))])
([col (in-range (sub1 (string-length line)) -1 -1)]
[c (string-reverse line)]
#:when (or (equal? c (car paren-pair)) (equal? c (cdr paren-pair)))
#:break (= l-counter 0)) ; todo start from p
(define local-counter
(cond
[(equal? c (car paren-pair))
(add1 l-counter)]
[else (sub1 l-counter)]))
(values local-counter col)))
(define (%-right-point p lines [count 1] [check? #t] [paren-lst #f])
(define-values (p-row p-col) (Point-row-col p))
(define-values (_ this after) (before-this-after lines p-row))
(define current-char (string-ref this p-col))
(define paren-pair (or paren-lst (get-paren-pair current-char)))
(unless (or (not check?) (equal? current-char (car paren-pair))) (error 'incorrect-paren (~v current-char)))
(define-values (init-counter init-col) (line-match-forwards paren-pair (substring this (add1 p-col)) count))
(define init-col+ (+ init-col p-col 1))
(define-values (c pp)
(for/fold ([counter init-counter]
[point (Point p-row init-col+ init-col+)])
([row (in-naturals (add1 p-row))]
[line after]
#:break (= counter 0))
(define-values (l-counter l-col) (line-match-forwards paren-pair line counter))
(values l-counter (Point row l-col l-col))
))
(unless (equal? c 0) (error 'no-matched-parens (~v c)))
pp)
(module+ test
(check-equal? (%-right-point (Point 0 1 1) '("((-[)])")) (Point 0 4 4))
(check-equal? (%-right-point (Point 0 3 3) '("((-["
")])")) (Point 1 1 1))
(check-equal? (%-right-point (Point 0 0 0) '("(123" "3))")) (Point 1 1 1))
)
(define (%-left-point p lines [count 1] [check? #t] [paren-lst #f])
(define-values (p-row p-col) (Point-row-col p))
(define-values (before this _) (before-this-after lines p-row))
(define current-char (string-ref this p-col))
(define paren-pair (or paren-lst (get-paren-pair current-char)))
(unless (or (not check?) (equal? current-char (cdr paren-pair))) (error 'incorrect-paren (~v current-char)))
(define-values (init-counter init-col) (line-match-backwards paren-pair (substring this 0 p-col) (- count)))
(define-values (c pp)
(for/fold ([counter init-counter]
[point (Point p-row init-col init-col)])
([row (in-range (sub1 p-row) -1 -1)]
[line (reverse before)]
#:break (= counter 0))
(define-values (l-counter l-col) (line-match-backwards paren-pair line counter))
(values l-counter (Point row l-col l-col))
))
(unless (equal? c 0) (error 'no-matched-parens (~v c)))
pp)
(module+ test
(check-equal? (%-left-point (Point 0 4 4) '("((-[)])")) (Point 0 1 1))
(check-equal? (%-left-point (Point 1 1 1) '("((-["
")])")) (Point 0 3 3))
(check-equal? (%-left-point (Point 1 1 1) '("(123" "3))")) (Point 0 0 0))
)
(define (is-left-paren? char [paren-pair #f])
(equal? char (car (or paren-pair (get-paren-pair char)))))
(define (is-right-paren? char [paren-pair #f])
(equal? char (cdr (or paren-pair (get-paren-pair char)))))
(define (%-point p lines)
(define-values (p-row p-col) (Point-row-col p))
(define-values (before this after) (before-this-after lines p-row))
(define char (string-ref this p-col))
(cond
[(is-left-paren? char)
(%-right-point p lines)]
[(is-right-paren? char)
(%-left-point p lines)]
[else (error 'not-on-a-paren)]))
(module+ test
(let ([lines '("((-"
"[)])")])
(check-equal? (%-point (%-point (Point 0 1 1) lines) lines) (Point 0 1 1))))
(define (a-paren-pair paren-pair p lines count) ;todo fix count
(define-values (p-row p-col) (Point-row-col p))
(define this (list-ref lines p-row))
(define char (string-ref this p-col))
(define left-p
(cond
[(is-left-paren? char paren-pair) p]
[else (%-left-point p lines count #f paren-pair)]))
(define right-p
(cond
[(is-right-paren? char paren-pair) p]
[else (%-right-point p lines count #f paren-pair)]))
(cons left-p right-p))
(module+ test
(let ([lines '("((-"
"[)])")])
(check-equal? (a-paren-pair '(#\( . #\)) (Point 0 1 1) lines 1)
(cons (Point 0 1 1) (Point 1 1 1)))
(check-equal? (a-paren-pair '(#\[ . #\]) (Point 1 1 1) lines 1)
(cons (Point 1 0 0) (Point 1 2 2)))
)
)