summaryrefslogtreecommitdiff
path: root/Zend/zend_language_parser.y
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2012-07-21 21:05:46 +0200
committerNikita Popov <nikic@php.net>2012-07-22 01:22:22 +0200
commit80748631aa1c4193cbc68f8854d82e7a57817fe2 (patch)
treeee081901714fba5399cd0aab9ac7f7ab9c8e79af /Zend/zend_language_parser.y
parent1f70a4c5fea97aa577aa5d9ee5f33d91d70e690d (diff)
downloadphp-git-80748631aa1c4193cbc68f8854d82e7a57817fe2.tar.gz
Require parenthesis around yield expressions
If yield is used in an expression context parenthesis are now required. This ensures that the code is unambiguos. Yield statements can still be used without parenthesis (which should be the most common case). Also yield expressions without value can be used without parenthesis, too (this should be the most common case for coroutines). If the yield expression is used in a context where parenthesis are required anyway, no additional parenthesis have to be inserted. Examples: // Statements don't need parenthesis yield $foo; yield $foo => $bar; // Yield without value doesn't need parenthesis either $data = yield; // Parentheses don't have to be duplicated foo(yield $bar); if (yield $bar) { ... } // But we have to use parentheses here $foo = (yield $bar); This commit also fixes an issue with by-ref passing of $foo[0] like variables. They previously weren't properly fetched for write. Additionally this fixes valgrind warnings which were caused by access to uninitialized memory in zend_is_function_or_method_call().
Diffstat (limited to 'Zend/zend_language_parser.y')
-rw-r--r--Zend/zend_language_parser.y91
1 files changed, 48 insertions, 43 deletions
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index b705d60d9a..e5f31b5d14 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -278,10 +278,10 @@ statement:
unticked_statement:
'{' inner_statement_list '}'
- | T_IF '(' expr ')' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } statement { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } elseif_list else_single { zend_do_if_end(TSRMLS_C); }
- | T_IF '(' expr ')' ':' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(TSRMLS_C); }
- | T_WHILE '(' { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' { zend_do_while_cond(&$4, &$5 TSRMLS_CC); } while_statement { zend_do_while_end(&$1, &$5 TSRMLS_CC); }
- | T_DO { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(TSRMLS_C); } statement T_WHILE '(' { $5.u.op.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' ';' { zend_do_do_while_end(&$1, &$5, &$7 TSRMLS_CC); }
+ | T_IF parenthesis_expr { zend_do_if_cond(&$2, &$1 TSRMLS_CC); } statement { zend_do_if_after_statement(&$1, 1 TSRMLS_CC); } elseif_list else_single { zend_do_if_end(TSRMLS_C); }
+ | T_IF parenthesis_expr ':' { zend_do_if_cond(&$2, &$1 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$1, 1 TSRMLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(TSRMLS_C); }
+ | T_WHILE { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); } parenthesis_expr { zend_do_while_cond(&$3, &$$ TSRMLS_CC); } while_statement { zend_do_while_end(&$1, &$4 TSRMLS_CC); }
+ | T_DO { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(TSRMLS_C); } statement T_WHILE { $4.u.op.opline_num = get_next_op_number(CG(active_op_array)); } parenthesis_expr ';' { zend_do_do_while_end(&$1, &$4, &$6 TSRMLS_CC); }
| T_FOR
'('
for_expr
@@ -291,7 +291,7 @@ unticked_statement:
for_expr
')' { zend_do_free(&$9 TSRMLS_CC); zend_do_for_before_statement(&$4, &$7 TSRMLS_CC); }
for_statement { zend_do_for_end(&$7 TSRMLS_CC); }
- | T_SWITCH '(' expr ')' { zend_do_switch_cond(&$3 TSRMLS_CC); } switch_case_list { zend_do_switch_end(&$6 TSRMLS_CC); }
+ | T_SWITCH parenthesis_expr { zend_do_switch_cond(&$2 TSRMLS_CC); } switch_case_list { zend_do_switch_end(&$4 TSRMLS_CC); }
| T_BREAK ';' { zend_do_brk_cont(ZEND_BRK, NULL TSRMLS_CC); }
| T_BREAK expr ';' { zend_do_brk_cont(ZEND_BRK, &$2 TSRMLS_CC); }
| T_CONTINUE ';' { zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); }
@@ -299,7 +299,7 @@ unticked_statement:
| T_RETURN ';' { zend_do_return(NULL, 0 TSRMLS_CC); }
| T_RETURN expr_without_variable ';' { zend_do_return(&$2, 0 TSRMLS_CC); }
| T_RETURN variable ';' { zend_do_return(&$2, 1 TSRMLS_CC); }
- | T_YIELD expr T_DOUBLE_ARROW expr ';' { zend_do_yield(&$$, &$4, &$2 TSRMLS_CC); }
+ | yield_expr ';' { $$ = $1; }
| T_GLOBAL global_var_list ';'
| T_STATIC static_var_list ';'
| T_ECHO echo_expr_list ';'
@@ -484,13 +484,13 @@ while_statement:
elseif_list:
/* empty */
- | elseif_list T_ELSEIF '(' expr ')' { zend_do_if_cond(&$4, &$5 TSRMLS_CC); } statement { zend_do_if_after_statement(&$5, 0 TSRMLS_CC); }
+ | elseif_list T_ELSEIF parenthesis_expr { zend_do_if_cond(&$3, &$2 TSRMLS_CC); } statement { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
;
new_elseif_list:
/* empty */
- | new_elseif_list T_ELSEIF '(' expr ')' ':' { zend_do_if_cond(&$4, &$5 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$5, 0 TSRMLS_CC); }
+ | new_elseif_list T_ELSEIF parenthesis_expr ':' { zend_do_if_cond(&$3, &$2 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
;
@@ -533,8 +533,9 @@ optional_class_type:
function_call_parameter_list:
- non_empty_function_call_parameter_list { $$ = $1; }
- | /* empty */ { Z_LVAL($$.u.constant) = 0; }
+ '(' ')' { Z_LVAL($$.u.constant) = 0; }
+ | '(' non_empty_function_call_parameter_list ')' { $$ = $2; }
+ | '(' yield_expr ')' { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$2, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); }
;
@@ -774,7 +775,7 @@ expr_without_variable:
| expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); }
| expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); }
| expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); }
- | '(' expr ')' { $$ = $2; }
+ | parenthesis_expr { $$ = $1; }
| new_expr { $$ = $1; }
| '(' new_expr ')' { $$ = $2; } instance_call { $$ = $5; }
| expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); }
@@ -797,8 +798,9 @@ expr_without_variable:
| combined_scalar { $$ = $1; }
| '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); }
| T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); }
- | T_YIELD { zend_do_yield(&$$, NULL, NULL TSRMLS_CC); }
- | T_YIELD expr { zend_do_yield(&$$, &$2, NULL TSRMLS_CC); }
+ | T_YIELD { zend_do_yield(&$$, NULL, NULL, 0 TSRMLS_CC); }
+ /*| T_YIELD expr_without_variable { zend_do_yield(&$$, &$2, NULL, 0 TSRMLS_CC); }
+ | T_YIELD variable { zend_do_yield(&$$, &$2, NULL, 1 TSRMLS_CC); }*/
| T_YIELD '*' expr { zend_do_delegate_yield(&$$, &$3 TSRMLS_CC); }
| function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); }
'(' parameter_list ')' lexical_vars
@@ -808,6 +810,13 @@ expr_without_variable:
'{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $4; }
;
+yield_expr:
+ T_YIELD expr_without_variable { zend_do_yield(&$$, &$2, NULL, 0 TSRMLS_CC); }
+ | T_YIELD variable { zend_do_yield(&$$, &$2, NULL, 1 TSRMLS_CC); }
+ | T_YIELD expr T_DOUBLE_ARROW expr_without_variable { zend_do_yield(&$$, &$4, &$2, 0 TSRMLS_CC); }
+ | T_YIELD expr T_DOUBLE_ARROW variable { zend_do_yield(&$$, &$4, &$2, 1 TSRMLS_CC); }
+;
+
combined_scalar_offset:
combined_scalar '[' dim_offset ']' { zend_do_begin_variable_parse(TSRMLS_C); fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
| combined_scalar_offset '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
@@ -834,30 +843,22 @@ lexical_var_list:
;
function_call:
- namespace_name '(' { $2.u.op.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); }
- function_call_parameter_list
- ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, $2.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
- | T_NAMESPACE T_NS_SEPARATOR namespace_name '(' { $1.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$1.u.constant); zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC); $4.u.op.opline_num = zend_do_begin_function_call(&$1, 0 TSRMLS_CC); }
- function_call_parameter_list
- ')' { zend_do_end_function_call(&$1, &$$, &$6, 0, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
- | T_NS_SEPARATOR namespace_name '(' { $3.u.op.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); }
- function_call_parameter_list
- ')' { zend_do_end_function_call(&$2, &$$, &$5, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
- | class_name T_PAAMAYIM_NEKUDOTAYIM variable_name '(' { $4.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); }
- function_call_parameter_list
- ')' { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, &$6, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
- | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); }
- function_call_parameter_list
- ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
- | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_name '(' { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); }
- function_call_parameter_list
- ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
- | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); }
- function_call_parameter_list
- ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
- | variable_without_objects '(' { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); }
- function_call_parameter_list ')'
- { zend_do_end_function_call(&$1, &$$, &$4, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
+ namespace_name { $$.u.op.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$3, 0, $2.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
+ | T_NAMESPACE T_NS_SEPARATOR namespace_name { $1.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$1.u.constant); zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC); $$.u.op.opline_num = zend_do_begin_function_call(&$1, 0 TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$5, 0, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
+ | T_NS_SEPARATOR namespace_name { $$.u.op.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call(&$2, &$$, &$4, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
+ | class_name T_PAAMAYIM_NEKUDOTAYIM variable_name { $$.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, &$5, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
+ | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call(NULL, &$$, &$5, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
+ | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_name { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call(NULL, &$$, &$5, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
+ | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call(NULL, &$$, &$5, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
+ | variable_without_objects { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$3, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
;
class_name:
@@ -902,7 +903,7 @@ dynamic_class_name_variable_property:
exit_expr:
/* empty */ { memset(&$$, 0, sizeof(znode)); $$.op_type = IS_UNUSED; }
| '(' ')' { memset(&$$, 0, sizeof(znode)); $$.op_type = IS_UNUSED; }
- | '(' expr ')' { $$ = $2; }
+ | parenthesis_expr { $$ = $1; }
;
backticks_expr:
@@ -913,8 +914,8 @@ backticks_expr:
ctor_arguments:
- /* empty */ { Z_LVAL($$.u.constant)=0; }
- | '(' function_call_parameter_list ')' { $$ = $2; }
+ /* empty */ { Z_LVAL($$.u.constant) = 0; }
+ | function_call_parameter_list { $$ = $1; }
;
@@ -986,6 +987,11 @@ expr:
| expr_without_variable { $$ = $1; }
;
+parenthesis_expr:
+ '(' expr ')' { $$ = $2; }
+ | '(' yield_expr ')' { $$ = $2; }
+;
+
r_variable:
variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; }
@@ -1025,9 +1031,8 @@ array_method_dereference:
;
method:
- '(' { zend_do_pop_object(&$1 TSRMLS_CC); zend_do_begin_method_call(&$1 TSRMLS_CC); }
- function_call_parameter_list ')'
- { zend_do_end_function_call(&$1, &$$, &$3, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
+ { zend_do_pop_object(&$$ TSRMLS_CC); zend_do_begin_method_call(&$$ TSRMLS_CC); }
+ function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$2, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
;
method_or_not: