2 * Copyright (c) 2018, 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 Env
= Format_env
12 module SourceText
= Full_fidelity_source_text
13 module Syntax
= Full_fidelity_editable_syntax
14 module SyntaxKind
= Full_fidelity_syntax_kind
15 module Token
= Full_fidelity_editable_token
16 module TokenKind
= Full_fidelity_token_kind
17 module Trivia
= Full_fidelity_editable_trivia
18 module TriviaKind
= Full_fidelity_trivia_kind
19 module Rewriter
= Full_fidelity_rewriter.WithSyntax
(Syntax
)
22 let is_trivia_kind_fallthrough = function
23 | TriviaKind.FallThrough
-> true
26 let is_trivia_kind_end_of_line = function
27 | TriviaKind.EndOfLine
-> true
30 let is_trivia_kind_white_space = function
31 | TriviaKind.WhiteSpace
-> true
34 let is_syntax_kind_parenthesized_exprression = function
35 | SyntaxKind.ParenthesizedExpression
-> true
38 let is_token_kind_xhp_body = function
39 | TokenKind.XHPBody
-> true
42 let is_token_kind_in_out = function
43 | TokenKind.Inout
-> true
46 let make_list = Syntax.make_list SourceText.empty
0
48 let make_missing () = Syntax.make_missing SourceText.empty
0
50 (* Main transform function, which takes a full-fidelity CST node and produces a
51 * Doc.t node (the IR which is fed to Chunk_builder.build).
53 * Exported via the `transform` alias below. *)
54 let rec t (env
: Env.t) (node
: Syntax.t) : Doc.t =
55 (* Leave this node as it was in the original source if it is preceded by a
56 hackfmt-ignore comment. *)
57 match transform_node_if_ignored node
with
60 (match Syntax.syntax node
with
61 | Syntax.Missing
-> Nothing
63 let token_kind = Token.kind x
in
68 | TokenKind.EndOfFile
->
69 let leading_trivia = Token.leading x
in
70 let trivia_without_trailing_invisibles =
71 let reversed = List.rev
leading_trivia in
72 List.rev
(List.drop_while
reversed ~f
:is_invisible
)
74 transform_leading_trivia
trivia_without_trailing_invisibles
75 | _
-> transform_leading_trivia
(Token.leading x
)
79 | TokenKind.EndOfFile
-> Nothing
80 | TokenKind.SingleQuotedStringLiteral
81 | TokenKind.DoubleQuotedStringLiteral
82 | TokenKind.DoubleQuotedStringLiteralHead
83 | TokenKind.StringLiteralBody
84 | TokenKind.DoubleQuotedStringLiteralTail
85 | TokenKind.HeredocStringLiteral
86 | TokenKind.HeredocStringLiteralHead
87 | TokenKind.HeredocStringLiteralTail
88 | TokenKind.NowdocStringLiteral
->
89 make_string
(Token.text x
) (Token.width x
)
90 | _
-> Text
(Token.text x
, Token.width x
)
92 transform_trailing_trivia
(Token.trailing x
);
94 | Syntax.SyntaxList _
->
97 "Error: SyntaxList should never be handled directly;
98 offending text is '%s'."
100 | Syntax.EndOfFile x
-> t env x
.end_of_file_token
103 match Syntax.syntax x
.script_declarations
with
104 | Syntax.SyntaxList
(header
:: declarations
)
105 when Syntax.is_markup_section header
->
106 Concat
[t env header
; Newline
; handle_list env declarations
]
107 | _
-> Concat
[handle_possible_list env x
.script_declarations
]
109 | Syntax.LiteralExpression
{ literal_expression
} ->
110 (* Double quoted string literals can create a list *)
111 let wrap_with_literal_type token transformed
=
112 match Token.kind token
with
113 | TokenKind.HeredocStringLiteral
114 | TokenKind.HeredocStringLiteralHead
115 | TokenKind.HeredocStringLiteralTail
116 | TokenKind.NowdocStringLiteral
->
117 DocLiteral transformed
118 | TokenKind.DecimalLiteral
119 | TokenKind.OctalLiteral
120 | TokenKind.HexadecimalLiteral
121 | TokenKind.BinaryLiteral
122 | TokenKind.FloatingLiteral
->
123 NumericLiteral transformed
127 match Syntax.syntax literal_expression
with
128 | Syntax.Token tok
->
129 wrap_with_literal_type tok
(t env literal_expression
)
130 | Syntax.SyntaxList l
->
131 let last = Syntax.trailing_token literal_expression
in
135 wrap_with_literal_type tok
(Concat
(List.map l
(t env
)))
136 | _
-> failwith
"Expected Token"
138 | _
-> failwith
"Expected Token or SyntaxList"
140 | Syntax.PrefixedStringExpression
141 { prefixed_string_name
= name
; prefixed_string_str
= str
} ->
142 Concat
[t env name
; t env str
]
143 | Syntax.MarkupSection
144 { markup_hashbang
= hashbang
; markup_suffix
= suffix
; _
} ->
146 match Syntax.syntax suffix
with
147 | Syntax.MarkupSuffix
148 { markup_suffix_name
= Syntax.{ syntax
= Token
t; _
}; _
} ->
149 String.equal
(Token.text
t) "hh"
152 let rec all_whitespaces s i
=
160 all_whitespaces s
(i
+ 1)
163 let text_contains_only_whitespaces =
164 match Syntax.syntax hashbang
with
165 | Syntax.Token
t -> all_whitespaces (Token.text
t) 0
168 if is_hh_script && text_contains_only_whitespaces then
171 transform_simple env node
172 | Syntax.MarkupSuffix _
173 | Syntax.SimpleTypeSpecifier _
174 | Syntax.VariableExpression _
175 | Syntax.PipeVariableExpression _
176 | Syntax.PropertyDeclarator _
177 | Syntax.ConstantDeclarator _
178 | Syntax.ScopeResolutionExpression _
179 | Syntax.EmbeddedMemberSelectionExpression _
180 | Syntax.EmbeddedSubscriptExpression _
181 | Syntax.PostfixUnaryExpression _
182 | Syntax.XHPRequired _
183 | Syntax.XHPLateinit _
184 | Syntax.XHPSimpleClassAttribute _
186 | Syntax.TypeConstant _
187 | Syntax.GenericTypeSpecifier _
188 | Syntax.NullableTypeSpecifier _
189 | Syntax.LikeTypeSpecifier _
190 | Syntax.SoftTypeSpecifier _
191 | Syntax.ListItem _
->
192 transform_simple env node
193 | Syntax.ReifiedTypeArgument
194 { reified_type_argument_reified
; reified_type_argument_type
} ->
197 t env reified_type_argument_reified
;
199 t env reified_type_argument_type
;
201 | Syntax.QualifiedName
{ qualified_name_parts
} ->
202 handle_possible_list env qualified_name_parts
203 | Syntax.ExpressionStatement _
-> transform_simple_statement env node
204 | Syntax.EnumDeclaration
206 enum_attribute_spec
= attr
;
209 enum_colon
= colon_kw
;
212 enum_includes_keyword
= enum_includes_kw
;
214 enum_left_brace
= left_b
;
215 enum_enumerators
= enumerators
;
216 enum_right_brace
= right_b
;
218 let after_each_ancestor is_last
=
227 when_present attr newline
;
234 Nest
[Space
; t env base
; Space
; t env enum_type
; Space
];
235 when_present enum_includes_kw
(fun () ->
240 t env enum_includes_kw
;
248 ( if list_length enum_includes_list
= 1 then
256 ~after_each
:after_each_ancestor
267 [handle_possible_list env enumerators
];
272 enumerator_name
= name
;
273 enumerator_equal
= eq_kw
;
274 enumerator_value
= value;
275 enumerator_semicolon
= semi
;
277 let value = t env
value in
284 ( if has_split
value then
292 | Syntax.RecordDeclaration
294 record_attribute_spec
= attr
;
295 record_modifier
= modifier
;
298 record_extends_keyword
= extends_kw
;
299 record_extends_opt
= extends
;
300 record_left_brace
= left_b
;
301 record_fields
= fields
;
302 record_right_brace
= right_b
;
304 let after_each_ancestor is_last
=
313 when_present attr newline
;
320 when_present extends_kw
(fun () ->
340 ~after_each
:after_each_ancestor
346 braced_block_nest env left_b right_b
[handle_possible_list env fields
];
352 record_field_name
= name
;
354 record_field_semi
= semi_kw
;
358 t env record_field_type
;
361 t env record_field_init
;
365 | Syntax.AliasDeclaration
367 alias_attribute_spec
= attr
;
370 alias_generic_parameter
= generic
;
371 alias_constraint
= type_constraint
;
374 alias_semicolon
= semi
;
376 (* TODO: revisit this for long names *)
380 when_present attr newline
;
386 t env type_constraint
;
391 Nest
[t env alias_type
];
395 | Syntax.PropertyDeclaration
397 property_attribute_spec
= attr
;
398 property_modifiers
= modifiers
;
399 property_type
= prop_type
;
400 property_declarators
= declarators
;
401 property_semicolon
= semi
;
406 handle_possible_list env ~after_each
:(fun _
-> Space
) modifiers
;
408 handle_declarator_list env declarators
;
413 if Syntax.is_missing attr
then
418 handle_attribute_spec env attr ~always_split
:false,
419 Concat
[Space
; Split
; declaration] )
420 | Syntax.NamespaceDeclaration
421 { namespace_header
= header
; namespace_body
= body
} ->
422 Concat
[t env header
; t env body
; Newline
]
423 | Syntax.NamespaceDeclarationHeader
424 { namespace_keyword
= kw
; namespace_name
= name
} ->
425 Concat
[t env kw
; Space
; t env name
]
426 | Syntax.NamespaceBody
428 namespace_left_brace
= left_b
;
429 namespace_declarations
= decls
;
430 namespace_right_brace
= right_b
;
435 braced_block_nest env left_b right_b
[handle_possible_list env decls
];
437 | Syntax.NamespaceEmptyBody
{ namespace_semicolon
= semi
} ->
439 | Syntax.NamespaceUseDeclaration
441 namespace_use_keyword
= kw
;
442 namespace_use_kind
= use_kind
;
443 namespace_use_clauses
= clauses
;
444 namespace_use_semicolon
= semi
;
451 when_present use_kind space
;
459 ~after_each
:after_each_argument
;
464 | Syntax.NamespaceGroupUseDeclaration
466 namespace_group_use_keyword
= kw
;
467 namespace_group_use_kind
= use_kind
;
468 namespace_group_use_prefix
= prefix
;
469 namespace_group_use_left_brace
= left_b
;
470 namespace_group_use_clauses
= clauses
;
471 namespace_group_use_right_brace
= right_b
;
472 namespace_group_use_semicolon
= semi
;
479 when_present use_kind space
;
481 transform_argish env left_b clauses right_b
;
485 | Syntax.NamespaceUseClause
487 namespace_use_clause_kind
= use_kind
;
488 namespace_use_name
= name
;
489 namespace_use_as
= as_kw
;
490 namespace_use_alias
= alias
;
495 when_present use_kind space
;
497 when_present as_kw space
;
499 when_present alias space
;
502 | Syntax.FunctionDeclaration
504 function_attribute_spec
= attr
;
505 function_declaration_header
= header
;
506 function_body
= body
;
511 when_present attr newline
;
513 handle_possible_compound_statement env ~allow_collapse
:true body
;
516 | Syntax.FunctionDeclarationHeader
518 function_modifiers
= modifiers
;
519 function_keyword
= kw
;
520 function_name
= name
;
521 function_type_parameter_list
= type_params
;
522 function_left_paren
= leftp
;
523 function_parameter_list
= params
;
524 function_right_paren
= rightp
;
525 function_capability
= cap
;
526 function_colon
= colon
;
527 function_type
= ret_type
;
528 function_where_clause
= where
;
532 Span
(transform_fn_decl_name env modifiers kw name type_params leftp
);
533 transform_fn_decl_args env params rightp
;
536 when_present colon space
;
538 when_present where space
;
542 { where_clause_keyword
= where
; where_clause_constraints
= constraints
}
548 handle_possible_list env constraints ~after_each
:(fun _
-> Space
);
550 | Syntax.WhereConstraint
552 where_constraint_left_type
= left
;
553 where_constraint_operator
= op
;
554 where_constraint_right_type
= right
;
556 Concat
[t env left
; Space
; t env op
; Space
; t env right
]
559 capability_left_bracket
= lb
;
560 capability_types
= tys
;
561 capability_right_bracket
= rb
;
563 Concat
[t env lb
; t env tys
; t env rb
]
564 | Syntax.MethodishDeclaration
566 methodish_attribute
= attr
;
567 methodish_function_decl_header
= func_decl
;
568 methodish_function_body
= body
;
569 methodish_semicolon
= semi
;
574 when_present attr newline
;
576 when_present body
(fun () ->
577 handle_possible_compound_statement env ~allow_collapse
:true body
);
581 | Syntax.MethodishTraitResolution
583 methodish_trait_attribute
= attr
;
584 methodish_trait_function_decl_header
= func_decl
;
585 methodish_trait_equal
= equal
;
586 methodish_trait_name
= name
;
587 methodish_trait_semicolon
= semi
;
592 when_present attr newline
;
599 | Syntax.ClassishDeclaration
601 classish_attribute
= attr
;
602 classish_modifiers
= modifiers
;
604 classish_keyword
= kw
;
605 classish_name
= name
;
606 classish_type_parameters
= type_params
;
607 classish_extends_keyword
= extends_kw
;
608 classish_extends_list
= extends
;
609 classish_implements_keyword
= impl_kw
;
610 classish_implements_list
= impls
;
611 classish_where_clause
= where
;
612 classish_body
= body
;
614 let after_each_ancestor is_last
=
623 when_present attr newline
;
626 handle_possible_list env ~after_each
:(fun _
-> Space
) modifiers
;
628 when_present xhp space
;
632 Nest
[t env name
; t env type_params
];
638 when_present extends_kw
(fun () ->
651 ( if list_length extends
= 1 then
659 ~after_each
:after_each_ancestor
665 when_present impl_kw
(fun () ->
678 ( if list_length impls
= 1 then
686 ~after_each
:after_each_ancestor
692 when_present where space
;
697 | Syntax.ClassishBody
699 classish_body_left_brace
= left_b
;
700 classish_body_elements
= body
;
701 classish_body_right_brace
= right_b
;
706 braced_block_nest env left_b right_b
[handle_possible_list env body
];
709 | Syntax.TraitUsePrecedenceItem
711 trait_use_precedence_item_name
= name
;
712 trait_use_precedence_item_keyword
= kw
;
713 trait_use_precedence_item_removed_names
= removed_names
;
725 handle_possible_list env ~before_each
:space_split removed_names
;
728 | Syntax.TraitUseAliasItem
730 trait_use_alias_item_aliasing_name
= aliasing_name
;
731 trait_use_alias_item_keyword
= kw
;
732 trait_use_alias_item_modifiers
= visibility
;
733 trait_use_alias_item_aliased_name
= aliased_name
;
745 | Syntax.TraitUseConflictResolution
747 trait_use_conflict_resolution_keyword
= kw
;
748 trait_use_conflict_resolution_names
= elements
;
749 trait_use_conflict_resolution_left_brace
= lb
;
750 trait_use_conflict_resolution_clauses
= clauses
;
751 trait_use_conflict_resolution_right_brace
= rb
;
758 Nest
[handle_possible_list env ~before_each
:space_split elements
]
763 Nest
[handle_possible_list env ~before_each
:newline clauses
];
769 trait_use_keyword
= kw
;
770 trait_use_names
= elements
;
771 trait_use_semicolon
= semi
;
776 (match Syntax.syntax elements
with
777 | Syntax.SyntaxList
[x
] -> Concat
[Space
; t env x
]
778 | Syntax.SyntaxList _
->
782 [handle_possible_list env ~before_each
:space_split elements
]
784 | _
-> Concat
[Space
; t env elements
]);
788 | Syntax.RequireClause
790 require_keyword
= kw
;
793 require_semicolon
= semi
;
795 let name = t env
name in
802 ( if has_split
name then
806 Nest
[name; t env semi
];
809 | Syntax.ConstDeclaration
811 const_modifiers
= modifiers
;
813 const_type_specifier
= const_type
;
814 const_declarators
= declarators
;
815 const_semicolon
= semi
;
819 handle_possible_list env ~after_each
:(fun _
-> Space
) modifiers
;
821 when_present const_type space
;
823 handle_declarator_list env declarators
;
827 | Syntax.TypeConstDeclaration
829 type_const_attribute_spec
= attr
;
830 type_const_modifiers
= modifiers
;
831 type_const_keyword
= kw
;
832 type_const_type_keyword
= type_kw
;
833 type_const_name
= name;
834 type_const_type_parameters
= type_params
;
835 type_const_type_constraint
= type_constraint
;
836 type_const_equal
= eq
;
837 type_const_type_specifier
= type_spec
;
838 type_const_semicolon
= semi
;
843 when_present attr newline
;
844 handle_possible_list env ~after_each
:(fun _
-> Space
) modifiers
;
852 when_present type_constraint space
;
853 t env type_constraint
;
854 when_present eq space
;
856 when_present type_spec
(fun _
->
857 Concat
[Space
; SplitWith
Cost.Base
; Nest
[t env type_spec
]]);
861 | Syntax.ParameterDeclaration
863 parameter_attribute
= attr
;
864 parameter_visibility
= visibility
;
865 parameter_call_convention
= callconv
;
866 parameter_type
= param_type
;
867 parameter_name
= name;
868 parameter_default_value
= default
;
872 handle_attribute_spec env attr ~always_split
:false;
873 when_present attr
(fun _
-> Concat
[Space
; SplitWith
Cost.Base
]);
875 when_present visibility space
;
877 when_present callconv space
;
880 Syntax.is_missing visibility
881 && Syntax.is_missing callconv
882 && Syntax.is_missing param_type
886 Concat
[Space
; SplitWith
Cost.Moderate
; Nest
[t env
name]] );
889 | Syntax.VariadicParameter
891 variadic_parameter_call_convention
= callconv
;
892 variadic_parameter_type
= type_var
;
893 variadic_parameter_ellipsis
= ellipsis
;
898 when_present callconv space
;
902 | Syntax.FileAttributeSpecification
904 file_attribute_specification_left_double_angle
= left_da
;
905 file_attribute_specification_keyword
= keyword
;
906 file_attribute_specification_colon
= colon
;
907 file_attribute_specification_attributes
= attrs
;
908 file_attribute_specification_right_double_angle
= right_da
;
915 when_present colon space
;
916 transform_possible_comma_list env ~allow_trailing
:false attrs right_da
;
919 | Syntax.OldAttributeSpecification _
920 | Syntax.AttributeSpecification _
->
921 handle_attribute_spec env node ~always_split
:true
922 | Syntax.Attribute
{ attribute_at
= at
; attribute_attribute_name
= attr
} ->
923 Concat
[t env at
; t env attr
]
924 | Syntax.AttributizedSpecifier
926 attributized_specifier_attribute_spec
= attr_spec
;
927 attributized_specifier_type
= attr_type
;
931 handle_attribute_spec env attr_spec ~always_split
:false;
935 | Syntax.InclusionExpression
936 { inclusion_require
= kw
; inclusion_filename
= expr
} ->
940 (match Syntax.syntax expr
with
941 | Syntax.ParenthesizedExpression _
-> Nothing
946 | Syntax.InclusionDirective
947 { inclusion_expression
= expr
; inclusion_semicolon
= semi
} ->
948 Concat
[t env expr
; t env semi
; Newline
]
949 | Syntax.CompoundStatement
950 { compound_left_brace
; compound_statements
; compound_right_brace
} ->
953 handle_compound_statement
957 compound_right_brace
;
960 | Syntax.UnsetStatement
963 unset_left_paren
= left_p
;
964 unset_variables
= args
;
965 unset_right_paren
= right_p
;
966 unset_semicolon
= semi
;
971 transform_argish env ~allow_trailing
:false left_p args right_p
;
975 | Syntax.WhileStatement x
->
978 t env x
.while_keyword
;
980 t env x
.while_left_paren
;
986 Nest
[t env x
.while_condition
];
988 t env x
.while_right_paren
;
990 handle_possible_compound_statement env x
.while_body
;
993 | Syntax.UsingStatementBlockScoped x
->
996 t env x
.using_block_await_keyword
;
997 when_present x
.using_block_await_keyword space
;
998 t env x
.using_block_using_keyword
;
1000 t env x
.using_block_left_paren
;
1008 handle_possible_list
1010 ~after_each
:separate_with_space_split
1011 x
.using_block_expressions
;
1014 t env x
.using_block_right_paren
;
1016 handle_possible_compound_statement env x
.using_block_body
;
1019 | Syntax.UsingStatementFunctionScoped x
->
1022 t env x
.using_function_await_keyword
;
1023 when_present x
.using_function_await_keyword space
;
1024 t env x
.using_function_using_keyword
;
1026 t env x
.using_function_expression
;
1027 t env x
.using_function_semicolon
;
1030 | Syntax.IfStatement
1033 if_left_paren
= left_p
;
1034 if_condition
= condition
;
1035 if_right_paren
= right_p
;
1036 if_statement
= if_body
;
1037 if_elseif_clauses
= elseif_clauses
;
1038 if_else_clause
= else_clause
;
1044 transform_condition env left_p condition right_p
;
1045 transform_consequence
t env if_body right_p
;
1046 handle_possible_list env elseif_clauses
;
1050 | Syntax.ElseifClause
1052 elseif_keyword
= kw
;
1053 elseif_left_paren
= left_p
;
1054 elseif_condition
= condition
;
1055 elseif_right_paren
= right_p
;
1056 elseif_statement
= body
;
1062 transform_condition env left_p condition right_p
;
1063 transform_consequence
t env body right_p
;
1065 | Syntax.ElseClause x
->
1068 t env x
.else_keyword
;
1069 (match Syntax.syntax x
.else_statement
with
1070 | Syntax.IfStatement _
->
1071 Concat
[Space
; t env x
.else_statement
; Space
]
1072 | _
-> transform_consequence
t env x
.else_statement x
.else_keyword
);
1074 | Syntax.TryStatement
1077 try_compound_statement
= body
;
1078 try_catch_clauses
= catch_clauses
;
1079 try_finally_clause
= finally_clause
;
1085 handle_possible_compound_statement env body
;
1086 handle_possible_list env catch_clauses
;
1087 t env finally_clause
;
1090 | Syntax.CatchClause
1093 catch_left_paren
= left_p
;
1094 catch_type
= ex_type
;
1095 catch_variable
= var
;
1096 catch_right_paren
= right_p
;
1107 [t env ex_type
; Space
; SplitWith
Cost.Base
; Nest
[t env var
]];
1108 handle_possible_compound_statement env body
;
1110 | Syntax.FinallyClause
{ finally_keyword
= kw
; finally_body
= body
} ->
1111 Concat
[t env kw
; Space
; handle_possible_compound_statement env body
]
1112 | Syntax.DoStatement
1116 do_while_keyword
= while_kw
;
1117 do_left_paren
= left_p
;
1118 do_condition
= cond
;
1119 do_right_paren
= right_p
;
1120 do_semicolon
= semi
;
1126 handle_possible_compound_statement env body
;
1129 transform_condition env left_p cond right_p
;
1133 | Syntax.ForStatement
1136 for_left_paren
= left_p
;
1137 for_initializer
= init
;
1138 for_first_semicolon
= semi1
;
1139 for_control
= control
;
1140 for_second_semicolon
= semi2
;
1141 for_end_of_loop
= after_iter
;
1142 for_right_paren
= right_p
;
1157 handle_possible_list
1159 ~after_each
:separate_with_space_split
1164 handle_possible_list
1166 ~after_each
:separate_with_space_split
1171 handle_possible_list
1173 ~after_each
:separate_with_space_split
1179 handle_possible_compound_statement env body
;
1182 | Syntax.ForeachStatement
1184 foreach_keyword
= kw
;
1185 foreach_left_paren
= left_p
;
1186 foreach_collection
= collection
;
1187 foreach_await_keyword
= await_kw
;
1190 foreach_arrow
= arrow
;
1191 foreach_value
= value;
1192 foreach_right_paren
= right_p
;
1193 foreach_body
= body
;
1210 SplitWith
Cost.Base
;
1219 SplitWith
Cost.Base
;
1224 handle_possible_compound_statement env body
;
1227 | Syntax.SwitchStatement
1229 switch_keyword
= kw
;
1230 switch_left_paren
= left_p
;
1231 switch_expression
= expr
;
1232 switch_right_paren
= right_p
;
1233 switch_left_brace
= left_b
;
1234 switch_sections
= sections
;
1235 switch_right_brace
= right_b
;
1237 let sections = Syntax.syntax_node_to_list
sections in
1242 delimited_nest env left_p right_p
[t env expr
];
1244 braced_block_nest env left_b right_b
(List.map
sections (t env
));
1247 | Syntax.SwitchSection
1249 switch_section_labels
= labels
;
1250 switch_section_statements
= statements
;
1251 switch_section_fallthrough
= fallthrough
;
1253 (* If there is FallThrough trivia leading the first case label, handle it
1254 * in a BlockNest so that it is indented to the same level as the previous
1255 * SwitchSection's statements. *)
1256 let (labels_leading
, labels
) = remove_leading_trivia labels
in
1257 let (after_fallthrough
, upto_fallthrough
) =
1258 List.split_while
(List.rev labels_leading
) ~f
:(fun t ->
1259 not
(is_trivia_kind_fallthrough (Trivia.kind
t)))
1261 let upto_fallthrough = List.rev
upto_fallthrough in
1262 let after_fallthrough = List.rev
after_fallthrough in
1263 let labels = Syntax.syntax_node_to_list
labels in
1264 let statements = Syntax.syntax_node_to_list
statements in
1265 (* When the statements in the SwitchSection are wrapped in a single
1266 * CompoundStatement, special-case the opening curly brace to appear on
1267 * the same line as the case label. *)
1268 let is_scoped_section =
1269 match statements with
1270 | [Syntax.{ syntax
= CompoundStatement _
; _
}] -> true
1275 ( if List.is_empty
upto_fallthrough then
1276 transform_leading_trivia
after_fallthrough
1280 BlockNest
[transform_leading_trivia
upto_fallthrough; Newline
];
1281 transform_trailing_trivia
after_fallthrough;
1283 handle_list env
labels ~after_each
:(fun is_last_label
->
1284 if is_last_label
&& is_scoped_section then
1288 ( if is_scoped_section then
1289 handle_list env
statements
1291 BlockNest
[handle_list env
statements] );
1295 { case_keyword
= kw
; case_expression
= expr
; case_colon
= colon
} ->
1296 Concat
[t env kw
; Space
; t env expr
; t env colon
]
1297 | Syntax.DefaultLabel
{ default_keyword
= kw
; default_colon
= colon
} ->
1298 Concat
[t env kw
; t env colon
]
1299 | Syntax.SwitchFallthrough
1300 { fallthrough_keyword
= kw
; fallthrough_semicolon
= semi
} ->
1301 Concat
[t env kw
; t env semi
]
1302 | Syntax.ReturnStatement
1304 return_keyword
= kw
;
1305 return_expression
= expr
;
1306 return_semicolon
= semi
;
1308 transform_keyword_expression_statement env kw expr semi
1309 | Syntax.ThrowStatement
1310 { throw_keyword
= kw
; throw_expression
= expr
; throw_semicolon
= semi
}
1312 transform_keyword_expression_statement env kw expr semi
1313 | Syntax.BreakStatement
{ break_keyword
= kw
; break_semicolon
= semi
}
1314 | Syntax.ContinueStatement
1315 { continue_keyword
= kw
; continue_semicolon
= semi
} ->
1316 Concat
[t env kw
; t env semi
; Newline
]
1317 | Syntax.EchoStatement
1320 echo_expressions
= expr_list
;
1321 echo_semicolon
= semi
;
1323 (match Syntax.syntax expr_list
with
1325 [Syntax.{ syntax
= ListItem
{ list_item
= expr
; _
}; _
}]
1326 when is_syntax_kind_parenthesized_exprression (Syntax.kind expr
) ->
1327 Concat
[t env kw
; t env expr
; t env semi
; Newline
]
1328 | _
-> transform_keyword_expr_list_statement env kw expr_list semi
)
1329 | Syntax.ConcurrentStatement
1330 { concurrent_keyword
= kw
; concurrent_statement
= statement
} ->
1335 handle_possible_compound_statement env statement
;
1338 | Syntax.SimpleInitializer
1339 { simple_initializer_equal
= eq_kw
; simple_initializer_value
= value }
1342 [Space
; t env eq_kw
; Space
; SplitWith
Cost.Base
; Nest
[t env
value]]
1343 | Syntax.AnonymousFunction
1345 anonymous_attribute_spec
= attr
;
1346 anonymous_static_keyword
= static_kw
;
1347 anonymous_async_keyword
= async_kw
;
1348 anonymous_function_keyword
= fun_kw
;
1349 anonymous_left_paren
= lp
;
1350 anonymous_parameters
= params
;
1351 anonymous_right_paren
= rp
;
1352 anonymous_colon
= colon
;
1353 anonymous_type
= ret_type
;
1354 anonymous_use
= use
;
1355 anonymous_body
= body
;
1359 handle_attribute_spec env attr ~always_split
:false;
1360 when_present attr space
;
1362 when_present static_kw space
;
1364 when_present async_kw space
;
1366 transform_argish_with_return_type env lp params rp colon ret_type
;
1368 handle_possible_compound_statement
1371 ~allow_collapse
:true
1374 | Syntax.AnonymousFunctionUseClause
1376 anonymous_use_keyword
= kw
;
1377 anonymous_use_left_paren
= left_p
;
1378 anonymous_use_variables
= vars
;
1379 anonymous_use_right_paren
= right_p
;
1382 Concat
[Space
; t env kw
; Space
; transform_argish env left_p vars right_p
]
1383 | Syntax.LambdaExpression
1385 lambda_attribute_spec
= attr
;
1386 lambda_async
= async
;
1387 lambda_signature
= signature
;
1388 lambda_arrow
= arrow
;
1393 handle_attribute_spec env attr ~always_split
:false;
1394 when_present attr space
;
1396 when_present async space
;
1400 handle_lambda_body env body
;
1402 | Syntax.LambdaSignature
1404 lambda_left_paren
= lp
;
1405 lambda_parameters
= params
;
1406 lambda_right_paren
= rp
;
1407 lambda_capability
= cap
;
1408 lambda_colon
= colon
;
1409 lambda_type
= ret_type
;
1414 when_present params split
;
1415 transform_fn_decl_args env params rp
;
1418 when_present colon space
;
1421 | Syntax.CastExpression _
-> Span
(List.map
(Syntax.children node
) (t env
))
1422 | Syntax.MemberSelectionExpression _
1423 | Syntax.SafeMemberSelectionExpression _
->
1424 handle_possible_chaining env node
1425 | Syntax.YieldExpression
{ yield_keyword
= kw
; yield_operand
= operand
} ->
1426 Concat
[t env kw
; Space
; SplitWith
Cost.Base
; Nest
[t env operand
]]
1427 | Syntax.PrefixUnaryExpression
1428 { prefix_unary_operator
= operator
; prefix_unary_operand
= operand
} ->
1432 (match Syntax.syntax operator
with
1434 let is_parenthesized =
1435 match Syntax.syntax operand
with
1436 | Syntax.ParenthesizedExpression _
-> true
1440 (match Token.kind x
with
1445 if is_parenthesized then
1453 | Syntax.BinaryExpression
1454 { binary_left_operand
; binary_operator
; binary_right_operand
} ->
1455 transform_binary_expression
1458 (binary_left_operand
, binary_operator
, binary_right_operand
)
1459 | Syntax.IsExpression
1460 { is_left_operand
= left
; is_operator
= kw
; is_right_operand
= right
}
1461 | Syntax.AsExpression
1462 { as_left_operand
= left
; as_operator
= kw
; as_right_operand
= right
}
1463 | Syntax.NullableAsExpression
1465 nullable_as_left_operand
= left
;
1466 nullable_as_operator
= kw
;
1467 nullable_as_right_operand
= right
;
1473 SplitWith
Cost.Base
;
1474 Nest
[t env kw
; Space
; t env right
];
1476 | Syntax.ConditionalExpression
1478 conditional_test
= test_expr
;
1479 conditional_question
= q_kw
;
1480 conditional_consequence
= true_expr
;
1481 conditional_colon
= c_kw
;
1482 conditional_alternative
= false_expr
;
1492 when_present true_expr
(fun () ->
1496 ( if env
.Env.indent_width
= 2 then
1497 Nest
[t env true_expr
]
1506 (not
(Syntax.is_missing true_expr
)) && env
.Env.indent_width
= 2
1508 Nest
[t env false_expr
]
1512 | Syntax.FunctionCallExpression _
-> handle_possible_chaining env node
1513 | Syntax.FunctionPointerExpression _
-> transform_simple env node
1514 | Syntax.EvalExpression
1517 eval_left_paren
= left_p
;
1518 eval_argument
= arg
;
1519 eval_right_paren
= right_p
;
1521 Concat
[t env kw
; transform_braced_item env left_p arg right_p
]
1522 | Syntax.IssetExpression
1525 isset_left_paren
= left_p
;
1526 isset_argument_list
= args
;
1527 isset_right_paren
= right_p
;
1532 transform_argish env ~allow_trailing
:false left_p args right_p
;
1534 | Syntax.DefineExpression
1536 define_keyword
= kw
;
1537 define_left_paren
= left_p
;
1538 define_argument_list
= args
;
1539 define_right_paren
= right_p
;
1541 Concat
[t env kw
; transform_argish env left_p args right_p
]
1542 | Syntax.ParenthesizedExpression
1544 parenthesized_expression_left_paren
= left_p
;
1545 parenthesized_expression_expression
= expr
;
1546 parenthesized_expression_right_paren
= right_p
;
1553 (Rule.Parental
, Concat
[Nest
[t env expr
]; Split
; t env right_p
]);
1555 | Syntax.BracedExpression
1557 braced_expression_left_brace
= left_b
;
1558 braced_expression_expression
= expr
;
1559 braced_expression_right_brace
= right_b
;
1561 (* TODO: revisit this *)
1568 List.is_empty
(Syntax.trailing_trivia left_b
)
1569 && List.is_empty
(Syntax.trailing_trivia expr
)
1571 Rule.Simple
Cost.Base
1575 WithRule
(rule, Concat
[Nest
[t env expr
]; Split
; t env right_b
]));
1577 | Syntax.EmbeddedBracedExpression
1579 embedded_braced_expression_left_brace
= left_b
;
1580 embedded_braced_expression_expression
= expr
;
1581 embedded_braced_expression_right_brace
= right_b
;
1583 (* TODO: Consider finding a way to avoid treating these expressions as
1584 opportunities for line breaks in long strings:
1586 $sql = "DELETE FROM `foo` WHERE `left` BETWEEN {$res->left} AND {$res
1587 ->right} ORDER BY `level` DESC";
1589 Concat
[t env left_b
; Nest
[t env expr
]; t env right_b
]
1590 | Syntax.ListExpression
1593 list_left_paren
= lp
;
1594 list_members
= members
;
1595 list_right_paren
= rp
;
1597 Concat
[t env kw
; transform_argish env lp members rp
]
1598 | Syntax.CollectionLiteralExpression
1600 collection_literal_name
= name;
1601 collection_literal_left_brace
= left_b
;
1602 collection_literal_initializers
= initializers
;
1603 collection_literal_right_brace
= right_b
;
1605 transform_container_literal
1612 | Syntax.ObjectCreationExpression
1613 { object_creation_new_keyword
= newkw
; object_creation_object
= what
}
1615 Concat
[t env newkw
; Space
; t env what
]
1616 | Syntax.ConstructorCall
1618 constructor_call_type
= obj_type
;
1619 constructor_call_left_paren
= left_p
;
1620 constructor_call_argument_list
= arg_list
;
1621 constructor_call_right_paren
= right_p
;
1623 Concat
[t env obj_type
; transform_argish env left_p arg_list right_p
]
1624 | Syntax.RecordCreationExpression
1626 record_creation_type
= rec_type
;
1627 record_creation_left_bracket
= left_b
;
1628 record_creation_members
= members
;
1629 record_creation_right_bracket
= right_b
;
1631 transform_container_literal env rec_type left_b members right_b
1632 | Syntax.AnonymousClass
1634 anonymous_class_class_keyword
= classkw
;
1635 anonymous_class_left_paren
= left_p
;
1636 anonymous_class_argument_list
= arg_list
;
1637 anonymous_class_right_paren
= right_p
;
1638 anonymous_class_extends_keyword
= extends_kw
;
1639 anonymous_class_extends_list
= extends
;
1640 anonymous_class_implements_keyword
= impl_kw
;
1641 anonymous_class_implements_list
= impls
;
1642 anonymous_class_body
= body
;
1644 let after_each_ancestor is_last
=
1653 transform_argish env left_p arg_list right_p
;
1654 when_present extends_kw
(fun () ->
1672 handle_possible_list
1674 ~after_each
:after_each_ancestor
1680 when_present impl_kw
(fun () ->
1698 handle_possible_list
1700 ~after_each
:after_each_ancestor
1708 | Syntax.DarrayIntrinsicExpression
1710 darray_intrinsic_keyword
= kw
;
1711 darray_intrinsic_explicit_type
= explicit_type
;
1712 darray_intrinsic_left_bracket
= left_p
;
1713 darray_intrinsic_members
= members
;
1714 darray_intrinsic_right_bracket
= right_p
;
1716 | Syntax.DictionaryIntrinsicExpression
1718 dictionary_intrinsic_keyword
= kw
;
1719 dictionary_intrinsic_explicit_type
= explicit_type
;
1720 dictionary_intrinsic_left_bracket
= left_p
;
1721 dictionary_intrinsic_members
= members
;
1722 dictionary_intrinsic_right_bracket
= right_p
;
1724 | Syntax.KeysetIntrinsicExpression
1726 keyset_intrinsic_keyword
= kw
;
1727 keyset_intrinsic_explicit_type
= explicit_type
;
1728 keyset_intrinsic_left_bracket
= left_p
;
1729 keyset_intrinsic_members
= members
;
1730 keyset_intrinsic_right_bracket
= right_p
;
1732 | Syntax.VarrayIntrinsicExpression
1734 varray_intrinsic_keyword
= kw
;
1735 varray_intrinsic_explicit_type
= explicit_type
;
1736 varray_intrinsic_left_bracket
= left_p
;
1737 varray_intrinsic_members
= members
;
1738 varray_intrinsic_right_bracket
= right_p
;
1740 | Syntax.VectorIntrinsicExpression
1742 vector_intrinsic_keyword
= kw
;
1743 vector_intrinsic_explicit_type
= explicit_type
;
1744 vector_intrinsic_left_bracket
= left_p
;
1745 vector_intrinsic_members
= members
;
1746 vector_intrinsic_right_bracket
= right_p
;
1748 transform_container_literal env kw ~explicit_type left_p members right_p
1749 | Syntax.ElementInitializer
1750 { element_key
= key
; element_arrow
= arrow
; element_value
= value } ->
1751 transform_mapish_entry env key arrow
value
1752 | Syntax.SubscriptExpression
1754 subscript_receiver
= receiver
;
1755 subscript_left_bracket
= lb
;
1756 subscript_index
= expr
;
1757 subscript_right_bracket
= rb
;
1759 Concat
[t env receiver
; transform_braced_item env lb expr rb
]
1760 | Syntax.AwaitableCreationExpression
1762 awaitable_attribute_spec
= attr
;
1763 awaitable_async
= async_kw
;
1764 awaitable_compound_statement
= body
;
1768 handle_attribute_spec env attr ~always_split
:false;
1769 when_present attr space
;
1771 when_present async_kw space
;
1772 (* TODO: rethink possible one line bodies *)
1773 (* TODO: correctly handle spacing after the closing brace *)
1774 handle_possible_compound_statement env ~space
:false body
;
1776 | Syntax.XHPChildrenDeclaration
1778 xhp_children_keyword
= kw
;
1779 xhp_children_expression
= expr
;
1780 xhp_children_semicolon
= semi
;
1782 Concat
[t env kw
; Space
; t env expr
; t env semi
; Newline
]
1783 | Syntax.XHPChildrenParenthesizedList
1785 xhp_children_list_left_paren
= left_p
;
1786 xhp_children_list_xhp_children
= expressions
;
1787 xhp_children_list_right_paren
= right_p
;
1790 [transform_argish env ~allow_trailing
:false left_p expressions right_p
]
1791 | Syntax.XHPCategoryDeclaration
1793 xhp_category_keyword
= kw
;
1794 xhp_category_categories
= categories
;
1795 xhp_category_semicolon
= semi
;
1800 (* TODO: Eliminate code duplication *)
1804 [handle_possible_list env ~before_each
:space_split categories
]
1809 | Syntax.XHPEnumType
1811 xhp_enum_keyword
= kw
;
1812 xhp_enum_left_brace
= left_b
;
1813 xhp_enum_values
= values
;
1814 xhp_enum_right_brace
= right_b
;
1816 Concat
[t env kw
; Space
; transform_argish env left_b values right_b
]
1817 | Syntax.XHPClassAttributeDeclaration
1819 xhp_attribute_keyword
= kw
;
1820 xhp_attribute_attributes
= xhp_attributes
;
1821 xhp_attribute_semicolon
= semi
;
1826 (match Syntax.syntax xhp_attributes
with
1827 | Syntax.Missing
-> Nothing
1828 | Syntax.SyntaxList
[attr
] ->
1829 WithRule
(Rule.Parental
, Nest
[Space
; Split
; t env attr
])
1830 | Syntax.SyntaxList attrs
->
1831 Nest
[handle_list env ~before_each
:newline attrs
]
1832 | _
-> failwith
"Expected SyntaxList");
1836 | Syntax.XHPClassAttribute
1838 xhp_attribute_decl_type
= attr_type
;
1839 xhp_attribute_decl_name
= name;
1840 xhp_attribute_decl_initializer
= init
;
1841 xhp_attribute_decl_required
= req
;
1843 (* TODO: figure out nesting here *)
1849 when_present init space
;
1851 when_present req space
;
1854 | Syntax.XHPSimpleAttribute
1856 xhp_simple_attribute_name
= name;
1857 xhp_simple_attribute_equal
= eq
;
1858 xhp_simple_attribute_expression
= expr
;
1860 Span
[t env
name; t env eq
; SplitWith
Cost.Base
; Nest
[t env expr
]]
1861 | Syntax.XHPSpreadAttribute
1863 xhp_spread_attribute_left_brace
= l_brace
;
1864 xhp_spread_attribute_spread_operator
= spread
;
1865 xhp_spread_attribute_expression
= expr
;
1866 xhp_spread_attribute_right_brace
= r_brace
;
1872 SplitWith
Cost.Base
;
1878 xhp_open_left_angle
= left_a
;
1879 xhp_open_name
= name;
1880 xhp_open_attributes
= attrs
;
1881 xhp_open_right_angle
= right_a
;
1887 (match Syntax.syntax attrs
with
1889 handle_xhp_open_right_angle_token env attrs right_a
1901 handle_possible_list
1903 ~after_each
:(fun is_last
->
1910 handle_xhp_open_right_angle_token env attrs right_a
;
1914 | Syntax.XHPExpression
{ xhp_open
; xhp_body
= body
; xhp_close
= close
} ->
1915 let handle_xhp_body body
=
1916 match Syntax.syntax body
with
1917 | Syntax.Missing
-> when_present close split
1918 | Syntax.SyntaxList xs
->
1919 (* Trivia is lexed differently within an XHP body because whitespace is
1920 semantically significant in an XHP body when it is adjacent to an
1921 XHPBody token. Any number of whitespaces or newlines adjacent to an
1922 XHPBody token will be rendered as a single space. In order to make it
1923 easier to determine whether a space character should be rendered next
1924 to an XHPBody token, all trailing trivia in an XHP body is lexed as
1925 leading trivia for the next token (except on XHPBody tokens, where
1926 trailing trivia is lexed normally). This ensures that any time
1927 semantically-significant whitespace is present, at least some of it
1928 occurs in the leading or trailing trivia list of an adjacent XHPBody
1931 To deal with this, we keep track of whether the last token we
1932 transformed was one that trailing trivia is scanned for. If it
1933 wasn't, we handle the next token's leading trivia list using
1934 transform_xhp_leading_trivia, which treats all trivia up to the first
1935 newline as trailing trivia. *)
1936 let prev_token_was_xhpbody = ref false in
1937 let transformed_body =
1939 (List.map xs ~f
:(fun node
->
1940 let node_is_xhpbody =
1941 match Syntax.syntax node
with
1942 | Syntax.Token
t -> is_token_kind_xhp_body (Token.kind
t)
1946 (* Here, we preserve newlines after XHPBody tokens and don't otherwise
1947 add splits between them. This means that we don't reflow paragraphs
1948 in XHP to fit in the desired line length. It would be nice to do
1949 so, but this is not possible with the current set of Rule types.
1951 If we were to add a split between each XHPBody token instead of
1952 splitting only where newlines were already present, we'd need a new
1953 Rule type to govern word-wrap style splitting, since using
1954 independent splits (e.g. SplitWith Cost.Base) between every token
1955 would make solving too expensive. *)
1956 let preserve_xhpbody_whitespace trivia
=
1957 if node_is_xhpbody then
1958 if has_newline trivia
then
1960 else if has_whitespace trivia
then
1967 let (leading
, node
) = remove_leading_trivia node
in
1968 let trailing = Syntax.trailing_trivia node
in
1969 let leading_whitespace =
1972 (* Whitespace in an XHP body is *only* significant when adjacent to
1973 an XHPBody token, so we are free to add splits between other
1974 nodes (like XHPExpressions and BracedExpressions). *)
1976 (not
!prev_token_was_xhpbody) && not
node_is_xhpbody
1981 (* If the previous token was an XHPBody token, the lexer will have
1982 scanned trailing trivia for it, so we can handle the leading
1983 trivia for this node normally. Otherwise, handle the trivia up to
1984 the first newline as trailing trivia. *)
1985 ( if !prev_token_was_xhpbody then
1986 transform_leading_trivia leading
1988 transform_xhp_leading_trivia leading
);
1991 prev_token_was_xhpbody := node_is_xhpbody;
1995 preserve_xhpbody_whitespace leading
;
1997 preserve_xhpbody_whitespace trailing;
2003 ( if !prev_token_was_xhpbody then
2006 (* Don't collapse XHPExpressions onto a single line if they were
2007 intentionally split across multiple lines in the original source.
2008 If there is a newline in the body's leading trivia, we consider
2009 that a signal that this expression was intended to be split
2010 across multiple lines. *)
2011 has_newline
(Syntax.leading_trivia body
)
2017 | _
-> failwith
"Expected SyntaxList"
2019 WithOverridingParentalRule
2023 Nest
[handle_xhp_body body
];
2024 when_present close
(fun () ->
2025 let (leading
, close
) = remove_leading_trivia close
in
2028 (* Ignore extra newlines by treating this as trailing trivia *)
2029 ignore_trailing_invisibles leading
;
2033 | Syntax.VarrayTypeSpecifier
2035 varray_keyword
= kw
;
2036 varray_left_angle
= left_a
;
2038 varray_trailing_comma
= trailing_comma
;
2039 varray_right_angle
= right_a
;
2044 transform_braced_item_with_trailer
2051 | Syntax.VectorTypeSpecifier
2053 vector_type_keyword
= kw
;
2054 vector_type_left_angle
= left_a
;
2055 vector_type_type
= vec_type
;
2056 vector_type_trailing_comma
= trailing_comma
;
2057 vector_type_right_angle
= right_a
;
2062 transform_braced_item_with_trailer
2069 | Syntax.KeysetTypeSpecifier
2071 keyset_type_keyword
= kw
;
2072 keyset_type_left_angle
= left_a
;
2073 keyset_type_type
= ks_type
;
2074 keyset_type_trailing_comma
= trailing_comma
;
2075 keyset_type_right_angle
= right_a
;
2080 transform_braced_item_with_trailer
2087 | Syntax.TypeParameter
2089 type_attribute_spec
= attr
;
2090 type_reified
= reified
;
2091 type_variance
= variance
;
2093 type_param_params
= params
;
2094 type_constraints
= constraints
;
2098 handle_attribute_spec env attr ~always_split
:false;
2099 when_present attr space
;
2101 when_present reified space
;
2105 when_present constraints space
;
2106 handle_possible_list env constraints ~after_each
:(fun is_last
->
2112 | Syntax.TypeConstraint
{ constraint_keyword
= kw
; constraint_type
} ->
2113 Concat
[t env kw
; Space
; t env constraint_type
]
2114 | Syntax.DarrayTypeSpecifier
2116 darray_keyword
= kw
;
2117 darray_left_angle
= left_a
;
2119 darray_comma
= comma_kw
;
2120 darray_value
= value;
2121 darray_trailing_comma
= trailing_comma
;
2122 darray_right_angle
= right_a
;
2124 let key_list_item = Syntax.make_list_item key comma_kw
in
2125 let val_list_item = Syntax.make_list_item
value trailing_comma
in
2126 let args = make_list [key_list_item; val_list_item] in
2129 t env kw
; transform_argish env ~allow_trailing
:true left_a
args right_a
;
2131 | Syntax.DictionaryTypeSpecifier
2133 dictionary_type_keyword
= kw
;
2134 dictionary_type_left_angle
= left_a
;
2135 dictionary_type_members
= members
;
2136 dictionary_type_right_angle
= right_a
;
2138 Concat
[t env kw
; transform_argish env left_a members right_a
]
2139 | Syntax.ClosureTypeSpecifier
2141 closure_outer_left_paren
= outer_left_p
;
2142 closure_function_keyword
= kw
;
2143 closure_inner_left_paren
= inner_left_p
;
2144 closure_parameter_list
= param_list
;
2145 closure_inner_right_paren
= inner_right_p
;
2146 closure_capability
= cap
;
2147 closure_colon
= colon
;
2148 closure_return_type
= ret_type
;
2149 closure_outer_right_paren
= outer_right_p
;
2156 when_present param_list split
;
2157 transform_fn_decl_args env param_list inner_right_p
;
2160 when_present colon space
;
2162 t env outer_right_p
;
2164 | Syntax.ClosureParameterTypeSpecifier
2166 closure_parameter_call_convention
= callconv
;
2167 closure_parameter_type
= cp_type
;
2169 Concat
[t env callconv
; when_present callconv space
; t env cp_type
]
2170 | Syntax.ClassnameTypeSpecifier
2172 classname_keyword
= kw
;
2173 classname_left_angle
= left_a
;
2174 classname_type
= class_type
;
2175 classname_trailing_comma
= trailing_comma
;
2176 classname_right_angle
= right_a
;
2181 transform_braced_item_with_trailer
2188 | Syntax.FieldSpecifier
2190 field_question
= question
;
2192 field_arrow
= arrow_kw
;
2196 [t env question
; transform_mapish_entry env
name arrow_kw field_type
]
2197 | Syntax.FieldInitializer
2199 field_initializer_name
= name;
2200 field_initializer_arrow
= arrow_kw
;
2201 field_initializer_value
= value;
2203 transform_mapish_entry env
name arrow_kw
value
2204 | Syntax.ShapeTypeSpecifier
2206 shape_type_keyword
= shape_kw
;
2207 shape_type_left_paren
= left_p
;
2208 shape_type_fields
= type_fields
;
2209 shape_type_ellipsis
= ellipsis
;
2210 shape_type_right_paren
= right_p
;
2213 if Syntax.is_missing ellipsis
then
2216 let missing_separator = make_missing () in
2218 [Syntax.make_list_item ellipsis
missing_separator]
2220 make_list (Syntax.children type_fields
@ ellipsis_list)
2222 transform_container_literal
2228 ~allow_trailing
:(Syntax.is_missing ellipsis
)
2229 | Syntax.ShapeExpression
2231 shape_expression_keyword
= shape_kw
;
2232 shape_expression_left_paren
= left_p
;
2233 shape_expression_fields
= fields;
2234 shape_expression_right_paren
= right_p
;
2236 transform_container_literal env shape_kw left_p
fields right_p
2237 | Syntax.TupleExpression
2239 tuple_expression_keyword
= kw
;
2240 tuple_expression_left_paren
= left_p
;
2241 tuple_expression_items
= items
;
2242 tuple_expression_right_paren
= right_p
;
2244 Concat
[t env kw
; transform_argish env left_p items right_p
]
2245 | Syntax.TypeArguments
2247 type_arguments_left_angle
= left_a
;
2248 type_arguments_types
= type_list
;
2249 type_arguments_right_angle
= right_a
;
2251 transform_argish env left_a type_list right_a
2252 | Syntax.TypeParameters
2254 type_parameters_left_angle
= left_a
;
2255 type_parameters_parameters
= param_list
;
2256 type_parameters_right_angle
= right_a
;
2258 transform_argish env left_a param_list right_a
2259 | Syntax.TupleTypeSpecifier
2261 tuple_left_paren
= left_p
;
2262 tuple_types
= types
;
2263 tuple_right_paren
= right_p
;
2265 transform_argish env left_p types right_p
2266 | Syntax.UnionTypeSpecifier
2268 union_left_paren
= left_p
;
2269 union_types
= types
;
2270 union_right_paren
= right_p
;
2277 handle_possible_list
2280 ~after_each
:(fun is_last
->
2285 ~handle_element
:(fun node
->
2286 match Syntax.syntax node
with
2287 | Syntax.ListItem
{ list_item
; list_separator
} ->
2291 when_present list_separator space
;
2292 t env list_separator
;
2296 | Syntax.IntersectionTypeSpecifier
2298 intersection_left_paren
= left_p
;
2299 intersection_types
= types
;
2300 intersection_right_paren
= right_p
;
2307 handle_possible_list
2310 ~after_each
:(fun is_last
->
2315 ~handle_element
:(fun node
->
2316 match Syntax.syntax node
with
2317 | Syntax.ListItem
{ list_item
; list_separator
} ->
2321 when_present list_separator space
;
2322 t env list_separator
;
2326 | Syntax.TupleTypeExplicitSpecifier
2328 tuple_type_keyword
= kw
;
2329 tuple_type_left_angle
= left_a
;
2330 tuple_type_types
= types
;
2331 tuple_type_right_angle
= right_a
;
2333 Concat
[t env kw
; transform_argish env left_a types right_a
]
2334 | Syntax.PrefixedCodeExpression
2336 prefixed_code_prefix
= prefix
;
2337 prefixed_code_left_backtick
= left_bt
;
2338 prefixed_code_expression
= expression
;
2339 prefixed_code_right_backtick
= right_bt
;
2342 [t env prefix
; transform_braced_item env left_bt expression right_bt
]
2343 | Syntax.DecoratedExpression
2345 decorated_expression_decorator
= op
;
2346 decorated_expression_expression
= expr
;
2352 match Syntax.syntax op
with
2353 | Syntax.Token
t when is_token_kind_in_out (Token.kind
t) -> Space
2358 | Syntax.ErrorSyntax _
-> raise
Hackfmt_error.InvalidSyntax
2359 | Syntax.EnumClassDeclaration
2361 enum_class_attribute_spec
= attr_spec
;
2362 enum_class_enum_keyword
= enum_kw
;
2363 enum_class_class_keyword
= class_kw
;
2364 enum_class_name
= name;
2365 enum_class_colon
= colon
;
2366 enum_class_base
= base
;
2367 enum_class_extends
= extends_kw
;
2368 enum_class_extends_list
= extends_list
;
2369 enum_class_left_brace
= left_brace
;
2370 enum_class_elements
= elements
;
2371 enum_class_right_brace
= right_brace
;
2373 let after_each_ancestor is_last
=
2382 when_present attr_spec newline
;
2390 SplitWith
Cost.Base
;
2391 Nest
[Space
; t env base
; Space
];
2392 when_present extends_kw
(fun () ->
2405 ( if list_length extends_list
= 1 then
2411 handle_possible_list
2413 ~after_each
:after_each_ancestor
2424 [handle_possible_list env elements
];
2427 | Syntax.EnumClassEnumerator
2429 enum_class_enumerator_name
= name;
2430 enum_class_enumerator_left_angle
= left_angle
;
2431 enum_class_enumerator_type
= type_
;
2432 enum_class_enumerator_right_angle
= right_angle
;
2433 enum_class_enumerator_left_paren
= left_paren
;
2434 enum_class_enumerator_initial_value
= initial_value
;
2435 enum_class_enumerator_right_paren
= right_paren
;
2436 enum_class_enumerator_semicolon
= semicolon
;
2445 t env initial_value
;
2450 | Syntax.EnumAtomExpression _
-> transform_simple env node
)
2452 and when_present node f
=
2453 match Syntax.syntax node
with
2454 | Syntax.Missing
-> Nothing
2457 and transform_simple env node
= Concat
(List.map
(Syntax.children node
) (t env
))
2459 and transform_simple_statement env node
=
2460 Concat
(List.map
(Syntax.children node
) (t env
) @ [Newline
])
2462 and braced_block_nest env ?
(allow_collapse
= true) open_b close_b nodes
=
2463 let nodes = Concat
nodes in
2464 match (allow_collapse
, has_printable_content
nodes, Syntax.syntax open_b
) with
2465 | (true, false, Syntax.Token ob
)
2466 when List.for_all
(Token.trailing ob
) (fun t ->
2467 not
(is_trivia_kind_end_of_line (Trivia.kind
t))) ->
2468 Concat
[t env open_b
; t env close_b
]
2469 | (true, false, Syntax.Missing
) -> Concat
[t env open_b
; t env close_b
]
2471 (* Remove the closing brace's leading trivia and handle it inside the
2472 * BlockNest, so that comments will be indented correctly. *)
2473 let (leading
, close_b
) = remove_leading_trivia close_b
in
2478 BlockNest
[nodes; transform_leading_trivia leading
; Newline
];
2484 ?
(split_when_children_split
= true)
2485 ?
(force_newlines
= false)
2491 | _
when force_newlines
-> Rule.Always
2492 | _
when split_when_children_split
-> Rule.Parental
2493 | _
-> Rule.Simple
Cost.Base
2495 Span
[t env left_delim
; WithRule
(rule, nest env right_delim
nodes)]
2497 and nest env ?
(spaces
= false) right_delim
nodes =
2498 (* Remove the right delimiter's leading trivia and handle it inside the
2499 * Nest, so that comments will be indented correctly. *)
2500 let (leading
, right_delim
) = remove_leading_trivia right_delim
in
2501 let nested_contents = Nest
[Concat
nodes; transform_leading_trivia leading
] in
2502 let content_present = has_printable_content
nested_contents in
2504 match (content_present, spaces
) with
2505 | (false, _
) -> Nothing
2506 | (true, false) -> Split
2507 | (true, true) -> space_split
()
2509 Concat
[maybe_split; nested_contents; maybe_split; t env right_delim
]
2511 and after_each_argument is_last
=
2517 and separate_with_space_split is_last
=
2523 and handle_attribute_spec env node ~always_split
=
2524 match Syntax.syntax node
with
2525 | Syntax.OldAttributeSpecification
2527 old_attribute_specification_left_double_angle
= left_da
;
2528 old_attribute_specification_attributes
= attrs
;
2529 old_attribute_specification_right_double_angle
= right_da
;
2531 transform_argish env left_da attrs right_da
2532 | Syntax.AttributeSpecification
{ attribute_specification_attributes
= attrs
}
2534 handle_possible_list
2536 ~after_each
:(fun _
->
2537 if always_split
then
2542 | Syntax.Missing
-> Nothing
2543 | _
-> failwith
"Attribute specification expected"
2545 and handle_lambda_body env node
=
2546 match Syntax.syntax node
with
2547 | Syntax.CompoundStatement
2548 { compound_left_brace
; compound_statements
; compound_right_brace
} ->
2549 handle_compound_statement
2551 ~allow_collapse
:true
2554 compound_right_brace
2555 | Syntax.XHPExpression _
->
2556 WithRule
(Rule.Parental
, Concat
[Space
; Split
; Nest
[t env node
]])
2557 | _
-> Concat
[Space
; SplitWith
Cost.Base
; Nest
[t env node
]]
2559 and handle_possible_compound_statement
2560 env ?
(space
= true) ?
(allow_collapse
= false) node
=
2561 match Syntax.syntax node
with
2562 | Syntax.CompoundStatement
2563 { compound_left_brace
; compound_statements
; compound_right_brace
} ->
2566 handle_compound_statement
2571 compound_right_brace
;
2577 | Syntax.Token _
-> t env node
2578 | _
-> Concat
[Newline
; BlockNest
[t env node
]]
2580 and handle_compound_statement
2581 env ?
(allow_collapse
= false) left_b
statements right_b
=
2590 [handle_possible_list env
statements];
2594 * Special-case handling for lists of declarators, where we want the splits
2595 * between declarators to break if their children break, but we want a single
2596 * declarator to stay joined with the line preceding it if it fits, even when
2597 * its children break.
2599 and handle_declarator_list env declarators
=
2600 match Syntax.syntax declarators
with
2601 | Syntax.Missing
-> Nothing
2602 | Syntax.SyntaxList
[declarator
] ->
2606 (* Use an independent split, so we don't break just because a line break
2607 * occurs in the declarator. *)
2608 SplitWith
Cost.Base
;
2611 | Syntax.SyntaxList xs
->
2612 (* Use Rule.Parental to break each declarator onto its own line if any
2613 * line break occurs in a declarator, or if they can't all fit onto one
2618 (List.map xs
(fun declarator
->
2619 Concat
[Space
; Split
; t env declarator
])) )
2620 | _
-> failwith
"SyntaxList expected"
2624 ?
(before_each
= (fun () -> Nothing
))
2625 ?
(after_each
= (fun _is_last
-> Nothing
))
2626 ?
(handle_element
= t env
)
2627 ?
(handle_last
= handle_element
)
2631 | [hd
] -> Concat
[before_each
(); handle_last hd
; after_each
true]
2633 Concat
[before_each
(); handle_element hd
; after_each
false; aux tl
]
2638 and list_length node
=
2639 match Syntax.syntax node
with
2640 | Syntax.Missing
-> 0
2641 | Syntax.SyntaxList x
-> List.length x
2644 and handle_possible_list
2645 env ?before_each ?after_each ?handle_element ?handle_last node
=
2646 match Syntax.syntax node
with
2647 | Syntax.Missing
-> Nothing
2648 | Syntax.SyntaxList x
->
2649 handle_list env x ?before_each ?after_each ?handle_element ?handle_last
2651 handle_list env
[node
] ?before_each ?after_each ?handle_element ?handle_last
2653 and handle_xhp_open_right_angle_token env attrs node
=
2654 match Syntax.syntax node
with
2655 | Syntax.Token token
->
2658 ( if String.equal
(Token.text token
) "/>" then
2659 Concat
[Space
; when_present attrs split
]
2664 | _
-> failwith
"expected xhp_open right_angle token"
2666 and handle_possible_chaining env node
=
2667 let rec handle_member_selection acc
(receiver
, arrow
, member
, targs
) args =
2668 let (first_receiver
, acc
) = handle_chaining acc receiver
in
2669 (first_receiver
, (arrow
, member
, targs
, args) :: acc
)
2670 and handle_fun_call acc node receiver targs lp
args rp
=
2671 match Syntax.syntax receiver
with
2672 | Syntax.MemberSelectionExpression
2673 { member_object
= obj
; member_operator
= arrow
; member_name
= member
}
2674 | Syntax.SafeMemberSelectionExpression
2676 safe_member_object
= obj
;
2677 safe_member_operator
= arrow
;
2678 safe_member_name
= member
;
2680 handle_member_selection
2685 if Syntax.is_missing targs
then
2689 (Some
(lp
, args, rp
))
2691 and handle_chaining acc node
=
2692 match Syntax.syntax node
with
2693 | Syntax.FunctionCallExpression
2695 function_call_receiver
= receiver
;
2696 function_call_type_args
= targs
;
2697 function_call_left_paren
= lp
;
2698 function_call_argument_list
= args;
2699 function_call_right_paren
= rp
;
2701 handle_fun_call acc node receiver targs lp
args rp
2702 | Syntax.MemberSelectionExpression
2703 { member_object
= obj
; member_operator
= arrow
; member_name
= member
}
2704 | Syntax.SafeMemberSelectionExpression
2706 safe_member_object
= obj
;
2707 safe_member_operator
= arrow
;
2708 safe_member_name
= member
;
2710 handle_member_selection acc
(obj
, arrow
, member
, None
) None
2713 (* It's easy to end up with an infinite loop by passing an unexpected node
2714 kind here, so confirm that we have an expected kind in hand. *)
2716 match Syntax.kind node
with
2717 | SyntaxKind.FunctionCallExpression
2718 | SyntaxKind.MemberSelectionExpression
2719 | SyntaxKind.SafeMemberSelectionExpression
->
2723 ( "Unexpected SyntaxKind in handle_possible_chaining: "
2724 ^
SyntaxKind.show kind
)
2726 (* Flatten nested member selection expressions into the first receiver and a
2727 list of member selections.
2728 E.g., transform $x->a->b->c into ($x, [->a; ->b; ->c]) *)
2729 let (first_receiver
, chain_list
) = handle_chaining
[] node
in
2730 let chain_list = List.rev
chain_list in
2731 let transform_chain (arrow
, member
, targs
, argish
) =
2736 Option.value_map targs ~default
:Nothing ~f
:(t env
);
2737 Option.value_map argish ~default
:Nothing ~f
:(fun (lp
, args, rp
) ->
2738 transform_argish env lp
args rp
);
2741 (* The actual transform for function call expressions (the default transform
2742 just calls into [handle_possible_chaining]). *)
2743 let transform_first_receiver node
=
2744 match Syntax.syntax node
with
2745 | Syntax.FunctionCallExpression
2747 function_call_receiver
= receiver
;
2748 function_call_type_args
= targs
;
2749 function_call_left_paren
= lp
;
2750 function_call_argument_list
= args;
2751 function_call_right_paren
= rp
;
2753 Concat
[t env receiver
; t env targs
; transform_argish env lp
args rp
]
2754 | Syntax.MemberSelectionExpression _
2755 | Syntax.SafeMemberSelectionExpression _
->
2757 "Should not be possible for a member selection expression to be considered first_receiver"
2760 let first_receiver_has_trailing_newline =
2761 node_has_trailing_newline first_receiver
2763 match chain_list with
2764 | [] -> transform_first_receiver first_receiver
2768 Span
[transform_first_receiver first_receiver
];
2769 ( if first_receiver_has_trailing_newline then
2772 SplitWith
Cost.High
);
2773 Nest
[transform_chain hd
];
2776 let transformed_hd = transform_chain hd
in
2777 let tl = List.map
tl transform_chain in
2780 | (_
, trailing, None
, None
)
2781 | (_
, _
, Some
trailing, None
)
2782 | (_
, _
, _
, Some
(_
, _
, trailing)) ->
2783 if node_has_trailing_newline
trailing then
2785 else if first_receiver_has_trailing_newline then
2788 (* If we have a chain where only the final item contains internal
2789 splits, use a Simple rule instead of a Parental one.
2790 This allows us to preserve this style:
2792 return $this->fooGenerator->generateFoo(
2798 let rev_tl_except_last = List.rev
tl |> List.tl_exn
in
2799 let items_except_last = transformed_hd :: rev_tl_except_last in
2800 if List.exists
items_except_last has_split
then
2803 Rule.Simple
Cost.NoCost
2811 transform_first_receiver first_receiver
;
2812 ( if first_receiver_has_trailing_newline then
2815 SplitWith
Cost.Base
);
2819 (* This needs to be nested separately due to the above SplitWith *)
2820 Nest
[transformed_hd];
2821 Nest
(List.map
tl ~f
:(fun x
-> Concat
[Split
; x
]));
2825 and transform_fn_decl_name env modifiers kw
name type_params leftp
=
2826 let mods = handle_possible_list env ~after_each
:(fun _
-> Space
) modifiers
in
2827 [mods; t env kw
; Space
; t env
name; t env type_params
; t env leftp
; Split
]
2829 and transform_fn_decl_args env params rightp
=
2830 (* It is a syntax error to follow a variadic parameter with a trailing
2831 * comma, so suppress trailing commas in that case. *)
2832 let allow_trailing =
2833 match Syntax.syntax params
with
2834 | Syntax.SyntaxList params
->
2836 match Syntax.syntax
(List.last_exn params
) with
2837 | Syntax.ListItem
{ list_item
; _
} -> list_item
2838 | _
-> failwith
"Expected ListItem"
2841 match Syntax.syntax
last_param with
2842 | Syntax.VariadicParameter _
2844 ParameterDeclaration
2851 decorated_expression_decorator
=
2854 Token
{ Token.kind
= TokenKind.DotDotDot
; _
};
2870 Concat
[transform_possible_comma_list env ~
allow_trailing params rightp
]
2873 and transform_argish_with_return_type env left_p params right_p colon ret_type
=
2877 when_present params split
;
2878 transform_fn_decl_args env params right_p
;
2880 when_present colon space
;
2884 and transform_argish
2886 ?
(allow_trailing = true)
2887 ?
(force_newlines
= false)
2892 (* It is a syntax error to follow a splat argument with a trailing comma, so
2893 suppress trailing commas in that case. *)
2894 let allow_trailing =
2895 match Syntax.syntax arg_list
with
2896 | Syntax.SyntaxList
args ->
2898 match Syntax.syntax
(List.last_exn
args) with
2899 | Syntax.ListItem
{ list_item
; _
} -> list_item
2900 | _
-> failwith
"Expected ListItem"
2903 match Syntax.syntax
last_arg with
2907 decorated_expression_decorator
=
2908 { syntax
= Token
{ Token.kind
= TokenKind.DotDotDot
; _
}; _
};
2912 | _
-> allow_trailing
2914 | _
-> allow_trailing
2917 (* When the last argument breaks across multiple lines, we want to allow the
2918 arg list rule to stay unbroken even though the last argument contains
2919 splits that may be broken on.
2923 // We do not want to break f's rule even though its child splits:
2925 $foo, // single-line comment forces the vec's rule to split
2929 // We do not want to break map's rule even though the lambda has splits:
2930 map($vec, $element ==> {
2934 let split_when_children_split =
2938 match Syntax.syntax arg_list
with
2939 | Syntax.SyntaxList
[] -> true
2940 | Syntax.SyntaxList
[x
] ->
2941 let has_surrounding_whitespace =
2943 ( List.is_empty
(Syntax.trailing_trivia left_p
)
2944 && List.is_empty
(Syntax.trailing_trivia arg_list
) )
2946 if has_surrounding_whitespace then
2949 looks_bad_in_non_parental_braces x
2950 | Syntax.SyntaxList items
->
2951 let last = List.last_exn items
in
2952 let has_surrounding_whitespace =
2954 ( List.is_empty
(Syntax.leading_trivia last)
2955 && List.is_empty
(Syntax.trailing_trivia
last) )
2957 if has_surrounding_whitespace then
2960 (* When there are multiple arguments, opt into this behavior only when we
2961 have no splits in any of the arguments except the last. *)
2962 match List.rev items
with
2963 | [] -> assert false
2965 let prev_args_may_split =
2966 rest
|> List.map ~f
:(t env
) |> List.exists ~f
:has_split
2968 if prev_args_may_split then
2971 looks_bad_in_non_parental_braces
last
2977 ~
split_when_children_split
2981 [transform_arg_list env ~
allow_trailing arg_list
]
2983 (** Sometimes, we want to use a non-Parental rule for function call argument
2984 lists and other similar constructs when not breaking around the argument
2985 list looks reasonable. For example:
2988 return do_something_with($x);
2991 Some constructs don't look so great when we do this:
2994 do_something_with($x));
3000 This function blacklists those constructs. *)
3001 and looks_bad_in_non_parental_braces item
=
3003 match Syntax.syntax
item with
3004 | Syntax.ListItem
{ list_item
; _
} -> list_item
3007 match Syntax.syntax
item with
3009 LambdaExpression
{ lambda_body
= { syntax
= CompoundStatement _
; _
}; _
})
3012 | Syntax.FunctionCallExpression
{ function_call_receiver
; _
} ->
3013 Syntax.is_member_selection_expression function_call_receiver
3014 | Syntax.ConditionalExpression _
3015 | Syntax.BinaryExpression _
3016 | Syntax.MemberSelectionExpression _
3017 | Syntax.FieldSpecifier _
3018 | Syntax.FieldInitializer _
3019 | Syntax.ElementInitializer _
3020 | Syntax.LambdaExpression _
3021 | Syntax.XHPExpression _
->
3025 and transform_braced_item env left_p
item right_p
=
3026 let has_no_surrounding_trivia =
3027 List.is_empty
(Syntax.trailing_trivia left_p
)
3028 && List.is_empty
(Syntax.leading_trivia item)
3029 && List.is_empty
(Syntax.trailing_trivia
item)
3030 && List.is_empty
(Syntax.leading_trivia right_p
)
3032 if has_no_surrounding_trivia && not
(looks_bad_in_non_parental_braces
item)
3034 Concat
(List.map
[left_p
; item; right_p
] (t env
))
3036 delimited_nest env left_p right_p
[t env
item]
3038 and transform_argish_item env x
=
3039 match Syntax.syntax x
with
3040 | Syntax.ListItem
{ list_item
; list_separator
} ->
3041 Concat
[transform_argish_item env list_item
; t env list_separator
]
3042 | Syntax.BinaryExpression
3044 binary_left_operand
= left
;
3045 binary_operator
= op
;
3046 binary_right_operand
= right
;
3048 when not
(is_concat op
) ->
3049 transform_binary_expression env ~is_nested
:true (left
, op
, right
)
3052 and transform_trailing_comma env ~
allow_trailing item comma
=
3053 (* PHP does not permit trailing commas in function calls. Rather than try to
3054 * account for where PHP's parser permits trailing commas, we just never add
3055 * them in PHP files. *)
3056 let allow_trailing = allow_trailing && env
.Env.add_trailing_commas
in
3057 match Syntax.syntax comma
with
3058 | Syntax.Token tok
->
3061 transform_argish_item env
item;
3062 transform_leading_trivia
(Token.leading tok
);
3063 ( if allow_trailing then
3067 Ignore
(Token.text tok
, Token.width tok
);
3068 transform_trailing_trivia
(Token.trailing tok
);
3071 let (item, item_trailing
) = remove_trailing_trivia
item in
3074 transform_argish_item env
item;
3075 ( if allow_trailing then
3079 transform_trailing_trivia item_trailing
;
3081 | _
-> failwith
"Expected Token"
3083 and transform_braced_item_with_trailer env left_p
item comma right_p
=
3084 let has_no_surrounding_trivia =
3085 List.is_empty
(Syntax.trailing_trivia left_p
)
3086 && List.is_empty
(Syntax.leading_trivia item)
3087 && List.is_empty
(Syntax.trailing_trivia
item)
3088 && List.is_empty
(Syntax.leading_trivia comma
)
3089 && List.is_empty
(Syntax.trailing_trivia comma
)
3090 && List.is_empty
(Syntax.leading_trivia right_p
)
3092 (* TODO: turn allow_trailing:true when HHVM versions that don't support
3093 trailing commas in all these places reach end-of-life. *)
3094 let item_and_comma =
3095 transform_trailing_comma env ~
allow_trailing:false item comma
3097 if has_no_surrounding_trivia && not
(looks_bad_in_non_parental_braces
item)
3099 Concat
[t env left_p
; item_and_comma; t env right_p
]
3101 delimited_nest env left_p right_p
[item_and_comma]
3103 and transform_arg_list env ?
(allow_trailing = true) items
=
3104 handle_possible_list
3107 ~after_each
:after_each_argument
3108 ~handle_last
:(transform_last_arg env ~
allow_trailing)
3109 ~handle_element
:(transform_argish_item env
)
3111 and transform_possible_comma_list env ?
(allow_trailing = true) items right_p
=
3112 nest env right_p
[transform_arg_list env ~
allow_trailing items
]
3114 and transform_container_literal
3123 let force_newlines = node_has_trailing_newline left_p
in
3125 match explicit_type
with
3126 | Some ex_ty
-> t env ex_ty
3146 and replace_leading_trivia node new_leading_trivia
=
3147 match Syntax.leading_token node
with
3149 | Some leading_token
->
3150 let rewritten_node =
3151 Rewriter.rewrite_pre
3152 (fun node_to_rewrite
->
3153 match Syntax.syntax node_to_rewrite
with
3154 | Syntax.Token
t when phys_equal
t leading_token
->
3156 (Syntax.make_token
{ t with Token.leading
= new_leading_trivia
})
3157 | _
-> Rewriter.Keep
)
3162 and remove_leading_trivia node
=
3163 match Syntax.leading_token node
with
3164 | None
-> ([], node
)
3165 | Some leading_token
->
3166 let rewritten_node =
3167 Rewriter.rewrite_pre
3168 (fun rewrite_node
->
3169 match Syntax.syntax rewrite_node
with
3170 | Syntax.Token
t when phys_equal
t leading_token
->
3171 Rewriter.Replace
(Syntax.make_token
{ t with Token.leading
= [] })
3172 | _
-> Rewriter.Keep
)
3175 (Token.leading leading_token
, rewritten_node)
3177 and remove_trailing_trivia node
=
3178 match Syntax.trailing_token node
with
3179 | None
-> (node
, [])
3180 | Some trailing_token
->
3181 let rewritten_node =
3182 Rewriter.rewrite_pre
3183 (fun rewrite_node
->
3184 match Syntax.syntax rewrite_node
with
3185 | Syntax.Token
t when phys_equal
t trailing_token
->
3186 Rewriter.Replace
(Syntax.make_token
{ t with Token.trailing = [] })
3187 | _
-> Rewriter.Keep
)
3190 (rewritten_node, Token.trailing trailing_token
)
3192 and transform_last_arg env ~
allow_trailing node
=
3193 match Syntax.syntax node
with
3194 | Syntax.ListItem
{ list_item
= item; list_separator
= separator
} ->
3195 transform_trailing_comma env ~
allow_trailing item separator
3196 | _
-> failwith
"Expected ListItem"
3198 and transform_mapish_entry env key arrow
value =
3205 SplitWith
Cost.Base
;
3209 and transform_keyword_expression_statement env kw expr semi
=
3213 when_present expr
(fun () ->
3214 Concat
[Space
; SplitWith
Cost.Moderate
; Nest
[t env expr
]]);
3219 and transform_keyword_expr_list_statement env kw expr_list semi
=
3220 Concat
[t env kw
; handle_declarator_list env expr_list
; t env semi
; Newline
]
3222 and transform_condition env left_p condition right_p
=
3228 (Rule.Parental
, Concat
[Nest
[t env condition
]; Split
; t env right_p
]);
3231 and get_operator_type op
=
3232 match Syntax.syntax op
with
3233 | Syntax.Token
t -> Full_fidelity_operator.trailing_from_token
(Token.kind
t)
3234 | _
-> failwith
"Operator should always be a token"
3237 match get_operator_type op
with
3238 | Full_fidelity_operator.ConcatenationOperator
-> true
3241 and transform_binary_expression env ~is_nested
(left
, operator
, right
) =
3242 let operator_has_surrounding_spaces op
= not
(is_concat op
) in
3243 let operator_is_leading op
=
3244 match get_operator_type op
with
3245 | Full_fidelity_operator.PipeOperator
-> true
3248 let operator_preserves_newlines op
=
3249 match get_operator_type op
with
3250 | Full_fidelity_operator.PipeOperator
-> true
3253 let operator_t = get_operator_type operator
in
3254 if Full_fidelity_operator.is_comparison
operator_t then
3257 Concat
[t env left
; Space
; t env operator
],
3258 Concat
[Space
; Split
; Nest
[t env right
]] )
3259 else if Full_fidelity_operator.is_assignment
operator_t then
3266 SplitWith
Cost.Moderate
;
3272 (let penv = Full_fidelity_parser_env.default
in
3273 let precedence = Full_fidelity_operator.precedence penv operator_t in
3274 let rec flatten_expression expr
=
3275 match Syntax.syntax expr
with
3276 | Syntax.BinaryExpression
3278 binary_left_operand
= left
;
3279 binary_operator
= operator
;
3280 binary_right_operand
= right
;
3282 let operator_t = get_operator_type operator
in
3284 Full_fidelity_operator.precedence penv operator_t
3286 if op_precedence = precedence then
3287 flatten_expression left
@ (operator
:: flatten_expression right
)
3292 let transform_operand operand
=
3293 match Syntax.syntax operand
with
3294 | Syntax.BinaryExpression
3295 { binary_left_operand
; binary_operator
; binary_right_operand
} ->
3296 transform_binary_expression
3299 (binary_left_operand
, binary_operator
, binary_right_operand
)
3300 | _
-> t env operand
3302 let binary_expression_syntax_list =
3304 (Syntax.make_binary_expression left operator right
)
3306 match binary_expression_syntax_list with
3310 transform_operand hd
,
3312 let last_operand = ref hd
in
3313 let last_op = ref (List.hd_exn
tl) in
3314 List.mapi
tl ~f
:(fun i x
->
3315 if i
mod 2 = 0 then (
3318 let op_has_spaces = operator_has_surrounding_spaces op in
3319 let op_is_leading = operator_is_leading op in
3320 let newline_before_op =
3321 operator_preserves_newlines op
3322 && node_has_trailing_newline
!last_operand
3326 ( if newline_before_op then
3328 else if op_is_leading then
3329 if op_has_spaces then
3333 else if op_has_spaces then
3337 ( if is_concat
op then
3338 ConcatOperator
(t env
op)
3346 operator_has_surrounding_spaces !last_op
3348 let op_is_leading = operator_is_leading !last_op in
3351 ( if op_is_leading then
3352 if op_has_spaces then
3356 else if op_has_spaces then
3360 transform_operand operand;
3366 ConditionalNest
expression )
3367 | _
-> failwith
"Expected non empty list of binary expression pieces");
3370 and make_string text width
=
3371 let split_text = Str.split_delim
(Str.regexp
"\n") text
in
3372 match split_text with
3373 | [_
] -> Text
(text
, width
)
3374 | _
-> MultilineString
(split_text, width
)
3376 (* Check the leading trivia of the node's leading token.
3377 Treat the node's text as a multiline string if the leading trivia contains
3378 an ignore comment. *)
3379 and transform_node_if_ignored node
=
3380 let (leading_before
, leading_including_and_after
) =
3381 leading_ignore_comment
(Syntax.leading_trivia node
)
3383 if List.length leading_including_and_after
= 0 then
3386 let node = replace_leading_trivia
node leading_including_and_after
in
3387 let (node, trailing_trivia
) = remove_trailing_trivia
node in
3389 match Trivia.kind
(List.hd_exn leading_including_and_after
) with
3390 | TriviaKind.(FixMe
| IgnoreError
) -> true
3396 transform_leading_trivia leading_before
;
3397 (* If we have a non-error-suppression comment here, then we want to
3398 ensure that we don't join it up onto the preceding line. Since we
3399 only scan leading trivia for hackfmt-ignore comments, and joining
3400 the comment onto the preceding line would make it trailing trivia,
3401 we would make the ignore comment useless if we joined it with the
3402 preceding line (breaking idempotence of hackfmt). Adding [Newline]
3403 here ensures a line break.
3405 Error-suppression comments are different--they are specially
3406 handled by the lexer to ensure that they always appear in leading
3412 make_string
(Syntax.text
node) (Syntax.width
node);
3413 transform_trailing_trivia trailing_trivia
;
3414 ( if has_newline trailing_trivia
then
3420 and ignore_re
= Str.regexp_string
"hackfmt-ignore"
3422 and is_ignore_comment trivia
=
3423 match Trivia.kind trivia
with
3424 (* We don't format the node after a comment containing "hackfmt-ignore". *)
3425 | TriviaKind.(DelimitedComment
| SingleLineComment
) ->
3427 try Str.search_forward ignore_re
(Trivia.text trivia
) 0 >= 0
3428 with Caml.Not_found
-> false
3432 and leading_ignore_comment trivia_list
=
3433 let before = List.take_while trivia_list ~f
:(Fn.non is_ignore_comment
) in
3434 let (_
, including_and_after
) =
3435 List.split_n trivia_list
(List.length
before)
3437 (before, including_and_after
)
3439 (* True if the trivia list contains WhiteSpace trivia.
3440 * Note that WhiteSpace includes spaces and tabs, but not newlines. *)
3441 and has_whitespace trivia_list
=
3442 List.exists trivia_list ~f
:(fun trivia
->
3443 is_trivia_kind_white_space (Trivia.kind trivia
))
3445 (* True if the trivia list contains EndOfLine trivia. *)
3446 and has_newline trivia_list
=
3447 List.exists trivia_list ~f
:(fun trivia
->
3448 is_trivia_kind_end_of_line (Trivia.kind trivia
))
3450 and is_invisible trivia
=
3451 match Trivia.kind trivia
with
3452 | TriviaKind.WhiteSpace
3453 | TriviaKind.EndOfLine
->
3457 and transform_leading_trivia
t = transform_trivia ~is_leading
:true t
3459 and transform_trailing_trivia
t = transform_trivia ~is_leading
:false t
3461 and transform_trivia ~is_leading trivia
=
3462 let new_line_regex = Str.regexp
"\n" in
3463 let indent = ref 0 in
3464 let currently_leading = ref is_leading
in
3465 let leading_invisibles = ref [] in
3466 let last_comment = ref None
in
3467 let last_comment_was_delimited = ref false in
3468 let newline_followed_last_comment = ref false in
3469 let whitespace_followed_last_comment = ref false in
3470 let trailing_invisibles = ref [] in
3471 let comments = ref [] in
3472 let make_comment _
=
3473 if Option.is_some
!last_comment then (
3474 newline_followed_last_comment := has_newline
!trailing_invisibles;
3475 whitespace_followed_last_comment := has_whitespace
!trailing_invisibles
3480 transform_leading_invisibles
(List.rev
!leading_invisibles);
3481 Option.value !last_comment ~default
:Nothing
;
3482 ignore_trailing_invisibles
(List.rev
!trailing_invisibles);
3483 ( if !last_comment_was_delimited && !whitespace_followed_last_comment
3486 else if !newline_followed_last_comment then
3492 last_comment := None
;
3493 leading_invisibles := [];
3494 trailing_invisibles := []
3496 List.iter trivia ~f
:(fun triv
->
3497 match Trivia.kind triv
with
3498 | TriviaKind.ExtraTokenError
3500 | TriviaKind.IgnoreError
3501 | TriviaKind.DelimitedComment
->
3502 let preceded_by_whitespace =
3503 if !currently_leading then
3504 has_whitespace
!leading_invisibles
3506 has_whitespace
!trailing_invisibles
3509 let delimited_lines = Str.split
new_line_regex (Trivia.text triv
) in
3511 let prefix_space_count str
=
3512 let len = String.length str
in
3514 if i
= len || Char.(str
.[i
] <> ' '
&& str
.[i
] <> '
\t'
) then
3521 (* If we're dealing with trailing trivia, then we don't have a good
3522 signal for the indent level, so we just cut all leading spaces.
3523 Otherwise, we cut a number of spaces equal to the indent before
3524 the delimited comment opener. *)
3527 min
!indent (prefix_space_count str
)
3529 prefix_space_count str
3531 let len = String.length str
- start_index in
3533 Trivia.create_delimited_comment
@@ String.sub str
start_index len
3539 Ignore
(String.make
start_index ' '
, start_index);
3540 Comment
(Trivia.text
dc, Trivia.width
dc);
3543 let hd = List.hd_exn
delimited_lines in
3544 let tl = List.tl_exn
delimited_lines in
3545 let hd = Comment
(hd, String.length
hd) in
3547 match Trivia.kind triv
with
3549 | TriviaKind.IgnoreError
->
3551 | _
-> !currently_leading
3557 ( if should_break then
3559 else if preceded_by_whitespace then
3563 Concat
(hd :: List.map
tl ~f
:map_tail);
3565 last_comment_was_delimited := true;
3566 currently_leading := false
3567 | TriviaKind.FallThrough
3568 | TriviaKind.SingleLineComment
->
3574 ( if !currently_leading then
3578 SingleLineComment
(Trivia.text triv
, Trivia.width triv
);
3580 last_comment_was_delimited := false;
3581 currently_leading := false
3582 | TriviaKind.EndOfLine
->
3584 if !currently_leading then
3585 leading_invisibles := triv
:: !leading_invisibles
3587 trailing_invisibles := triv
:: !trailing_invisibles;
3590 currently_leading := true
3591 | TriviaKind.WhiteSpace
->
3592 if !currently_leading then (
3593 indent := Trivia.width triv
;
3594 leading_invisibles := triv
:: !leading_invisibles
3596 trailing_invisibles := triv
:: !trailing_invisibles);
3597 if List.is_empty
!comments then
3599 transform_leading_invisibles trivia
3601 ignore_trailing_invisibles trivia
3604 Concat
(List.rev
!comments)
3607 and _MAX_CONSECUTIVE_BLANK_LINES
= 2
3609 and transform_leading_invisibles triv
=
3610 let newlines = ref 0 in
3612 (List.map triv ~f
:(fun t ->
3613 let ignored = Ignore
(Trivia.text
t, Trivia.width
t) in
3614 match Trivia.kind
t with
3615 | TriviaKind.EndOfLine
->
3616 newlines := !newlines + 1;
3620 ( if !newlines <= _MAX_CONSECUTIVE_BLANK_LINES
then
3627 and ignore_trailing_invisibles triv
=
3628 Concat
(List.map triv ~f
:(fun t -> Ignore
(Trivia.text
t, Trivia.width
t)))
3630 and transform_xhp_leading_trivia triv
=
3631 let (up_to_first_newline
, after_newline
, _
) =
3632 List.fold triv ~init
:([], [], false) ~f
:(fun (upto
, after
, seen
) t ->
3634 (upto
, t :: after
, true)
3636 (t :: upto
, after
, is_trivia_kind_end_of_line (Trivia.kind
t)))
3640 ignore_trailing_invisibles up_to_first_newline
;
3641 transform_leading_invisibles after_newline
;
3644 and node_has_trailing_newline
node =
3645 let trivia = Syntax.trailing_trivia
node in
3646 List.exists
trivia ~f
:(fun x
-> is_trivia_kind_end_of_line (Trivia.kind x
))
3648 and transform_consequence
3649 t (env
: Env.t) (node_body
: Syntax.t) (node_newline
: Syntax.t) =
3650 match Syntax.syntax node_body
with
3651 | Syntax.CompoundStatement _
->
3652 handle_possible_compound_statement env node_body
3657 ( if has_newline
(Syntax.trailing_trivia node_newline
) then
3658 Concat
[Newline
; Nest
[t env node_body
]]
3660 WithRule
(Rule.Parental
, Nest
[Span
[Space
; Split
; t env node_body
]])
3664 let transform (env
: Env.t) (node : Syntax.t) : Doc.t = t env
node