mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Port parameter defs
Has one bug re \self
This commit is contained in:
parent
47f0717a69
commit
1ee3277aba
@ -93,6 +93,10 @@ enum _zend_ast_kind {
|
||||
ZEND_AST_TRY,
|
||||
ZEND_AST_CATCH_LIST,
|
||||
ZEND_AST_CATCH,
|
||||
|
||||
ZEND_AST_PARAM_LIST,
|
||||
ZEND_AST_PARAM,
|
||||
ZEND_AST_TYPE,
|
||||
};
|
||||
|
||||
typedef unsigned short zend_ast_kind;
|
||||
|
@ -5361,10 +5361,16 @@ static zend_bool zend_can_write_to_variable(zend_ast *ast) {
|
||||
static zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) {
|
||||
zval *name;
|
||||
int fetch_type;
|
||||
|
||||
if (name_ast->kind != ZEND_AST_ZVAL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fully qualified names are always default refs */
|
||||
/*if (!name_ast->attr) {
|
||||
return 1;
|
||||
}*/
|
||||
|
||||
name = zend_ast_get_zval(name_ast);
|
||||
fetch_type = zend_get_class_fetch_type(Z_STRVAL_P(name), Z_STRLEN_P(name));
|
||||
return fetch_type == ZEND_FETCH_CLASS_DEFAULT;
|
||||
@ -6824,6 +6830,136 @@ void zend_compile_stmt_list(zend_ast *ast TSRMLS_DC) {
|
||||
}
|
||||
}
|
||||
|
||||
void zend_compile_params(zend_ast *ast TSRMLS_DC) {
|
||||
zend_uint i;
|
||||
zend_op_array *op_array = CG(active_op_array);
|
||||
zend_arg_info *arg_infos;
|
||||
|
||||
if (ast->children == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
arg_infos = safe_emalloc(sizeof(zend_arg_info), ast->children, 0);
|
||||
for (i = 0; i < ast->children; ++i) {
|
||||
zend_ast *param_ast = ast->child[i];
|
||||
zend_ast *type_ast = param_ast->child[0];
|
||||
zend_ast *var_ast = param_ast->child[1];
|
||||
zend_ast *default_ast = param_ast->child[2];
|
||||
zend_string *name = Z_STR_P(zend_ast_get_zval(var_ast));
|
||||
zend_bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
|
||||
zend_bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
|
||||
|
||||
znode var_node, default_node;
|
||||
zend_uchar opcode;
|
||||
zend_op *opline;
|
||||
zend_arg_info *arg_info;
|
||||
|
||||
if (zend_is_auto_global(name TSRMLS_CC)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s",
|
||||
name->val);
|
||||
}
|
||||
|
||||
var_node.op_type = IS_CV;
|
||||
var_node.u.op.var = lookup_cv(CG(active_op_array), STR_COPY(name) TSRMLS_CC);
|
||||
|
||||
if (name->len == sizeof("this") - 1 && !memcmp(name->val, "this", sizeof("this") - 1)) {
|
||||
if (op_array->scope && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
|
||||
}
|
||||
op_array->this_var = var_node.u.op.var;
|
||||
}
|
||||
|
||||
if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Only the last parameter can be variadic");
|
||||
}
|
||||
|
||||
if (is_variadic) {
|
||||
opcode = ZEND_RECV_VARIADIC;
|
||||
default_node.op_type = IS_UNUSED;
|
||||
op_array->fn_flags |= ZEND_ACC_VARIADIC;
|
||||
|
||||
if (default_ast) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"Variadic parameter cannot have a default value");
|
||||
}
|
||||
} else if (default_ast) {
|
||||
opcode = ZEND_RECV_INIT;
|
||||
default_node.op_type = IS_CONST;
|
||||
_tmp_compile_const_expr(&default_node.u.constant, default_ast TSRMLS_CC);
|
||||
} else {
|
||||
opcode = ZEND_RECV;
|
||||
default_node.op_type = IS_UNUSED;
|
||||
op_array->required_num_args = i + 1;
|
||||
}
|
||||
|
||||
opline = emit_op(NULL, opcode, NULL, &default_node TSRMLS_CC);
|
||||
SET_NODE(opline->result, &var_node);
|
||||
opline->op1.num = i + 1;
|
||||
|
||||
arg_info = &arg_infos[i];
|
||||
arg_info->name = estrndup(name->val, name->len);
|
||||
arg_info->name_len = name->len;
|
||||
arg_info->pass_by_reference = is_ref;
|
||||
arg_info->is_variadic = is_variadic;
|
||||
arg_info->type_hint = 0;
|
||||
arg_info->allow_null = 1;
|
||||
arg_info->class_name = NULL;
|
||||
arg_info->class_name_len = 0;
|
||||
|
||||
if (type_ast) {
|
||||
zend_bool has_null_default = default_ast
|
||||
&& (Z_TYPE(default_node.u.constant) == IS_NULL
|
||||
|| (Z_TYPE(default_node.u.constant) == IS_CONSTANT
|
||||
&& strcasecmp(Z_STRVAL(default_node.u.constant), "NULL"))
|
||||
|| Z_TYPE(default_node.u.constant) == IS_CONSTANT_AST); // ???
|
||||
|
||||
op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
|
||||
arg_info->allow_null = has_null_default;
|
||||
|
||||
if (type_ast->kind == ZEND_AST_TYPE) {
|
||||
arg_info->type_hint = type_ast->attr;
|
||||
if (arg_info->type_hint == IS_ARRAY) {
|
||||
if (default_ast && !has_null_default
|
||||
&& Z_TYPE(default_node.u.constant) != IS_ARRAY
|
||||
) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
|
||||
"with array type hint can only be an array or NULL");
|
||||
}
|
||||
} else if (arg_info->type_hint == IS_CALLABLE && default_ast) {
|
||||
if (default_ast && !has_null_default) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
|
||||
"with callable type hint can only be NULL");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zend_string *class_name = Z_STR_P(zend_ast_get_zval(type_ast));
|
||||
zend_bool is_fully_qualified = !type_ast->attr;
|
||||
|
||||
if (zend_is_const_default_class_ref(type_ast)) {
|
||||
class_name = zend_resolve_class_name(class_name, is_fully_qualified TSRMLS_CC);
|
||||
} else {
|
||||
STR_ADDREF(class_name);
|
||||
}
|
||||
|
||||
arg_info->type_hint = IS_OBJECT;
|
||||
arg_info->class_name = estrndup(class_name->val, class_name->len);
|
||||
arg_info->class_name_len = class_name->len;
|
||||
|
||||
STR_RELEASE(class_name);
|
||||
|
||||
if (default_ast && !has_null_default) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
|
||||
"with a class type hint can only be NULL");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* These are assigned at the end to avoid unitialized memory in case of an error */
|
||||
op_array->num_args = ast->children;
|
||||
op_array->arg_info = arg_infos;
|
||||
}
|
||||
|
||||
void zend_compile_binary_op(znode *result, zend_ast *ast TSRMLS_DC) {
|
||||
zend_ast *left_ast = ast->child[0];
|
||||
zend_ast *right_ast = ast->child[1];
|
||||
|
@ -661,6 +661,9 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC);
|
||||
#define ZEND_PARSED_NEW (1<<6)
|
||||
#define ZEND_PARSED_LIST_EXPR (1<<7)
|
||||
|
||||
#define ZEND_PARAM_REF (1<<0)
|
||||
#define ZEND_PARAM_VARIADIC (1<<1)
|
||||
|
||||
|
||||
/* unset types */
|
||||
#define ZEND_UNSET_REG 0
|
||||
|
@ -397,18 +397,18 @@ class_declaration_statement:
|
||||
|
||||
is_reference:
|
||||
/* empty */ { $$.op_type = 0; }
|
||||
| '&' { $$.op_type = 1; }
|
||||
| '&' { $$.op_type = ZEND_PARAM_REF; }
|
||||
;
|
||||
|
||||
is_variadic:
|
||||
/* empty */ { $$.op_type = 0; }
|
||||
| T_ELLIPSIS { $$.op_type = 1; }
|
||||
| T_ELLIPSIS { $$.op_type = ZEND_PARAM_VARIADIC; }
|
||||
;
|
||||
|
||||
unticked_function_declaration_statement:
|
||||
function is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); }
|
||||
'(' parameter_list ')'
|
||||
'{' inner_statement_list '}' { AS($9); zend_do_end_function_declaration(&$1 TSRMLS_CC); }
|
||||
'(' parameter_list ')' { zend_compile_params($6.u.ast TSRMLS_CC); zend_ast_destroy($6.u.ast); }
|
||||
'{' inner_statement_list '}' { AS($10); zend_do_end_function_declaration(&$1 TSRMLS_CC); }
|
||||
;
|
||||
|
||||
unticked_class_declaration_statement:
|
||||
@ -550,29 +550,33 @@ alt_if_stmt:
|
||||
;
|
||||
|
||||
parameter_list:
|
||||
non_empty_parameter_list
|
||||
| /* empty */
|
||||
non_empty_parameter_list { $$.u.ast = $1.u.ast; }
|
||||
| /* empty */ { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_PARAM_LIST); }
|
||||
;
|
||||
|
||||
|
||||
non_empty_parameter_list:
|
||||
parameter
|
||||
{ $$.u.ast = zend_ast_create_dynamic_and_add(ZEND_AST_PARAM_LIST, $1.u.ast); }
|
||||
| non_empty_parameter_list ',' parameter
|
||||
{ $$.u.ast = zend_ast_dynamic_add($1.u.ast, $3.u.ast); }
|
||||
;
|
||||
|
||||
parameter:
|
||||
optional_class_type is_reference is_variadic T_VARIABLE
|
||||
{ zend_do_receive_param(ZEND_RECV, &$4, NULL, &$1, $2.op_type, $3.op_type TSRMLS_CC); }
|
||||
| optional_class_type is_reference is_variadic T_VARIABLE '=' static_scalar
|
||||
{ zend_do_receive_param(ZEND_RECV_INIT, &$4, &$6, &$1, $2.op_type, $3.op_type TSRMLS_CC); }
|
||||
optional_type is_reference is_variadic T_VARIABLE
|
||||
{ $$.u.ast = zend_ast_create_ex(3, ZEND_AST_PARAM, $2.op_type | $3.op_type,
|
||||
$1.u.ast, AST_ZVAL(&$4), NULL); }
|
||||
| optional_type is_reference is_variadic T_VARIABLE '=' expr
|
||||
{ $$.u.ast = zend_ast_create_ex(3, ZEND_AST_PARAM, $2.op_type | $3.op_type,
|
||||
$1.u.ast, AST_ZVAL(&$4), $6.u.ast); }
|
||||
;
|
||||
|
||||
|
||||
optional_class_type:
|
||||
/* empty */ { $$.op_type = IS_UNUSED; }
|
||||
| T_ARRAY { $$.op_type = IS_CONST; Z_TYPE_INFO($$.u.constant)=IS_ARRAY; }
|
||||
| T_CALLABLE { $$.op_type = IS_CONST; Z_TYPE_INFO($$.u.constant)=IS_CALLABLE; }
|
||||
| fully_qualified_class_name { $$ = $1; }
|
||||
optional_type:
|
||||
/* empty */ { $$.u.ast = NULL; }
|
||||
| T_ARRAY { $$.u.ast = zend_ast_create_ex(0, ZEND_AST_TYPE, IS_ARRAY); }
|
||||
| T_CALLABLE { $$.u.ast = zend_ast_create_ex(0, ZEND_AST_TYPE, IS_CALLABLE); }
|
||||
| name { $$.u.ast = $1.u.ast; }
|
||||
;
|
||||
|
||||
argument_list:
|
||||
@ -629,8 +633,8 @@ class_statement:
|
||||
| class_constant_declaration ';'
|
||||
| trait_use_statement
|
||||
| method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); }
|
||||
'(' parameter_list ')'
|
||||
method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
|
||||
'(' parameter_list ')' { zend_compile_params($7.u.ast TSRMLS_CC); zend_ast_destroy($7.u.ast); }
|
||||
method_body { zend_do_abstract_method(&$4, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
|
||||
;
|
||||
|
||||
trait_use_statement:
|
||||
@ -870,11 +874,11 @@ expr_without_variable:
|
||||
| T_YIELD expr T_DOUBLE_ARROW expr
|
||||
{ $$.u.ast = zend_ast_create_binary(ZEND_YIELD, $4.u.ast, $2.u.ast); }
|
||||
| function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); }
|
||||
'(' parameter_list ')' lexical_vars
|
||||
'{' inner_statement_list '}' { AS($9); zend_do_end_function_declaration(&$1 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$3); }
|
||||
'(' parameter_list ')' { zend_compile_params($5.u.ast TSRMLS_CC); zend_ast_destroy($5.u.ast); } lexical_vars
|
||||
'{' inner_statement_list '}' { AS($10); zend_do_end_function_declaration(&$1 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$3); }
|
||||
| T_STATIC function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); }
|
||||
'(' parameter_list ')' lexical_vars
|
||||
'{' inner_statement_list '}' { AS($10); zend_do_end_function_declaration(&$2 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$4); }
|
||||
'(' parameter_list ')' { zend_compile_params($6.u.ast TSRMLS_CC); zend_ast_destroy($6.u.ast); } lexical_vars
|
||||
'{' inner_statement_list '}' { AS($11); zend_do_end_function_declaration(&$2 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$4); }
|
||||
;
|
||||
|
||||
function:
|
||||
|
Loading…
Reference in New Issue
Block a user