From: Nikita Popov Date: Sat, 21 Jun 2014 18:03:29 +0000 (+0200) Subject: Support string interpolation X-Git-Tag: POST_AST_MERGE^2~193 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=90d36554e208cea9d5600d1a9bdee909002a2352;p=php Support string interpolation --- diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index d789d909d2..b1b9c17589 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -77,6 +77,8 @@ enum _zend_ast_kind { ZEND_AST_CONST, ZEND_AST_CLASS_CONST, ZEND_AST_RESOLVE_CLASS_NAME, + + ZEND_AST_ENCAPS_LIST, }; typedef unsigned short zend_ast_kind; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 017967ec23..8397843ef1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1155,58 +1155,6 @@ void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS } /* }}} */ -void zend_do_add_string(znode *result, znode *op1, znode *op2 TSRMLS_DC) /* {{{ */ -{ - zend_op *opline; - - if (Z_STRLEN(op2->u.constant) > 1) { - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_ADD_STRING; - } else if (Z_STRLEN(op2->u.constant) == 1) { - int ch = *Z_STRVAL(op2->u.constant); - - /* Free memory and use ZEND_ADD_CHAR in case of 1 character strings */ - STR_FREE(Z_STR(op2->u.constant)); - ZVAL_LONG(&op2->u.constant, ch); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_ADD_CHAR; - } else { /* String can be empty after a variable at the end of a heredoc */ - STR_FREE(Z_STR(op2->u.constant)); - return; - } - - if (op1) { - SET_NODE(opline->op1, op1); - SET_NODE(opline->result, op1); - } else { - SET_UNUSED(opline->op1); - opline->result_type = IS_TMP_VAR; - opline->result.var = get_temporary_variable(CG(active_op_array)); - } - SET_NODE(opline->op2, op2); - GET_NODE(result, opline->result); -} -/* }}} */ - -void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - opline->opcode = ZEND_ADD_VAR; - - if (op1) { - SET_NODE(opline->op1, op1); - SET_NODE(opline->result, op1); - } else { - SET_UNUSED(opline->op1); - opline->result_type = IS_TMP_VAR; - opline->result.var = get_temporary_variable(CG(active_op_array)); - } - SET_NODE(opline->op2, op2); - GET_NODE(result, opline->result); -} -/* }}} */ - void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */ { if (op1->op_type==IS_TMP_VAR) { @@ -7877,6 +7825,56 @@ void zend_compile_resolve_class_name(znode *result, zend_ast *ast TSRMLS_DC) { } } +void zend_compile_encaps_list(znode *result, zend_ast *ast TSRMLS_DC) { + zend_uint i; + + ZEND_ASSERT(ast->children > 0); + + result->op_type = IS_TMP_VAR; + result->u.op.var = get_temporary_variable(CG(active_op_array)); + + for (i = 0; i < ast->children; ++i) { + zend_ast *elem_ast = ast->child[i]; + znode elem_node; + zend_op *opline; + + zend_compile_expr(&elem_node, elem_ast TSRMLS_CC); + + if (elem_ast->kind == ZEND_CONST) { + zval *zv = &elem_node.u.constant; + ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING); + + if (Z_STRLEN_P(zv) > 1) { + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_ADD_STRING; + } else if (Z_STRLEN_P(zv) == 1) { + char ch = *Z_STRVAL_P(zv); + STR_RELEASE(Z_STR_P(zv)); + ZVAL_LONG(zv, ch); + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_ADD_CHAR; + } else { + /* String can be empty after a variable at the end of a heredoc */ + STR_RELEASE(Z_STR_P(zv)); + continue; + } + } else { + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_ADD_VAR; + ZEND_ASSERT(elem_node.op_type != IS_CONST); + } + + if (i == 0) { + SET_UNUSED(opline->op1); + } else { + SET_NODE(opline->op1, result); + } + SET_NODE(opline->op2, &elem_node); + SET_NODE(opline->result, result); + } +} + void zend_compile_stmt(zend_ast *ast TSRMLS_DC) { switch (ast->kind) { case ZEND_AST_GLOBAL: @@ -7992,6 +7990,9 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) { case ZEND_AST_RESOLVE_CLASS_NAME: zend_compile_resolve_class_name(result, ast TSRMLS_CC); return; + case ZEND_AST_ENCAPS_LIST: + zend_compile_encaps_list(result, ast TSRMLS_CC); + return; default: ZEND_ASSERT(0 /* not supported */); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 734c677958..6e66b9e9d6 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -506,9 +506,6 @@ void zend_check_writable_variable(const znode *variable); void zend_do_free(znode *op1 TSRMLS_DC); -void zend_do_add_string(znode *result, znode *op1, znode *op2 TSRMLS_DC); -void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC); - int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier); void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 1b6433ddff..40d887664c 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -940,7 +940,7 @@ backticks_expr: { zval empty_str; ZVAL_EMPTY_STRING(&empty_str); $$.u.ast = zend_ast_create_constant(&empty_str); } | T_ENCAPSED_AND_WHITESPACE { $$.u.ast = AST_ZVAL(&$1); } - | encaps_list { $$.u.ast = AST_ZNODE(&$1); } + | encaps_list { $$.u.ast = $1.u.ast; } ; @@ -1051,8 +1051,8 @@ scalar: Z_STR($2.u.constant) = Z_STR(tmp); $$.u.ast = zend_ast_create_unary(ZEND_AST_CONST, AST_ZVAL(&$2)); } | common_scalar { $$.u.ast = $1.u.ast; } - | '"' encaps_list '"' { $$ = $2; AZ($$); } - | T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; AZ($$); } + | '"' encaps_list '"' { $$.u.ast = $2.u.ast; } + | T_START_HEREDOC encaps_list T_END_HEREDOC { $$.u.ast = $2.u.ast; } | T_CLASS_C { if (Z_TYPE($1.u.constant) == IS_CONSTANT) {zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC); AZ($$); } else { $$.u.ast = AST_ZVAL(&$1); } } | dereferencable_scalar { $$.u.ast = $1.u.ast; } ; @@ -1207,12 +1207,14 @@ array_pair: encaps_list: encaps_list encaps_var - { AST_COMPILE(&$2, $2.u.ast); zend_do_add_variable(&$$, &$1, &$2 TSRMLS_CC); } - | encaps_list T_ENCAPSED_AND_WHITESPACE { zend_do_add_string(&$$, &$1, &$2 TSRMLS_CC); } - | encaps_var { AST_COMPILE(&$1, $1.u.ast); zend_do_add_variable(&$$, NULL, &$1 TSRMLS_CC); } + { $$.u.ast = zend_ast_dynamic_add($1.u.ast, $2.u.ast); } + | encaps_list T_ENCAPSED_AND_WHITESPACE + { $$.u.ast = zend_ast_dynamic_add($1.u.ast, AST_ZVAL(&$2)); } + | encaps_var + { $$.u.ast = zend_ast_create_dynamic_and_add(ZEND_AST_ENCAPS_LIST, $1.u.ast); } | T_ENCAPSED_AND_WHITESPACE encaps_var - { zend_do_add_string(&$$, NULL, &$1 TSRMLS_CC); - AST_COMPILE(&$2, $2.u.ast); zend_do_add_variable(&$$, &$$, &$2 TSRMLS_CC); } + { $$.u.ast = zend_ast_dynamic_add(zend_ast_create_dynamic_and_add( + ZEND_AST_ENCAPS_LIST, AST_ZVAL(&$1)), $2.u.ast); } ; encaps_var: