]> granicus.if.org Git - php/commitdiff
Support string interpolation
authorNikita Popov <nikic@php.net>
Sat, 21 Jun 2014 18:03:29 +0000 (20:03 +0200)
committerNikita Popov <nikic@php.net>
Sat, 21 Jun 2014 18:06:46 +0000 (20:06 +0200)
Zend/zend_ast.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y

index d789d909d2d8ca6238ca43ed6049daad84d8c26d..b1b9c17589d597545d5337337101957a231b9064 100644 (file)
@@ -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;
index 017967ec2318c78cbbd3f0c812102b80305a22c9..8397843ef12cd9130ec3d7df3c9347bcefb9eff3 100644 (file)
@@ -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 */);
        }
index 734c6779589888eb8bc6b05319c7e7d6b33607e3..6e66b9e9d66be4e66908c5d8228b58f1723cb015 100644 (file)
@@ -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);
index 1b6433ddff5c4c40c6dd1e005df4939a200ec5d2..40d887664c3a176ffc0941f561de6259dda49bd1 100644 (file)
@@ -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: