Skip to content
This repository has been archived by the owner on Jun 4, 2019. It is now read-only.

Commit

Permalink
Merge pull request #154 from soutaro/variadic-param-typing
Browse files Browse the repository at this point in the history
Variadic parameters with type hint
  • Loading branch information
aryx committed Jan 14, 2017
2 parents 27294e9 + ff982ac commit 65e4790
Show file tree
Hide file tree
Showing 20 changed files with 93 additions and 16 deletions.
2 changes: 2 additions & 0 deletions lang_php/analyze/foundation/ast_php_simple.ml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ and hint_type =
| HintCallback of hint_type list * (hint_type option)
| HintShape of (string_const_expr * hint_type) list
| HintTypeConst of (hint_type * hint_type)
| HintVariadic of hint_type option

and class_name = hint_type

Expand Down Expand Up @@ -350,6 +351,7 @@ and func_def = {
p_name: var;
p_default: expr option;
p_attrs: attribute list;
p_variadic: bool
}

(* for methods, and below for fields too *)
Expand Down
5 changes: 5 additions & 0 deletions lang_php/analyze/foundation/ast_php_simple_build.ml
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,9 @@ and hint_type env = function
))
| HintTypeConst (lhs, _tok, rhs) ->
A.HintTypeConst (hint_type env lhs, hint_type env rhs)
| HintVariadic (_, hint) ->
let hint = map_opt (hint_type env) hint in
A.HintVariadic hint

(* ------------------------------------------------------------------------- *)
(* Definitions *)
Expand Down Expand Up @@ -766,12 +769,14 @@ and parameter env
p_modifier = _mTODO;
(* don't care about the soft type annot, it's useful only for the runtime *)
p_soft_type = _;
p_variadic = variadic;
} =
{ A.p_type = opt hint_type env t;
A.p_ref = r <> None;
A.p_name = dname name;
A.p_default = opt static_scalar_affect env d;
A.p_attrs = attributes env a;
A.p_variadic = variadic <> None;
}

(*****************************************************************************)
Expand Down
1 change: 1 addition & 0 deletions lang_php/analyze/foundation/database_prolog_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ let rec string_of_hint_type x =
| HintCallback _ -> "callback"
| HintShape _ -> "shape"
| HintTypeConst _ -> "typeconst"
| HintVariadic _ -> "..."

let string_of_hint_type_opt h =
match h with
Expand Down
2 changes: 1 addition & 1 deletion lang_php/analyze/foundation/dependencies_toposort_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ module Deps = struct
| HintTypeConst (x1, x2) ->
List.fold_left (fun accp x ->
SSet.union accp (hint_type_ accp x)) acc [x1; x2]
| HintVariadic x -> hint_type acc x


and class_def acc c =
Expand Down
1 change: 1 addition & 0 deletions lang_php/analyze/foundation/graph_code_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ and hint_type env t =
| HintTypeConst (x1, x2) ->
hint_type env x1;
hint_type env x2
| HintVariadic t -> do_option (hint_type env) t

(* ---------------------------------------------------------------------- *)
(* Expr *)
Expand Down
8 changes: 7 additions & 1 deletion lang_php/analyze/foundation/meta_ast_php_simple.ml
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ and
p_type = v_p_type;
p_ref = v_p_ref;
p_name = v_p_name;
p_default = v_p_default
p_default = v_p_default;
p_variadic = v_p_variadic
} =
let bnds = [] in
let arg = Ocaml.vof_option vof_expr v_p_default in
Expand All @@ -331,6 +332,9 @@ and
let arg = vof_wrapped_string v_p_name in
let bnd = ("p_name", arg) in
let bnds = bnd :: bnds in
let arg = Ocaml.vof_bool v_p_variadic in
let bnd = ("p_variadic", arg) in
let bnds = bnd :: bnds in
Ocaml.VDict bnds
and vof_hint_type =
function
Expand All @@ -355,6 +359,8 @@ and vof_hint_type =
let v1 = vof_hint_type v1
and v2 = vof_hint_type v2
in Ocaml.VSum (("HintTypeConst", [ v1; v2]))
| HintVariadic None -> Ocaml.VSum (("HintVariadic", []))
| HintVariadic (Some v1) -> Ocaml.VSum (("HintVariadic", [vof_hint_type v1]))

