Delete provisional syntax for capabilities
[hiphop-php.git] / hphp / hack / src / hackfmt / hack_format.ml
blobbada72d79e3aa3804d0843ec45ed8ecf218ad190
1 (*
2 * Copyright (c) 2018, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 open Hh_prelude
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)
20 open Doc
22 let is_trivia_kind_fallthrough = function
23 | TriviaKind.FallThrough -> true
24 | _ -> false
26 let is_trivia_kind_end_of_line = function
27 | TriviaKind.EndOfLine -> true
28 | _ -> false
30 let is_trivia_kind_white_space = function
31 | TriviaKind.WhiteSpace -> true
32 | _ -> false
34 let is_syntax_kind_parenthesized_exprression = function
35 | SyntaxKind.ParenthesizedExpression -> true
36 | _ -> false
38 let is_token_kind_xhp_body = function
39 | TokenKind.XHPBody -> true
40 | _ -> false
42 let is_token_kind_in_out = function
43 | TokenKind.Inout -> true
44 | _ -> false
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
58 | Some doc -> doc
59 | None ->
60 (match Syntax.syntax node with
61 | Syntax.Missing -> Nothing
62 | Syntax.Token x ->
63 let token_kind = Token.kind x in
64 Concat
66 begin
67 match token_kind with
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)
76 end;
77 begin
78 match token_kind with
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)
91 end;
92 transform_trailing_trivia (Token.trailing x);
94 | Syntax.SyntaxList _ ->
95 failwith
96 (Printf.sprintf
97 "Error: SyntaxList should never be handled directly;
98 offending text is '%s'."
99 (Syntax.text node))
100 | Syntax.EndOfFile x -> t env x.end_of_file_token
101 | Syntax.Script x ->
102 begin
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
124 | _ -> transformed
126 begin
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
132 begin
133 match last with
134 | Some tok ->
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; _ } ->
145 let is_hh_script =
146 match Syntax.syntax suffix with
147 | Syntax.MarkupSuffix
148 { markup_suffix_name = Syntax.{ syntax = Token t; _ }; _ } ->
149 String.equal (Token.text t) "hh"
150 | _ -> false
152 let rec all_whitespaces s i =
153 i >= String.length s
155 match s.[i] with
156 | ' '
157 | '\t'
158 | '\r'
159 | '\n' ->
160 all_whitespaces s (i + 1)
161 | _ -> false
163 let text_contains_only_whitespaces =
164 match Syntax.syntax hashbang with
165 | Syntax.Token t -> all_whitespaces (Token.text t) 0
166 | _ -> false
168 if is_hh_script && text_contains_only_whitespaces then
169 t env suffix
170 else
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 _
185 | Syntax.XHPClose _
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 } ->
195 Concat
197 t env reified_type_argument_reified;
198 Space;
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;
207 enum_keyword = kw;
208 enum_name = name;
209 enum_colon = colon_kw;
210 enum_base = base;
211 enum_type;
212 enum_includes_keyword = enum_includes_kw;
213 enum_includes_list;
214 enum_left_brace = left_b;
215 enum_enumerators = enumerators;
216 enum_right_brace = right_b;
217 } ->
218 let after_each_ancestor is_last =
219 if is_last then
220 Nothing
221 else
222 space_split ()
224 Concat
226 t env attr;
227 when_present attr newline;
228 t env kw;
229 Space;
230 t env name;
231 t env colon_kw;
232 Space;
233 SplitWith Cost.Base;
234 Nest [Space; t env base; Space; t env enum_type; Space];
235 when_present enum_includes_kw (fun () ->
236 Nest
238 Space;
239 Split;
240 t env enum_includes_kw;
241 WithRule
242 ( Rule.Parental,
243 Nest
245 Span
247 Space;
248 ( if list_length enum_includes_list = 1 then
249 SplitWith Cost.Base
250 else
251 Split );
252 Nest
254 handle_possible_list
256 ~after_each:after_each_ancestor
257 enum_includes_list;
260 ] );
262 Space;
263 braced_block_nest
265 left_b
266 right_b
267 [handle_possible_list env enumerators];
268 Newline;
270 | Syntax.Enumerator
272 enumerator_name = name;
273 enumerator_equal = eq_kw;
274 enumerator_value = value;
275 enumerator_semicolon = semi;
276 } ->
277 let value = t env value in
278 Concat
280 t env name;
281 Space;
282 t env eq_kw;
283 Space;
284 ( if has_split value then
285 SplitWith Cost.Base
286 else
287 Nothing );
288 Nest [value];
289 t env semi;
290 Newline;
292 | Syntax.RecordDeclaration
294 record_attribute_spec = attr;
295 record_modifier = modifier;
296 record_keyword = kw;
297 record_name = name;
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;
303 } ->
304 let after_each_ancestor is_last =
305 if is_last then
306 Nothing
307 else
308 space_split ()
310 Concat
312 t env attr;
313 when_present attr newline;
314 t env modifier;
315 Space;
316 t env kw;
317 Space;
318 t env name;
319 Space;
320 when_present extends_kw (fun () ->
321 Concat
323 Space;
324 Split;
325 WithRule
326 ( Rule.Parental,
327 Nest
329 Span
331 t env extends_kw;
332 Space;
333 Split;
334 WithRule
335 ( Rule.Parental,
336 Nest
338 handle_possible_list
340 ~after_each:after_each_ancestor
341 extends;
342 ] );
344 ] );
346 braced_block_nest env left_b right_b [handle_possible_list env fields];
347 Newline;
349 | Syntax.RecordField
351 record_field_type;
352 record_field_name = name;
353 record_field_init;
354 record_field_semi = semi_kw;
355 } ->
356 Concat
358 t env record_field_type;
359 Space;
360 t env name;
361 t env record_field_init;
362 t env semi_kw;
363 Newline;
365 | Syntax.AliasDeclaration
367 alias_attribute_spec = attr;
368 alias_keyword = kw;
369 alias_name = name;
370 alias_generic_parameter = generic;
371 alias_constraint = type_constraint;
372 alias_equal = eq_kw;
373 alias_type;
374 alias_semicolon = semi;
375 } ->
376 (* TODO: revisit this for long names *)
377 Concat
379 t env attr;
380 when_present attr newline;
381 t env kw;
382 Space;
383 t env name;
384 t env generic;
385 Space;
386 t env type_constraint;
387 Space;
388 t env eq_kw;
389 Space;
390 SplitWith Cost.Base;
391 Nest [t env alias_type];
392 t env semi;
393 Newline;
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;
402 } ->
403 let declaration =
404 Concat
406 handle_possible_list env ~after_each:(fun _ -> Space) modifiers;
407 t env prop_type;
408 handle_declarator_list env declarators;
409 t env semi;
410 Newline;
413 if Syntax.is_missing attr then
414 declaration
415 else
416 WithLazyRule
417 ( Rule.Parental,
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;
431 } ->
432 Concat
434 Space;
435 braced_block_nest env left_b right_b [handle_possible_list env decls];
437 | Syntax.NamespaceEmptyBody { namespace_semicolon = semi } ->
438 Concat [t env 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;
445 } ->
446 Concat
448 t env kw;
449 Space;
450 t env use_kind;
451 when_present use_kind space;
452 WithRule
453 ( Rule.Parental,
454 Nest
456 handle_possible_list
458 clauses
459 ~after_each:after_each_argument;
460 ] );
461 t env semi;
462 Newline;
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;
473 } ->
474 Concat
476 t env kw;
477 Space;
478 t env use_kind;
479 when_present use_kind space;
480 t env prefix;
481 transform_argish env left_b clauses right_b;
482 t env semi;
483 Newline;
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;
491 } ->
492 Concat
494 t env use_kind;
495 when_present use_kind space;
496 t env name;
497 when_present as_kw space;
498 t env as_kw;
499 when_present alias space;
500 t env alias;
502 | Syntax.FunctionDeclaration
504 function_attribute_spec = attr;
505 function_declaration_header = header;
506 function_body = body;
507 } ->
508 Concat
510 t env attr;
511 when_present attr newline;
512 t env header;
513 handle_possible_compound_statement env ~allow_collapse:true body;
514 Newline;
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;
529 } ->
530 Concat
532 Span (transform_fn_decl_name env modifiers kw name type_params leftp);
533 transform_fn_decl_args env params rightp;
534 t env cap;
535 t env colon;
536 when_present colon space;
537 t env ret_type;
538 when_present where space;
539 t env where;
541 | Syntax.WhereClause
542 { where_clause_keyword = where; where_clause_constraints = constraints }
544 Concat
546 t env where;
547 Space;
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;
555 } ->
556 Concat [t env left; Space; t env op; Space; t env right]
557 | Syntax.Capability
559 capability_left_bracket = lb;
560 capability_types = tys;
561 capability_right_bracket = rb;
562 } ->
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;
570 } ->
571 Concat
573 t env attr;
574 when_present attr newline;
575 t env func_decl;
576 when_present body (fun () ->
577 handle_possible_compound_statement env ~allow_collapse:true body);
578 t env semi;
579 Newline;
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;
588 } ->
589 Concat
591 t env attr;
592 when_present attr newline;
593 t env func_decl;
594 t env equal;
595 t env name;
596 t env semi;
597 Newline;
599 | Syntax.ClassishDeclaration
601 classish_attribute = attr;
602 classish_modifiers = modifiers;
603 classish_xhp = xhp;
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;
613 } ->
614 let after_each_ancestor is_last =
615 if is_last then
616 Nothing
617 else
618 space_split ()
620 Concat
622 t env attr;
623 when_present attr newline;
624 Span
626 handle_possible_list env ~after_each:(fun _ -> Space) modifiers;
627 t env xhp;
628 when_present xhp space;
629 t env kw;
630 Space;
631 SplitWith Cost.Base;
632 Nest [t env name; t env type_params];
634 WithRule
635 ( Rule.Parental,
636 Concat
638 when_present extends_kw (fun () ->
639 Nest
641 Space;
642 Split;
643 t env extends_kw;
644 WithRule
645 ( Rule.Parental,
646 Nest
648 Span
650 Space;
651 ( if list_length extends = 1 then
652 SplitWith Cost.Base
653 else
654 Split );
655 Nest
657 handle_possible_list
659 ~after_each:after_each_ancestor
660 extends;
663 ] );
665 when_present impl_kw (fun () ->
666 Nest
668 Space;
669 Split;
670 t env impl_kw;
671 WithRule
672 ( Rule.Parental,
673 Nest
675 Span
677 Space;
678 ( if list_length impls = 1 then
679 SplitWith Cost.Base
680 else
681 Split );
682 Nest
684 handle_possible_list
686 ~after_each:after_each_ancestor
687 impls;
690 ] );
692 when_present where space;
693 t env where;
694 ] );
695 t env body;
697 | Syntax.ClassishBody
699 classish_body_left_brace = left_b;
700 classish_body_elements = body;
701 classish_body_right_brace = right_b;
702 } ->
703 Concat
705 Space;
706 braced_block_nest env left_b right_b [handle_possible_list env body];
707 Newline;
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;
714 } ->
715 Concat
717 t env name;
718 Space;
719 t env kw;
720 Space;
721 WithRule
722 ( Rule.Parental,
723 Nest
725 handle_possible_list env ~before_each:space_split removed_names;
726 ] );
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;
734 } ->
735 Concat
737 t env aliasing_name;
738 Space;
739 t env kw;
740 Space;
741 t env visibility;
742 Space;
743 t env 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;
752 } ->
753 Concat
755 t env kw;
756 WithRule
757 ( Rule.Parental,
758 Nest [handle_possible_list env ~before_each:space_split elements]
760 Space;
761 t env lb;
762 Newline;
763 Nest [handle_possible_list env ~before_each:newline clauses];
764 Newline;
765 t env rb;
767 | Syntax.TraitUse
769 trait_use_keyword = kw;
770 trait_use_names = elements;
771 trait_use_semicolon = semi;
772 } ->
773 Concat
775 t env kw;
776 (match Syntax.syntax elements with
777 | Syntax.SyntaxList [x] -> Concat [Space; t env x]
778 | Syntax.SyntaxList _ ->
779 WithRule
780 ( Rule.Parental,
781 Nest
782 [handle_possible_list env ~before_each:space_split elements]
784 | _ -> Concat [Space; t env elements]);
785 t env semi;
786 Newline;
788 | Syntax.RequireClause
790 require_keyword = kw;
791 require_kind = kind;
792 require_name = name;
793 require_semicolon = semi;
794 } ->
795 let name = t env name in
796 Concat
798 t env kw;
799 Space;
800 t env kind;
801 Space;
802 ( if has_split name then
803 SplitWith Cost.High
804 else
805 Nothing );
806 Nest [name; t env semi];
807 Newline;
809 | Syntax.ConstDeclaration
811 const_modifiers = modifiers;
812 const_keyword = kw;
813 const_type_specifier = const_type;
814 const_declarators = declarators;
815 const_semicolon = semi;
816 } ->
817 Concat
819 handle_possible_list env ~after_each:(fun _ -> Space) modifiers;
820 t env kw;
821 when_present const_type space;
822 t env const_type;
823 handle_declarator_list env declarators;
824 t env semi;
825 Newline;
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;
839 } ->
840 Concat
842 t env attr;
843 when_present attr newline;
844 handle_possible_list env ~after_each:(fun _ -> Space) modifiers;
845 Space;
846 t env kw;
847 Space;
848 t env type_kw;
849 Space;
850 t env name;
851 t env type_params;
852 when_present type_constraint space;
853 t env type_constraint;
854 when_present eq space;
855 t env eq;
856 when_present type_spec (fun _ ->
857 Concat [Space; SplitWith Cost.Base; Nest [t env type_spec]]);
858 t env semi;
859 Newline;
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;
869 } ->
870 Concat
872 handle_attribute_spec env attr ~always_split:false;
873 when_present attr (fun _ -> Concat [Space; SplitWith Cost.Base]);
874 t env visibility;
875 when_present visibility space;
876 t env callconv;
877 when_present callconv space;
878 t env param_type;
879 ( if
880 Syntax.is_missing visibility
881 && Syntax.is_missing callconv
882 && Syntax.is_missing param_type
883 then
884 t env name
885 else
886 Concat [Space; SplitWith Cost.Moderate; Nest [t env name]] );
887 t env default;
889 | Syntax.VariadicParameter
891 variadic_parameter_call_convention = callconv;
892 variadic_parameter_type = type_var;
893 variadic_parameter_ellipsis = ellipsis;
894 } ->
895 Concat
897 t env callconv;
898 when_present callconv space;
899 t env type_var;
900 t env ellipsis;
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;
909 } ->
910 Concat
912 t env left_da;
913 t env keyword;
914 t env colon;
915 when_present colon space;
916 transform_possible_comma_list env ~allow_trailing:false attrs right_da;
917 Newline;
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;
928 } ->
929 Concat
931 handle_attribute_spec env attr_spec ~always_split:false;
932 Space;
933 t env attr_type;
935 | Syntax.InclusionExpression
936 { inclusion_require = kw; inclusion_filename = expr } ->
937 Concat
939 t env kw;
940 (match Syntax.syntax expr with
941 | Syntax.ParenthesizedExpression _ -> Nothing
942 | _ -> Space);
943 SplitWith Cost.Base;
944 t env expr;
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 } ->
951 Concat
953 handle_compound_statement
955 compound_left_brace
956 compound_statements
957 compound_right_brace;
958 Newline;
960 | Syntax.UnsetStatement
962 unset_keyword = kw;
963 unset_left_paren = left_p;
964 unset_variables = args;
965 unset_right_paren = right_p;
966 unset_semicolon = semi;
967 } ->
968 Concat
970 t env kw;
971 transform_argish env ~allow_trailing:false left_p args right_p;
972 t env semi;
973 Newline;
975 | Syntax.WhileStatement x ->
976 Concat
978 t env x.while_keyword;
979 Space;
980 t env x.while_left_paren;
981 Split;
982 WithRule
983 ( Rule.Parental,
984 Concat
986 Nest [t env x.while_condition];
987 Split;
988 t env x.while_right_paren;
989 ] );
990 handle_possible_compound_statement env x.while_body;
991 Newline;
993 | Syntax.UsingStatementBlockScoped x ->
994 Concat
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;
999 Space;
1000 t env x.using_block_left_paren;
1001 Split;
1002 WithRule
1003 ( Rule.Parental,
1004 Concat
1006 Nest
1008 handle_possible_list
1010 ~after_each:separate_with_space_split
1011 x.using_block_expressions;
1013 Split;
1014 t env x.using_block_right_paren;
1015 ] );
1016 handle_possible_compound_statement env x.using_block_body;
1017 Newline;
1019 | Syntax.UsingStatementFunctionScoped x ->
1020 Concat
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;
1025 Space;
1026 t env x.using_function_expression;
1027 t env x.using_function_semicolon;
1028 Newline;
1030 | Syntax.IfStatement
1032 if_keyword = kw;
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;
1039 } ->
1040 Concat
1042 t env kw;
1043 Space;
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;
1047 t env else_clause;
1048 Newline;
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;
1057 } ->
1058 Concat
1060 t env kw;
1061 Space;
1062 transform_condition env left_p condition right_p;
1063 transform_consequence t env body right_p;
1065 | Syntax.ElseClause x ->
1066 Concat
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
1076 try_keyword = kw;
1077 try_compound_statement = body;
1078 try_catch_clauses = catch_clauses;
1079 try_finally_clause = finally_clause;
1080 } ->
1081 (* TODO: revisit *)
1082 Concat
1084 t env kw;
1085 handle_possible_compound_statement env body;
1086 handle_possible_list env catch_clauses;
1087 t env finally_clause;
1088 Newline;
1090 | Syntax.CatchClause
1092 catch_keyword = kw;
1093 catch_left_paren = left_p;
1094 catch_type = ex_type;
1095 catch_variable = var;
1096 catch_right_paren = right_p;
1097 catch_body = body;
1098 } ->
1099 Concat
1101 t env kw;
1102 Space;
1103 delimited_nest
1105 left_p
1106 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
1114 do_keyword = do_kw;
1115 do_body = body;
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;
1121 } ->
1122 Concat
1124 t env do_kw;
1125 Space;
1126 handle_possible_compound_statement env body;
1127 t env while_kw;
1128 Space;
1129 transform_condition env left_p cond right_p;
1130 t env semi;
1131 Newline;
1133 | Syntax.ForStatement
1135 for_keyword = kw;
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;
1143 for_body = body;
1144 } ->
1145 Concat
1147 t env kw;
1148 Space;
1149 t env left_p;
1150 WithRule
1151 ( Rule.Parental,
1152 Concat
1154 Split;
1155 Nest
1157 handle_possible_list
1159 ~after_each:separate_with_space_split
1160 init;
1161 t env semi1;
1162 Space;
1163 Split;
1164 handle_possible_list
1166 ~after_each:separate_with_space_split
1167 control;
1168 t env semi2;
1169 Space;
1170 Split;
1171 handle_possible_list
1173 ~after_each:separate_with_space_split
1174 after_iter;
1176 Split;
1177 t env right_p;
1178 ] );
1179 handle_possible_compound_statement env body;
1180 Newline;
1182 | Syntax.ForeachStatement
1184 foreach_keyword = kw;
1185 foreach_left_paren = left_p;
1186 foreach_collection = collection;
1187 foreach_await_keyword = await_kw;
1188 foreach_as = as_kw;
1189 foreach_key = key;
1190 foreach_arrow = arrow;
1191 foreach_value = value;
1192 foreach_right_paren = right_p;
1193 foreach_body = body;
1194 } ->
1195 Concat
1197 t env kw;
1198 Space;
1199 delimited_nest
1201 left_p
1202 right_p
1204 t env collection;
1205 Space;
1206 t env await_kw;
1207 Space;
1208 t env as_kw;
1209 Space;
1210 SplitWith Cost.Base;
1211 Nest
1213 Span
1215 t env key;
1216 Space;
1217 t env arrow;
1218 Space;
1219 SplitWith Cost.Base;
1220 Nest [t env value];
1224 handle_possible_compound_statement env body;
1225 Newline;
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;
1236 } ->
1237 let sections = Syntax.syntax_node_to_list sections in
1238 Concat
1240 t env kw;
1241 Space;
1242 delimited_nest env left_p right_p [t env expr];
1243 Space;
1244 braced_block_nest env left_b right_b (List.map sections (t env));
1245 Newline;
1247 | Syntax.SwitchSection
1249 switch_section_labels = labels;
1250 switch_section_statements = statements;
1251 switch_section_fallthrough = fallthrough;
1252 } ->
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
1271 | _ -> false
1273 Concat
1275 ( if List.is_empty upto_fallthrough then
1276 transform_leading_trivia after_fallthrough
1277 else
1278 Concat
1280 BlockNest [transform_leading_trivia upto_fallthrough; Newline];
1281 transform_trailing_trivia after_fallthrough;
1282 ] );
1283 handle_list env labels ~after_each:(fun is_last_label ->
1284 if is_last_label && is_scoped_section then
1285 Nothing
1286 else
1287 Newline);
1288 ( if is_scoped_section then
1289 handle_list env statements
1290 else
1291 BlockNest [handle_list env statements] );
1292 t env fallthrough;
1294 | Syntax.CaseLabel
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;
1307 } ->
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
1319 echo_keyword = kw;
1320 echo_expressions = expr_list;
1321 echo_semicolon = semi;
1322 } ->
1323 (match Syntax.syntax expr_list with
1324 | Syntax.SyntaxList
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 } ->
1331 Concat
1333 t env kw;
1334 Space;
1335 handle_possible_compound_statement env statement;
1336 Newline;
1338 | Syntax.SimpleInitializer
1339 { simple_initializer_equal = eq_kw; simple_initializer_value = value }
1341 Concat
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;
1356 } ->
1357 Concat
1359 handle_attribute_spec env attr ~always_split:false;
1360 when_present attr space;
1361 t env static_kw;
1362 when_present static_kw space;
1363 t env async_kw;
1364 when_present async_kw space;
1365 t env fun_kw;
1366 transform_argish_with_return_type env lp params rp colon ret_type;
1367 t env use;
1368 handle_possible_compound_statement
1370 ~space:false
1371 ~allow_collapse:true
1372 body;
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;
1380 } ->
1381 (* TODO: Revisit *)
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;
1389 lambda_body = body;
1390 } ->
1391 Concat
1393 handle_attribute_spec env attr ~always_split:false;
1394 when_present attr space;
1395 t env async;
1396 when_present async space;
1397 t env signature;
1398 Space;
1399 t env arrow;
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;
1410 } ->
1411 Concat
1413 t env lp;
1414 when_present params split;
1415 transform_fn_decl_args env params rp;
1416 t env cap;
1417 t env colon;
1418 when_present colon space;
1419 t env ret_type;
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 } ->
1429 Concat
1431 t env operator;
1432 (match Syntax.syntax operator with
1433 | Syntax.Token x ->
1434 let is_parenthesized =
1435 match Syntax.syntax operand with
1436 | Syntax.ParenthesizedExpression _ -> true
1437 | _ -> false
1439 TokenKind.(
1440 (match Token.kind x with
1441 | Await
1442 | Clone ->
1443 Space
1444 | Print ->
1445 if is_parenthesized then
1446 Nothing
1447 else
1448 Space
1449 | _ -> Nothing))
1450 | _ -> Nothing);
1451 t env operand;
1453 | Syntax.BinaryExpression
1454 { binary_left_operand; binary_operator; binary_right_operand } ->
1455 transform_binary_expression
1457 ~is_nested:false
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;
1468 } ->
1469 Concat
1471 t env left;
1472 Space;
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;
1483 } ->
1484 WithLazyRule
1485 ( Rule.Parental,
1486 t env test_expr,
1487 Nest
1489 Space;
1490 Split;
1491 t env q_kw;
1492 when_present true_expr (fun () ->
1493 Concat
1495 Space;
1496 ( if env.Env.indent_width = 2 then
1497 Nest [t env true_expr]
1498 else
1499 t env true_expr );
1500 Space;
1501 Split;
1503 t env c_kw;
1504 Space;
1505 ( if
1506 (not (Syntax.is_missing true_expr)) && env.Env.indent_width = 2
1507 then
1508 Nest [t env false_expr]
1509 else
1510 t env false_expr );
1512 | Syntax.FunctionCallExpression _ -> handle_possible_chaining env node
1513 | Syntax.FunctionPointerExpression _ -> transform_simple env node
1514 | Syntax.EvalExpression
1516 eval_keyword = kw;
1517 eval_left_paren = left_p;
1518 eval_argument = arg;
1519 eval_right_paren = right_p;
1520 } ->
1521 Concat [t env kw; transform_braced_item env left_p arg right_p]
1522 | Syntax.IssetExpression
1524 isset_keyword = kw;
1525 isset_left_paren = left_p;
1526 isset_argument_list = args;
1527 isset_right_paren = right_p;
1528 } ->
1529 Concat
1531 t env kw;
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;
1540 } ->
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;
1547 } ->
1548 Concat
1550 t env left_p;
1551 Split;
1552 WithRule
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;
1560 } ->
1561 (* TODO: revisit this *)
1562 Concat
1564 t env left_b;
1565 Split;
1566 (let rule =
1568 List.is_empty (Syntax.trailing_trivia left_b)
1569 && List.is_empty (Syntax.trailing_trivia expr)
1570 then
1571 Rule.Simple Cost.Base
1572 else
1573 Rule.Parental
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;
1582 } ->
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
1592 list_keyword = kw;
1593 list_left_paren = lp;
1594 list_members = members;
1595 list_right_paren = rp;
1596 } ->
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;
1604 } ->
1605 transform_container_literal
1607 ~space:true
1608 name
1609 left_b
1610 initializers
1611 right_b
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;
1622 } ->
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;
1630 } ->
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;
1643 } ->
1644 let after_each_ancestor is_last =
1645 if is_last then
1646 Nothing
1647 else
1648 space_split ()
1650 Concat
1652 t env classkw;
1653 transform_argish env left_p arg_list right_p;
1654 when_present extends_kw (fun () ->
1655 Concat
1657 Space;
1658 Split;
1659 WithRule
1660 ( Rule.Parental,
1661 Nest
1663 Span
1665 t env extends_kw;
1666 Space;
1667 Split;
1668 WithRule
1669 ( Rule.Parental,
1670 Nest
1672 handle_possible_list
1674 ~after_each:after_each_ancestor
1675 extends;
1676 ] );
1678 ] );
1680 when_present impl_kw (fun () ->
1681 Concat
1683 Space;
1684 Split;
1685 WithRule
1686 ( Rule.Parental,
1687 Nest
1689 Span
1691 t env impl_kw;
1692 Space;
1693 Split;
1694 WithRule
1695 ( Rule.Parental,
1696 Nest
1698 handle_possible_list
1700 ~after_each:after_each_ancestor
1701 impls;
1702 ] );
1704 ] );
1706 t env body;
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;
1747 } ->
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;
1758 } ->
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;
1765 } ->
1766 Concat
1768 handle_attribute_spec env attr ~always_split:false;
1769 when_present attr space;
1770 t env async_kw;
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;
1781 } ->
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;
1788 } ->
1789 Concat
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;
1796 } ->
1797 Concat
1799 t env kw;
1800 (* TODO: Eliminate code duplication *)
1801 WithRule
1802 ( Rule.Parental,
1803 Nest
1804 [handle_possible_list env ~before_each:space_split categories]
1806 t env semi;
1807 Newline;
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;
1815 } ->
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;
1822 } ->
1823 Concat
1825 t env kw;
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");
1833 t env semi;
1834 Newline;
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;
1842 } ->
1843 (* TODO: figure out nesting here *)
1844 Concat
1846 t env attr_type;
1847 Space;
1848 t env name;
1849 when_present init space;
1850 t env init;
1851 when_present req space;
1852 t env req;
1854 | Syntax.XHPSimpleAttribute
1856 xhp_simple_attribute_name = name;
1857 xhp_simple_attribute_equal = eq;
1858 xhp_simple_attribute_expression = expr;
1859 } ->
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;
1867 } ->
1868 Span
1870 t env l_brace;
1871 t env spread;
1872 SplitWith Cost.Base;
1873 Nest [t env expr];
1874 t env r_brace;
1876 | Syntax.XHPOpen
1878 xhp_open_left_angle = left_a;
1879 xhp_open_name = name;
1880 xhp_open_attributes = attrs;
1881 xhp_open_right_angle = right_a;
1882 } ->
1883 Concat
1885 t env left_a;
1886 t env name;
1887 (match Syntax.syntax attrs with
1888 | Syntax.Missing ->
1889 handle_xhp_open_right_angle_token env attrs right_a
1890 | _ ->
1891 Concat
1893 Space;
1894 Split;
1895 WithRule
1896 ( Rule.Parental,
1897 Concat
1899 Nest
1901 handle_possible_list
1903 ~after_each:(fun is_last ->
1904 if not is_last then
1905 space_split ()
1906 else
1907 Nothing)
1908 attrs;
1910 handle_xhp_open_right_angle_token env attrs right_a;
1911 ] );
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
1929 token.
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 =
1938 Concat
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)
1943 | _ -> false
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
1959 Newline
1960 else if has_whitespace trivia then
1961 Space
1962 else
1963 Nothing
1964 else
1965 Nothing
1967 let (leading, node) = remove_leading_trivia node in
1968 let trailing = Syntax.trailing_trivia node in
1969 let leading_whitespace =
1970 Concat
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). *)
1975 ( if
1976 (not !prev_token_was_xhpbody) && not node_is_xhpbody
1977 then
1978 Split
1979 else
1980 Nothing );
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
1987 else
1988 transform_xhp_leading_trivia leading );
1991 prev_token_was_xhpbody := node_is_xhpbody;
1992 Concat
1994 leading_whitespace;
1995 preserve_xhpbody_whitespace leading;
1996 t env node;
1997 preserve_xhpbody_whitespace trailing;
2000 Concat
2002 transformed_body;
2003 ( if !prev_token_was_xhpbody then
2004 Nothing
2005 else if
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)
2012 then
2013 Newline
2014 else
2015 Split );
2017 | _ -> failwith "Expected SyntaxList"
2019 WithOverridingParentalRule
2020 (Concat
2022 t env xhp_open;
2023 Nest [handle_xhp_body body];
2024 when_present close (fun () ->
2025 let (leading, close) = remove_leading_trivia close in
2026 Concat
2028 (* Ignore extra newlines by treating this as trailing trivia *)
2029 ignore_trailing_invisibles leading;
2030 t env close;
2033 | Syntax.VarrayTypeSpecifier
2035 varray_keyword = kw;
2036 varray_left_angle = left_a;
2037 varray_type;
2038 varray_trailing_comma = trailing_comma;
2039 varray_right_angle = right_a;
2040 } ->
2041 Concat
2043 t env kw;
2044 transform_braced_item_with_trailer
2046 left_a
2047 varray_type
2048 trailing_comma
2049 right_a;
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;
2058 } ->
2059 Concat
2061 t env kw;
2062 transform_braced_item_with_trailer
2064 left_a
2065 vec_type
2066 trailing_comma
2067 right_a;
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;
2076 } ->
2077 Concat
2079 t env kw;
2080 transform_braced_item_with_trailer
2082 left_a
2083 ks_type
2084 trailing_comma
2085 right_a;
2087 | Syntax.TypeParameter
2089 type_attribute_spec = attr;
2090 type_reified = reified;
2091 type_variance = variance;
2092 type_name = name;
2093 type_param_params = params;
2094 type_constraints = constraints;
2095 } ->
2096 Concat
2098 handle_attribute_spec env attr ~always_split:false;
2099 when_present attr space;
2100 t env reified;
2101 when_present reified space;
2102 t env variance;
2103 t env name;
2104 t env params;
2105 when_present constraints space;
2106 handle_possible_list env constraints ~after_each:(fun is_last ->
2107 if is_last then
2108 Nothing
2109 else
2110 Space);
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;
2118 darray_key = key;
2119 darray_comma = comma_kw;
2120 darray_value = value;
2121 darray_trailing_comma = trailing_comma;
2122 darray_right_angle = right_a;
2123 } ->
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
2127 Concat
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;
2137 } ->
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;
2150 } ->
2151 Concat
2153 t env outer_left_p;
2154 t env kw;
2155 t env inner_left_p;
2156 when_present param_list split;
2157 transform_fn_decl_args env param_list inner_right_p;
2158 t env cap;
2159 t env colon;
2160 when_present colon space;
2161 t env ret_type;
2162 t env outer_right_p;
2164 | Syntax.ClosureParameterTypeSpecifier
2166 closure_parameter_call_convention = callconv;
2167 closure_parameter_type = cp_type;
2168 } ->
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;
2177 } ->
2178 Concat
2180 t env kw;
2181 transform_braced_item_with_trailer
2183 left_a
2184 class_type
2185 trailing_comma
2186 right_a;
2188 | Syntax.FieldSpecifier
2190 field_question = question;
2191 field_name = name;
2192 field_arrow = arrow_kw;
2193 field_type;
2194 } ->
2195 Concat
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;
2202 } ->
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;
2211 } ->
2212 let fields =
2213 if Syntax.is_missing ellipsis then
2214 type_fields
2215 else
2216 let missing_separator = make_missing () in
2217 let ellipsis_list =
2218 [Syntax.make_list_item ellipsis missing_separator]
2220 make_list (Syntax.children type_fields @ ellipsis_list)
2222 transform_container_literal
2224 shape_kw
2225 left_p
2226 fields
2227 right_p
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;
2235 } ->
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;
2243 } ->
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;
2250 } ->
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;
2257 } ->
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;
2264 } ->
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;
2271 } ->
2272 delimited_nest
2274 left_p
2275 right_p
2277 handle_possible_list
2279 types
2280 ~after_each:(fun is_last ->
2281 if is_last then
2282 Split
2283 else
2284 space_split ())
2285 ~handle_element:(fun node ->
2286 match Syntax.syntax node with
2287 | Syntax.ListItem { list_item; list_separator } ->
2288 Concat
2290 t env list_item;
2291 when_present list_separator space;
2292 t env list_separator;
2294 | _ -> t env node);
2296 | Syntax.IntersectionTypeSpecifier
2298 intersection_left_paren = left_p;
2299 intersection_types = types;
2300 intersection_right_paren = right_p;
2301 } ->
2302 delimited_nest
2304 left_p
2305 right_p
2307 handle_possible_list
2309 types
2310 ~after_each:(fun is_last ->
2311 if is_last then
2312 Split
2313 else
2314 space_split ())
2315 ~handle_element:(fun node ->
2316 match Syntax.syntax node with
2317 | Syntax.ListItem { list_item; list_separator } ->
2318 Concat
2320 t env list_item;
2321 when_present list_separator space;
2322 t env list_separator;
2324 | _ -> t env node);
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;
2332 } ->
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;
2340 } ->
2341 Concat
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;
2347 } ->
2348 Concat
2350 t env op;
2351 begin
2352 match Syntax.syntax op with
2353 | Syntax.Token t when is_token_kind_in_out (Token.kind t) -> Space
2354 | _ -> Nothing
2355 end;
2356 t env expr;
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;
2372 } ->
2373 let after_each_ancestor is_last =
2374 if is_last then
2375 Nothing
2376 else
2377 space_split ()
2379 Concat
2381 t env attr_spec;
2382 when_present attr_spec newline;
2383 t env enum_kw;
2384 Space;
2385 t env class_kw;
2386 Space;
2387 t env name;
2388 t env colon;
2389 Space;
2390 SplitWith Cost.Base;
2391 Nest [Space; t env base; Space];
2392 when_present extends_kw (fun () ->
2393 Nest
2395 Space;
2396 Split;
2397 t env extends_kw;
2398 WithRule
2399 ( Rule.Parental,
2400 Nest
2402 Span
2404 Space;
2405 ( if list_length extends_list = 1 then
2406 SplitWith Cost.Base
2407 else
2408 Split );
2409 Nest
2411 handle_possible_list
2413 ~after_each:after_each_ancestor
2414 extends_list;
2417 ] );
2419 Space;
2420 braced_block_nest
2422 left_brace
2423 right_brace
2424 [handle_possible_list env elements];
2425 Newline;
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;
2437 } ->
2438 Concat
2440 t env name;
2441 t env left_angle;
2442 t env type_;
2443 t env right_angle;
2444 t env left_paren;
2445 t env initial_value;
2446 t env right_paren;
2447 t env semicolon;
2448 Newline;
2450 | Syntax.EnumAtomExpression _ -> transform_simple env node)
2452 and when_present node f =
2453 match Syntax.syntax node with
2454 | Syntax.Missing -> Nothing
2455 | _ -> f ()
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]
2470 | _ ->
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
2474 Concat
2476 t env open_b;
2477 Newline;
2478 BlockNest [nodes; transform_leading_trivia leading; Newline];
2479 t env close_b;
2482 and delimited_nest
2484 ?(split_when_children_split = true)
2485 ?(force_newlines = false)
2486 left_delim
2487 right_delim
2488 nodes =
2489 let rule =
2490 match () with
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
2503 let maybe_split =
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 =
2512 if is_last then
2513 Split
2514 else
2515 space_split ()
2517 and separate_with_space_split is_last =
2518 if is_last then
2519 Nothing
2520 else
2521 space_split ()
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;
2530 } ->
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
2538 Newline
2539 else
2540 Space)
2541 attrs
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
2552 compound_left_brace
2553 compound_statements
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 } ->
2564 Concat
2566 handle_compound_statement
2568 ~allow_collapse
2569 compound_left_brace
2570 compound_statements
2571 compound_right_brace;
2572 ( if space then
2573 Space
2574 else
2575 Nothing );
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 =
2582 Concat
2584 Space;
2585 braced_block_nest
2587 ~allow_collapse
2588 left_b
2589 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] ->
2603 Nest
2605 Space;
2606 (* Use an independent split, so we don't break just because a line break
2607 * occurs in the declarator. *)
2608 SplitWith Cost.Base;
2609 t env declarator;
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
2614 * line. *)
2615 WithRule
2616 ( Rule.Parental,
2617 Nest
2618 (List.map xs (fun declarator ->
2619 Concat [Space; Split; t env declarator])) )
2620 | _ -> failwith "SyntaxList expected"
2622 and handle_list
2624 ?(before_each = (fun () -> Nothing))
2625 ?(after_each = (fun _is_last -> Nothing))
2626 ?(handle_element = t env)
2627 ?(handle_last = handle_element)
2628 list =
2629 let rec aux l =
2630 match l with
2631 | [hd] -> Concat [before_each (); handle_last hd; after_each true]
2632 | hd :: tl ->
2633 Concat [before_each (); handle_element hd; after_each false; aux tl]
2634 | [] -> Nothing
2636 aux list
2638 and list_length node =
2639 match Syntax.syntax node with
2640 | Syntax.Missing -> 0
2641 | Syntax.SyntaxList x -> List.length x
2642 | _ -> 1
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
2650 | _ ->
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 ->
2656 Concat
2658 ( if String.equal (Token.text token) "/>" then
2659 Concat [Space; when_present attrs split]
2660 else
2661 Nothing );
2662 t env node;
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;
2679 } ->
2680 handle_member_selection
2682 ( obj,
2683 arrow,
2684 member,
2685 if Syntax.is_missing targs then
2686 None
2687 else
2688 Some targs )
2689 (Some (lp, args, rp))
2690 | _ -> (node, [])
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;
2700 } ->
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;
2709 } ->
2710 handle_member_selection acc (obj, arrow, member, None) None
2711 | _ -> (node, [])
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. *)
2715 let () =
2716 match Syntax.kind node with
2717 | SyntaxKind.FunctionCallExpression
2718 | SyntaxKind.MemberSelectionExpression
2719 | SyntaxKind.SafeMemberSelectionExpression ->
2721 | kind ->
2722 failwith
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) =
2732 Concat
2734 t env arrow;
2735 t env member;
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;
2752 } ->
2753 Concat [t env receiver; t env targs; transform_argish env lp args rp]
2754 | Syntax.MemberSelectionExpression _
2755 | Syntax.SafeMemberSelectionExpression _ ->
2756 failwith
2757 "Should not be possible for a member selection expression to be considered first_receiver"
2758 | _ -> t env node
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
2765 | [hd] ->
2766 Concat
2768 Span [transform_first_receiver first_receiver];
2769 ( if first_receiver_has_trailing_newline then
2770 Newline
2771 else
2772 SplitWith Cost.High );
2773 Nest [transform_chain hd];
2775 | hd :: tl ->
2776 let transformed_hd = transform_chain hd in
2777 let tl = List.map tl transform_chain in
2778 let rule_type =
2779 match hd with
2780 | (_, trailing, None, None)
2781 | (_, _, Some trailing, None)
2782 | (_, _, _, Some (_, _, trailing)) ->
2783 if node_has_trailing_newline trailing then
2784 Rule.Always
2785 else if first_receiver_has_trailing_newline then
2786 Rule.Parental
2787 else
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(
2793 $argument_one,
2794 $argument_two,
2795 $argument_three,
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
2801 Rule.Parental
2802 else
2803 Rule.Simple Cost.NoCost
2805 Span
2807 WithLazyRule
2808 ( rule_type,
2809 Concat
2811 transform_first_receiver first_receiver;
2812 ( if first_receiver_has_trailing_newline then
2813 Newline
2814 else
2815 SplitWith Cost.Base );
2817 Concat
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]));
2822 ] );
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 ->
2835 let last_param =
2836 match Syntax.syntax (List.last_exn params) with
2837 | Syntax.ListItem { list_item; _ } -> list_item
2838 | _ -> failwith "Expected ListItem"
2840 begin
2841 match Syntax.syntax last_param with
2842 | Syntax.VariadicParameter _
2843 | Syntax.(
2844 ParameterDeclaration
2846 parameter_name =
2848 syntax =
2849 DecoratedExpression
2851 decorated_expression_decorator =
2853 syntax =
2854 Token { Token.kind = TokenKind.DotDotDot; _ };
2862 }) ->
2863 false
2864 | _ -> true
2866 | _ -> true
2868 WithRule
2869 ( Rule.Parental,
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 =
2874 Concat
2876 t env left_p;
2877 when_present params split;
2878 transform_fn_decl_args env params right_p;
2879 t env colon;
2880 when_present colon space;
2881 t env ret_type;
2884 and transform_argish
2886 ?(allow_trailing = true)
2887 ?(force_newlines = false)
2888 ?(spaces = false)
2889 left_p
2890 arg_list
2891 right_p =
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 ->
2897 let last_arg =
2898 match Syntax.syntax (List.last_exn args) with
2899 | Syntax.ListItem { list_item; _ } -> list_item
2900 | _ -> failwith "Expected ListItem"
2902 begin
2903 match Syntax.syntax last_arg with
2904 | Syntax.(
2905 DecoratedExpression
2907 decorated_expression_decorator =
2908 { syntax = Token { Token.kind = TokenKind.DotDotDot; _ }; _ };
2910 }) ->
2911 false
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.
2921 For example:
2923 // We do not want to break f's rule even though its child splits:
2924 f(vec[
2925 $foo, // single-line comment forces the vec's rule to split
2926 $bar,
2929 // We do not want to break map's rule even though the lambda has splits:
2930 map($vec, $element ==> {
2931 // ...
2934 let split_when_children_split =
2935 if spaces then
2936 true
2937 else
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
2947 true
2948 else
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
2958 true
2959 else (
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
2964 | last :: rest ->
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
2969 true
2970 else
2971 looks_bad_in_non_parental_braces last
2973 | _ -> true
2975 delimited_nest
2977 ~split_when_children_split
2978 ~force_newlines
2979 left_p
2980 right_p
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:
2987 f($x ==> {
2988 return do_something_with($x);
2991 Some constructs don't look so great when we do this:
2993 f($x ==>
2994 do_something_with($x));
2996 f($x
2997 ? $y
2998 : $z);
3000 This function blacklists those constructs. *)
3001 and looks_bad_in_non_parental_braces item =
3002 let item =
3003 match Syntax.syntax item with
3004 | Syntax.ListItem { list_item; _ } -> list_item
3005 | _ -> item
3007 match Syntax.syntax item with
3008 | Syntax.(
3009 LambdaExpression { lambda_body = { syntax = CompoundStatement _; _ }; _ })
3011 false
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 _ ->
3022 true
3023 | _ -> false
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)
3033 then
3034 Concat (List.map [left_p; item; right_p] (t env))
3035 else
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)
3050 | _ -> t env x
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 ->
3059 Concat
3061 transform_argish_item env item;
3062 transform_leading_trivia (Token.leading tok);
3063 ( if allow_trailing then
3064 TrailingComma true
3065 else
3066 Nothing );
3067 Ignore (Token.text tok, Token.width tok);
3068 transform_trailing_trivia (Token.trailing tok);
3070 | Syntax.Missing ->
3071 let (item, item_trailing) = remove_trailing_trivia item in
3072 Concat
3074 transform_argish_item env item;
3075 ( if allow_trailing then
3076 TrailingComma false
3077 else
3078 Nothing );
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)
3098 then
3099 Concat [t env left_p; item_and_comma; t env right_p]
3100 else
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
3106 items
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
3116 ?(space = false)
3117 ?allow_trailing
3118 ?explicit_type
3120 left_p
3121 members
3122 right_p =
3123 let force_newlines = node_has_trailing_newline left_p in
3124 let ty =
3125 match explicit_type with
3126 | Some ex_ty -> t env ex_ty
3127 | None -> Nothing
3129 Concat
3131 t env kw;
3133 ( if space then
3134 Space
3135 else
3136 Nothing );
3137 transform_argish
3139 ~force_newlines
3140 ?allow_trailing
3141 left_p
3142 members
3143 right_p;
3146 and replace_leading_trivia node new_leading_trivia =
3147 match Syntax.leading_token node with
3148 | None -> node
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 ->
3155 Rewriter.Replace
3156 (Syntax.make_token { t with Token.leading = new_leading_trivia })
3157 | _ -> Rewriter.Keep)
3158 node
3160 rewritten_node
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)
3173 node
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)
3188 node
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 =
3199 Concat
3201 t env key;
3202 Space;
3203 t env arrow;
3204 Space;
3205 SplitWith Cost.Base;
3206 Nest [t env value];
3209 and transform_keyword_expression_statement env kw expr semi =
3210 Concat
3212 t env kw;
3213 when_present expr (fun () ->
3214 Concat [Space; SplitWith Cost.Moderate; Nest [t env expr]]);
3215 t env semi;
3216 Newline;
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 =
3223 Concat
3225 t env left_p;
3226 Split;
3227 WithRule
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"
3236 and is_concat op =
3237 match get_operator_type op with
3238 | Full_fidelity_operator.ConcatenationOperator -> true
3239 | _ -> false
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
3246 | _ -> false
3248 let operator_preserves_newlines op =
3249 match get_operator_type op with
3250 | Full_fidelity_operator.PipeOperator -> true
3251 | _ -> false
3253 let operator_t = get_operator_type operator in
3254 if Full_fidelity_operator.is_comparison operator_t then
3255 WithLazyRule
3256 ( Rule.Parental,
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
3260 Concat
3262 t env left;
3263 Space;
3264 t env operator;
3265 Space;
3266 SplitWith Cost.Moderate;
3267 Nest [t env right];
3269 else
3270 Concat
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;
3281 } ->
3282 let operator_t = get_operator_type operator in
3283 let op_precedence =
3284 Full_fidelity_operator.precedence penv operator_t
3286 if op_precedence = precedence then
3287 flatten_expression left @ (operator :: flatten_expression right)
3288 else
3289 [expr]
3290 | _ -> [expr]
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
3298 ~is_nested:true
3299 (binary_left_operand, binary_operator, binary_right_operand)
3300 | _ -> t env operand
3302 let binary_expression_syntax_list =
3303 flatten_expression
3304 (Syntax.make_binary_expression left operator right)
3306 match binary_expression_syntax_list with
3307 | hd :: tl ->
3308 WithLazyRule
3309 ( Rule.Parental,
3310 transform_operand hd,
3311 let expression =
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 (
3316 let op = x in
3317 last_op := op;
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
3324 Concat
3326 ( if newline_before_op then
3327 Newline
3328 else if op_is_leading then
3329 if op_has_spaces then
3330 space_split ()
3331 else
3332 Split
3333 else if op_has_spaces then
3334 Space
3335 else
3336 Nothing );
3337 ( if is_concat op then
3338 ConcatOperator (t env op)
3339 else
3340 t env op );
3342 ) else
3343 let operand = x in
3344 last_operand := x;
3345 let op_has_spaces =
3346 operator_has_surrounding_spaces !last_op
3348 let op_is_leading = operator_is_leading !last_op in
3349 Concat
3351 ( if op_is_leading then
3352 if op_has_spaces then
3353 Space
3354 else
3355 Nothing
3356 else if op_has_spaces then
3357 space_split ()
3358 else
3359 Split );
3360 transform_operand operand;
3363 if is_nested then
3364 Nest expression
3365 else
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
3384 None
3385 else
3386 let node = replace_leading_trivia node leading_including_and_after in
3387 let (node, trailing_trivia) = remove_trailing_trivia node in
3388 let is_fixme =
3389 match Trivia.kind (List.hd_exn leading_including_and_after) with
3390 | TriviaKind.(FixMe | IgnoreError) -> true
3391 | _ -> false
3393 Some
3394 (Concat
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
3407 trivia. *)
3408 ( if is_fixme then
3409 Nothing
3410 else
3411 Newline );
3412 make_string (Syntax.text node) (Syntax.width node);
3413 transform_trailing_trivia trailing_trivia;
3414 ( if has_newline trailing_trivia then
3415 Newline
3416 else
3417 Nothing );
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) ->
3426 begin
3427 try Str.search_forward ignore_re (Trivia.text trivia) 0 >= 0
3428 with Caml.Not_found -> false
3430 | _ -> 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 ->
3454 true
3455 | _ -> false
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
3477 comments :=
3478 Concat
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
3484 then
3485 Space
3486 else if !newline_followed_last_comment then
3487 Newline
3488 else
3489 Nothing );
3491 :: !comments;
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
3499 | TriviaKind.FixMe
3500 | TriviaKind.IgnoreError
3501 | TriviaKind.DelimitedComment ->
3502 let preceded_by_whitespace =
3503 if !currently_leading then
3504 has_whitespace !leading_invisibles
3505 else
3506 has_whitespace !trailing_invisibles
3508 make_comment ();
3509 let delimited_lines = Str.split new_line_regex (Trivia.text triv) in
3510 let map_tail str =
3511 let prefix_space_count str =
3512 let len = String.length str in
3513 let rec aux i =
3514 if i = len || Char.(str.[i] <> ' ' && str.[i] <> '\t') then
3516 else
3517 1 + aux (i + 1)
3519 aux 0
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. *)
3525 let start_index =
3526 if is_leading then
3527 min !indent (prefix_space_count str)
3528 else
3529 prefix_space_count str
3531 let len = String.length str - start_index in
3532 let dc =
3533 Trivia.create_delimited_comment @@ String.sub str start_index len
3535 Concat
3537 Ignore ("\n", 1);
3538 Newline;
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
3546 let should_break =
3547 match Trivia.kind triv with
3548 | TriviaKind.FixMe
3549 | TriviaKind.IgnoreError ->
3550 false
3551 | _ -> !currently_leading
3553 last_comment :=
3554 Some
3555 (Concat
3557 ( if should_break then
3558 Newline
3559 else if preceded_by_whitespace then
3560 Space
3561 else
3562 Nothing );
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 ->
3569 make_comment ();
3570 last_comment :=
3571 Some
3572 (Concat
3574 ( if !currently_leading then
3575 Newline
3576 else
3577 Space );
3578 SingleLineComment (Trivia.text triv, Trivia.width triv);
3580 last_comment_was_delimited := false;
3581 currently_leading := false
3582 | TriviaKind.EndOfLine ->
3583 indent := 0;
3584 if !currently_leading then
3585 leading_invisibles := triv :: !leading_invisibles
3586 else (
3587 trailing_invisibles := triv :: !trailing_invisibles;
3588 make_comment ()
3590 currently_leading := true
3591 | TriviaKind.WhiteSpace ->
3592 if !currently_leading then (
3593 indent := Trivia.width triv;
3594 leading_invisibles := triv :: !leading_invisibles
3595 ) else
3596 trailing_invisibles := triv :: !trailing_invisibles);
3597 if List.is_empty !comments then
3598 if is_leading then
3599 transform_leading_invisibles trivia
3600 else
3601 ignore_trailing_invisibles trivia
3602 else (
3603 make_comment ();
3604 Concat (List.rev !comments)
3607 and _MAX_CONSECUTIVE_BLANK_LINES = 2
3609 and transform_leading_invisibles triv =
3610 let newlines = ref 0 in
3611 Concat
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;
3617 Concat
3619 ignored;
3620 ( if !newlines <= _MAX_CONSECUTIVE_BLANK_LINES then
3621 BlankLine
3622 else
3623 Nothing );
3625 | _ -> ignored))
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 ->
3633 if seen then
3634 (upto, t :: after, true)
3635 else
3636 (t :: upto, after, is_trivia_kind_end_of_line (Trivia.kind t)))
3638 Concat
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
3653 | _ ->
3654 Concat
3656 Space;
3657 ( if has_newline (Syntax.trailing_trivia node_newline) then
3658 Concat [Newline; Nest [t env node_body]]
3659 else
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