2 * Copyright (c) 2017, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
11 module SN
= Naming_special_names
13 let quote_string s
= "\"" ^
Php_escaping.escape s ^
"\""
14 let quote_string_with_escape ?
(f
= Php_escaping.escape_char
) s
=
15 "\\\"" ^
Php_escaping.escape ~f s ^
"\\\""
16 let single_quote_string_with_escape ?
(f
= Php_escaping.escape_char
) s
=
17 "'" ^
Php_escaping.escape ~f s ^
"'"
18 let triple_quote_string s
= "\"\"\"" ^
Php_escaping.escape s ^
"\"\"\""
20 let prefix_namespace n s
= n ^
"\\" ^ s
21 let strip_global_ns s
=
22 if String.length s
> 0 || s
.[0] = '
\\'
23 then String_utils.lstrip s
"\\"
26 let rx = Str.regexp
{|.*\\|} in
27 (* strip zero or more chars followed by a backslash *)
28 fun s
-> Str.replace_first
rx "" s
30 let rx = Str.regexp
{|.+\\.+|} in
31 fun s
-> Str.string_match
rx s
0
33 let rx = Str.regexp
{|<.*>|} in
34 fun s
-> Str.global_replace
rx "" s
36 let cmp ?
(case_sensitive
=true) ?
(ignore_ns
=false) s1 s2
=
38 if case_sensitive
then s1, s2
else
39 String.lowercase
s1, String.lowercase s2
42 if not ignore_ns
then s1, s2
else
43 strip_ns s1, strip_ns s2
48 String.lowercase s
= SN.Classes.cSelf
51 String.lowercase s
= SN.Classes.cParent
54 String.lowercase s
= SN.Classes.cStatic
57 String.lowercase s
= SN.Members.mClass
59 let mangle_meth_caller mangled_cls_name f_name
=
60 "\\MethCaller$" ^ mangled_cls_name ^
"::" ^ f_name
63 let fix_casing s
= match String.lowercase s
with
64 | "vector" -> "Vector"
65 | "immvector" -> "ImmVector"
67 | "immset" -> "ImmSet"
69 | "immmap" -> "ImmMap"
74 (* Integers are represented as strings *)
75 module Integer
= struct
76 (* Dont accidentally convert 0 to 0o *)
77 let to_decimal s
= Int64.to_string
@@ Int64.of_string
@@
78 if String.length s
> 1 && s
.[0] = '
0'
then
85 | _
-> "0o" ^
String_utils.lstrip s
"0"
88 (* In order for this to be true, every char has to be a number as well as
89 * if the first digit is a zero, then there cannot be more digits
90 * negative zero is dealt specially as it is not casted to zero
94 * -0 -> false (special case)
96 * 0b1 -> false (binary)
99 let is_decimal_int s
= if s
= "-0" then false else
100 let s = String_utils.lstrip
s "-" in
101 String_utils.fold_left
s
103 ~f
:(fun acc i
-> String_utils.is_decimal_digit i
&& acc
)
104 && (String.length
s = 1 || (s.[0] <> '
0'
))
107 module Float
= struct
109 match Printf.sprintf
"%0.17g" f
with
115 (* Unfortunately the g flag does not provide enough of a match with hhvm,
116 * hence we go for manual manipulation *)
117 let with_scientific_notation f
=
118 if String.contains f 'E'
|| String.contains f 'e'
119 then Printf.sprintf
"%0.1E" (float_of_string f
)
123 module Locals
= struct
125 let strip_dollar s = String_utils.lstrip
s "$"
129 module Classes
= struct
131 let mangle_class prefix scope ix
=
134 ^
(if ix
= 1 then "" else "#" ^ string_of_int ix
)
136 (* Anonymous classes have names of the form
137 * class@anonymous$ scope ix ; num
141 * | <class-name> :: <method-name>
146 let mangle_anonymous_class scope ix
=
147 mangle_class "class@anonymous" scope ix
149 let is_anonymous_class_name n
=
150 String_utils.string_starts_with n
"class@anonymous"
153 module Closures
= struct
155 let is_closure_name s =
156 String_utils.string_starts_with
s "Closure$"
157 (* Closure classes have names of the form
158 * Closure prefix $ scope ix ; num
161 * $ <prefix-attribute>
165 * | <class-name> :: <method-name>
170 let unmangle_closure =
172 match String.lsplit2
s ~on
:'#'
with
173 | Some
(prefix
, _
) -> prefix
176 match String.split
s ~on
:'$'
with
177 | ["Closure"; _prefix
; scope
] -> Some
(strip_index scope
)
178 | ["Closure"; scope
] -> Some
(strip_index scope
)
181 let mangle_closure scope ix name
=
183 | Some
s -> Classes.mangle_class ("Closure$" ^
s) scope ix
184 | None
-> Classes.mangle_class "Closure" scope ix
187 (* XHP name mangling *)
189 let is_xhp s = String.length
s <> 0 && s.[0] = '
:'
191 let strip_colon s = String_utils.lstrip
s ":"
193 let clean s = if not
(is_xhp s) then s else strip_colon s
196 Classes.is_anonymous_class_name s || Closures.is_closure_name s
198 (* Mangle an unqualified ID *)
199 let mangle_id_worker =
200 let rx_colon = Str.regexp
":" in
201 let rx_dash = Str.regexp
"-" in
203 if ignore_id s then s
205 let need_prefix = is_xhp s in
206 let s = if need_prefix then (strip_colon s) else s in
209 |> Str.global_replace
rx_colon "__"
210 |> Str.global_replace
rx_dash "_" in
211 if need_prefix then "xhp_" ^
s else s
214 if ignore_id s then s else mangle_id_worker s
216 (* Mangle a possibly-qualified ID *)
218 let rx = Str.regexp
"\\" in
220 if ignore_id s then s
222 match List.rev
(Str.split_delim
rx s) with
225 String.concat ~sep
:"\\" (List.rev
(mangle_id_worker id
:: rest
))
227 let unmangle_id_worker =
228 let rx_dunder = Str.regexp
"__" in
229 let rx_under = Str.regexp
"_" in
231 let has_prefix = String_utils.string_starts_with
s "xhp_" in
232 let s = if has_prefix then String_utils.lstrip
s "xhp_" else s in
235 |> Str.global_replace
rx_dunder ":"
236 |>Str.global_replace
rx_under "-" in
237 if has_prefix then ":" ^
s else s
240 let rx = Str.regexp
"\\" in
242 if ignore_id s then s
244 match List.rev
(Str.split_delim
rx s) with
247 String.concat ~sep
:"\\" (List.rev
(unmangle_id_worker id
:: rest
))
251 (* Reified param mangling *)
252 module Reified
= struct
253 let mangle_reified_param ?
(nodollar
= false) s =
254 (if nodollar
then "" else "$") ^
"__reified$" ^
s
256 let reified_prop_name = "86reified_prop"
258 let reified_init_method_name = "86reifiedinit"
260 let reified_init_method_param_name = "$__typestructures"
262 let reified_generics_local_name = "$0ReifiedGenerics"
264 let reified_generic_captured_name is_fun i
=
265 let type_ = if is_fun
then "function" else "class" in
266 Printf.sprintf
"$__captured$reifiedgeneric$%s$%d" type_ i
268 let is_captured_generic id
=
269 let prefix = "$__captured$reifiedgeneric$" in
270 let (>>=) = Option.(>>=) in
271 String.chop_prefix ~
prefix id
272 >>= String.lsplit2 ~on
:'$'
273 >>= (fun v
-> try match v
with
274 | ("function", i
) -> Some
(true, int_of_string i
)
275 | ("class", i
) -> Some
(false, int_of_string i
)