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 Acc
= Mutable_accumulator
14 module SU
= Hhbc_string_utils
15 module SN
= Naming_special_names
16 module ULS
= Unique_list_string
20 let sep pieces
= String.concat ~
sep:" " pieces
24 let string_of_optional_value f v
=
27 ~f
:(fun s
-> " " ^
(f s
))
29 let string_of_class_id id
=
30 SU.quote_string
(Hhbc_id.Class.to_raw_string id
)
31 let string_of_function_id id
=
32 SU.quote_string
(Hhbc_id.Function.to_raw_string id
)
33 let string_of_method_id id
=
34 SU.quote_string
(Hhbc_id.Method.to_raw_string id
)
35 let string_of_const_id id
=
36 SU.quote_string
(Hhbc_id.Const.to_raw_string id
)
37 let string_of_prop_id id
=
38 SU.quote_string
(Hhbc_id.Prop.to_raw_string id
)
39 let string_of_class_num id
=
41 let string_of_function_num id
=
43 let string_of_typedef_num id
=
45 let string_of_pos pos
=
46 let {line_begin
; line_end
; col_begin
; col_end
} = pos
in
47 Printf.sprintf
"%d:%d,%d:%d" line_begin col_begin line_end col_end
48 let string_of_span (line_begin
, line_end
) =
49 Printf.sprintf
"(%d,%d)" line_begin line_end
51 (* Naming convention for functions below:
52 * string_of_X converts an X to a string
53 * add_X takes a buffer and an X, and appends to the buffer
55 let string_of_basic instruction
=
56 match instruction
with
58 | EntryNop
-> "EntryNop"
66 let string_of_list_of_shape_fields sl
=
67 String.concat ~
sep:" " @@ List.map ~f
:SU.quote_string sl
69 let string_of_stack_index si
= string_of_int si
71 let string_of_classref id
= string_of_int id
73 let string_of_adata_id id
= "@" ^ id
75 let string_of_param_id x
=
77 | Param_unnamed i
-> string_of_int i
80 let string_of_param_num i
= string_of_int i
82 let string_of_local_id x
=
84 | Local.Unnamed i
-> "_" ^
(string_of_int i
)
87 let string_of_lit_const instruction
=
88 match instruction
with
90 | Int i
-> sep ["Int"; Int64.to_string i
]
91 | String str
-> sep ["String"; SU.quote_string str
]
94 | Double d
-> sep ["Double"; d
]
95 | AddElemC
-> "AddElemC"
96 | AddNewElemC
-> "AddNewElemC"
97 | Array id
-> sep ["Array"; string_of_adata_id id
]
98 | Dict id
-> sep ["Dict"; string_of_adata_id id
]
99 | Keyset id
-> sep ["Keyset"; string_of_adata_id id
]
100 | Vec id
-> sep ["Vec"; string_of_adata_id id
]
101 | TypedValue _tv
-> failwith
"string_of_lit_const: TypedValue"
102 | ColFromArray t
-> sep ["ColFromArray"; CollectionType.to_string t
]
103 | NewCol t
-> sep ["NewCol"; CollectionType.to_string t
]
104 | NewDictArray i
-> sep ["NewDictArray"; string_of_int i
]
105 | NewKeysetArray i
-> sep ["NewKeysetArray"; string_of_int i
]
106 | NewVecArray i
-> sep ["NewVecArray"; string_of_int i
]
107 | NewVArray i
-> sep ["NewVArray"; string_of_int i
]
108 | NewDArray i
-> sep ["NewDArray"; string_of_int i
]
109 | NewMixedArray i
-> sep ["NewMixedArray"; string_of_int i
]
110 | NewPackedArray i
-> sep ["NewPackedArray"; string_of_int i
]
111 | NewStructArray l
->
112 sep ["NewStructArray"; "<" ^
string_of_list_of_shape_fields l ^
">"]
113 | NewStructDArray l
->
114 sep ["NewStructDArray"; "<" ^
string_of_list_of_shape_fields l ^
">"]
116 sep ["NewStructDict"; "<" ^
string_of_list_of_shape_fields l ^
">"]
117 | NewPair
-> "NewPair"
118 | ClsCns
(cnsid
, cr
) ->
119 sep ["ClsCns"; string_of_const_id cnsid
; string_of_classref cr
]
120 | ClsCnsD
(cnsid
, cid
) ->
121 sep ["ClsCnsD"; string_of_const_id cnsid
; string_of_class_id cid
]
124 | NullUninit
-> "NullUninit"
125 | AddElemV
-> "AddElemV"
126 | AddNewElemV
-> "AddNewElemV"
128 | NewArray n
-> sep ["NewArray"; string_of_int n
]
129 | NewLikeArrayL
(id
, n
) ->
130 sep ["NewLikeArrayL"; string_of_local_id id
; string_of_int n
]
131 | Cns cnsid
-> sep ["Cns"; string_of_const_id cnsid
]
132 | CnsE cnsid
-> sep ["CnsE"; string_of_const_id cnsid
]
134 sep ["CnsU"; string_of_const_id id1
; SU.quote_string id2
]
135 | CnsUE
(id1
, id2
) ->
136 sep ["CnsUE"; string_of_const_id id1
; SU.quote_string id2
]
139 let string_of_typestruct_resolve_op = function
140 | Resolve
-> "Resolve"
141 | DontResolve
-> "DontResolve"
143 let string_of_reifiedgeneric_op = function
144 | ClsGeneric
-> "ClsGeneric"
145 | FunGeneric
-> "FunGeneric"
147 let string_of_has_generics_op = function
148 | NoGenerics
-> "NoGenerics"
149 | HasGenerics
-> "HasGenerics"
150 | MaybeGenerics
-> "MaybeGenerics"
152 let string_of_operator instruction
=
153 match instruction
with
155 | ConcatN n
-> sep ["ConcatN"; string_of_int n
]
186 | CastBool
-> "CastBool"
187 | CastInt
-> "CastInt"
188 | CastDouble
-> "CastDouble"
189 | CastString
-> "CastString"
190 | CastArray
-> "CastArray"
191 | CastObject
-> "CastObject"
192 | CastVec
-> "CastVec"
193 | CastDict
-> "CastDict"
194 | CastKeyset
-> "CastKeyset"
195 | CastVArray
-> "CastVArray"
196 | CastDArray
-> "CastDArray"
197 | InstanceOf
-> "InstanceOf"
198 | InstanceOfD id
-> sep ["InstanceOfD"; string_of_class_id id
]
199 | IsTypeStructC op
->
200 sep ["IsTypeStructC"; string_of_typestruct_resolve_op op
]
201 | AsTypeStructC op
->
202 sep ["AsTypeStructC"; string_of_typestruct_resolve_op op
]
203 | CombineAndResolveTypeStruct n
->
204 sep ["CombineAndResolveTypeStruct"; string_of_int n
]
208 | ResolveFunc id
-> sep ["ResolveFunc"; string_of_function_id id
]
209 | ResolveObjMethod
-> sep ["ResolveObjMethod"]
210 | ResolveClsMethod
-> sep ["ResolveClsMethod"]
211 | Fatal op
-> sep ["Fatal"; FatalOp.to_string op
]
213 let string_of_get x
=
215 | CGetL id
-> sep ["CGetL"; string_of_local_id id
]
216 | CGetQuietL id
-> sep ["CGetQuietL"; string_of_local_id id
]
217 | CGetL2 id
-> sep ["CGetL2"; string_of_local_id id
]
218 | CUGetL id
-> sep ["CUGetL"; string_of_local_id id
]
219 | PushL id
-> sep ["PushL"; string_of_local_id id
]
221 | CGetQuietN
-> "CGetQuietN"
223 | CGetQuietG
-> "CGetQuietG"
224 | CGetS id
-> sep ["CGetS"; string_of_classref id
]
227 | VGetS id
-> sep ["VGetS"; string_of_classref id
]
228 | VGetL id
-> sep ["VGetL"; string_of_local_id id
]
229 | ClsRefGetL
(id
, cr
) ->
230 sep ["ClsRefGetL"; string_of_local_id id
; string_of_int cr
]
231 | ClsRefGetC cr
-> sep ["ClsRefGetC"; string_of_int cr
]
232 | ClsRefGetTS cr
-> sep ["ClsRefGetTS"; string_of_int cr
]
234 let string_of_member_key mk
=
235 let open MemberKey
in
237 | EC i
-> "EC:" ^
string_of_stack_index i
238 | EL id
-> "EL:" ^
string_of_local_id id
239 | ET str
-> "ET:" ^
SU.quote_string str
240 | EI i
-> "EI:" ^
Int64.to_string i
241 | PC i
-> "PC:" ^
string_of_stack_index i
242 | PL id
-> "PL:" ^
string_of_local_id id
243 | PT id
-> "PT:" ^
string_of_prop_id id
244 | QT id
-> "QT:" ^
string_of_prop_id id
247 let string_of_setrange_op = function
248 | Forward
-> "Forward"
249 | Reverse
-> "Reverse"
251 let string_of_eq_op op
=
253 | PlusEqual
-> "PlusEqual"
254 | MinusEqual
-> "MinusEqual"
255 | MulEqual
-> "MulEqual"
256 | ConcatEqual
-> "ConcatEqual"
257 | DivEqual
-> "DivEqual"
258 | PowEqual
-> "PowEqual"
259 | ModEqual
-> "ModEqual"
260 | AndEqual
-> "AndEqual"
261 | OrEqual
-> "OrEqual"
262 | XorEqual
-> "XorEqual"
263 | SlEqual
-> "SlEqual"
264 | SrEqual
-> "SrEqual"
265 | PlusEqualO
-> "PlusEqualO"
266 | MinusEqualO
-> "MinusEqualO"
267 | MulEqualO
-> "MulEqualO"
269 let string_of_incdec_op op
=
272 | PostInc
-> "PostInc"
274 | PostDec
-> "PostDec"
275 | PreIncO
-> "PreIncO"
276 | PostIncO
-> "PostIncO"
277 | PreDecO
-> "PreDecO"
278 | PostDecO
-> "PostDecO"
280 let string_of_istype_op op
=
290 | OpScalar
-> "Scalar"
293 | OpKeyset
-> "Keyset"
294 | OpArrLike
-> "ArrLike"
295 | OpVArray
-> "VArray"
296 | OpDArray
-> "DArray"
298 let string_of_initprop_op op
=
300 | NonStatic
-> "NonStatic"
303 let string_of_mutator x
=
305 | SetL id
-> sep ["SetL"; string_of_local_id id
]
306 | PopL id
-> sep ["PopL"; string_of_local_id id
]
309 | SetS id
-> sep ["SetS"; string_of_classref id
]
311 sep ["SetOpL"; string_of_local_id id
; string_of_eq_op op
]
312 | SetOpN op
-> sep ["SetOpN"; string_of_eq_op op
]
313 | SetOpG op
-> sep ["SetOpG"; string_of_eq_op op
]
314 | SetOpS
(op
, id
) -> sep ["SetOpS"; string_of_eq_op op
; string_of_classref id
]
315 | IncDecL
(id
, op
) ->
316 sep ["IncDecL"; string_of_local_id id
; string_of_incdec_op op
]
317 | IncDecN op
-> sep ["IncDecN"; string_of_incdec_op op
]
318 | IncDecG op
-> sep ["IncDecG"; string_of_incdec_op op
]
319 | IncDecS
(op
, id
) ->
320 sep ["IncDecS"; string_of_incdec_op op
; string_of_classref id
]
321 | BindL id
-> sep ["BindL"; string_of_local_id id
]
324 | BindS id
-> sep ["BindS"; string_of_classref id
]
325 | UnsetL id
-> sep ["UnsetL"; string_of_local_id id
]
328 | CheckProp id
-> sep ["CheckProp"; string_of_prop_id id
]
329 | InitProp
(id
, op
) -> sep ["InitProp"; string_of_prop_id id
;
330 string_of_initprop_op op
]
332 let string_of_label = function
333 | Label.Regular id
-> "L" ^
(string_of_int id
)
334 | Label.Catch id
-> "C" ^
(string_of_int id
)
335 | Label.Fault id
-> "F" ^
(string_of_int id
)
336 | Label.DefaultArg id
-> "DV" ^
(string_of_int id
)
337 | Label.Named id
-> id
339 let string_of_optional_label opt_label
=
342 | Some label
-> string_of_label label
344 let string_of_fcall_flags fl
=
346 if fl.has_unpack
then "Unpack" else "";
347 if fl.supports_async_eager_return
then "SupportsAER" else "";
349 "<" ^
(String.concat ~
sep:" " @@ List.filter ~f
:(fun f
-> f
<> "") fl) ^
">"
351 let string_of_fcall_args fcall_args
=
352 let flags, num_args
, num_rets
, async_eager_label
= fcall_args
in
354 string_of_fcall_flags flags;
355 string_of_int num_args
;
356 string_of_int num_rets
;
357 string_of_optional_label async_eager_label
360 let string_of_switch_kind = function
361 | H.Unbounded
-> "Unbounded"
362 | H.Bounded
-> "Bounded"
364 let string_of_switch kind base labels
=
365 let kind = string_of_switch_kind kind in
366 let labels = String.concat ~
sep:" " @@ List.map ~f
:string_of_label labels in
367 Printf.sprintf
"Switch %s %d <%s>" kind base
labels
369 let string_of_sswitch cases
=
370 let revcases = List.rev cases
in
372 | [] -> failwith
"sswitch should have at least one case"
373 | (_dummystring
, lastlabel
) :: revrest
->
375 String.concat ~
sep:" " @@
376 List.rev_map ~f
:(function (s
,l
) -> SU.quote_string s ^
":" ^
string_of_label l
) revrest
in
377 let laststring = "-:" ^
string_of_label lastlabel
in
378 Printf.sprintf
"SSwitch <%s %s>" reststring laststring
380 let string_of_control_flow instruction
=
381 match instruction
with
382 | Jmp l
-> "Jmp " ^
string_of_label l
383 | JmpNS l
-> "JmpNS " ^
string_of_label l
384 | JmpZ l
-> "JmpZ " ^
string_of_label l
385 | JmpNZ l
-> "JmpNZ " ^
string_of_label l
387 | RetCSuspended
-> "RetCSuspended"
388 | RetM p
-> "RetM " ^ string_of_int p
391 | Switch
(kind, base
, labels) -> string_of_switch kind base
labels
392 | SSwitch cases
-> string_of_sswitch cases
394 let string_of_iterator_id i
= Iterator.to_string i
395 let string_of_null_flavor nf
=
397 | Ast.OG_nullthrows
-> "NullThrows"
398 | Ast.OG_nullsafe
-> "NullSafe"
400 let string_of_class_kind ck
=
403 | KInterface
-> "Interface"
406 let string_of_isset instruction
=
407 match instruction
with
409 | IssetL id
-> "IssetL " ^
string_of_local_id id
412 | IssetS cls
-> "IssetS " ^ string_of_int cls
413 | EmptyL id
-> "EmptyL " ^
string_of_local_id id
416 | EmptyS cls
-> "EmptyS " ^ string_of_int cls
417 | IsTypeC op
-> "IsTypeC " ^
string_of_istype_op op
418 | IsTypeL
(id
, op
) ->
419 "IsTypeL " ^
string_of_local_id id ^
" " ^
string_of_istype_op op
421 let string_of_base x
=
424 sep ["BaseNC"; string_of_stack_index si
; MemberOpMode.to_string m
]
426 sep ["BaseNL"; string_of_local_id id
; MemberOpMode.to_string m
]
428 sep ["BaseGC"; string_of_stack_index si
; MemberOpMode.to_string m
]
430 sep ["BaseGL"; string_of_local_id id
; MemberOpMode.to_string m
]
431 | BaseSC
(si
, id
, m
) ->
433 string_of_stack_index si
; string_of_classref id
; MemberOpMode.to_string m
]
434 | BaseSL
(lid
, si
, m
) ->
436 string_of_local_id lid
; string_of_stack_index si
; MemberOpMode.to_string m
]
438 sep ["BaseL"; string_of_local_id lid
; MemberOpMode.to_string m
]
440 sep ["BaseC"; string_of_stack_index si
; MemberOpMode.to_string m
]
444 sep ["Dim"; MemberOpMode.to_string m
; string_of_member_key mk
]
446 let string_of_final instruction
=
447 match instruction
with
448 | QueryM
(n
, op
, mk
) ->
450 string_of_int n
; QueryOp.to_string op
; string_of_member_key mk
]
453 string_of_int n
; string_of_member_key mk
]
456 string_of_int n
; string_of_member_key mk
]
459 string_of_int n
; string_of_member_key mk
]
462 string_of_param_num i
; string_of_member_key mk
]
463 | SetOpM
(i
, op
, mk
) ->
465 string_of_param_num i
; string_of_eq_op op
; string_of_member_key mk
]
466 | IncDecM
(i
, op
, mk
) ->
468 string_of_param_num i
; string_of_incdec_op op
; string_of_member_key mk
]
469 | SetRangeM
(i
, op
, s
) ->
471 string_of_int i
; string_of_setrange_op op
; string_of_int s
]
474 | IncDecM of num_params * incdec_op * MemberKey.t
475 | SetOpM of num_params * eq_op * MemberKey.t
478 let string_of_param_locations pl
=
479 if List.length pl
= 0 then "" else
480 "<" ^
(String.concat ~
sep:", " (List.map ~f
:string_of_int pl
)) ^
">"
482 let string_of_list_of_bools l
=
483 if List.length l
= 0 then "" else
484 let bool_to_str b
= if b
then "1" else "0" in
485 "\"" ^
(String.concat ~
sep:"" (List.map ~f
:bool_to_str l
)) ^
"\""
487 let string_of_call instruction
=
488 match instruction
with
489 | FPushFunc
(n
, pl
) ->
490 sep ["FPushFunc"; string_of_int n
; string_of_param_locations pl
]
491 | FPushFuncD
(n
, id
) ->
492 sep ["FPushFuncD"; string_of_int n
; string_of_function_id id
]
493 | FPushFuncU
(n
, id1
, id2
) ->
494 sep ["FPushFuncU"; string_of_int n
; string_of_function_id id1
; SU.quote_string id2
]
495 | FPushObjMethod
(n
, nf
, pl
) ->
496 sep ["FPushObjMethod"; string_of_int n
; string_of_null_flavor nf
; string_of_param_locations pl
]
497 | FPushObjMethodD
(n
, id
, nf
) ->
498 sep ["FPushObjMethodD";
499 string_of_int n
; string_of_method_id id
; string_of_null_flavor nf
]
500 | FPushClsMethod
(n
, id
, pl
) ->
501 sep ["FPushClsMethod"; string_of_int n
; string_of_classref id
; string_of_param_locations pl
]
502 | FPushClsMethodD
(n
, id
, cid
) ->
503 sep ["FPushClsMethodD";
505 string_of_method_id id
; string_of_class_id cid
]
506 | FPushClsMethodS
(n
, r
) ->
507 sep ["FPushClsMethodS";
509 SpecialClsRef.to_string r
]
510 | FPushClsMethodSD
(n
, r
, id
) ->
511 sep ["FPushClsMethodSD";
513 SpecialClsRef.to_string r
;
514 string_of_method_id id
]
516 sep ["NewObj"; string_of_int id
; string_of_has_generics_op op
]
518 sep ["NewObjD"; string_of_class_id cid
]
520 sep ["NewObjI"; string_of_classref id
]
522 sep ["NewObjS"; SpecialClsRef.to_string r
]
524 sep ["FPushCtor"; string_of_int n
]
525 | FThrowOnRefMismatch l
->
526 sep ["FThrowOnRefMismatch"; string_of_list_of_bools l
]
527 | FCall
(fcall_args
, c
, f
) ->
529 string_of_fcall_args fcall_args
;
530 string_of_class_id c
; string_of_function_id f
]
531 | FCallBuiltin
(n1
, n2
, id
) ->
532 sep ["FCallBuiltin"; string_of_int n1
; string_of_int n2
; SU.quote_string id
]
534 let string_of_barethis_op i
=
537 | NoNotice
-> "NoNotice"
538 | NeverNull
-> "NeverNull"
540 let string_of_op_silence op
=
545 let string_of_misc instruction
=
546 match instruction
with
548 | BareThis op
-> sep ["BareThis"; string_of_barethis_op op
]
549 | Self id
-> sep ["Self"; string_of_classref id
]
550 | Parent id
-> sep ["Parent"; string_of_classref id
]
551 | LateBoundCls id
-> sep ["LateBoundCls"; string_of_classref id
]
552 | ClsRefName id
-> sep ["ClsRefName"; string_of_classref id
]
553 | ReifiedName
(n
, op
) ->
554 sep ["ReifiedName"; string_of_int n
; string_of_reifiedgeneric_op op
]
555 | ReifiedGeneric
(op
, n
) ->
556 sep ["ReifiedGeneric"; string_of_reifiedgeneric_op op
; string_of_int n
]
557 | RecordReifiedGeneric n
-> sep ["RecordReifiedGeneric"; string_of_int n
]
558 | CheckReifiedGenericMismatch
-> "CheckReifiedGenericMismatch"
559 | VerifyParamType id
-> sep ["VerifyParamType"; string_of_param_id id
]
560 | VerifyParamTypeTS id
-> sep ["VerifyParamTypeTS"; string_of_param_id id
]
561 | VerifyOutType id
-> sep ["VerifyOutType"; string_of_param_id id
]
562 | VerifyRetTypeC
-> "VerifyRetTypeC"
564 | ChainFaults
-> "ChainFaults"
565 | CheckThis
-> "CheckThis"
566 | CGetCUNop
-> "CGetCUNop"
567 | UGetCUNop
-> "UGetCUNop"
568 | StaticLocCheck
(local
, text
) ->
569 sep ["StaticLocCheck"; string_of_local_id local
; "\"" ^ text ^
"\""]
570 | StaticLocDef
(local
, text
) ->
571 sep ["StaticLocDef"; string_of_local_id local
; "\"" ^ text ^
"\""]
572 | StaticLocInit
(local
, text
) ->
573 sep ["StaticLocInit"; string_of_local_id local
; "\"" ^ text ^
"\""]
574 | MemoGet
(label
, Some
(Local.Unnamed first
, local_count
)) ->
575 Printf.sprintf
"MemoGet %s L:%d+%d"
576 (string_of_label label
) first local_count
577 | MemoGet
(label
, None
) ->
578 Printf.sprintf
"MemoGet %s L:0+0" (string_of_label label
)
579 | MemoGet _
-> failwith
"MemoGet needs an unnamed local"
580 | MemoGetEager
(label1
, label2
, Some
(Local.Unnamed first
, local_count
)) ->
581 Printf.sprintf
"MemoGetEager %s %s L:%d+%d"
582 (string_of_label label1
) (string_of_label label2
) first local_count
583 | MemoGetEager
(label1
, label2
, None
) ->
584 Printf.sprintf
"MemoGetEager %s %s L:0+0" (string_of_label label1
) (string_of_label label2
)
585 | MemoGetEager _
-> failwith
"MemoGetEager needs an unnamed local"
586 | MemoSet
(Some
(Local.Unnamed first
, local_count
)) ->
587 Printf.sprintf
"MemoSet L:%d+%d" first local_count
589 Printf.sprintf
"MemoSet L:0+0"
590 | MemoSet _
-> failwith
"MemoSet needs an unnamed local"
591 | MemoSetEager
(Some
(Local.Unnamed first
, local_count
)) ->
592 Printf.sprintf
"MemoSetEager L:%d+%d" first local_count
593 | MemoSetEager None
->
594 Printf.sprintf
"MemoSetEager L:0+0"
595 | MemoSetEager _
-> failwith
"MemoSetEager needs an unnamed local"
596 | GetMemoKeyL local
->
597 sep ["GetMemoKeyL"; string_of_local_id local
]
598 | CreateCl
(n
, cid
) ->
599 sep ["CreateCl"; string_of_int n
; string_of_int cid
]
601 | ArrayIdx
-> "ArrayIdx"
602 | InitThisLoc id
-> sep ["InitThisLoc"; string_of_local_id id
]
603 | AKExists
-> "AKExists"
604 | OODeclExists ck
-> sep ["OODeclExists"; string_of_class_kind ck
]
605 | Silence
(local
, op
) ->
606 sep ["Silence"; string_of_local_id local
; string_of_op_silence op
]
607 | AssertRATL
(local
, s
) ->
608 sep ["AssertRATL"; string_of_local_id local
; s
]
609 | AssertRATStk
(n
, s
) ->
610 sep ["AssertRATStk"; string_of_int n
; s
]
611 | NativeImpl
-> "NativeImpl"
612 | BreakTraceHint
-> "BreakTraceHint"
614 let iterator_instruction_name_prefix instruction
=
615 let iterator_instruction_name =
616 match instruction
with
617 | IterInit _
-> "IterInit"
618 | LIterInit _
-> "LIterInit"
619 | IterInitK _
-> "IterInitK"
620 | LIterInitK _
-> "LIterInitK"
621 | IterNext _
-> "IterNext"
622 | LIterNext _
-> "LIterNext"
623 | IterNextK _
-> "IterNextK"
624 | LIterNextK _
-> "LIterNextK"
625 | IterFree _
-> "IterFree"
626 | LIterFree _
-> "LIterFree"
627 | _
-> failwith
"invalid iterator instruction"
629 iterator_instruction_name ^
" "
631 let string_of_iterator instruction
=
632 match instruction
with
633 | IterInit
(id
, label
, value) ->
634 (iterator_instruction_name_prefix instruction
) ^
635 (string_of_iterator_id id
) ^
" " ^
636 (string_of_label label
) ^
" " ^
637 (string_of_local_id value)
638 | LIterInit
(id
, base
, label
, value) ->
639 (iterator_instruction_name_prefix instruction
) ^
640 (string_of_iterator_id id
) ^
" " ^
641 (string_of_local_id base
) ^
" " ^
642 (string_of_label label
) ^
" " ^
643 (string_of_local_id value)
644 | IterInitK
(id
, label
, key
, value) ->
645 (iterator_instruction_name_prefix instruction
) ^
646 (string_of_iterator_id id
) ^
" " ^
647 (string_of_label label
) ^
" " ^
648 (string_of_local_id key
) ^
" " ^
649 (string_of_local_id value)
650 | LIterInitK
(id
, base
, label
, key
, value) ->
651 (iterator_instruction_name_prefix instruction
) ^
652 (string_of_iterator_id id
) ^
" " ^
653 (string_of_local_id base
) ^
" " ^
654 (string_of_label label
) ^
" " ^
655 (string_of_local_id key
) ^
" " ^
656 (string_of_local_id value)
657 | IterNext
(id
, label
, value) ->
658 (iterator_instruction_name_prefix instruction
) ^
659 (string_of_iterator_id id
) ^
" " ^
660 (string_of_label label
) ^
" " ^
661 (string_of_local_id value)
662 | LIterNext
(id
, base
, label
, value) ->
663 (iterator_instruction_name_prefix instruction
) ^
664 (string_of_iterator_id id
) ^
" " ^
665 (string_of_local_id base
) ^
" " ^
666 (string_of_label label
) ^
" " ^
667 (string_of_local_id value)
668 | IterNextK
(id
, label
, key
, value) ->
669 (iterator_instruction_name_prefix instruction
) ^
670 (string_of_iterator_id id
) ^
" " ^
671 (string_of_label label
) ^
" " ^
672 (string_of_local_id key
) ^
" " ^
673 (string_of_local_id value)
674 | LIterNextK
(id
, base
, label
, key
, value) ->
675 (iterator_instruction_name_prefix instruction
) ^
676 (string_of_iterator_id id
) ^
" " ^
677 (string_of_local_id base
) ^
" " ^
678 (string_of_label label
) ^
" " ^
679 (string_of_local_id key
) ^
" " ^
680 (string_of_local_id value)
682 (iterator_instruction_name_prefix instruction
) ^
683 (string_of_iterator_id id
)
684 | LIterFree
(id
, base
) ->
685 (iterator_instruction_name_prefix instruction
) ^
686 (string_of_iterator_id id
) ^
" " ^
687 (string_of_local_id base
)
688 | IterBreak
(label
, iterlist
) ->
689 let map_item (kind, id
) =
690 let id = string_of_iterator_id id in
692 | Iter
-> "(Iter) " ^
id
693 | LIter
-> "(LIter) " ^
id
696 String.concat ~
sep:", " (List.rev_map ~f
:map_item iterlist
) in
697 "IterBreak " ^
(string_of_label label
) ^
" <" ^
values ^
">"
699 let string_of_try instruction
=
700 match instruction
with
701 | TryFaultBegin label
->
702 ".try_fault " ^
(string_of_label label
) ^
" {"
703 | TryCatchLegacyBegin label
->
704 ".try_catch " ^
(string_of_label label
) ^
" {"
706 | TryCatchLegacyEnd
-> "}"
707 | TryCatchBegin
-> ".try {"
708 | TryCatchMiddle
-> "} .catch {"
711 let string_of_async = function
713 | WHResult
-> "WHResult"
714 | AwaitAll
(Some
(Local.Unnamed local
, count
)) ->
715 Printf.sprintf
"AwaitAll L:%d+%d" local count
717 Printf.sprintf
"AwaitAll L:0+0"
718 | AwaitAll _
-> failwith
"AwaitAll needs an unnamed local"
720 let string_of_generator = function
721 | CreateCont
-> "CreateCont"
722 | ContEnter
-> "ContEnter"
723 | ContRaise
-> "ContRaise"
726 | ContCheck IgnoreStarted
-> "ContCheck IgnoreStarted"
727 | ContCheck CheckStarted
-> "ContCheck CheckStarted"
728 | ContValid
-> "ContValid"
729 | ContKey
-> "ContKey"
730 | ContGetReturn
-> "ContGetReturn"
731 | ContCurrent
-> "ContCurrent"
733 let string_of_include_eval_define = function
735 | InclOnce
-> "InclOnce"
737 | ReqOnce
-> "ReqOnce"
740 | AliasCls
(c1
, c2
) ->
741 sep ["AliasCls"; SU.quote_string c1
; SU.quote_string c2
]
742 | DefFunc
id -> sep ["DefFunc"; string_of_function_num id]
743 | DefCls
id -> sep ["DefCls"; string_of_class_num id]
744 | DefClsNop
id -> sep ["DefClsNop"; string_of_class_num id]
745 | DefCns
id -> sep ["DefCns"; string_of_const_id id]
746 | DefTypeAlias
id -> sep ["DefTypeAlias"; string_of_typedef_num id]
748 let string_of_free_iterator = function
749 | IgnoreIter
-> "IgnoreIter"
750 | FreeIter
-> "FreeIter"
752 let string_of_gen_delegation = function
753 | ContAssignDelegate i
-> sep ["ContAssignDelegate"; string_of_iterator_id i
]
754 | ContEnterDelegate
-> "ContEnterDelegate"
755 | YieldFromDelegate
(i
, l
) ->
756 sep ["YieldFromDelegate"; string_of_iterator_id i
; string_of_label l
]
757 | ContUnsetDelegate
(free
, i
) ->
758 sep ["ContUnsetDelegate";
759 string_of_free_iterator free
;
760 string_of_iterator_id i
]
762 let string_of_instruction instruction
=
763 let s = match instruction
with
764 | IIterator i
-> string_of_iterator i
765 | IBasic i
-> string_of_basic i
766 | ILitConst i
-> string_of_lit_const i
767 | IOp i
-> string_of_operator i
768 | IContFlow i
-> string_of_control_flow i
769 | ICall i
-> string_of_call i
770 | IMisc i
-> string_of_misc i
771 | IGet i
-> string_of_get i
772 | IMutator i
-> string_of_mutator i
773 | ILabel l
-> string_of_label l ^
":"
774 | IIsset i
-> string_of_isset i
775 | IBase i
-> string_of_base i
776 | IFinal i
-> string_of_final i
777 | ITry i
-> string_of_try i
778 | IComment
s -> "# " ^
s
779 | ISrcLoc p
-> ".srcloc " ^
string_of_pos p ^
";"
780 | IAsync i
-> string_of_async i
781 | IGenerator i
-> string_of_generator i
782 | IIncludeEvalDefine i
-> string_of_include_eval_define i
783 | IGenDelegation i
-> string_of_gen_delegation i
784 | _
-> failwith
"invalid instruction" in
787 let adjusted_indent instruction indent
=
788 match instruction
with
792 | ITry TryCatchLegacyEnd
793 | ITry TryCatchMiddle
794 | ITry TryCatchEnd
-> indent
- 2
797 let new_indent instruction indent
=
798 match instruction
with
799 | ITry
(TryFaultBegin _
)
800 | ITry
(TryCatchLegacyBegin _
)
801 | ITry TryCatchBegin
-> indent
+ 2
803 | ITry TryCatchLegacyEnd
804 | ITry TryCatchEnd
-> indent
- 2
807 let add_instruction_list buffer indent instructions
=
808 let rec aux instructions indent
=
809 match instructions
with
811 | ISpecialFlow _
:: t
->
813 Emit_fatal.emit_fatal_runtime
Pos.none
"Cannot break/continue 1 level"
815 let fatal = Instruction_sequence.instr_seq_to_list
fatal in
818 | instruction
:: t
->
820 let actual_indent = adjusted_indent instruction indent
in
821 Acc.add buffer
(String.make
actual_indent ' '
);
822 Acc.add buffer
(string_of_instruction instruction
);
823 aux t
(new_indent instruction indent
)
825 aux instructions indent
827 (* HHVM uses `N` to denote absence of type information. Otherwise the type
828 * is a quoted string *)
829 let quote_str_option s =
832 | Some
s -> SU.quote_string
s
834 let string_of_type_flags flags =
835 let flag_strs = List.map ~f
:Hhas_type_constraint.string_of_flag
flags in
836 let flags_text = String.concat ~
sep:" " flag_strs in
839 let string_of_type_info ?
(is_enum
= false) ti
=
840 let user_type = Hhas_type_info.user_type ti
in
841 let type_constraint = Hhas_type_info.type_constraint ti
in
842 let flags = Hhas_type_constraint.flags type_constraint in
843 let flags_text = string_of_type_flags flags in
844 let name = Hhas_type_constraint.name type_constraint in
845 "<" ^
quote_str_option user_type ^
" "
846 ^
(if not is_enum
then quote_str_option name ^
" " else "")
850 let string_of_typedef_info ti
=
851 let type_constraint = Hhas_type_info.type_constraint ti
in
852 let name = Hhas_type_constraint.name type_constraint in
853 let flags = Hhas_type_constraint.flags type_constraint in
854 (* TODO: check if other flags are emitted for type aliases *)
856 List.filter ~f
:(fun f
-> f
= Hhas_type_constraint.Nullable
) flags in
857 let flags_text = string_of_type_flags flags in
858 "<" ^
SU.quote_string
(Option.value ~default
:"" name)
859 ^
" " ^
flags_text ^
" >"
861 let string_of_type_info_option tio
=
864 | Some ti
-> string_of_type_info ti ^
" "
866 type default_value_printing_env
= {
867 codegen_env
: Emit_env.t
option;
871 let rec string_of_afield ~env
= function
873 string_of_param_default_value ~env e
874 | A.AFkvalue
(k
, v
) ->
875 string_of_param_default_value ~env k ^
876 " => " ^ string_of_param_default_value ~env v
878 and string_of_afield_list ~env afl
=
879 if List.length afl
= 0
881 else String.concat ~
sep:", " @@ List.map ~f
:(string_of_afield ~env
) afl
883 and shape_field_name_to_expr
= function
884 | A.SFlit_int
(pos
, s) -> (pos
, A.Int
s)
885 | A.SFlit_str
(pos
, s)
886 | A.SFclass_const
(_
, (pos
, s)) -> (pos
, A.String
s)
888 and string_of_bop
= function
897 | A.Eq
(Some bop
) -> "=" ^ string_of_bop bop
915 | A.QuestionQuestion
-> "\\?\\?"
917 and string_of_uop
= function
928 -> failwith
"string_of_uop - should have been captures earlier"
930 and string_of_hint ~ns h
=
932 Emit_type_hint.fmt_hint
934 ~namespace
:Namespace_env.empty_with_default_popt
937 let h = if ns
then h else SU.strip_ns
h in
938 Php_escaping.escape
h
940 and string_of_import_flavor
= function
941 | A.Include
-> "include"
942 | A.Require
-> "require"
943 | A.IncludeOnce
-> "include_once"
944 | A.RequireOnce
-> "require_once"
946 and string_of_is_variadic b
=
947 if b
then "..." else ""
948 and string_of_is_reference b
=
949 if b
then "&" else ""
951 and string_of_fun ~env f use_list
=
952 let string_of_args p
=
953 match snd
@@ p
.A.param_id
with
956 let inout = if p
.A.param_callconv
= Some
A.Pinout
then "inout " else "" in
958 Option.value_map p
.A.param_hint ~default
:"" ~f
:(string_of_hint ~ns
:true)
964 ~f
:(fun e
-> " = " ^
(string_of_param_default_value ~env e
)) in
966 inout ^ string_of_is_variadic p
.A.param_is_variadic ^
hint in
968 if String.length
param_text = 0
970 else param_text ^
" " in
972 param_text ^ string_of_is_reference p
.A.param_is_reference ^
name in
973 Some
(param_text ^
default_val)
975 let args = String.concat ~
sep:", " @@ List.filter_map ~f
:string_of_args f
.A.f_params
in
976 let use_list_helper ((_
, id), b
) = (if b
then "&" else "") ^
id in
977 let use_statement = match use_list
with
981 ^
(String.concat ~
sep:", " @@ List.map ~f
:use_list_helper use_list
)
984 (if f
.A.f_static
then "static " else "")
985 ^
(if f
.A.f_fun_kind
= A.FAsync
|| f
.A.f_fun_kind
= A.FAsyncGenerator
then "async " else "")
990 ^
(string_of_statement ~env ~indent
:"" (Pos.none
, A.Block f
.A.f_body
))
992 and string_of_optional_expr ~env e
=
993 string_of_optional_value (string_of_expression ~env
) e
995 and string_of_block_ ~env ~start_indent ~block_indent ~end_indent block
=
997 (String.concat ~
sep:"" @@
998 List.map ~f
:(string_of_statement ~env ~indent
:block_indent
) block
) in
999 start_indent ^
"{\\n" ^
lines ^ end_indent ^
"}\\n"
1001 and string_of_block ~env ~indent
(block
:A.stmt list
) =
1003 | [] | [_
, A.Noop
] -> ""
1004 | [(_
, A.Block
([_
] as block
))]
1005 | (_
::_
::_
as block
)->
1009 ~block_indent
:(indent ^
indent_text)
1013 string_of_statement ~env ~indent
:"" stmt
1015 and string_of_statement ~env ~indent
((_
, stmt_
) : A.stmt
) =
1016 let text, is_single_line
=
1019 "return" ^
(string_of_optional_expr ~env e
), true
1021 string_of_expression ~env e
, true
1022 | A.Break level_opt
->
1023 "break" ^
(string_of_optional_expr ~env level_opt
), true
1024 | A.Continue level_opt
->
1025 "continue" ^
(string_of_optional_expr ~env level_opt
), true
1027 "throw " ^
(string_of_expression ~env e
), true
1031 ~start_indent
:indent
1032 ~block_indent
:(indent ^
indent_text)
1036 | A.While
(cond
, body
) ->
1038 indent ^
"while (" ^
(string_of_expression ~env cond
) ^
") " in
1044 header_text ^
body_text, false
1046 | A.If
(cond
, then_block
, else_block
) ->
1048 indent ^
"if (" ^
(string_of_expression ~env cond
) ^
") " in
1049 let then_text = string_of_block
1053 let else_text = string_of_block
1057 header_text ^
then_text ^
1058 (if String.length
else_text <> 0 then " else " ^
else_text else ""),
1060 | A.Noop
-> "", false
1061 | _
-> (* TODO(T29869930) *) "NYI: Default value printing", false in
1063 if is_single_line
then indent ^
text ^
";\\n"
1067 and string_of_expression ~env e
=
1068 string_of_param_default_value ~env e
1070 and string_of_xml ~env
(_
, id) attributes children
=
1071 let env = { env with in_xhp
= true } in
1073 let name = SU.Xhp.mangle
id in
1075 List.fold_right ~f
:(string_of_xhp_attr
p) attributes ~init
:(0, [])
1077 let attributes = string_of_param_default_value ~
env (p, A.Darray
attributes) in
1078 let children = string_of_param_default_value ~
env
1079 (p, A.Varray
children)
1087 ^
", __FILE__, __LINE__)"
1089 and string_of_xhp_attr
p attr
(spread_id
, attrs
) = match attr
with
1090 | A.Xhp_simple
((_, s), e
) -> (spread_id
, ((p, A.String
s), e
)::attrs
)
1092 let s = "...$" ^
(string_of_int spread_id
) in
1093 (spread_id
+ 1, ((p, A.String
s), e
)::attrs
)
1095 and string_of_param_default_value ~
env expr
=
1097 let middle_aux e1
s e2
=
1098 let e1 = string_of_param_default_value ~
env e1 in
1099 let e2 = string_of_param_default_value ~
env e2 in
1102 let fmt_class_name ~is_class_constant cn
=
1103 let cn = if SU.Xhp.is_xhp
(Utils.strip_ns
cn)
1104 then SU.Xhp.mangle
cn else cn in
1105 let cn = (Php_escaping.escape
(SU.strip_global_ns
cn)) in
1106 if is_class_constant
then "\\\\" ^
cn else cn in
1107 let get_special_class_name ~
env ~is_class_constant
id =
1108 let scope = match env with
1109 | None
-> Ast_scope.Scope.toplevel
1110 | Some
env -> Emit_env.get_scope
env in
1111 let module ACE
= Ast_class_expr
in
1113 let p0 = Pos.none
in
1114 (p0, (A.Id
(p0, id))) in
1115 fmt_class_name ~is_class_constant
@@
1116 match ACE.expr_to_class_expr ~check_traits
:true ~resolve_self
:true scope e with
1117 | ACE.Class_id
(_, name) -> name
1120 let get_class_name_from_id ~
env ~should_format ~is_class_constant
id =
1121 if id = SN.Classes.cSelf
|| id = SN.Classes.cParent
|| id = SN.Classes.cStatic
1122 then get_special_class_name ~
env ~is_class_constant
id
1127 Hhbc_id.Class.to_raw_string
@@ fst
@@
1128 Hhbc_id.Class.elaborate_id
1129 (Emit_env.get_namespace
env) (p, id)
1132 if should_format
then fmt_class_name ~is_class_constant
id else id
1134 let handle_possible_colon_colon_class_expr ~
env ~is_array_get
= function
1135 | _, A.Class_const
((_, A.Id
(p, s1
)), (_, s2
))
1136 when SU.is_class s2
&& not
1137 (SU.is_self s1
|| SU.is_parent s1
|| SU.is_static s1
) ->
1139 let s1 = get_class_name_from_id
1140 ~
env:env.codegen_env ~should_format
:false ~is_class_constant
:false s1 in
1142 (fst expr
, if is_array_get
then A.Id
(p, s1) else A.String
s1) in
1143 Some
(string_of_param_default_value ~
env e)
1146 let escape_char_for_printing = function
1147 | '
\\'
| '$'
| '
"' -> "\\\\"
1148 | '\n' | '\r' | '\t' -> "\\"
1149 | c when not (Php_escaping.is_lit_printable c) -> "\\"
1152 let escape_fn c = escape_char_for_printing c ^ Php_escaping.escape_char c in
1155 let id = match env.codegen_env with
1156 | Some env when SU.has_ns id ->
1158 Hhbc_id.Const.elaborate_id
1159 (Emit_env.get_namespace env) (p, id)
1161 "\\" ^ Hhbc_id.Const.to_raw_string id
1164 Php_escaping.escape id
1165 | A.Lvar (_, litstr) -> Php_escaping.escape litstr
1166 | A.Float litstr -> SU.Float.with_scientific_notation litstr
1167 | A.Int litstr -> SU.Integer.to_decimal litstr
1168 | A.String litstr ->
1169 SU.quote_string_with_escape ~f:escape_fn litstr
1172 | A.False -> "false"
1173 (* For arrays and collections, we are making a conscious decision to not
1174 * match HHMV has HHVM's emitter has inconsistencies in the pretty printer
1175 * https://fburl.com/tzom2qoe *)
1177 "array
(" ^ string_of_afield_list ~env afl ^ ")"
1178 | A.Collection ((_, name), afl) when
1179 name = "vec
" || name = "dict
" || name = "keyset
" ->
1180 name ^ "[" ^ string_of_afield_list ~env afl ^ "]"
1181 | A.Collection ((_, name), afl) ->
1182 let name = SU.Types.fix_casing @@ SU.strip_ns name in
1183 begin match name with
1184 | "Set
" | "Pair
" | "Vector
" | "Map
"
1185 | "ImmSet
" | "ImmVector
" | "ImmMap
" ->
1186 let elems = string_of_afield_list ~env afl in
1188 if String.length elems <> 0 then " " ^ elems ^ " " else elems in
1189 "HH
\\\\" ^ name ^ " {" ^ elems ^ "}"
1191 failwith ("Default
value for an unknown collection
- " ^ name)
1196 ~f:(fun (f_name, e) ->
1197 (shape_field_name_to_expr f_name, e))
1200 string_of_param_default_value ~env (fst expr, A.Darray fl)
1201 | A.Binop (bop, e1, e2) ->
1202 let bop = string_of_bop bop in
1203 let e1 = string_of_param_default_value ~env e1 in
1204 let e2 = string_of_param_default_value ~env e2 in
1205 e1 ^ " " ^ bop ^ " " ^ e2
1206 | A.New (e, _, es, ues)
1207 | A.Call (e, _, es, ues) ->
1208 let e = String_utils.lstrip (string_of_param_default_value ~env e) "\\\\" in
1209 let es = List.map ~f:(string_of_param_default_value ~env) (es @ ues) in
1210 let prefix = match snd expr with A.New (_, _, _, _) -> "new " | _ -> "" in
1214 ^ String.concat ~sep:", " es
1216 | A.NewAnonClass (es, ues, _) ->
1217 let es = List.map ~f:(string_of_param_default_value ~env) (es @ ues) in
1220 ^ String.concat ~sep:", " es
1222 | A.Class_get (e1, e2) ->
1223 let s1 = match snd e1 with
1225 get_class_name_from_id
1226 ~env:env.codegen_env ~should_format:true ~is_class_constant:false s1
1227 | _ -> string_of_param_default_value ~env e1 in
1228 let s2 = string_of_param_default_value ~env e2 in
1230 | A.Class_const (e1, (_, s2)) ->
1232 handle_possible_colon_colon_class_expr ~env ~is_array_get:false expr in
1233 begin match snd e1, cexpr_o with
1234 | _, Some cexpr_o -> cexpr_o
1235 | A.Id (_, s1), _ ->
1236 let s1 = get_class_name_from_id
1237 ~env:env.codegen_env ~should_format:true ~is_class_constant:true s1 in
1240 let s1 = string_of_param_default_value ~env e1 in
1243 | A.Unop (uop, e) -> begin
1244 let e = string_of_param_default_value ~env e in
1246 | A.Upincr -> e ^ "++"
1247 | A.Updecr -> e ^ "--"
1248 | _ -> string_of_uop uop ^ e
1250 | A.Obj_get (e1, e2, f) ->
1251 let e1 = string_of_param_default_value ~env e1 in
1252 let e2 = string_of_param_default_value ~env e2 in
1253 let f = match f with A.OG_nullthrows -> "->" | A.OG_nullsafe -> "\\?
->" in
1255 | A.Clone e -> "clone
" ^ string_of_param_default_value ~env e
1256 | A.Array_get (e, eo) ->
1257 let e = string_of_param_default_value ~env e in
1259 Option.value_map eo ~default:""
1262 handle_possible_colon_colon_class_expr
1263 ~env ~is_array_get:true e in
1266 | None -> string_of_param_default_value ~env e)
1270 String.concat ~sep:" . " @@ List.map ~f:(string_of_param_default_value ~env) es
1271 | A.PrefixedString (name, e) ->
1272 String.concat ~sep:" . " @@ [name; string_of_param_default_value ~env e]
1273 | A.Execution_operator es ->
1275 String.concat ~sep:" . " @@ List.map ~f:(string_of_param_default_value ~env) es in
1276 "shell_exec
(" ^ s ^ ")"
1277 | A.Eif (cond, etrue, efalse) ->
1278 let cond = string_of_param_default_value ~env cond in
1280 Option.value_map etrue ~default:"" ~f:(string_of_param_default_value ~env)
1282 let efalse = string_of_param_default_value ~env efalse in
1283 cond ^ " \\?
" ^ etrue ^ " : " ^ efalse
1284 | A.Unsafeexpr e -> string_of_param_default_value ~env e
1285 | A.BracedExpr e -> "{" ^ string_of_param_default_value ~env e ^ "}"
1286 | A.ParenthesizedExpr e -> "(" ^ string_of_param_default_value ~env e ^ ")"
1288 let h = string_of_hint ~ns: false h in
1289 let e = string_of_param_default_value ~env e in
1291 | A.Pipe (e1, e2) -> middle_aux e1 " |> " e2
1292 | A.InstanceOf (e1, e2) -> middle_aux e1 " instanceof
" e2
1294 let e = string_of_param_default_value ~env e in
1295 let h = string_of_hint ~ns:true h in
1298 let e = string_of_param_default_value ~env e in
1299 let o = if b then " ?
as " else " as " in
1300 let h = string_of_hint ~ns:true h in
1303 let es = List.map ~f:(string_of_param_default_value ~env) es in
1304 "varray
[" ^ (String.concat ~sep:", " es) ^ "]"
1306 let es = List.map ~f:(fun (e1, e2) -> A.AFkvalue (e1, e2)) es in
1307 "darray
[" ^ (string_of_afield_list ~env es) ^ "]"
1309 let l = List.map ~f:(string_of_param_default_value ~env) l in
1310 "list
(" ^ (String.concat ~sep:", " l) ^ ")"
1312 "yield
" ^ (string_of_afield ~env y)
1314 "await
" ^ (string_of_param_default_value ~env a)
1318 "yield from
" ^ (string_of_param_default_value ~env e)
1319 | A.Import (fl, e) ->
1320 let fl = string_of_import_flavor fl in
1321 let e = string_of_param_default_value ~env e in
1323 | A.Xml (id, attributes, children) ->
1324 string_of_xml ~env id attributes children
1325 | A.Efun (f, use_list) -> string_of_fun ~env f use_list
1328 failwith "expected Lfun
to be converted
to Efun during closure conversion
"
1331 | A.Expr_list _ -> failwith "illegal default
value"
1333 let string_of_param_default_value_option env = function
1335 | Some (label, expr) ->
1336 let env = { codegen_env = env; in_xhp = false } in
1338 ^ (string_of_label label)
1340 ^ (string_of_param_default_value ~env expr)
1343 let string_of_param_user_attributes p =
1344 match Hhas_param.user_attributes p with
1347 let attrs = Emit_adata.attributes_to_strings user_attrs in
1348 "[" ^ (String.concat ~sep:" " attrs) ^ "]"
1350 let string_of_is_inout b = if b then "inout " else ""
1352 let string_of_param env p =
1353 let param_type_info = Hhas_param.type_info p in
1354 let param_name = Hhas_param.name p in
1355 let param_default_value = Hhas_param.default_value p in
1356 string_of_param_user_attributes p
1357 ^ string_of_is_inout (Hhas_param.is_inout p)
1358 ^ string_of_is_variadic (Hhas_param.is_variadic p)
1359 ^ string_of_type_info_option param_type_info
1360 ^ string_of_is_reference (Hhas_param.is_reference p)
1362 ^ string_of_param_default_value_option env param_default_value
1364 let string_of_params env ps =
1365 "(" ^ String.concat ~sep:", " (List.map ~f:(string_of_param env) ps) ^ ")"
1367 let add_indent buf indent = Acc.add buf (String.make indent ' ')
1368 let add_indented_line buf indent str =
1370 add_indent buf indent;
1373 let add_num_cls_ref_slots buf indent num_cls_ref_slots =
1374 if num_cls_ref_slots <> 0
1375 then add_indented_line buf indent
1376 (Printf.sprintf ".numclsrefslots %d
;" num_cls_ref_slots)
1378 let is_bareword_char c =
1379 match Char.lowercase c with
1380 | '_' | '.' | '$' | '\\' -> true
1381 | c -> (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')
1383 let is_bareword_string s =
1385 i >= String.length s || (is_bareword_char (String.get s i) && aux (i + 1)) in
1388 let add_decl_vars buf indent decl_vars =
1389 let decl_vars = List.map ~f:(fun s ->
1390 if is_bareword_string s
1392 else "\"" ^ (Php_escaping.escape s) ^ "\""
1395 then add_indented_line buf indent
1396 (".declvars
" ^ String.concat ~sep:" " decl_vars ^ ";")
1398 let add_num_iters buf indent num_iters =
1400 then add_indented_line buf indent
1401 (Printf.sprintf ".numiters %d
;" num_iters)
1403 let add_static_default_value_option buf indent label =
1404 add_indented_line buf indent (".static
" ^ label ^ ";")
1406 let add_static_values buf indent lst =
1407 Hh_core.List.iter lst
1408 (fun label -> add_static_default_value_option buf indent label)
1410 let add_doc buf indent doc_comment =
1411 match doc_comment with
1413 add_indented_line buf indent @@
1414 Printf.sprintf ".doc %s
;" (SU.triple_quote_string cmt)
1417 let add_body buf indent body =
1418 add_doc buf indent (Hhas_body.doc_comment body);
1419 if Hhas_body.is_memoize_wrapper body
1420 then add_indented_line buf indent ".ismemoizewrapper
;";
1421 if Hhas_body.is_memoize_wrapper_lsb body
1422 then add_indented_line buf indent ".ismemoizewrapperlsb
;";
1423 add_num_iters buf indent (Hhas_body.num_iters body);
1424 add_num_cls_ref_slots buf indent (Hhas_body.num_cls_ref_slots body);
1425 add_decl_vars buf indent (Hhas_body.decl_vars body);
1426 add_static_values buf indent (Hhas_body.static_inits body);
1428 add_instruction_list buf indent
1429 (Instruction_sequence.instr_seq_to_list (Hhas_body.instrs body))
1431 let function_attributes f =
1432 let user_attrs = Hhas_function.attributes f in
1433 let attrs = Emit_adata.attributes_to_strings user_attrs in
1434 let attrs = if Emit_env.is_systemlib ()
1435 then "unique
" :: "builtin
" :: "persistent
" :: attrs else attrs in
1437 if Emit_env.is_systemlib () ||
1438 ((Hhas_attribute.has_dynamically_callable user_attrs) &&
1439 not (Hhas_function.is_memoize_impl f))
1440 then "dyn_callable
" :: attrs else attrs
1443 if Hhas_attribute.is_reads_caller_frame user_attrs && not (Hhas_function.inout_wrapper f) then "reads_frame
" :: attrs else attrs in
1445 if Hhas_attribute.is_writes_caller_frame user_attrs && not (Hhas_function.inout_wrapper f) then "writes_frame
" :: attrs else attrs in
1447 if not (Hhas_function.is_top f) then "nontop
" :: attrs else attrs in
1449 if Hhas_function.inout_wrapper f then "inout_wrapper
" :: attrs else attrs in
1451 if Hhas_function.no_injection f then "no_injection
" :: attrs else attrs in
1453 if Hhas_attribute.has_native user_attrs then "skip_frame
" :: attrs else attrs in
1455 if Hhas_attribute.has_foldable user_attrs then "foldable
" :: attrs else attrs in
1457 if Hhas_function.is_interceptable f then "interceptable
" :: attrs else attrs in
1458 let attrs = match Rx.rx_level_to_attr_string (Hhas_function.rx_level f) with
1459 | Some s -> s :: attrs
1462 let text = String.concat ~sep:" " attrs in
1463 if text = "" then "" else "[" ^ text ^ "] "
1465 let add_fun_def buf fun_def =
1466 let function_name = Hhas_function.name fun_def in
1467 let function_body = Hhas_function.body fun_def in
1468 let function_span = Hhas_function.span fun_def in
1469 let function_return_type = Hhas_body.return_type function_body in
1470 let env = Hhas_body.env function_body in
1471 let function_params = Hhas_body.params function_body in
1472 let function_is_async = Hhas_function.is_async fun_def in
1473 let function_is_generator = Hhas_function.is_generator fun_def in
1474 let function_is_pair_generator = Hhas_function.is_pair_generator fun_def in
1475 let function_rx_disabled = Hhas_function.rx_disabled fun_def in
1476 Acc.add buf "\n.function ";
1477 Acc.add buf (function_attributes fun_def);
1478 if Hhbc_options.source_mapping !Hhbc_options.compiler_options
1479 then Acc.add buf (string_of_span function_span ^ " ");
1480 Acc.add buf (string_of_type_info_option function_return_type);
1481 Acc.add buf (Hhbc_id.Function.to_raw_string function_name);
1482 Acc.add buf (string_of_params env function_params);
1483 if function_is_generator then Acc.add buf " isGenerator
";
1484 if function_is_async then Acc.add buf " isAsync
";
1485 if function_is_pair_generator then Acc.add buf " isPairGenerator
";
1486 if function_rx_disabled then Acc.add buf " isRxDisabled
";
1488 add_body buf 2 function_body;
1491 let attributes_to_string attrs =
1492 let text = String.concat ~sep:" " attrs in
1493 let text = if text = "" then "" else "[" ^ text ^ "] " in
1496 let method_attributes m =
1497 let user_attrs = Hhas_method.attributes m in
1498 let attrs = Emit_adata.attributes_to_strings user_attrs in
1499 let is_native_opcode_impl = Hhas_attribute.is_native_opcode_impl user_attrs in
1500 let is_native = not is_native_opcode_impl && Hhas_attribute.has_native user_attrs in
1501 let is_systemlib = Emit_env.is_systemlib () in
1503 if Emit_env.is_systemlib () ||
1504 ((Hhas_attribute.has_dynamically_callable user_attrs) &&
1505 not (Hhas_method.is_memoize_impl m))
1506 then "dyn_callable
" :: attrs else attrs
1508 let attrs = if is_systemlib && is_native then "persistent
" :: attrs else attrs in
1509 let attrs = if is_systemlib then "builtin
" :: attrs else attrs in
1510 let attrs = if is_systemlib && is_native then "unique
" :: attrs else attrs in
1512 if Hhas_attribute.is_reads_caller_frame user_attrs && not (Hhas_method.inout_wrapper m) then "reads_frame
" :: attrs else attrs in
1514 if Hhas_attribute.is_writes_caller_frame user_attrs && not (Hhas_method.inout_wrapper m) then "writes_frame
" :: attrs else attrs in
1515 let attrs = if Hhas_method.inout_wrapper m then "inout_wrapper
" :: attrs else attrs in
1516 let attrs = if Hhas_method.no_injection m then "no_injection
" :: attrs else attrs in
1517 let attrs = if is_systemlib && is_native then "skip_frame
" :: attrs else attrs in
1519 if Hhas_attribute.has_foldable user_attrs then "foldable
" :: attrs else attrs in
1520 let attrs = if Hhas_method.is_abstract m then "abstract
" :: attrs else attrs in
1521 let attrs = if Hhas_method.is_final m then "final
" :: attrs else attrs in
1522 let attrs = if Hhas_method.is_static m then "static
" :: attrs else attrs in
1523 let attrs = if Hhas_method.is_public m then "public
" :: attrs else attrs in
1524 let attrs = if Hhas_method.is_protected m then "protected
" :: attrs else attrs in
1525 let attrs = if Hhas_method.is_private m then "private" :: attrs else attrs in
1526 let attrs = if Hhas_method.is_interceptable m then "interceptable
" :: attrs else attrs in
1527 let attrs = match Rx.rx_level_to_attr_string (Hhas_method.rx_level m) with
1528 | Some s -> s :: attrs
1531 attributes_to_string attrs
1533 let typedef_attributes t =
1534 let user_attrs = Hhas_typedef.attributes t in
1535 let attrs = Emit_adata.attributes_to_strings user_attrs in
1537 if Emit_env.is_systemlib () then "persistent
" :: attrs else attrs in
1538 attributes_to_string attrs
1540 let add_method_def buf method_def =
1541 let method_name = Hhas_method.name method_def in
1542 let method_body = Hhas_method.body method_def in
1543 let method_return_type = Hhas_body.return_type method_body in
1544 let method_params = Hhas_body.params method_body in
1545 let env = Hhas_body.env method_body in
1546 let method_span = Hhas_method.span method_def in
1547 let method_is_async = Hhas_method.is_async method_def in
1548 let method_is_generator = Hhas_method.is_generator method_def in
1549 let method_is_pair_generator = Hhas_method.is_pair_generator method_def in
1550 let method_is_closure_body = Hhas_method.is_closure_body method_def in
1551 let method_rx_disabled = Hhas_method.rx_disabled method_def in
1552 Acc.add buf "\n .method ";
1553 Acc.add buf (method_attributes method_def);
1554 if Hhbc_options.source_mapping !Hhbc_options.compiler_options
1555 then Acc.add buf (string_of_span method_span ^ " ");
1556 Acc.add buf (string_of_type_info_option method_return_type);
1557 Acc.add buf (Hhbc_id.Method.to_raw_string method_name);
1558 Acc.add buf (string_of_params env method_params);
1559 if method_is_generator then Acc.add buf " isGenerator
";
1560 if method_is_async then Acc.add buf " isAsync
";
1561 if method_is_pair_generator then Acc.add buf " isPairGenerator
";
1562 if method_is_closure_body then Acc.add buf " isClosureBody
";
1563 if method_rx_disabled then Acc.add buf " isRxDisabled
";
1565 add_body buf 4 method_body;
1568 let class_special_attributes c =
1569 let user_attrs = Hhas_class.attributes c in
1570 let attrs = Emit_adata.attributes_to_strings user_attrs in
1571 let attrs = if Hhas_class.needs_no_reifiedinit c
1572 then "noreifiedinit
" :: attrs else attrs in
1573 let attrs = if Hhas_class.no_dynamic_props c
1574 then "no_dynamic_props
" :: attrs else attrs in
1576 if Hhas_class.has_immutable c then "has_immutable
" :: attrs else attrs in
1578 if Hhas_class.is_immutable c then "is_immutable
" :: attrs else attrs in
1580 if Hhas_attribute.has_foldable user_attrs then "foldable
" :: attrs else attrs in
1581 let attrs = if Emit_env.is_systemlib ()
1582 then "unique
" :: "builtin
" :: "persistent
" :: attrs else attrs in
1584 if Hhas_attribute.has_dynamically_constructible user_attrs
1585 then "dyn_constructible
" :: attrs else attrs
1587 let attrs = if not (Hhas_class.is_top c) then "nontop
" :: attrs else attrs in
1589 if Hhas_class.is_closure_class c && not @@ Emit_env.is_systemlib ()
1590 then "unique
" :: attrs else attrs in
1592 if Hhas_class.is_closure_class c then "no_override
" :: attrs else attrs in
1593 let attrs = if Hhas_class.is_trait c then "trait
" :: attrs else attrs in
1595 if Hhas_class.is_interface c then "interface
" :: attrs else attrs
1597 let attrs = if Hhas_class.is_final c then "final
" :: attrs else attrs in
1598 let attrs = if Hhas_class.is_sealed c then "sealed
" :: attrs else attrs in
1600 if Hhas_class.enum_type c <> None then "enum
" :: attrs else attrs
1602 let attrs = if Hhas_class.is_abstract c then "abstract
" :: attrs else attrs in
1603 let text = String.concat ~sep:" " attrs in
1604 let text = if text = "" then "" else "[" ^ text ^ "] " in
1607 let add_extends buf class_base =
1608 match class_base with
1612 Acc.add buf " extends
";
1613 Acc.add buf (Hhbc_id.Class.to_raw_string name);
1616 let add_implements buf class_implements =
1617 match class_implements with
1621 Acc.add buf " implements
(";
1622 Acc.add buf (String.concat ~sep:" "
1623 (List.map ~f:Hhbc_id.Class.to_raw_string class_implements));
1627 let property_attributes p =
1628 let module P = Hhas_property in
1629 let user_attrs = P.attributes p in
1630 let attrs = Emit_adata.attributes_to_strings user_attrs in
1631 let attrs = if P.is_late_init p then "late_init
" :: attrs else attrs in
1632 let attrs = if P.is_soft_late_init p then "late_init_soft
" :: attrs else attrs in
1633 let attrs = if P.is_no_bad_redeclare p then "no_bad_redeclare
" :: attrs else attrs in
1634 let attrs = if P.initial_satisfies_tc p then "initial_satisfies_tc
" :: attrs else attrs in
1635 let attrs = if P.no_implicit_null p then "no_implicit_null
" :: attrs else attrs in
1636 let attrs = if P.has_system_initial p then "sys_initial_val
" :: attrs else attrs in
1637 let attrs = if P.is_immutable p then "is_immutable
" :: attrs else attrs in
1638 let attrs = if P.is_deep_init p then "deep_init
" :: attrs else attrs in
1639 let attrs = if P.is_lsb p then "lsb
" :: attrs else attrs in
1640 let attrs = if P.is_static p then "static
" :: attrs else attrs in
1641 let attrs = if P.is_public p then "public
" :: attrs else attrs in
1642 let attrs = if P.is_protected p then "protected
" :: attrs else attrs in
1643 let attrs = if P.is_private p then "private" :: attrs else attrs in
1644 let text = String.concat ~sep:" " attrs in
1645 let text = if text = "" then "" else "[" ^ text ^ "] " in
1648 let property_type_info p =
1649 let tinfo = Hhas_property.type_info p in
1650 (string_of_type_info ~is_enum:false tinfo) ^ " "
1652 let property_doc_comment p =
1653 match Hhas_property.doc_comment p with
1655 | Some s -> Printf.sprintf "%s
" (SU.triple_quote_string s)
1657 let add_property class_def buf property =
1658 Acc.add buf "\n .property
";
1659 Acc.add buf (property_attributes property);
1660 Acc.add buf (property_doc_comment property);
1661 Acc.add buf (property_type_info property);
1662 Acc.add buf (Hhbc_id.Prop.to_raw_string (Hhas_property.name property));
1663 Acc.add buf " =\n ";
1664 let initial_value = Hhas_property.initial_value property in
1665 if Hhas_class.is_closure_class class_def
1666 || initial_value = Some Typed_value.Uninit
1667 then Acc.add buf "uninit
;"
1669 Acc.add buf "\"\"\"";
1670 begin match initial_value with
1671 | None -> Acc.add buf "N
;"
1672 | Some value -> Emit_adata.adata_to_buffer buf value
1674 Acc.add buf "\"\"\";"
1677 let add_constant buf c =
1678 let name = Hhas_constant.name c in
1679 let value = Hhas_constant.value c in
1680 Acc.add buf "\n .const
";
1682 begin match value with
1683 | Some Typed_value.Uninit ->
1684 Acc.add buf " = uninit
"
1686 Acc.add buf " = \"\"\"";
1687 Emit_adata.adata_to_buffer buf value;
1688 Acc.add buf "\"\"\""
1693 let add_type_constant buf c =
1694 Acc.add buf "\n .const
";
1695 Acc.add buf (Hhas_type_constant.name c);
1696 let initializer_t = Hhas_type_constant.initializer_t c in
1697 Acc.add buf " isType
";
1698 match initializer_t with
1700 Acc.add buf " = \"\"\"";
1701 Emit_adata.adata_to_buffer buf init;
1702 Acc.add buf "\"\"\";"
1703 | None -> Acc.add buf ";"
1705 let add_requirement buf r =
1706 Acc.add buf "\n .require
";
1708 | (Ast.MustExtend, name) ->
1709 Acc.add buf ("extends
<" ^ name ^ ">;")
1710 | (Ast.MustImplement, name) ->
1711 Acc.add buf ("implements
<" ^ name ^ ">;")
1713 let add_enum_ty buf c =
1714 match Hhas_class.enum_type c with
1716 Acc.add buf "\n .enum_ty
";
1717 Acc.add buf @@ string_of_type_info ~is_enum:true et;
1721 let add_use_precedence buf (id1, id2, ids) =
1722 let name = id1 ^ "::" ^ id2 in
1723 let unique_ids = List.fold_left ~f:ULS.add ~init:ULS.empty ids in
1724 let ids = String.concat ~sep:" " @@ ULS.items unique_ids in
1725 Acc.add buf @@ Printf.sprintf "\n %s insteadof %s
;" name ids
1727 let add_use_alias buf (ido1, id, ido2, kindl) =
1729 Option.value_map ~f:(fun id1 -> id1 ^ "::" ^ id) ~default:id ido1
1734 | x -> Some ("[" ^ (String.concat ~sep:" " @@ List.map ~f:Ast.string_of_kind x ) ^ "]")
1736 let rest = Option.merge kind ido2 ~f:(fun x y -> x ^ " " ^ y) in
1737 let rest = Option.value ~default:"" rest in
1738 Acc.add buf @@ Printf.sprintf "\n %s
as %s
;" aliasing_id rest
1740 let add_replace buf (trait, id, new_id, kindl, fun_kind) =
1741 Acc.add buf @@ Printf.sprintf
1742 "\n %s
::%s
as strict
"
1744 if fun_kind = Ast_defs.FAsync || fun_kind = Ast_defs.FAsyncGenerator
1745 then Acc.add buf "async
";
1747 let rec concat kindl =
1751 Acc.add buf (Printf.sprintf "%s
" (Ast.string_of_kind kind))
1753 Acc.add buf (Printf.sprintf "%s
" (Ast.string_of_kind kind));
1757 Acc.add buf (Printf.sprintf "%s
;" new_id)
1759 let add_uses buf c =
1760 let use_l = Hhas_class.class_uses c in
1761 let use_alias_list = Hhas_class.class_use_aliases c in
1762 let use_precedence_list = Hhas_class.class_use_precedences c in
1763 let class_method_trait_resolutions = Hhas_class.class_method_trait_resolutions c in
1764 if use_l = [] && class_method_trait_resolutions = [] then () else
1767 List.fold_left ~f:(fun l e -> ULS.add l (Utils.strip_ns e)) ~init:ULS.empty use_l
1769 let use_l = String.concat ~sep:" " @@ ULS.items unique_ids in
1770 Acc.add buf @@ Printf.sprintf "\n .use %s
" use_l;
1771 if use_alias_list = [] && use_precedence_list = [] && class_method_trait_resolutions = []
1772 then Acc.add buf ";" else
1775 List.iter ~f:(add_use_precedence buf) use_precedence_list;
1776 List.iter ~f:(add_use_alias buf) use_alias_list;
1777 List.iter ~f:(add_replace buf) class_method_trait_resolutions;
1782 let add_class_def buf class_def =
1783 let class_name = Hhas_class.name class_def in
1784 (* TODO: user attributes *)
1785 Acc.add buf "\n.class ";
1786 Acc.add buf (class_special_attributes class_def);
1787 Acc.add buf (Hhbc_id.Class.to_raw_string class_name);
1788 if Hhbc_options.source_mapping !Hhbc_options.compiler_options
1789 then Acc.add buf (" " ^ string_of_span (Hhas_class.span class_def));
1790 add_extends buf (Hhas_class.base class_def);
1791 add_implements buf (Hhas_class.implements class_def);
1793 add_doc buf 2 (Hhas_class.doc_comment class_def);
1794 add_uses buf class_def;
1795 add_enum_ty buf class_def;
1796 List.iter ~f:(add_requirement buf) (Hhas_class.requirements class_def);
1797 List.iter ~f:(add_constant buf) (Hhas_class.constants class_def);
1798 List.iter ~f:(add_type_constant buf) (Hhas_class.type_constants class_def);
1799 List.iter ~f:(add_property class_def buf) (Hhas_class.properties class_def);
1800 List.iter ~f:(add_method_def buf) (Hhas_class.methods class_def);
1801 (* TODO: other members *)
1804 let add_data_region_element buf argument =
1805 Acc.add buf ".adata
";
1806 Acc.add buf @@ (Hhas_adata.id argument);
1807 Acc.add buf " = \"\"\"";
1808 Emit_adata.adata_to_buffer buf (Hhas_adata.value argument);
1809 Acc.add buf "\"\"\";\n"
1811 let add_data_region buf adata =
1812 List.iter ~f:(add_data_region_element buf) adata;
1815 let add_top_level buf body =
1816 Acc.add buf ".main
";
1817 if Hhbc_options.source_mapping !Hhbc_options.compiler_options
1818 then Acc.add buf "(1,1) ";
1820 add_body buf 2 body;
1823 let add_typedef buf typedef =
1824 let name = Hhas_typedef.name typedef in
1825 let type_info = Hhas_typedef.type_info typedef in
1826 let opt_ts = Hhas_typedef.type_structure typedef in
1827 Acc.add buf "\n.alias
";
1828 Acc.add buf (typedef_attributes typedef);
1829 Acc.add buf (Hhbc_id.Class.to_raw_string name);
1830 Acc.add buf (" = " ^ string_of_typedef_info type_info);
1833 Acc.add buf " \"\"\"";
1834 Emit_adata.adata_to_buffer buf ts;
1835 Acc.add buf "\"\"\";"
1839 let add_file_attributes buf file_attributes =
1840 match file_attributes with
1843 let attrs = Emit_adata.attributes_to_strings file_attributes in
1844 let attrs = attributes_to_string attrs in
1845 Acc.add buf "\n.file_attributes
";
1849 let add_include_region
1850 ?path ?doc_root ?search_paths ?include_roots ?(check_paths_exist=true)
1852 let write_if_exists p =
1853 if not check_paths_exist || Sys.file_exists p
1854 then (Acc.add buf ("\n " ^ p); true)
1856 let write_include inc =
1857 let include_roots = Option.value include_roots ~default:SMap.empty in
1858 match Hhas_symbol_refs.resolve_to_doc_root_relative inc ~include_roots with
1859 | Hhas_symbol_refs.Absolute p -> ignore @@ write_if_exists p
1860 | Hhas_symbol_refs.SearchPathRelative p ->
1861 if not check_paths_exist
1862 then Acc.add buf ("\n " ^ p)
1864 let rec try_paths = function
1867 if write_if_exists (Filename.concat prefix p)
1869 else try_paths rest in
1871 Option.value_map path ~default:[] ~f:(fun p -> [Filename.dirname p]) in
1872 try_paths (dirname @ Option.value search_paths ~default:[])
1873 | Hhas_symbol_refs.IncludeRootRelative (v, p) -> if p <> "" then
1874 Option.iter (SMap.find_opt v include_roots) (fun ir ->
1875 let doc_root = Option.value doc_root ~default:"" in
1876 let resolved = Filename.concat doc_root (Filename.concat ir p) in
1877 ignore @@ write_if_exists resolved)
1878 | Hhas_symbol_refs.DocRootRelative p -> ignore @@
1879 let doc_root = Option.value doc_root ~default:"" in
1880 let resolved = Filename.concat doc_root p in
1881 write_if_exists resolved
1883 if not (Hhas_symbol_refs.IncludePathSet.is_empty includes) then begin
1884 Acc.add buf "\n.includes
{";
1885 Hhas_symbol_refs.IncludePathSet.iter write_include includes;
1889 let add_symbol_ref_regions buf symbol_refs =
1890 let add_region name refs =
1891 if not (SSet.is_empty refs) then begin
1892 Acc.add buf ("\n." ^ name);
1894 SSet.iter (fun s -> Acc.add buf ("\n " ^ s)) refs;
1895 Acc.add buf "\n}\n";
1897 add_region "constant_refs
" symbol_refs.Hhas_symbol_refs.constants;
1898 add_region "function_refs
" symbol_refs.Hhas_symbol_refs.functions;
1899 add_region "class_refs
" symbol_refs.Hhas_symbol_refs.classes
1901 let add_program_content ?path dump_symbol_refs buf hhas_prog =
1902 let is_hh = if Hhas_program.is_hh hhas_prog then "1" else "0" in
1903 Acc.add buf @@ "\n.hh_file
" ^ is_hh ^ ";\n";
1904 let functions = Hhas_program.functions hhas_prog in
1905 let top_level_body = Hhas_program.main hhas_prog in
1906 let classes = Hhas_program.classes hhas_prog in
1907 let adata = Hhas_program.adata hhas_prog in
1908 let symbol_refs = Hhas_program.symbol_refs hhas_prog in
1909 add_data_region buf adata;
1910 add_top_level buf top_level_body;
1911 List.iter ~f:(add_fun_def buf) functions;
1912 List.iter ~f:(add_class_def buf) classes;
1913 List.iter ~f:(add_typedef buf) (Hhas_program.typedefs hhas_prog);
1914 add_file_attributes buf (Hhas_program.file_attributes hhas_prog);
1915 if dump_symbol_refs then begin
1916 let opts = !Hhbc_options.compiler_options in
1917 add_include_region ?path buf symbol_refs.Hhas_symbol_refs.includes
1918 ~doc_root:(Hhbc_options.doc_root opts)
1919 ~search_paths:(Hhbc_options.include_search_paths opts)
1920 ~include_roots:(Hhbc_options.include_roots opts);
1921 add_symbol_ref_regions buf symbol_refs
1924 let add_program ?path dump_symbol_refs buf hhas_prog =
1926 match Hhas_program.strict_types hhas_prog with
1927 | Some true -> ".strict
1;\n\n"
1928 | Some false -> ".strict
0;\n\n"
1932 let p = Php_escaping.escape @@ Relative_path.to_absolute p in
1934 (Printf.sprintf "# %s starts here
\n\n%s
.filepath
\"%s
\";\n" p strict_types p);
1935 add_program_content ~path:p dump_symbol_refs buf hhas_prog;
1936 Acc.add buf (Printf.sprintf "\n# %s ends here
\n" p)
1938 Acc.add buf "#starts here
\n";
1939 Acc.add buf strict_types;
1940 add_program_content dump_symbol_refs buf hhas_prog;
1941 Acc.add buf "\n#ends here
\n"
1943 let to_segments ?path ?(dump_symbol_refs=false) hhas_prog =
1944 let buf = Acc.create () in
1945 add_program ?path dump_symbol_refs buf hhas_prog;
1948 let to_string ?path ?dump_symbol_refs =
1949 Fn.compose (String.concat ~sep:"") (to_segments ?path ?dump_symbol_refs)