and
vof_class_def {
Expand Down
6 changes: 4 additions & 2 deletions lang_php/analyze/foundation/typing_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -776,8 +776,7 @@ and make_return env r =
| _ -> ()

and parameter env p =
let pval =
match p.p_type with
let rec hint = function
| None -> Tvar (fresh())
| Some (Hint [(x, tok)]) ->
(try get_hard_object env x
Expand All @@ -793,6 +792,9 @@ and parameter env p =
| Some (HintCallback _) -> Tvar (fresh())
| Some (HintShape _) -> failwith "no support for shape yet"
| Some (HintTypeConst _) -> failwith "no support for type consts"
| Some (HintVariadic x) -> array (int, hint x)
in
let pval = hint p.p_type
in
(match p.p_default with
| None -> ()
Expand Down
1 change: 1 addition & 0 deletions lang_php/analyze/visual/highlight_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ let visit_program ~tag _prefs hentities (ast, toks) =
(* todo: colorize as record the keys? *)
| HintShape _
| HintTypeConst _
| HintVariadic _
->
()
);
Expand Down
10 changes: 9 additions & 1 deletion lang_php/matcher/php_vs_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2526,14 +2526,22 @@ and m_hint_type a b =
return (A.HintTypeConst(a1, a2, a3),
B.HintTypeConst(b1, b2, b3)
))))

| A.HintVariadic (a1, a2), B.HintVariadic (b1, b2) ->
m_tok a1 b1 >>= (fun (a1, b1) ->
m_option m_hint_type a2 b2 >>= (fun (a2, b2) ->
return (
A.HintVariadic (a1, a2),
B.HintVariadic (b1, b2)
)
))
| A.Hint _, _
| A.HintArray _, _
| A.HintQuestion _, _
| A.HintTuple _, _
| A.HintCallback _, _
| A.HintShape _, _
| A.HintTypeConst _, _
| A.HintVariadic _, _
-> fail ()
and m_hint_type_ret (a1, a2, a3) (b1, b2, b3) =
m_tok a1 b1 >>= (fun (a1, b1) ->
Expand Down
1 change: 1 addition & 0 deletions lang_php/matcher/refactoring_code_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ let refactor refactorings (ast, tokens) =
| HintCallback (lparen,_,_) -> lparen
| HintShape (tok, _) -> tok
| HintTypeConst (hint, _, _) -> leftmost_tok hint
| HintVariadic (tok, _) -> tok
in
let tok = leftmost_tok x in
if tok_pos_equal_refactor_pos tok pos_opt then begin
Expand Down
2 changes: 2 additions & 0 deletions lang_php/parsing/ast_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ type hint_type =
hint_type (* lhs *)
* tok (* '::' *)
* hint_type (* rhs *)
| HintVariadic of (tok * hint_type option)

and type_args = hint_type comma_list single_angle

Expand Down Expand Up @@ -546,6 +547,7 @@ and func_def = {
p_ref: is_ref;
p_name: dname;
p_default: static_scalar_affect option;
p_variadic: tok (* ... *) option;
}
and is_ref = tok (* bool wrap ? *) option
(* the f_name in func_def should be a fake name *)
Expand Down
11 changes: 9 additions & 2 deletions lang_php/parsing/map_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,8 @@ and
p_type = v_p_type;
p_ref = v_p_ref;
p_name = v_p_name;
p_default = v_p_default
p_default = v_p_default;
p_variadic = v_p_variadic
} =
let v_p_default = map_of_option map_static_scalar_affect v_p_default in
let v_p_name = map_dname v_p_name in
Expand All @@ -780,14 +781,16 @@ and
let v_p_type = map_of_option map_hint_type v_p_type in
let v_p_soft_type = map_of_option map_tok v_p_soft_type in
let v_p_attrs = map_of_option map_attributes v_p_attrs in
let v_p_variadic = map_of_option map_tok v_p_variadic in
{
p_attrs = v_p_attrs;
p_modifier = v_p_modifier;
p_soft_type = v_p_soft_type;
p_type = v_p_type;
p_ref = v_p_ref;
p_name = v_p_name;
p_default = v_p_default
p_default = v_p_default;
p_variadic = v_p_variadic
}

