@@ -9,23 +9,23 @@ let trim_non_content: Segment.t => Segment.t =
99
1010let prev_pieces = (seg: Segment . t ): list(option(Piece . t)) => {
1111 let rec go =
12- (xs: list (Piece . t ), prev: option (Piece . t ))
12+ (acc , xs: list (Piece . t ), prev: option (Piece . t ))
1313 : list(option(Piece . t)) =>
1414 switch (xs) {
15- | [] => []
16- | [ x , ... xs ] => [ prev, ... go( xs, Some (x))]
15+ | [] => List . rev(acc)
16+ | [ x , ... xs ] => go( [ prev, ... acc ] , xs, Some (x))
1717 };
18- go(seg, None );
18+ go([] , seg, None );
1919};
2020
2121let next_pieces = (seg: Segment . t ): list(option(Piece . t)) => {
22- let rec go = (xs: list (Piece . t )): list(option(Piece . t)) =>
22+ let rec go = (acc , xs: list (Piece . t )): list(option(Piece . t)) =>
2323 switch (xs) {
24- | [] => []
25- | [ _ ] => [ None ]
26- | [ _ , next , ... rest ] => [ Some (next), ... go( [ next, ... rest] )]
24+ | [] => List . rev(acc)
25+ | [ _ ] => List . rev( [ None , ... acc ] )
26+ | [ _ , next , ... rest ] => go( [ Some (next), ... acc ] , [ next, ... rest] )
2727 };
28- go(seg);
28+ go([] , seg);
2929};
3030
3131let union_all =
@@ -35,20 +35,27 @@ let union_all =
3535 );
3636
3737/* This does not strictly 'complete' a segment but rather does a
38- * rough version of it that suffices for indentation calculation */
39- let rec shallow_complete_segment = (seg: Segment . t ): Segment . t =>
40- switch (seg) {
41- | [] => []
42- | [Tile (t ), ... rest ] when ! Tile . is_complete(t) => [
43- Tile ({
44- ... t,
45- shards: List . init(List . length(t. label), i => i),
46- children: t. children @ [ shallow_complete_segment(rest)] ,
47- /* Note: Potentially wrong number of children */
48- }),
49- ]
50- | [ p , ... rest ] => [ p, ... shallow_complete_segment(rest)]
51- };
38+ * rough version of it that suffices for indentation calculation.
39+ * Tail-recursive in segment length (recursion depth is bounded by
40+ * the number of incomplete tiles, not the number of pieces). */
41+ let rec shallow_complete_segment = (seg: Segment . t ): Segment . t => {
42+ let rec go = (acc, seg: Segment . t ): Segment . t =>
43+ switch (seg) {
44+ | [] => List . rev(acc)
45+ | [Tile (t ), ... rest ] when ! Tile . is_complete(t) =>
46+ List . rev([
47+ Piece . Tile ({
48+ ... t,
49+ shards: List . init(List . length(t. label), i => i),
50+ children: t. children @ [ shallow_complete_segment(rest)] ,
51+ /* Note: Potentially wrong number of children */
52+ }),
53+ ... acc,
54+ ] )
55+ | [ p , ... rest ] => go([ p, ... acc] , rest)
56+ };
57+ go([] , seg);
58+ };
5259
5360/* Find the shortest prefix of the segment containing all incomplete tiles
5461 * followed by two consecutive linebreaks (aka a blank line) */
@@ -174,9 +181,13 @@ let rec go' = ((not_top, base: int, seg: Segment.t)) => {
174181 },
175182 (base, Id . Map . empty),
176183 complete_trimmed_seg,
177- List . combine(
178- prev_pieces(complete_trimmed_seg),
179- next_pieces(complete_trimmed_seg),
184+ /* stack-safe zip (List.combine is not tail-recursive) */
185+ List . rev(
186+ List . rev_map2(
187+ (prev, next) => (prev, next),
188+ prev_pieces(complete_trimmed_seg),
189+ next_pieces(complete_trimmed_seg),
190+ ),
180191 ),
181192 );
182193 map;
0 commit comments