1+ type path_item =
2+ | Module of string
3+ | AnonymousFunction of int * int * string option
4+ | NamedFunction of string
5+ | AnonymousModule of int * int * string option
6+
7+ (* Create a path representing Foo.Bar.baz
8+ as
9+ let n = [Module "Foo"; Module "Bar"; NamedFunction "baz"]
10+ *)
11+ type path = path_item list
12+
13+ let is_out_char = function
14+ | '0' .. '9' | 'A' .. 'Z' | 'a' .. 'z' | '_' -> true
15+ | _ -> false
16+
17+ let upper = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
18+ let hex = " 0123456789abcdef"
19+
20+ (* * Encode a length as base-26 number using [[A-Z]] *)
21+ let rec encode_len buf len =
22+ let r = len mod 26 and q = len / 26 in
23+ if q > 0 then encode_len buf q;
24+ Buffer. add_char buf upper.[r]
25+
26+ let encode_char buf c =
27+ let c = Char. code c in
28+ let h = (c lsr 4 ) land 0xf and l = c land 0xf in
29+ Buffer. add_char buf (hex.[h]);
30+ Buffer. add_char buf (hex.[l])
31+
32+ type encode_state = Raw | Enc
33+
34+ let encode (sym : string ) =
35+ let raw = Buffer. create (String. length sym)
36+ and enc = Buffer. create (2 * String. length sym)
37+ and ins_pos = ref 0 in
38+ let rec aux i = function
39+ | _ when i > = String. length sym ->
40+ Printf. sprintf " %s_%s" (Buffer. contents enc) (Buffer. contents raw)
41+ | Raw ->
42+ if is_out_char sym.[i] then (
43+ Buffer. add_char raw sym.[i];
44+ incr ins_pos;
45+ aux (i + 1 ) Raw )
46+ else (
47+ encode_len enc ! ins_pos;
48+ encode_char enc sym.[i];
49+ aux (i + 1 ) Enc )
50+ | Enc ->
51+ if is_out_char sym.[i] then (
52+ Buffer. add_char raw sym.[i];
53+ ins_pos := 1 ;
54+ aux (i + 1 ) Raw )
55+ else (
56+ encode_char enc sym.[i];
57+ aux (i + 1 ) Enc )
58+ in
59+ aux 0 Raw
60+
61+ let mangle_chunk = function
62+ | Module sym ->
63+ let pref, rsym =
64+ if String. for_all is_out_char sym then (" " , sym) else (" u" , encode sym)
65+ in
66+ Printf. sprintf " %s%d%s" pref (String. length rsym) rsym
67+ | NamedFunction sym ->
68+ let pref, rsym =
69+ if String. for_all is_out_char sym then (" " , sym) else (" u" , encode sym)
70+ in
71+ Printf. sprintf " %s%d%s" pref (String. length rsym) rsym
72+ | AnonymousFunction (line , col , file_opt ) ->
73+ let file_name = Option. value ~default: " " file_opt in
74+ let ts = Printf. sprintf " %s_%d_%d" file_name line col in
75+ Printf. sprintf " %d%s" (String. length ts) ts
76+ | AnonymousModule (line , col , file_opt ) ->
77+ let file_name = Option. value ~default: " " file_opt in
78+ let ts = Printf. sprintf " %s_%d_%d" file_name line col in
79+ Printf. sprintf " %d%s" (String. length ts) ts
80+
81+ let mangle_path (path : path ) : string =
82+ let b = Buffer. create 10 in
83+ List. iter (fun s -> Buffer. add_string b (mangle_chunk s)) path;
84+ Buffer. contents b
85+
86+ let mangle_path_with_prefix (path : path ) : string =
87+ let b = Buffer. create 10 in
88+ Buffer. add_string b " _O" ;
89+ List. iter (fun s -> Buffer. add_string b (mangle_chunk s)) path;
90+ Buffer. contents b
91+
92+ let mangle_comp_unit (cu : Compilation_unit.t ) : string =
93+ let for_pack_prefix, name, flattened_instance_args = Compilation_unit. flatten cu in
94+ let name = Compilation_unit.Name. to_string name in
95+ if not (Compilation_unit.Prefix. is_empty for_pack_prefix)
96+ then begin
97+ assert (flattened_instance_args = [] );
98+ let pack_names =
99+ Compilation_unit.Prefix. to_list for_pack_prefix
100+ |> List. map (fun x -> Module (Compilation_unit.Name. to_string x))
101+ in
102+ mangle_path_with_prefix (Module name :: (pack_names @ [Module name]))
103+ end else begin
104+ (* TODO For Parameterised libraries??? *)
105+ let instance_separator = " ____" in
106+ let instance_separator_depth_char = '_' in
107+ let arg_segments =
108+ List. map
109+ (fun (depth , _param , value ) ->
110+ let extra_separators =
111+ String. make depth instance_separator_depth_char
112+ in
113+ let value = value |> Compilation_unit.Name. to_string in
114+ Module (String. concat " " [instance_separator; extra_separators; value]))
115+ flattened_instance_args
116+ in
117+ mangle_path ((Module name) :: arg_segments)
118+ end
119+
120+ let mangle_ident (cu : Compilation_unit.t ) (path : path ) =
121+ let b = Buffer. create 10 in
122+ Buffer. add_string b (mangle_comp_unit cu);
123+ Buffer. add_string b (mangle_path path);
124+ Buffer. contents b
125+
0 commit comments