33 Nodes, along with holding an object, also include additional metadata such as their position and
44 surrounding trivia. *)
55
6- (* * A "trivial" part of the program, which is not important for the execution of the program, but
7- may be useful for understanding or recreating it. *)
8- type trivial =
9- | LineComment of string (* * A short, comment which is terminated by a newline. *)
10- | BlockComment of string (* * A long comment, which may span multiple lines. *)
11- | Whitespace of string (* * Any whitespace, such as spaces, newlines or tabs. *)
12- [@@ deriving show ]
6+ module Trivia = struct
7+ type kind =
8+ | LineComment (* * A short, comment which is terminated by a newline. *)
9+ | BlockComment (* * A long comment, which may span multiple lines. *)
10+ | Whitespace (* * Any whitespace, such as spaces, newlines or tabs. *)
11+
12+ (* * A "trivial" part of the program, which is not important for the execution of the program, but
13+ may be useful for understanding or recreating it. *)
14+ type t =
15+ { start : Illuaminate.Position_map .pos ;
16+ kind : kind ;
17+ contents : string
18+ }
19+
20+ let make kind contents start = { kind; contents; start }
21+ let pp out (x : t ) = Format. fprintf out " Trivia(%S)" x.contents
22+ let start t = t.start
23+
24+ let finish t : Illuaminate.Position_map.pos =
25+ let (Pos start) = t.start in
26+ Pos (start + String. length t.contents - 1 )
27+
28+ let span root trivia =
29+ let open Illuaminate.Lens in
30+ let (Illuaminate.Position_map. Pos start) = start trivia in
31+ let (Illuaminate.Position_map. Pos finish) = finish trivia in
32+ root |> Span. start_offset ^= start |> Span. finish_offset ^= finish
33+ end
1334
1435(* * A node, such as a token or identifier, but with additional metadata.
1536
16- Every node has leading and trailing trivia, represented as a list of {!Span.spanned} {!trivial}
17- nodes. Nodes generated by the parser will generally have a {!Node} type, while generated nodes
18- (who have not got any trivia) are built from {!SimpleNode} s. *)
37+ Every node has leading and trailing trivia, represented as an array of {!Trivia.t } nodes. *)
1938type 'a t =
20- | SimpleNode of { contents : 'a }
21- (* * A "simple" node, which was generated by the compiler rather than taken from source code.
22- *)
23- | Node of
24- { leading_trivia : trivial Span .spanned list ;
25- trailing_trivia : trivial Span .spanned list ;
26- contents : 'a ;
27- span : Span .t (* * The position of the node, not including leading or trailing trivia. *)
28- }
29- (* * A token with full metadata, which can {i generally} be traced to a concrete position in
30- the source code. *)
39+ { leading_trivia : Trivia .t Illuaminate.IArray .t ;
40+ trailing_trivia : Trivia .t Illuaminate.IArray .t ;
41+ contents : 'a ;
42+ span : Span .t (* * The position of the node, not including leading or trailing trivia. *)
43+ }
3144[@@ deriving show ]
3245
3346(* * Update the contents of this node. *)
34- let with_contents contents = function
35- | SimpleNode _ -> SimpleNode { contents }
36- | Node n -> Node { n with contents }
47+ let with_contents contents (node : _ t ) = { node with contents }
3748
3849(* * Get the span of this node, if defined. Otherwise throw an exception. *)
39- let span = function
40- | Node { span; _ } -> span
41- | SimpleNode _ -> failwith " No span."
42-
43- (* * Get the span of the first trivia node, or the current node *)
44- let trivia_start = function
45- | Node { span; leading_trivia; _ } -> (
46- match leading_trivia with
47- | [] -> span
48- | t :: _ -> t.span)
49- | SimpleNode _ -> failwith " No span."
50-
51- (* * Get the span of the last trivia node, or the current node *)
52- let trivia_finish = function
53- | Node { span; trailing_trivia; _ } -> (
54- match CCList. last_opt trailing_trivia with
55- | None -> span
56- | Some t -> t.span)
57- | SimpleNode _ -> failwith " No span."
58-
59- (* * Get the span of this node, including trivia of this node. *)
60- let trivia_span n = Span. of_span2 (trivia_start n) (trivia_finish n)
50+ let span node = node.span
6151
6252open Illuaminate.Lens
6353
6454(* * A lens which exposes the contents of the term. *)
6555let contents =
66- let get (SimpleNode { contents } | Node { contents; _ } ) = contents
67- and over f = function
68- | SimpleNode n -> SimpleNode { contents = f n.contents }
69- | Node n -> Node { n with contents = f n.contents }
70- in
56+ let get (n : _ t ) = n.contents in
57+ let over f (n : _ t ) = { n with contents = f n.contents } in
7158 { get; over }
7259
7360(* * Embed a lens which transforms the whole node with a view on the body. *)
@@ -85,60 +72,40 @@ let lens_embed (type s u a b) (inner : (s, u, a, b) lens) : (s t, u t, a t, b t)
8572 When converting a term from a {!SimpleNode} to a {!Node}, we will use the position of the first
8673 trivial node. *)
8774let trailing_trivia =
88- let get = function
89- | SimpleNode _ -> []
90- | Node { trailing_trivia = t ; _ } -> t
91- in
92- let over f x =
93- let t = f (get x) in
94- match (x, t) with
95- | SimpleNode _ , [] -> x
96- | SimpleNode { contents } , { Span. span; _ } :: _ ->
97- Node { span; contents; trailing_trivia = t; leading_trivia = [] }
98- | Node n , _ -> Node { n with trailing_trivia = t }
99- in
75+ let get n = n.trailing_trivia in
76+ let over f n = { n with trailing_trivia = f n.trailing_trivia } in
10077 { get; over }
10178
10279(* * A lens which exposes the leading trivia of a term.
10380
10481 When converting a term from a {!SimpleNode} to a {!Node}, we will use the position of the first
10582 trivial node. *)
10683let leading_trivia =
107- let get = function
108- | SimpleNode _ -> []
109- | Node { leading_trivia = t ; _ } -> t
110- in
111- let over f x =
112- let t = f (get x) in
113- match (x, t) with
114- | SimpleNode _ , [] -> x
115- | SimpleNode { contents } , { Span. span; _ } :: _ ->
116- Node { span; contents; leading_trivia = t; trailing_trivia = [] }
117- | Node n , _ -> Node { n with leading_trivia = t }
118- in
84+ let get n = n.leading_trivia in
85+ let over f n = { n with leading_trivia = f n.leading_trivia } in
11986 { get; over }
12087
12188(* * Join two lists of trivial nodes together. While {!(\@)} will normally suffice for this,
12289 {!join_trivia} attempts to merge whitespace between adjacent nodes too. *)
123- let join_trivia xs ys : trivial Span.spanned list =
124- match ys with
125- | [] -> xs
126- | { Span. value = Whitespace r ; span = rs } :: ys' ->
127- let is_space = function
128- | ' ' | '\t' -> true
129- | _ -> false
130- in
131- let rec go = function
132- | [] -> ys
133- | [ ({ Span. value = Whitespace l; span = ls } as x) ] ->
134- if l = " " then ys
135- else if is_space l.[ String. length l - 1 ] then
136- { Span. value = Whitespace ( CCString. rdrop_while is_space l ^ r);
137- span = Span. of_span2 ls rs
138- }
139- :: ys'
140- else x :: ys
141- | x :: xs -> x :: go xs
142- in
143- go xs
144- | ys -> xs @ ys
90+ let join_trivia xs ys : Trivia.t Illuaminate.IArray.t =
91+ let module IArray = Illuaminate. IArray in
92+ if IArray. is_empty xs then ys
93+ else if IArray. is_empty ys then xs
94+ else
95+ let is_space = function
96+ | ' ' | '\t' -> true
97+ | _ -> false
98+ in
99+ match ( IArray. last xs, IArray. first ys) with
100+ (* If our first trivia ends in a space (" ") and the second trivia starts with any whitespace,
101+ drop that space and just use the leading whitespace. *)
102+ | { kind = Whitespace ; contents = last_c; _ }, { kind = Whitespace ; _ }
103+ when is_space last_c.[ String. length last_c - 1 ] ->
104+ (* Build an array of xs[:-1] @ ys *)
105+ let xs_len = IArray. length xs - 1 in
106+ let out =
107+ Array. init (xs_len + IArray. length ys) @@ fun i ->
108+ if i < xs_len then IArray. get xs i else IArray. get ys (i - xs_len)
109+ in
110+ IArray. of_array out
111+ | _ -> IArray. append xs ys
0 commit comments