Skip to content

Commit

Permalink
Add the location of function signatures to the AST
Browse files Browse the repository at this point in the history
Summary: This was reconstructed later in `statement.ml`. Now we construct the location in the parser so we don't need to use `Loc.btwn`.

Reviewed By: mroch

Differential Revision: D12944974

fbshipit-source-id: 03cbd8a935499fe0e7a9c8596dd56bb36be46ee5
  • Loading branch information
nmote authored and facebook-github-bot committed Nov 9, 2018
1 parent 4f56c22 commit d0016fd
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 124 deletions.
54 changes: 29 additions & 25 deletions src/parser/declaration_parser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -219,33 +219,36 @@ module Declaration

let _function = with_loc (fun env ->
let async = async env in
Expect.token env T_FUNCTION;
let generator = generator env in
let (tparams, id) = (
match in_export env, Peek.token env with
| true, T_LPAREN -> (None, None)
| true, T_LESS_THAN ->
let typeParams = Type.type_parameter_declaration env in
let id = if Peek.token env = T_LPAREN then None else Some (
Parse.identifier ~restricted_error:Error.StrictFunctionName env
) in
(typeParams, id)
| _ ->
let id =
Parse.identifier ~restricted_error:Error.StrictFunctionName env
let sig_loc, (generator, tparams, id, params, return, predicate) = with_loc (fun env ->
Expect.token env T_FUNCTION;
let generator = generator env in
let (tparams, id) = (
match in_export env, Peek.token env with
| true, T_LPAREN -> (None, None)
| true, T_LESS_THAN ->
let typeParams = Type.type_parameter_declaration env in
let id = if Peek.token env = T_LPAREN then None else Some (
Parse.identifier ~restricted_error:Error.StrictFunctionName env
) in
(typeParams, id)
| _ ->
let id =
Parse.identifier ~restricted_error:Error.StrictFunctionName env
in
(Type.type_parameter_declaration env, Some id)
) in
let params =
let yield, await = match async, generator with
| true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorDeclaration *)
| true, false -> false, allow_await env (* #prod-AsyncFunctionDeclaration *)
| false, true -> true, false (* #prod-GeneratorDeclaration *)
| false, false -> false, false (* #prod-FunctionDeclaration *)
in
(Type.type_parameter_declaration env, Some id)
) in
let params =
let yield, await = match async, generator with
| true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorDeclaration *)
| true, false -> false, allow_await env (* #prod-AsyncFunctionDeclaration *)
| false, true -> true, false (* #prod-GeneratorDeclaration *)
| false, false -> false, false (* #prod-FunctionDeclaration *)
function_params ~await ~yield env
in
function_params ~await ~yield env
in
let (return, predicate) = Type.annotation_and_predicate_opt env in
let (return, predicate) = Type.annotation_and_predicate_opt env in
(generator, tparams, id, params, return, predicate)
) env in
let _, body, strict = function_body env ~async ~generator in
let simple = is_simple_function_params params in
strict_post_check env ~strict ~simple id params;
Expand All @@ -258,6 +261,7 @@ module Declaration
predicate;
return;
tparams;
sig_loc;
}
)

Expand Down
63 changes: 35 additions & 28 deletions src/parser/expression_parser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -792,31 +792,34 @@ module Expression
and _function env =
let start_loc = Peek.loc env in
let async = Declaration.async env in
Expect.token env T_FUNCTION;
let generator = Declaration.generator env in
let yield, await = match async, generator with
| true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorExpression *)
| true, false -> false, true (* #prod-AsyncFunctionExpression *)
| false, true -> true, false (* #prod-GeneratorExpression *)
| false, false -> false, false (* #prod-FunctionExpression *)
in
let id, tparams =
if Peek.token env = T_LPAREN
then None, None
else begin
let id = match Peek.token env with
| T_LESS_THAN -> None
| _ ->
let env = env |> with_allow_await await |> with_allow_yield yield in
Some (Parse.identifier ~restricted_error:Error.StrictFunctionName env) in
id, Type.type_parameter_declaration env
end in

(* #sec-function-definitions-static-semantics-early-errors *)
let env = env |> with_allow_super No_super in

let params = Declaration.function_params ~await ~yield env in
let return, predicate = Type.annotation_and_predicate_opt env in
let sig_loc, (id, params, generator, predicate, return, tparams) = with_loc (fun env ->
Expect.token env T_FUNCTION;
let generator = Declaration.generator env in
let yield, await = match async, generator with
| true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorExpression *)
| true, false -> false, true (* #prod-AsyncFunctionExpression *)
| false, true -> true, false (* #prod-GeneratorExpression *)
| false, false -> false, false (* #prod-FunctionExpression *)
in
let id, tparams =
if Peek.token env = T_LPAREN
then None, None
else begin
let id = match Peek.token env with
| T_LESS_THAN -> None
| _ ->
let env = env |> with_allow_await await |> with_allow_yield yield in
Some (Parse.identifier ~restricted_error:Error.StrictFunctionName env) in
id, Type.type_parameter_declaration env
end in

(* #sec-function-definitions-static-semantics-early-errors *)
let env = env |> with_allow_super No_super in

let params = Declaration.function_params ~await ~yield env in
let return, predicate = Type.annotation_and_predicate_opt env in
(id, params, generator, predicate, return, tparams)
) env in
let end_loc, body, strict =
Declaration.function_body env ~async ~generator in
let simple = Declaration.is_simple_function_params params in
Expand All @@ -830,6 +833,7 @@ module Expression
predicate;
return;
tparams;
sig_loc;
}))

and number env kind raw =
Expand Down Expand Up @@ -1077,8 +1081,8 @@ module Expression
(* a T_ASYNC could either be a parameter name or it could be indicating
* that it's an async function *)
let async = Peek.ith_token ~i:1 env <> T_ARROW && Declaration.async env in
let tparams = Type.type_parameter_declaration env in
let params, return, predicate =
let sig_loc, (tparams, params, return, predicate) = with_loc (fun env ->
let tparams = Type.type_parameter_declaration env in
(* Disallow all fancy features for identifier => body *)
if Peek.is_identifier env && tparams = None
then
Expand All @@ -1089,6 +1093,7 @@ module Expression
annot= Ast.Type.Missing (Peek.loc_skip_lookahead env);
optional=false;
} in
tparams,
(loc, { Ast.Function.Params.params = [param]; rest = None }),
Ast.Type.Missing Loc.({ loc with start = loc._end }),
None
Expand All @@ -1105,7 +1110,8 @@ module Expression
let return, predicate = env
|> with_no_anon_function_type true
|> Type.annotation_and_predicate_opt in
params, return, predicate in
tparams, params, return, predicate
) env in

(* It's hard to tell if an invalid expression was intended to be an
* arrow function before we see the =>. If there are no params, that
Expand Down Expand Up @@ -1142,6 +1148,7 @@ module Expression
predicate;
return;
tparams;
sig_loc;
}))

and sequence env acc =
Expand Down
5 changes: 5 additions & 0 deletions src/parser/flow_ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,11 @@ and Function : sig
predicate: ('M, 'T) Type.Predicate.t option;
return: ('M, 'T) Type.annotation_or_hint;
tparams: ('M, 'T) Type.ParameterDeclaration.t option;
(* Location of the signature portion of a function, e.g.
* function foo(): void {}
* ^^^^^^^^^^^^^^^^^^^^
*)
sig_loc: 'M;
}

and ('M, 'T) body =
Expand Down
82 changes: 47 additions & 35 deletions src/parser/object_parser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,24 @@ module Object
(* #sec-function-definitions-static-semantics-early-errors *)
let env = env |> with_allow_super Super_prop in

(* It's not clear how type params on getters & setters would make sense
* in Flow's type system. Since this is a Flow syntax extension, we might
* as well disallow it until we need it *)
let tparams = None in
let params = Declaration.function_params ~await:false ~yield:false env in
begin match is_getter, params with
| true, (_, { Ast.Function.Params.params = []; rest = None }) -> ()
| false, (_, { Ast.Function.Params.rest = Some _; _ }) ->
(* rest params don't make sense on a setter *)
error_at env (key_loc, Error.SetterArity)
| false, (_, { Ast.Function.Params.params = [_]; _ }) -> ()
| true, _ -> error_at env (key_loc, Error.GetterArity)
| false, _ -> error_at env (key_loc, Error.SetterArity)
end;
let return = Type.annotation_opt env in
let sig_loc, (tparams, params, return) = with_loc (fun env ->
(* It's not clear how type params on getters & setters would make sense
* in Flow's type system. Since this is a Flow syntax extension, we might
* as well disallow it until we need it *)
let tparams = None in
let params = Declaration.function_params ~await:false ~yield:false env in
begin match is_getter, params with
| true, (_, { Ast.Function.Params.params = []; rest = None }) -> ()
| false, (_, { Ast.Function.Params.rest = Some _; _ }) ->
(* rest params don't make sense on a setter *)
error_at env (key_loc, Error.SetterArity)
| false, (_, { Ast.Function.Params.params = [_]; _ }) -> ()
| true, _ -> error_at env (key_loc, Error.GetterArity)
| false, _ -> error_at env (key_loc, Error.SetterArity)
end;
let return = Type.annotation_opt env in
(tparams, params, return)
) env in
let _, body, strict = Declaration.function_body env ~async ~generator in
let simple = Declaration.is_simple_function_params params in
Declaration.strict_post_check env ~strict ~simple None params;
Expand All @@ -114,6 +117,7 @@ module Object
predicate = None; (* setters/getter are not predicates *)
return;
tparams;
sig_loc;
}
) env in
key, value
Expand Down Expand Up @@ -170,17 +174,20 @@ module Object
(* #sec-function-definitions-static-semantics-early-errors *)
let env = env |> with_allow_super Super_prop in

let tparams = Type.type_parameter_declaration env in
let params =
let yield, await = match async, generator with
| true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorMethod *)
| true, false -> false, allow_await env (* #prod-AsyncMethod *)
| false, true -> true, false (* #prod-GeneratorMethod *)
| false, false -> false, false (* #prod-MethodDefinition *)
let sig_loc, (tparams, params, return) = with_loc (fun env ->
let tparams = Type.type_parameter_declaration env in
let params =
let yield, await = match async, generator with
| true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorMethod *)
| true, false -> false, allow_await env (* #prod-AsyncMethod *)
| false, true -> true, false (* #prod-GeneratorMethod *)
| false, false -> false, false (* #prod-MethodDefinition *)
in
Declaration.function_params ~await ~yield env
in
Declaration.function_params ~await ~yield env
in
let return = Type.annotation_opt env in
let return = Type.annotation_opt env in
(tparams, params, return)
) env in
let _, body, strict =
Declaration.function_body env ~async ~generator in
let simple = Declaration.is_simple_function_params params in
Expand All @@ -195,6 +202,7 @@ module Object
predicate = None;
return;
tparams;
sig_loc;
}
) in

Expand Down Expand Up @@ -532,17 +540,20 @@ module Object
env |> with_allow_super Super_prop
in
let value = with_loc (fun env ->
let tparams = Type.type_parameter_declaration env in
let params =
let yield, await = match async, generator with
| true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorMethod *)
| true, false -> false, allow_await env (* #prod-AsyncMethod *)
| false, true -> true, false (* #prod-GeneratorMethod *)
| false, false -> false, false (* #prod-MethodDefinition *)
let sig_loc, (tparams, params, return) = with_loc (fun env ->
let tparams = Type.type_parameter_declaration env in
let params =
let yield, await = match async, generator with
| true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorMethod *)
| true, false -> false, allow_await env (* #prod-AsyncMethod *)
| false, true -> true, false (* #prod-GeneratorMethod *)
| false, false -> false, false (* #prod-MethodDefinition *)
in
Declaration.function_params ~await ~yield env
in
Declaration.function_params ~await ~yield env
in
let return = Type.annotation_opt env in
let return = Type.annotation_opt env in
(tparams, params, return)
) env in
let _, body, strict =
Declaration.function_body env ~async ~generator in
let simple = Declaration.is_simple_function_params params in
Expand All @@ -557,6 +568,7 @@ module Object
predicate = None;
return;
tparams;
sig_loc;
}
) env in
Ast.Class.(Body.Method (Loc.btwn start_loc (fst value), { Method.
Expand Down
1 change: 1 addition & 0 deletions src/parser_utils/ast_builder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ module Functions = struct
predicate = None;
return = Ast.Type.Missing Loc.none;
tparams = None;
sig_loc = Loc.none;
}
end

Expand Down
4 changes: 2 additions & 2 deletions src/parser_utils/flow_ast_differ.ml
Original file line number Diff line number Diff line change
Expand Up @@ -513,11 +513,11 @@ let program (algo : diff_algorithm)
let open Ast.Function in
let {
id = id1; params = params1; body = body1; async = async1; generator = generator1;
predicate = predicate1; return = return1; tparams = tparams1;
predicate = predicate1; return = return1; tparams = tparams1; sig_loc = _;
} = func1 in
let {
id = id2; params = params2; body = body2; async = async2; generator = generator2;
predicate = predicate2; return = return2; tparams = tparams2;
predicate = predicate2; return = return2; tparams = tparams2; sig_loc = _;
} = func2 in

if id1 != id2 || (* body handled below *) async1 != async2
Expand Down
4 changes: 2 additions & 2 deletions src/parser_utils/flow_ast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ class ['loc] mapper = object(this)
let open Flow_ast.Function in
let {
id = ident; params; body; async; generator;
predicate; return; tparams;
predicate; return; tparams; sig_loc;
} = expr in
let ident' = map_opt this#function_identifier ident in
let params' = this#function_params params in
Expand All @@ -709,7 +709,7 @@ class ['loc] mapper = object(this)
&& tparams == tparams' then expr
else {
id = ident'; params = params'; return = return'; body = body';
async; generator; predicate; tparams = tparams';
async; generator; predicate; tparams = tparams'; sig_loc;
}

method function_params (params: ('loc, 'loc) Flow_ast.Function.Params.t) =
Expand Down
5 changes: 3 additions & 2 deletions src/parser_utils/flow_polymorphic_ast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ class virtual ['M, 'T, 'N, 'U] mapper = object(this)
let open Ast.Function in
let {
id = ident; params; body; async; generator;
predicate; return; tparams;
predicate; return; tparams; sig_loc;
} = expr in
let ident' = Option.map ~f:this#t_function_identifier ident in
this#type_parameter_declaration_opt tparams (fun tparams' ->
Expand All @@ -784,9 +784,10 @@ class virtual ['M, 'T, 'N, 'U] mapper = object(this)
BodyExpression (this#expression expr)
in
let predicate' = Option.map ~f:this#type_predicate predicate in
let sig_loc' = this#on_loc_annot sig_loc in
{
id = ident'; params = params'; return = return'; body = body';
async; generator; predicate = predicate'; tparams = tparams';
async; generator; predicate = predicate'; tparams = tparams'; sig_loc = sig_loc'
}
)

Expand Down
Loading

0 comments on commit d0016fd

Please sign in to comment.