Skip to content
Permalink
Browse files

Refactor handle_possible_chaining

Summary:
Currently, `handle_possible_chaining` is a bit of a misnomer--if there is no chaining, then an exception `Failure "Expected a chain of at least length 1"` is raised. This means that any time we want to make use of the behavior of `handle_possible_chaining`, for example, in `handle_function_call_expression`, we must first look at the receiver to confirm that it is a member selection expression, so that we know it is safe to invoke `handle_possible_chaining`.

This seems a little silly. It would be much simpler if `handle_possible_chaining` performed chain-formatting when member selections were present, and simply formatted function calls normally otherwise (this is, after all, what the name `handle_possible_chaining` would seem to imply). This diff makes that change, and also does a bit of refactoring in an attempt to make `handle_possible_chaining` easier to follow.

Reviewed By: pittsw

Differential Revision: D13959285

fbshipit-source-id: 86cd90d4c8f82e3904d31641d045e16fea572e41
  • Loading branch information...
Jake Bailey (Hacklang) authored and hhvm-bot committed Feb 6, 2019
1 parent 7558dec commit 6db8ef7c1afc847cb81f12270d66e12c609801b9
Showing with 84 additions and 146 deletions.
  1. +84 −146 hphp/hack/src/hackfmt/hack_format.ml
@@ -1378,30 +1378,9 @@ let rec t (env: Env.t) (node: Syntax.t) : Doc.t =
transform_argish_with_return_type env lp params rp colon ret_type
| Syntax.CastExpression _ ->
Span (List.map (Syntax.children node) (t env))
| Syntax.MemberSelectionExpression {
member_object;
member_operator;
member_name; } ->
handle_possible_chaining env
(
member_object,
member_operator,
member_name,
None
)
None
| Syntax.SafeMemberSelectionExpression {
safe_member_object;
safe_member_operator;
safe_member_name; } ->
handle_possible_chaining env
(
safe_member_object,
safe_member_operator,
safe_member_name,
None
)
None
| Syntax.MemberSelectionExpression _
| Syntax.SafeMemberSelectionExpression _ ->
handle_possible_chaining env node
| Syntax.YieldExpression {
yield_keyword = kw;
yield_operand = operand; } ->
@@ -1552,28 +1531,9 @@ let rec t (env: Env.t) (node: Syntax.t) : Doc.t =
then Nest [t env false_expr]
else t env false_expr;
])
| Syntax.FunctionCallExpression {
function_call_receiver;
function_call_left_paren;
function_call_argument_list;
function_call_right_paren; } ->
handle_function_call_expression env
function_call_receiver
function_call_left_paren
function_call_argument_list
function_call_right_paren
| Syntax.FunctionCallWithTypeArgumentsExpression {
function_call_with_type_arguments_receiver;
function_call_with_type_arguments_type_args;
function_call_with_type_arguments_left_paren;
function_call_with_type_arguments_argument_list;
function_call_with_type_arguments_right_paren; } ->
handle_function_call_with_type_arguments_expression env
function_call_with_type_arguments_receiver
function_call_with_type_arguments_type_args
function_call_with_type_arguments_left_paren
function_call_with_type_arguments_argument_list
function_call_with_type_arguments_right_paren
| Syntax.FunctionCallExpression _
| Syntax.FunctionCallWithTypeArgumentsExpression _ ->
handle_possible_chaining env node
| Syntax.EvalExpression {
eval_keyword = kw;
eval_left_paren = left_p;
@@ -2552,116 +2512,60 @@ and handle_xhp_open_right_angle_token env attrs node =
]
| _ -> failwith "expected xhp_open right_angle token"

and handle_function_call_expression env
receiver
lp
args
rp
=
match Syntax.syntax receiver with
| Syntax.MemberSelectionExpression {
member_object;
member_operator;
member_name; } ->
handle_possible_chaining env
(member_object, member_operator, member_name, None)
(Some (lp, args, rp))
| Syntax.SafeMemberSelectionExpression {
safe_member_object;
safe_member_operator;
safe_member_name; } ->
handle_possible_chaining env
(safe_member_object, safe_member_operator, safe_member_name, None)
(Some (lp, args, rp))
| _ ->
Concat [
t env receiver;
transform_argish env lp args rp
]

and handle_function_call_with_type_arguments_expression env
receiever
tyargs
lp
args
rp
=
match Syntax.syntax receiever with
| Syntax.MemberSelectionExpression {
member_object;
member_operator;
member_name; } ->
handle_possible_chaining env
(member_object, member_operator, member_name, Some tyargs)
(Some (lp, args, rp))
| Syntax.SafeMemberSelectionExpression {
safe_member_object;
safe_member_operator;
safe_member_name; } ->
handle_possible_chaining env
(safe_member_object, safe_member_operator, safe_member_name, Some tyargs)
(Some (lp, args, rp))
| _ ->
Concat [
t env receiever;
t env tyargs;
transform_argish env lp args rp
]
and handle_possible_chaining env node =
let rec handle_member_selection acc (receiver, arrow, member, targs) args =
let first_receiver, acc = handle_chaining acc receiver in
first_receiver, (arrow, member, targs, args) :: acc

