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
open Source
type line_feed = LF | CRLF
type 'l trivia = Comment of string | Space of int | Tab of int | Line of 'l
type void = |
let absurd : void -> 'a = function _ -> .
let map_trivia : ('a -> 'b) -> 'a trivia -> 'b trivia =
fun f -> function
| Comment str -> Comment str
| Space n -> Space n
| Tab n -> Tab n
| Line l -> Line (f l)
let string_of_line_feed = function LF -> "LF" | CRLF -> "CRLF"
let string_of_trivia : ('a -> string) -> 'a trivia -> string =
fun f t ->
match t with
| Comment str -> str
| Space n -> Printf.sprintf "Space(%d)" n
| Tab n -> Printf.sprintf "Tab(%d)" n
| Line l -> Printf.sprintf "Line(%s)" (f l)
let string_of_trivia_lf : line_feed trivia -> string =
string_of_trivia string_of_line_feed
type trivia_info = {
leading_trivia : line_feed trivia list;
trailing_trivia : void trivia list;
}
let string_of_trivia_info (info : trivia_info) : string =
let leading = List.map (string_of_trivia string_of_line_feed) info.leading_trivia |> String.concat ", " in
let trailing = List.map (string_of_trivia (fun _ -> "")) info.trailing_trivia |> String.concat ", " in
Printf.sprintf "Leading: [%s]; Trailing: [%s]" leading trailing
type pos = { line : int; column : int }
let pos_of_lexpos : Lexing.position -> pos =
fun lexpos ->
Lexing.{ line = lexpos.pos_lnum; column = lexpos.pos_cnum - lexpos.pos_bol }
module PosHash = struct
type t = pos
let equal i j = i = j
let hash ({ line; column } : pos) = column lor 20 land line
end
module PosHashtbl = Hashtbl.Make (PosHash)
(* type triv_table = trivia_info IntHashtbl.t *)
type triv_table = trivia_info PosHashtbl.t
let empty_triv_table = PosHashtbl.create 0
let find_trivia triv_table (parser_pos : Source.region) : trivia_info =
PosHashtbl.find triv_table
{ line = parser_pos.left.line; column = parser_pos.left.column }
let deprecated_of_trivia_info : trivia_info -> string option =
fun info ->
let lines =
List.filter_map
(function
| Comment s -> (
match Lib.String.chop_prefix "/// @deprecated" s with
| Some "" -> Some ""
| Some line_comment ->
(* We expect a documentation line comment to start with a space
* (which we remove here) *)
Lib.String.chop_prefix " " line_comment
| None -> None )
| _ -> None)
info.leading_trivia
in
if lines = [] then None else Some (String.concat "\n" lines)
type doc = LineComment of string | BlockComment of string
let docs_of_trivia_info (info : trivia_info) : doc list =
List.filter_map
(function
| Comment s -> (
match Lib.String.chop_prefix "///" s with
| Some "" -> Some (LineComment "")
| Some line_comment ->
(* We expect a documentation line comment to start with a space
* (which we remove here) *)
Lib.String.chop_prefix " " line_comment
|> Option.map (fun c -> LineComment c)
| None ->
Option.bind
(Lib.String.chop_prefix "/**" s)
(Lib.String.chop_suffix "*/")
|> Option.map String.trim
|> Option.map (fun c -> BlockComment c))
| _ -> None)
info.leading_trivia
let doc_comment_of_trivia_info (info : trivia_info) : string option =
let docs = docs_of_trivia_info info in
let lines = List.map (function BlockComment s | LineComment s -> s) docs in
if lines = [] then None else Some (String.concat "\n" lines)