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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
open CamomileLibraryDyn.Camomile
exception Out_of_bounds
type t =
| String of int
| Return
| Concat of t * t * int * int * int
let length = function
| String len -> len
| Return -> 1
| Concat(_, _, len, _, _) -> len
let count = function
| String _ -> 0
| Return -> 1
| Concat(_, _, _, count, _) -> count
let depth = function
| String _ | Return -> 0
| Concat(_, _, _, _, d) -> d
let empty = String 0
let rec line_index_rec set ofs acc =
match set with
| String _ ->
acc
| Return ->
if ofs = 0 then
acc
else
acc + 1
| Concat(s1, s2, _, _, _) ->
let len1 = length s1 in
if ofs < len1 then
line_index_rec s1 ofs acc
else
line_index_rec s2 (ofs - len1) (acc + count s1)
let line_index set ofs =
if ofs < 0 || ofs > length set then
raise Out_of_bounds
else
line_index_rec set ofs 0
let rec line_start_rec set idx acc =
match set with
| String _ ->
acc
| Return ->
if idx = 0 then
acc
else
acc + 1
| Concat(s1, s2, _, _, _) ->
let count1 = count s1 in
if idx <= count1 then
line_start_rec s1 idx acc
else
line_start_rec s2 (idx - count1) (acc + length s1)
let line_start set idx =
if idx < 0 || idx > count set then
raise Out_of_bounds
else
line_start_rec set idx 0
let line_stop set idx =
if idx = count set
then length set
else line_start set (idx + 1) - 1
let line_length set idx =
line_stop set idx - line_start set idx
let concat set1 set2 =
Concat(set1, set2,
length set1 + length set2,
count set1 + count set2,
1 + max (depth set1) (depth set2))
let append set1 set2 =
match set1, set2 with
| String 0, _ -> set2
| _, String 0 -> set1
| String len1, String len2 ->
String(len1 + len2)
| String len1, Concat(String len2, set, len, count, h) ->
Concat(String(len1 + len2), set, len + len1, count, h)
| Concat(set, String len1, len, count, h), String len2 ->
Concat(set, String(len1 + len2), len + len2, count, h)
| _ ->
let d1 = depth set1 and d2 = depth set2 in
if d1 > d2 + 2 then begin
match set1 with
| String _ | Return ->
assert false
| Concat(set1_1, set1_2, _, _, _) ->
if depth set1_1 >= depth set1_2 then
concat set1_1 (concat set1_2 set2)
else begin
match set1_2 with
| String _ | Return ->
assert false
| Concat(set1_2_1, set1_2_2, _, _, _) ->
concat (concat set1_1 set1_2_1) (concat set1_2_2 set2)
end
end else if d2 > d1 + 2 then begin
match set2 with
| String _ | Return ->
assert false
| Concat(set2_1, set2_2, _, _, _) ->
if depth set2_2 >= depth set2_1 then
concat (concat set1 set2_1) set2_2
else begin
match set2_1 with
| String _ | Return ->
assert false
| Concat(set2_1_1, set2_1_2, _, _, _) ->
concat (concat set1 set2_1_1) (concat set2_1_2 set2_2)
end
end else
concat set1 set2
let rec unsafe_sub set idx len =
match set with
| String _ ->
String len
| Return ->
if len = 1 then
Return
else
String 0
| Concat(set_l, set_r, len', _, _) ->
let len_l = length set_l in
if len = len' then
set
else if idx >= len_l then
unsafe_sub set_r (idx - len_l) len
else if idx + len <= len_l then
unsafe_sub set_l idx len
else
append
(unsafe_sub set_l idx (len_l - idx))
(unsafe_sub set_r 0 (len - len_l + idx))
let sub set idx len =
if idx < 0 || len < 0 || idx + len > length set then
raise Out_of_bounds
else
unsafe_sub set idx len
let break set ofs =
let len = length set in
if ofs < 0 || ofs > len then
raise Out_of_bounds
else
(unsafe_sub set 0 ofs, unsafe_sub set ofs (len - ofs))
let insert set ofs set' =
let set1, set2 = break set ofs in
append set1 (append set' set2)
let remove set ofs len =
append (sub set 0 ofs) (sub set (ofs + len) (length set - ofs - len))
let replace set ofs len repl =
append (sub set 0 ofs) (append repl (sub set (ofs + len) (length set - ofs - len)))
let of_rope rope =
let rec loop zip len acc =
if Zed_rope.Zip.at_eos zip then
append acc (String len)
else
let ch, zip = Zed_rope.Zip.next zip in
if UChar.code ch = 10 then
loop0 zip (append (append acc (String len)) Return)
else
loop zip (len + 1) acc
and loop0 zip acc =
if Zed_rope.Zip.at_eos zip then
acc
else
let ch, zip = Zed_rope.Zip.next zip in
if UChar.code ch = 10 then
loop0 zip (append acc Return)
else
loop zip 1 acc
in
loop0 (Zed_rope.Zip.make_f rope 0) empty