and handle_possible_chaining env (obj, arrow1, member1, targs1) argish =
let rec handle_chaining obj =
let handle_mse_or_smse (obj, arrow, member, targs) fun_paren_args =
let (obj, l) = handle_chaining obj in
obj, l @ [(arrow, member, targs, fun_paren_args)]
in
let handle_fun_call receiver ?targs lp args rp =
match Syntax.syntax receiver with
| Syntax.MemberSelectionExpression {
member_object = obj;
member_operator = arrow;
member_name = member; }
| Syntax.SafeMemberSelectionExpression {
safe_member_object = obj;
safe_member_operator = arrow;
safe_member_name = member; } ->
handle_mse_or_smse
(obj, arrow, member, targs)
(Some (lp, args, rp))
| _ -> obj, []
in
match Syntax.syntax obj with
and handle_fun_call acc node receiver ?targs lp args rp =
match Syntax.syntax receiver with
| Syntax.MemberSelectionExpression {
member_object = obj;
member_operator = arrow;
member_name = member; }
| Syntax.SafeMemberSelectionExpression {
safe_member_object = obj;
safe_member_operator = arrow;
safe_member_name = member; } ->
handle_member_selection acc
(obj, arrow, member, targs)
(Some (lp, args, rp))
| _ -> node, []

and handle_chaining acc node =
match Syntax.syntax node with
| Syntax.FunctionCallExpression {
function_call_receiver = receiver;
function_call_left_paren = lp;
function_call_argument_list = args;
function_call_right_paren = rp; } ->
handle_fun_call receiver lp args rp
handle_fun_call acc node receiver lp args rp
| Syntax.FunctionCallWithTypeArgumentsExpression {
function_call_with_type_arguments_receiver = receiver;
function_call_with_type_arguments_type_args = targs;
function_call_with_type_arguments_left_paren = lp;
function_call_with_type_arguments_argument_list = args;
function_call_with_type_arguments_right_paren = rp; } ->
handle_fun_call receiver ~targs lp args rp
handle_fun_call acc node receiver ~targs lp args rp
| Syntax.MemberSelectionExpression {
member_object;
member_operator;
member_name; } ->
handle_mse_or_smse
(member_object, member_operator, member_name, None)
None
member_object = obj;
member_operator = arrow;
member_name = member; }
| Syntax.SafeMemberSelectionExpression {
safe_member_object;
safe_member_operator;
safe_member_name; } ->
handle_mse_or_smse
(safe_member_object, safe_member_operator, safe_member_name, None)
safe_member_object = obj;
safe_member_operator = arrow;
safe_member_name = member; } ->
handle_member_selection acc
(obj, arrow, member, None)
None
| _ -> obj, []
| _ -> node, []
in

let (obj, chain_list) = handle_chaining obj in
let chain_list = chain_list @ [(arrow1, member1, targs1, argish)] in
(* Flatten nested member selection expressions into the first receiver and a
list of member selections.
E.g., transform $x->a->b->c into ($x, [->a; ->b; ->c]) *)
let first_receiver, chain_list = handle_chaining [] node in
let chain_list = List.rev chain_list in

let transform_chain (arrow, member, targs, argish) =
Concat [
@@ -2672,12 +2576,47 @@ and handle_possible_chaining env (obj, arrow1, member1, targs1) argish =
~f:(fun (lp, args, rp) -> transform_argish env lp args rp);
]
in
let obj_has_trailing_newline = node_has_trailing_newline obj in

(* The actual transform for function call expressions (the default transform
just calls into [handle_possible_chaining]). *)
let transform_first_receiver node =
match Syntax.syntax node with
| Syntax.FunctionCallExpression {
function_call_receiver = receiver;
function_call_left_paren = lp;
function_call_argument_list = args;
function_call_right_paren = rp; } ->
Concat [
t env receiver;
transform_argish env lp args rp;
]
| Syntax.FunctionCallWithTypeArgumentsExpression {
function_call_with_type_arguments_receiver = receiver;
function_call_with_type_arguments_type_args = targs;
function_call_with_type_arguments_left_paren = lp;
function_call_with_type_arguments_argument_list = args;
function_call_with_type_arguments_right_paren = rp; } ->
Concat [
t env receiver;
t env targs;
transform_argish env lp args rp;
]
| Syntax.MemberSelectionExpression _
| Syntax.SafeMemberSelectionExpression _ ->
failwith ("Should not be possible for a member selection expression to \
be considered first_receiver")
| _ -> t env node
in

let first_receiver_has_trailing_newline =
node_has_trailing_newline first_receiver
in
match chain_list with
| [] -> transform_first_receiver first_receiver
| hd :: [] ->
Concat [
Span [t env obj];
if obj_has_trailing_newline
Span [transform_first_receiver first_receiver];
if first_receiver_has_trailing_newline
then Newline
else SplitWith Cost.High;
Nest [transform_chain hd];
@@ -2691,7 +2630,7 @@ and handle_possible_chaining env (obj, arrow1, member1, targs1) argish =
| (_, _, _, Some (_, _, trailing)) ->
if node_has_trailing_newline trailing
then Rule.Always
else if obj_has_trailing_newline
else if first_receiver_has_trailing_newline
then Rule.Parental
else
(* If we have a chain where only the final item contains internal
@@ -2713,8 +2652,8 @@ and handle_possible_chaining env (obj, arrow1, member1, targs1) argish =
Span [
WithLazyRule (rule_type,
Concat [
t env obj;
if obj_has_trailing_newline
transform_first_receiver first_receiver;
if first_receiver_has_trailing_newline
then Newline
else SplitWith Cost.Base;
],
@@ -2724,7 +2663,6 @@ and handle_possible_chaining env (obj, arrow1, member1, targs1) argish =
Nest (List.map tl ~f:(fun x -> Concat [Split; x]))
])
]
| _ -> failwith "Expected a chain of at least length 1"

and transform_fn_decl_name env modifiers kw name type_params leftp =
let mods = handle_possible_list env ~after_each:(fun _ -> Space) modifiers in

0 comments on commit 6db8ef7

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.