and map_hint_type =
Expand Down Expand Up @@ -836,6 +839,10 @@ and map_hint_type =
and v2 = map_tok v2
and v3 = map_hint_type v3
in HintTypeConst ((v1, v2, v3))
| HintVariadic (v1, v2) ->
let v1 = map_tok v1
and v2 = map_option map_hint_type v2
in HintVariadic (v1, v2)

and map_is_ref v = map_of_option map_tok v
and map_lambda_def (v1, v2) =
Expand Down
10 changes: 9 additions & 1 deletion lang_php/parsing/meta_ast_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,8 @@ and
p_type = v_p_type;
p_ref = v_p_ref;
p_name = v_p_name;
p_default = v_p_default
p_default = v_p_default;
p_variadic = v_p_variadic
} =
let bnds = [] in
let arg = vof_option vof_static_scalar_affect v_p_default in
Expand All @@ -820,6 +821,9 @@ and
let arg = vof_option vof_attributes v_p_attrs in
let bnd = ("p_attrs", arg) in
let bnds = bnd :: bnds in
let arg = vof_option vof_tok v_p_variadic in
let bnd = ("p_variadic", arg) in
let bnds = bnd :: bnds in
Ocaml.VDict bnds
and vof_hint_type =
function
Expand Down Expand Up @@ -867,6 +871,10 @@ and vof_hint_type =
and v2 = vof_tok v2
and v3 = vof_hint_type v3
in Ocaml.VSum (("HintTypeConst", [ v1; v2; v3]))
| HintVariadic (v1, v2) ->
let v1 = vof_tok v1 in
let v2 = vof_option vof_hint_type v2 in
Ocaml.VSum (("HintVariadic", [v1; v2]))


and vof_is_ref v = vof_option vof_tok v
Expand Down
12 changes: 8 additions & 4 deletions lang_php/parsing/parser_php.mly
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,12 @@ parameter_list:
parameter: attributes_opt ctor_modifier_opt at_opt type_php_opt parameter_bis
{
match $5 with
Left3 param -> Left3 { param with p_modifier = $2; p_attrs = $1; p_type = $4; p_soft_type= $3; }
Left3 param ->
let hint = match param.p_type with
| Some(HintVariadic (tok, _)) -> Some(HintVariadic (tok, $4))
| _ -> $4
in
Left3 { param with p_modifier = $2; p_attrs = $1; p_type = hint; p_soft_type= $3; }
| _ -> match ($1, $2, $3, $4) with
(None, None, None, None) -> $5
| _ -> raise Parsing.Parse_error
Expand All @@ -574,11 +579,10 @@ parameter_bis:
{ let p = H.mk_param $1 in Left3 {p with p_default=Some($2,$3)} }
| TAND T_VARIABLE TEQ static_scalar
{ let p = H.mk_param $2 in Left3 {p with p_ref=Some $1; p_default=Some($3,$4)} }
/*(* todo: with is_variadic = true *)*/
| T_ELLIPSIS T_VARIABLE
{ Left3 (H.mk_param $2) }
{ let p = H.mk_param $2 in Left3 {p with p_variadic=Some $1; p_type=Some(HintVariadic ($1, None))} }
| TAND T_ELLIPSIS T_VARIABLE
{ let p = H.mk_param $3 in Left3 {p with p_ref=Some $1} }
{ let p = H.mk_param $3 in Left3 {p with p_ref=Some $1; p_variadic=Some $2; p_type=Some(HintVariadic ($2, None))} }
/*(* varargs extension *)*/
| T_ELLIPSIS
{ Middle3 $1 }
Expand Down
9 changes: 7 additions & 2 deletions lang_php/parsing/parser_php_mly_helper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,15 @@ let sgrep_guard v =
(* shortcuts *)
(*****************************************************************************)
(*s: AST builder *)
let mk_param s =
let mk_param s =
{ p_type = None;
p_attrs = None;
p_ref = None;
p_name = DName s;
p_default = None;
p_modifier = None;
p_soft_type = None;
p_variadic = None;
}
(* old: e, Ast_php.noType() *)
let mk_e e = e
Expand All @@ -172,7 +173,11 @@ let mk_var (s, tok) =
let rec validate_parameter_list = function
| [] -> ()
| Middle3 _ :: params -> validate_parameter_list_empty params
| Left3 _ :: params -> validate_parameter_list params
| Left3 param :: params ->
if param.p_variadic <> None then
validate_parameter_list_empty params
else
validate_parameter_list params
| Right3 _ :: params -> validate_parameter_list params

and validate_parameter_list_empty = function
Expand Down
9 changes: 9 additions & 0 deletions lang_php/parsing/unit_parsing_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ let unittest =
()
);

"rejecting multiple variadic params" >:: (fun () ->
Flag_parsing_php.show_parsing_error := false;
try
let _ = Parse_php.program_of_string "function foo($x, ...$rest, ...$another) {}" in
assert_failure "it should have thrown a Parse_error exception"
with
Parse_php.Parse_error _ ->
()
);
"rejecting non-tail variadic param without variable name" >:: (fun () ->
Flag_parsing_php.show_parsing_error := false;
try
Expand Down
10 changes: 8 additions & 2 deletions lang_php/parsing/visitor_php.ml
Original file line number Diff line number Diff line change
Expand Up @@ -824,15 +824,17 @@ and v_parameter x =
p_type = v_p_type;
p_ref = v_p_ref;
p_name = v_p_name;
p_default = v_p_default
p_default = v_p_default;
p_variadic = v_p_variadic
} ->
let arg = v_option v_attributes v_p_attrs in
let arg = v_option (v_wrap v_modifier) v_p_modifier in
let arg = v_option v_hint_type v_p_type in
let arg = v_option v_tok v_p_soft_type in
let arg = v_is_ref v_p_ref in
let arg = v_dname v_p_name in
let arg = v_option v_static_scalar_affect v_p_default
let arg = v_option v_static_scalar_affect v_p_default in
let arg = v_option v_tok v_p_variadic
in ()
in
vin.kparameter (k, all_functions) x
Expand Down Expand Up @@ -880,6 +882,10 @@ and v_hint_type x =
and v2 = v_tok v2
and v3 = v_hint_type v3
in ()
| HintVariadic (v1, v2) ->
let v1 = v_tok v1
and v2 = v_option v_hint_type v2
in ()
in
vin.khint_type (k, all_functions) x

Expand Down
2 changes: 2 additions & 0 deletions lang_php/pretty/ast_pp.ml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ and hint_type =
| HintQuestion of hint_type
| HintTuple of hint_type list
| HintCallback of hint_type list * (hint_type option)
| HintVariadic of hint_type option

(* ------------------------------------------------------------------------- *)
(* Definitions *)
Expand All @@ -193,6 +194,7 @@ and parameter = {
p_ref: bool;
p_name: string;
p_default: expr option;
p_variadic: bool;
}

and lambda_def = {
Expand Down
3 changes: 3 additions & 0 deletions lang_php/pretty/ast_pp_build.ml
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ and lexical_var _env = function
A.p_ref = is_ref <> None;
A.p_name = dname name;
A.p_default = None;
A.p_variadic = false;
}

and scalar env = function
Expand Down Expand Up @@ -623,6 +624,7 @@ and hint_type env = function
failwith "no support for shape"
| HintTypeConst _ ->
failwith "no support for type consts"
| HintVariadic (_, hint) -> A.HintVariadic (Common.map_opt (hint_type env) hint)

and class_name_reference env a = expr env a

Expand Down Expand Up @@ -772,6 +774,7 @@ and parameter env p =
A.p_ref = p.p_ref <> None;
A.p_name = dname p.p_name;
A.p_default = opt static_scalar_affect env p.p_default;
A.p_variadic = p.p_variadic <> None;
}

and func_def env f =
Expand Down
Loading

0 comments on commit 65e4790

Please sign in to comment.