]> granicus.if.org Git - php/commitdiff
AST stage 2.4
authorNikita Popov <nikic@php.net>
Thu, 19 Jun 2014 11:57:29 +0000 (13:57 +0200)
committerNikita Popov <nikic@php.net>
Sat, 21 Jun 2014 16:54:13 +0000 (18:54 +0200)
Zend/tests/isset_func_error.phpt
Zend/zend_ast.c
Zend/zend_ast.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y
Zend/zend_opcode.c

index 7d1036def8e2a4d135c58b1163b3e4cf996756e8..7d6616b96d41692ec2ee9905286dcf38fb19ca07 100644 (file)
@@ -5,4 +5,4 @@ Error message for isset(func())
 isset(abc());
 ?>
 --EXPECTF--
-Fatal error: Cannot use isset() on the result of a function call (you can use "null !== func()" instead) in %s on line %d
+Fatal error: Cannot use isset() on the result of an expression (you can use "null !== expression" instead) in %s on line %d
index 98aca3c6af8144367da5ada52d58547f92390693..84243c2793edca3a42ab7c18625de7a3f87dc74b 100644 (file)
@@ -41,6 +41,15 @@ ZEND_API zend_ast *zend_ast_create_znode(znode *node)
        return (zend_ast *) ast;
 }
 
+ZEND_API zend_ast *zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr)
+{
+       zend_ast_zval *ast = emalloc(sizeof(zend_ast_zval));
+       ast->kind = ZEND_CONST;
+       ast->attr = attr;
+       ZVAL_COPY_VALUE(&ast->val, zv);
+       return (zend_ast *) ast;
+}
+
 ZEND_API zend_ast* zend_ast_create_unary_ex(zend_ast_kind kind, zend_ast_attr attr, zend_ast *op0)
 {
        zend_ast *ast = emalloc(sizeof(zend_ast));
index 83e1f64bd90fe1c13d6e22ae9356f771c6dc4ccd..cfe0ffae14870acde2d10876b22eb5a4e2800957 100644 (file)
@@ -53,8 +53,8 @@ enum _zend_ast_kind {
        ZEND_AST_PARAMS,
        ZEND_AST_UNPACK,
 
-       ZEND_AST_NAME,
-       ZEND_AST_NAME_FQ,
+       ZEND_AST_ASSIGN_OP,
+       ZEND_AST_BINARY_OP,
 
        ZEND_AST_AND,
        ZEND_AST_OR,
@@ -62,15 +62,21 @@ enum _zend_ast_kind {
        ZEND_AST_GREATER,
        ZEND_AST_GREATER_EQUAL,
 
-       ZEND_AST_CAST_NULL,
-       ZEND_AST_CAST_BOOL,
-       ZEND_AST_CAST_INT,
-       ZEND_AST_CAST_DOUBLE,
-       ZEND_AST_CAST_STRING,
-       ZEND_AST_CAST_ARRAY,
-       ZEND_AST_CAST_OBJECT,
+       ZEND_AST_CAST,
 
        ZEND_AST_CONDITIONAL,
+
+       ZEND_AST_EMPTY,
+       ZEND_AST_ISSET,
+
+       ZEND_AST_SILENCE,
+       ZEND_AST_SHELL_EXEC,
+       ZEND_AST_ARRAY,
+       ZEND_AST_ARRAY_ELEM,
+
+       ZEND_AST_CONST,
+       ZEND_AST_CLASS_CONST,
+       ZEND_AST_RESOLVE_CLASS_NAME,
 };
 
 typedef unsigned short zend_ast_kind;
@@ -95,6 +101,8 @@ static inline zval *zend_ast_get_zval(zend_ast *ast) {
 
 ZEND_API zend_ast *zend_ast_create_constant(zval *zv);
 
+ZEND_API zend_ast *zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr);
+
 ZEND_API zend_ast *zend_ast_create_unary_ex(
        zend_ast_kind kind, zend_ast_attr attr, zend_ast *op0);
 ZEND_API zend_ast *zend_ast_create_binary_ex(
@@ -113,6 +121,9 @@ ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *s
 ZEND_API zend_ast *zend_ast_copy(zend_ast *ast);
 ZEND_API void zend_ast_destroy(zend_ast *ast);
 
+static inline zend_ast *zend_ast_create_zval(zval *zv) {
+       return zend_ast_create_zval_ex(zv, 0);
+}
 static inline zend_ast *zend_ast_create_unary(zend_ast_kind kind, zend_ast *op0) {
        return zend_ast_create_unary_ex(kind, 0, op0);
 }
@@ -128,6 +139,12 @@ static inline zend_ast *zend_ast_create_ternary(
 static inline zend_ast *zend_ast_create_var(zval *name) {
        return zend_ast_create_unary(ZEND_AST_VAR, zend_ast_create_constant(name));
 }
+static inline zend_ast *zend_ast_create_binary_op(zend_uint opcode, zend_ast *op0, zend_ast *op1) {
+       return zend_ast_create_binary_ex(ZEND_AST_BINARY_OP, opcode, op0, op1);
+}
+static inline zend_ast *zend_ast_create_assign_op(zend_uint opcode, zend_ast *op0, zend_ast *op1) {
+       return zend_ast_create_binary_ex(ZEND_AST_ASSIGN_OP, opcode, op0, op1);
+}
 
 /* Temporary, for porting */
 #define AST_COMPILE(res, ast) do { \
index 4972ecc15cd3ef3e64c6502ab477901f1cf17fd9..9fc035e0d6cbc36e7c56a042ce827c205bb3ea78 100644 (file)
@@ -5637,6 +5637,8 @@ void zend_do_instanceof(znode *result, znode *expr, znode *class_znode, int type
 }
 /* }}} */
 
+static zend_bool zend_can_write_to_variable(zend_ast *ast);
+
 void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, znode *array, znode *as_token, int variable TSRMLS_DC) /* {{{ */
 {
        zend_op *opline;
@@ -5646,7 +5648,7 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno
        open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
        if (variable) {
                // TODO.AST or !zend_can_parse_variable_for_write(array TSRMLS_CC)
-               if (zend_is_call(array->u.ast)) {
+               if (zend_is_call(array->u.ast) || !zend_can_write_to_variable(array->u.ast)) {
                        is_variable = 0;
                        AST_COMPILE_VAR(array, array->u.ast, BP_VAR_R);
                } else {
@@ -5700,6 +5702,7 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno
 
 void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC);
 static void zend_compile_list_assign(znode *result, zend_ast *list_ast, znode *expr_node TSRMLS_DC);
+zend_op *zend_compile_assign_ref_common(znode *result, zend_ast *target_ast, znode *source_node TSRMLS_DC);
 
 void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token, const znode *as_token, znode *value, znode *key TSRMLS_DC) /* {{{ */
 {
@@ -5765,9 +5768,8 @@ void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token
                zend_ast_destroy(value->u.ast);
        } else {
                if (assign_by_ref) {
-                       zend_ast *assign_ast = zend_ast_create_binary(
-                               ZEND_AST_ASSIGN_REF, value->u.ast, AST_ZNODE(&value_node));
-                       AST_COMPILE(NULL, assign_ast);
+                       zend_compile_assign_ref_common(NULL, value->u.ast, &value_node TSRMLS_CC);
+                       zend_ast_destroy(value->u.ast);
                } else {
                        zend_ast *assign_ast = zend_ast_create_binary(
                                ZEND_AST_ASSIGN, value->u.ast, AST_ZNODE(&value_node));
@@ -6758,7 +6760,11 @@ static zend_op *emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, znode
        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
        opline->opcode = opcode;
 
-       SET_NODE(opline->op1, op1);
+       if (op1 == NULL) {
+               SET_UNUSED(opline->op1);
+       } else {
+               SET_NODE(opline->op1, op1);
+       }
 
        if (op2 == NULL) {
                SET_UNUSED(opline->op2);
@@ -6774,7 +6780,8 @@ static zend_op *emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, znode
 }
 
 static zend_bool zend_is_variable(zend_ast *ast) {
-       return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP
+       return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM
+               || ast->kind == ZEND_AST_PROP || ast->kind == ZEND_AST_STATIC_PROP
                || ast->kind == ZEND_AST_CALL || ast->kind == ZEND_AST_METHOD_CALL
                || ast->kind == ZEND_AST_STATIC_CALL;
 }
@@ -6785,6 +6792,14 @@ static zend_bool zend_is_call(zend_ast *ast) {
                || ast->kind == ZEND_AST_STATIC_CALL;
 }
 
+static zend_bool zend_can_write_to_variable(zend_ast *ast) {
+       while (ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP) {
+               ast = ast->child[0];
+       }
+
+       return zend_is_variable(ast);
+}
+
 static zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) {
        zval *name;
        int fetch_type;
@@ -6797,6 +6812,33 @@ static zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) {
        return fetch_type == ZEND_FETCH_CLASS_DEFAULT;
 }
 
+static zend_bool zend_is_compound_name(zval *name) {
+       return NULL != memchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name));
+}
+
+static void zend_handle_numeric_op2(zend_op *opline TSRMLS_DC) {
+       if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) {
+               ulong index;
+               int numeric = 0;
+
+               ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
+               if (numeric) {
+                       zval_dtor(&CONSTANT(opline->op2.constant));
+                       ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
+               }
+       }
+}
+
+static void zend_set_class_name_op1(zend_op *opline, znode *class_node TSRMLS_DC) {
+       if (class_node->op_type == IS_CONST) {
+               opline->op1_type = IS_CONST;
+               opline->op1.constant =
+                       zend_add_class_name_literal(CG(active_op_array), &class_node->u.constant TSRMLS_CC);
+       } else {
+               SET_NODE(opline->op1, class_node);
+       }
+}
+
 static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast TSRMLS_DC) {
        znode name_node;
        zend_op *opline;
@@ -6836,11 +6878,7 @@ static int zend_try_compile_cv(znode *result, zend_ast *ast TSRMLS_DC) {
        if (name_ast->kind == ZEND_CONST) {
                zend_string *name = zval_get_string(zend_ast_get_zval(name_ast));
 
-               if (zend_is_auto_global(name TSRMLS_CC) ||
-                   (CG(active_op_array)->last != 0 &&
-                    CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode == ZEND_BEGIN_SILENCE)
-               ) {
-                       // TODO.AST: handle ZEND_BEGIN_SILENCE properly
+               if (zend_is_auto_global(name TSRMLS_CC)) {
                        STR_RELEASE(name);
                        return FAILURE;
                }
@@ -6893,19 +6931,6 @@ static void zend_compile_simple_var(znode *result, zend_ast *ast, int type TSRML
        }
 }
 
-static void handle_numeric_op2(zend_op *opline TSRMLS_DC) {
-       if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) {
-               ulong index;
-               int numeric = 0;
-
-               ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
-               if (numeric) {
-                       zval_dtor(&CONSTANT(opline->op2.constant));
-                       ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
-               }
-       }
-}
-
 static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, int type TSRMLS_DC) {
        if (type != BP_VAR_R && type != BP_VAR_IS && zend_is_call(ast)) {
                zend_op *opline = emit_op(NULL, ZEND_SEPARATE, node, NULL TSRMLS_CC);
@@ -6937,7 +6962,7 @@ zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, int type TSRMLS_D
        zend_separate_if_call_and_write(&var_node, var_ast, type TSRMLS_CC);
 
        opline = emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node TSRMLS_CC);
-       handle_numeric_op2(opline TSRMLS_CC);
+       zend_handle_numeric_op2(opline TSRMLS_CC);
 
        return opline;
 }
@@ -6985,7 +7010,7 @@ void zend_compile_prop(znode *result, zend_ast *ast, int type TSRMLS_DC) {
        zend_adjust_for_fetch_type(opline, type);
 }
 
-void zend_compile_static_prop(znode *result, zend_ast *ast, int type TSRMLS_DC) {
+zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, int type TSRMLS_DC) {
        zend_ast *class_ast = ast->child[0];
        zend_ast *prop_ast = ast->child[1];
 
@@ -7002,7 +7027,6 @@ void zend_compile_static_prop(znode *result, zend_ast *ast, int type TSRMLS_DC)
        zend_compile_expr(&prop_node, prop_ast TSRMLS_CC);
 
        opline = emit_op(result, ZEND_FETCH_R, &prop_node, NULL TSRMLS_CC);
-       zend_adjust_for_fetch_type(opline, type);
        if (opline->op1_type == IS_CONST) {
                GET_POLYMORPHIC_CACHE_SLOT(opline->op1.constant);
        }
@@ -7014,6 +7038,13 @@ void zend_compile_static_prop(znode *result, zend_ast *ast, int type TSRMLS_DC)
                SET_NODE(opline->op2, &class_node);
        }
        opline->extended_value |= ZEND_FETCH_STATIC_MEMBER;
+
+       return opline;
+}
+
+void zend_compile_static_prop(znode *result, zend_ast *ast, zend_uint type TSRMLS_DC) {
+       zend_op *opline = zend_compile_static_prop_common(result, ast, type TSRMLS_CC);
+       zend_adjust_for_fetch_type(opline, type);
 }
 
 static zend_uchar get_list_fetch_opcode(zend_uchar op_type) {
@@ -7198,6 +7229,7 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast TSRMLS_DC) {
 void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) {
        zend_ast *var_ast = ast->child[0];
        zend_ast *expr_ast = ast->child[1];
+       zend_uint opcode = ast->attr;
 
        znode var_node, expr_node;
        zend_op *opline;
@@ -7208,11 +7240,11 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) {
        switch (var_ast->kind) {
                case ZEND_AST_VAR:
                        zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC);
-                       emit_op(result, ast->kind, &var_node, &expr_node TSRMLS_CC);
+                       emit_op(result, opcode, &var_node, &expr_node TSRMLS_CC);
                        return;
                case ZEND_AST_DIM:
                        opline = zend_compile_dim_common(result, var_ast, BP_VAR_RW TSRMLS_CC);
-                       opline->opcode = ast->kind;
+                       opline->opcode = opcode;
                        opline->extended_value = ZEND_ASSIGN_DIM;
 
                        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
@@ -7223,7 +7255,7 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) {
                        return;
                case ZEND_AST_PROP:
                        opline = zend_compile_prop_common(result, var_ast, BP_VAR_RW TSRMLS_CC);
-                       opline->opcode = ast->kind;
+                       opline->opcode = opcode;
                        opline->extended_value = ZEND_ASSIGN_OBJ;
 
                        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
@@ -7360,16 +7392,10 @@ zend_op *zend_compile_call_common(znode *result, zend_ast *params_ast, zend_func
 }
 
 zend_bool zend_compile_function_name(znode *name_node, zend_ast *name_ast TSRMLS_DC) {
-       zend_bool check_namespace;
-       char *is_compound;
-
-       zval *name = &name_node->u.constant;
-       ZVAL_COPY(name, zend_ast_get_zval(name_ast->child[0]));
-       name_node->op_type = IS_CONST;
-
-       check_namespace = name_ast->kind == ZEND_AST_NAME;
-       is_compound = memchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name));
+       zend_bool check_namespace = name_ast->attr;
+       zend_bool is_compound = zend_is_compound_name(zend_ast_get_zval(name_ast));
 
+       zend_compile_expr(name_node, name_ast TSRMLS_CC);
        zend_resolve_function_name(name_node, &check_namespace TSRMLS_CC);
 
        return check_namespace && Z_TYPE(CG(current_namespace)) != IS_UNDEF && !is_compound;
@@ -7421,7 +7447,7 @@ void zend_compile_call(znode *result, zend_ast *ast, int type TSRMLS_DC) {
 
        znode name_node;
 
-       if (name_ast->kind != ZEND_AST_NAME && name_ast->kind != ZEND_AST_NAME_FQ) {
+       if (name_ast->kind != ZEND_CONST) {
                zend_compile_expr(&name_node, name_ast TSRMLS_CC);
                zend_compile_dynamic_call(result, &name_node, params_ast TSRMLS_CC);
                return;
@@ -7536,13 +7562,7 @@ void zend_compile_static_call(znode *result, zend_ast *ast, int type TSRMLS_DC)
        opline->result.num = CG(context).nested_calls;
        opline->extended_value = extended_value;
 
-       if (class_node.op_type == IS_CONST) {
-               opline->op1_type = IS_CONST;
-               opline->op1.constant =
-                       zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
-       } else {
-               SET_NODE(opline->op1, &class_node);
-       }
+       zend_set_class_name_op1(opline, &class_node TSRMLS_CC);
 
        if (method_node.op_type == IS_CONST) {
                opline->op2_type = IS_CONST;
@@ -7623,7 +7643,7 @@ void zend_compile_unset(zend_ast *ast TSRMLS_DC) {
        zend_op *opline;
        switch (var_ast->kind) {
                case ZEND_AST_VAR:
-                       if (zend_try_compile_cv(&var_node, ast TSRMLS_CC) == SUCCESS) {
+                       if (zend_try_compile_cv(&var_node, var_ast TSRMLS_CC) == SUCCESS) {
                                opline = emit_op(NULL, ZEND_UNSET_VAR, &var_node, NULL TSRMLS_CC);
                                opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
                        } else {
@@ -7639,6 +7659,10 @@ void zend_compile_unset(zend_ast *ast TSRMLS_DC) {
                        opline = zend_compile_prop_common(NULL, var_ast, BP_VAR_UNSET TSRMLS_CC);
                        opline->opcode = ZEND_UNSET_OBJ;
                        return;
+               case ZEND_AST_STATIC_PROP:
+                       opline = zend_compile_static_prop_common(NULL, var_ast, BP_VAR_UNSET TSRMLS_CC);
+                       opline->opcode = ZEND_UNSET_VAR;
+                       return;
                EMPTY_SWITCH_DEFAULT_CASE()
        }
 }
@@ -7646,12 +7670,13 @@ void zend_compile_unset(zend_ast *ast TSRMLS_DC) {
 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];
+       zend_uint opcode = ast->attr;
 
        znode left_node, right_node;
        zend_compile_expr(&left_node, left_ast TSRMLS_CC);
        zend_compile_expr(&right_node, right_ast TSRMLS_CC);
 
-       emit_op_tmp(result, ast->kind, &left_node, &right_node TSRMLS_CC);
+       emit_op_tmp(result, opcode, &left_node, &right_node TSRMLS_CC);
 }
 
 /* We do not use zend_compile_binary_op for this because we want to retain the left-to-right
@@ -7772,16 +7797,7 @@ void zend_compile_cast(znode *result, zend_ast *ast TSRMLS_DC) {
        zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
 
        opline = emit_op(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC);
-       switch (ast->kind) {
-               case ZEND_AST_CAST_NULL:   opline->extended_value = IS_NULL; break;
-               case ZEND_AST_CAST_BOOL:   opline->extended_value = _IS_BOOL; break;
-               case ZEND_AST_CAST_INT:    opline->extended_value = IS_LONG; break;
-               case ZEND_AST_CAST_DOUBLE: opline->extended_value = IS_DOUBLE; break;
-               case ZEND_AST_CAST_STRING: opline->extended_value = IS_STRING; break;
-               case ZEND_AST_CAST_ARRAY:  opline->extended_value = IS_ARRAY; break;
-               case ZEND_AST_CAST_OBJECT: opline->extended_value = IS_OBJECT; break;
-               EMPTY_SWITCH_DEFAULT_CASE()
-       }
+       opline->extended_value = ast->attr;
 }
 
 static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast TSRMLS_DC) {
@@ -7944,6 +7960,356 @@ void zend_compile_instanceof(znode *result, zend_ast *ast TSRMLS_DC) {
        emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, &class_node TSRMLS_CC);
 }
 
+void zend_compile_include_or_eval(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+       znode expr_node;
+       zend_op *opline;
+
+       zend_do_extended_fcall_begin(TSRMLS_C);
+       zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+
+       opline = emit_op(result, ZEND_INCLUDE_OR_EVAL, &expr_node, NULL TSRMLS_CC);
+       opline->extended_value = ast->attr;
+
+       zend_do_extended_fcall_end(TSRMLS_C);
+}
+
+void zend_compile_isset_or_empty(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *var_ast = ast->child[0];
+
+       znode var_node;
+       zend_op *opline;
+
+       ZEND_ASSERT(ast->kind == ZEND_AST_ISSET || ast->kind == ZEND_AST_EMPTY);
+
+       if (!zend_is_variable(var_ast) || zend_is_call(var_ast)) {
+               if (ast->kind == ZEND_AST_EMPTY) {
+                       /* empty(expr) can be transformed to !expr */
+                       zend_ast *not_ast = zend_ast_create_unary(ZEND_BOOL_NOT, var_ast);
+                       zend_compile_expr(result, not_ast TSRMLS_CC);
+                       efree(not_ast);
+                       return;
+               } else {
+                       zend_error_noreturn(E_COMPILE_ERROR,
+                               "Cannot use isset() on the result of an expression "
+                               "(you can use \"null !== expression\" instead)");
+               }
+       }
+
+       switch (var_ast->kind) {
+               case ZEND_AST_VAR:
+                       if (zend_try_compile_cv(&var_node, var_ast TSRMLS_CC) == SUCCESS) {
+                               opline = emit_op(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL TSRMLS_CC);
+                               opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
+                       } else {
+                               opline = zend_compile_simple_var_no_cv(result, var_ast, BP_VAR_IS TSRMLS_CC);
+                               opline->opcode = ZEND_ISSET_ISEMPTY_VAR;
+                       }
+                       break;
+               case ZEND_AST_DIM:
+                       opline = zend_compile_dim_common(result, var_ast, BP_VAR_IS TSRMLS_CC);
+                       opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ;
+                       break;
+               case ZEND_AST_PROP:
+                       opline = zend_compile_prop_common(result, var_ast, BP_VAR_IS TSRMLS_CC);
+                       opline->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ;
+                       break;
+               case ZEND_AST_STATIC_PROP:
+                       opline = zend_compile_static_prop_common(result, var_ast, BP_VAR_IS TSRMLS_CC);
+                       opline->opcode = ZEND_ISSET_ISEMPTY_VAR;
+                       break;
+               EMPTY_SWITCH_DEFAULT_CASE()
+       }
+
+       opline->result_type = IS_TMP_VAR;
+       opline->extended_value |= ast->kind == ZEND_AST_ISSET ? ZEND_ISSET : ZEND_ISEMPTY;
+}
+
+void zend_compile_silence(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+       znode silence_node;
+
+       emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL TSRMLS_CC);
+
+       if (expr_ast->kind == ZEND_AST_VAR) {
+               /* For @$var we need to force a FETCH instruction, otherwise the CV access will
+                * happen outside the silenced section. */
+               zend_compile_simple_var_no_cv(result, expr_ast, BP_VAR_R TSRMLS_CC);
+       } else {
+               zend_compile_expr(result, expr_ast TSRMLS_CC);
+       }
+
+       emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL TSRMLS_CC);
+}
+
+void zend_compile_shell_exec(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+
+       zval fn_name;
+       zend_ast *name_ast, *params_ast, *call_ast;
+
+       ZVAL_STRING(&fn_name, "shell_exec");
+       name_ast = zend_ast_create_zval(&fn_name);
+       params_ast = zend_ast_create_dynamic(ZEND_AST_PARAMS);
+       zend_ast_dynamic_add(&params_ast, expr_ast);
+       call_ast = zend_ast_create_binary(ZEND_AST_CALL, name_ast, params_ast);
+
+       zend_compile_expr(result, call_ast TSRMLS_CC);
+
+       efree(call_ast);
+       efree(params_ast);
+       zend_ast_destroy(name_ast);
+}
+
+int zend_try_ct_compile_array(zval *array, zend_ast *ast TSRMLS_DC) {
+       zend_uint i;
+
+       ZVAL_UNDEF(array);
+       for (i = 0; i < ast->children; ++i) {
+               zend_ast *elem_ast = ast->child[i];
+               zend_ast *value_ast = elem_ast->child[0];
+               zend_ast *key_ast = elem_ast->child[1];
+               zend_bool by_ref = elem_ast->attr;
+
+               znode key_node, value_node;
+               zval *key = &key_node.u.constant, *value = &value_node.u.constant;
+
+               if (by_ref) {
+                       goto failure;
+               }
+
+               if (FAILURE == zend_compile_expr_maybe_ct(&value_node, value_ast, 1 TSRMLS_CC)) {
+                       goto failure;
+               }
+
+               if (key_ast) {
+                       if (FAILURE == zend_compile_expr_maybe_ct(&key_node, key_ast, 1 TSRMLS_CC)) {
+                               zval_ptr_dtor(value);
+                               goto failure;
+                       }
+               }
+
+               if (Z_TYPE_P(array) == IS_UNDEF) {
+                       array_init_size(array, ast->children);
+               }
+
+               if (key_ast) {
+                       switch (Z_TYPE_P(key)) {
+                               case IS_LONG:
+                                       zend_hash_index_update(Z_ARRVAL_P(array), Z_LVAL_P(key), value);
+                                       break;
+                               case IS_STRING:
+                                       zend_symtable_update(Z_ARRVAL_P(array), Z_STR_P(key), value);
+                                       break;
+                               case IS_DOUBLE:
+                                       zend_hash_index_update(Z_ARRVAL_P(array),
+                                               zend_dval_to_lval(Z_DVAL_P(key)), value);
+                                       break;
+                               case IS_FALSE:
+                                       zend_hash_index_update(Z_ARRVAL_P(array), 0, value);
+                                       break;
+                               case IS_TRUE:
+                                       zend_hash_index_update(Z_ARRVAL_P(array), 1, value);
+                                       break;
+                               case IS_NULL:
+                                       zend_hash_update(Z_ARRVAL_P(array), STR_EMPTY_ALLOC(), value);
+                                       break;
+                               default:
+                                       zend_error(E_COMPILE_ERROR, "Illegal offset type");
+                                       break;
+                       }
+                       zval_ptr_dtor(key);
+               } else {
+                       zend_hash_next_index_insert(Z_ARRVAL_P(array), value);
+               }
+       }
+
+       if (!ast->children) {
+               array_init(array);
+       }
+
+       zend_make_immutable_array(array TSRMLS_CC);
+       return SUCCESS;
+
+failure:
+       zval_dtor(array);
+       return FAILURE;
+}
+
+int zend_compile_array_maybe_ct(znode *result, zend_ast *ast, zend_bool ct_required TSRMLS_DC) {
+       zend_op *opline;
+       zend_uint i, opnum_init;
+       zend_bool packed = 1;
+
+       zval array;
+
+       if (SUCCESS == zend_try_ct_compile_array(&array, ast TSRMLS_CC)) {
+               result->op_type = IS_CONST;
+               ZVAL_COPY_VALUE(&result->u.constant, &array);
+               return SUCCESS;
+       } else if (ct_required) {
+               return FAILURE;
+       }
+
+       opnum_init = get_next_op_number(CG(active_op_array));
+
+       for (i = 0; i < ast->children; ++i) {
+               zend_ast *elem_ast = ast->child[i];
+               zend_ast *value_ast = elem_ast->child[0];
+               zend_ast *key_ast = elem_ast->child[1];
+               zend_bool by_ref = elem_ast->attr;
+
+               znode value_node, key_node, *key_node_ptr = NULL;
+
+               if (key_ast) {
+                       zend_compile_expr(&key_node, key_ast TSRMLS_CC);
+                       key_node_ptr = &key_node;
+               }
+
+               if (by_ref) {
+                       zend_ensure_writable_variable(value_ast);
+                       zend_compile_var(&value_node, value_ast, BP_VAR_W TSRMLS_CC);
+               } else {
+                       zend_compile_expr(&value_node, value_ast TSRMLS_CC);
+               }
+
+               if (i == 0) {
+                       opline = emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr TSRMLS_CC);
+                       opline->extended_value = ast->children << ZEND_ARRAY_SIZE_SHIFT;
+               } else {
+                       opline = emit_op(NULL, ZEND_ADD_ARRAY_ELEMENT, &value_node, key_node_ptr TSRMLS_CC);
+                       SET_NODE(opline->result, result);
+               }
+               opline->extended_value |= by_ref;
+
+               if (key_ast) {
+                       if (key_node.op_type == IS_CONST && Z_TYPE(key_node.u.constant) == IS_STRING) {
+                               zend_handle_numeric_op2(opline TSRMLS_CC);
+                               packed = 0;
+                       }
+               }
+       }
+
+       /* Handle empty array */
+       if (!ast->children) {
+               emit_op_tmp(result, ZEND_INIT_ARRAY, NULL, NULL TSRMLS_CC);
+       }
+
+       /* Add a flag to INIT_ARRAY if we know this array cannot be packed */
+       if (!packed) {
+               opline = &CG(active_op_array)->opcodes[opnum_init];
+               opline->extended_value |= ZEND_ARRAY_NOT_PACKED;
+       }
+
+       return FAILURE;
+}
+
+void zend_compile_const(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *name_ast = ast->child[0];
+       zend_bool check_namespace = name_ast->attr;
+
+       zend_bool is_compound = zend_is_compound_name(zend_ast_get_zval(name_ast));
+       znode name_node;
+       zend_op *opline;
+
+       zend_compile_expr(&name_node, name_ast TSRMLS_CC);
+       zend_resolve_const_name(&name_node, &check_namespace TSRMLS_CC);
+
+       if (zend_constant_ct_subst(result, &name_node.u.constant, 1 TSRMLS_CC)) {
+               return;
+       }
+
+       opline = emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL TSRMLS_CC);
+       opline->op2_type = IS_CONST;
+
+       if (is_compound) {
+               /* the name is unambiguous */
+               opline->op2.constant = zend_add_const_name_literal(
+                       CG(active_op_array), &name_node.u.constant, 0 TSRMLS_CC);
+       } else {
+               opline->extended_value = IS_CONSTANT_UNQUALIFIED;
+               if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) {
+                       opline->extended_value |= IS_CONSTANT_IN_NAMESPACE;
+                       opline->op2.constant = zend_add_const_name_literal(
+                               CG(active_op_array), &name_node.u.constant, 1 TSRMLS_CC);
+               } else {
+                       opline->op2.constant = zend_add_const_name_literal(
+                               CG(active_op_array), &name_node.u.constant, 0 TSRMLS_CC);
+               }
+       }
+       GET_CACHE_SLOT(opline->op2.constant);
+}
+
+void zend_compile_class_const(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *class_ast = ast->child[0];
+       zend_ast *const_ast = ast->child[1];
+
+       znode class_node, const_node;
+       zend_op *opline;
+
+       if (zend_is_const_default_class_ref(class_ast)) {
+               zend_compile_expr(&class_node, class_ast TSRMLS_CC);
+               zend_resolve_class_name(&class_node TSRMLS_CC);
+       } else {
+               zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
+       }
+
+       zend_compile_expr(&const_node, const_ast TSRMLS_CC);
+
+       opline = emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, &const_node TSRMLS_CC);
+
+       zend_set_class_name_op1(opline, &class_node TSRMLS_CC);
+
+       if (opline->op1_type == IS_CONST) {
+               GET_CACHE_SLOT(opline->op2.constant);
+       } else {
+               GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant);
+       }
+}
+
+void zend_compile_resolve_class_name(znode *result, zend_ast *ast TSRMLS_DC) {
+       zend_ast *name_ast = ast->child[0];
+       zval *name = zend_ast_get_zval(name_ast);
+       int fetch_type = zend_get_class_fetch_type(Z_STRVAL_P(name), Z_STRLEN_P(name));
+
+       switch (fetch_type) {
+               case ZEND_FETCH_CLASS_SELF:
+                       if (!CG(active_class_entry)) {
+                               zend_error_noreturn(E_COMPILE_ERROR,
+                                       "Cannot access self::class when no class scope is active");
+                       }
+                       result->op_type = IS_CONST;
+                       ZVAL_STR(&result->u.constant, STR_COPY(CG(active_class_entry)->name));
+                       break;
+        case ZEND_FETCH_CLASS_STATIC:
+        case ZEND_FETCH_CLASS_PARENT:
+                       if (!CG(active_class_entry)) {
+                               zend_error_noreturn(E_COMPILE_ERROR,
+                                       "Cannot access %s::class when no class scope is active",
+                                       fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent");
+                       } else {
+                               zval class_str_zv;
+                               zend_ast *class_str_ast, *class_const_ast;
+
+                               ZVAL_STRING(&class_str_zv, "class");
+                               class_str_ast = zend_ast_create_zval(&class_str_zv);
+                               class_const_ast = zend_ast_create_binary(
+                                       ZEND_AST_CLASS_CONST, name_ast, class_str_ast);
+
+                               zend_compile_expr(result, class_const_ast TSRMLS_CC);
+
+                               zend_ast_destroy(class_str_ast);
+                               efree(class_const_ast);
+                       }
+                       break;
+               case ZEND_FETCH_CLASS_DEFAULT:
+                       zend_compile_expr(result, name_ast TSRMLS_CC);
+                       zend_resolve_class_name(result TSRMLS_CC);
+                       break;
+               EMPTY_SWITCH_DEFAULT_CASE()
+       }
+}
+
 void zend_compile_stmt(zend_ast *ast TSRMLS_DC) {
        switch (ast->kind) {
                case ZEND_AST_GLOBAL:
@@ -7986,39 +8352,10 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) {
                case ZEND_CLONE:
                        zend_compile_clone(result, ast TSRMLS_CC);
                        return;
-               case ZEND_ASSIGN_ADD:
-               case ZEND_ASSIGN_SUB:
-               case ZEND_ASSIGN_MUL:
-               case ZEND_ASSIGN_POW:
-               case ZEND_ASSIGN_DIV:
-               case ZEND_ASSIGN_CONCAT:
-               case ZEND_ASSIGN_MOD:
-               case ZEND_ASSIGN_BW_AND:
-               case ZEND_ASSIGN_BW_OR:
-               case ZEND_ASSIGN_BW_XOR:
-               case ZEND_ASSIGN_SL:
-               case ZEND_ASSIGN_SR:
+               case ZEND_AST_ASSIGN_OP:
                        zend_compile_compound_assign(result, ast TSRMLS_CC);
                        return;
-               case ZEND_BOOL_XOR:
-               case ZEND_BW_OR:
-               case ZEND_BW_AND:
-               case ZEND_BW_XOR:
-               case ZEND_CONCAT:
-               case ZEND_ADD:
-               case ZEND_SUB:
-               case ZEND_MUL:
-               case ZEND_POW:
-               case ZEND_DIV:
-               case ZEND_MOD:
-               case ZEND_SL:
-               case ZEND_SR:
-               case ZEND_IS_IDENTICAL:
-               case ZEND_IS_NOT_IDENTICAL:
-               case ZEND_IS_EQUAL:
-               case ZEND_IS_NOT_EQUAL:
-               case ZEND_IS_SMALLER:
-               case ZEND_IS_SMALLER_OR_EQUAL:
+               case ZEND_AST_BINARY_OP:
                        zend_compile_binary_op(result, ast TSRMLS_CC);
                        return;
                case ZEND_AST_GREATER:
@@ -8045,13 +8382,7 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) {
                case ZEND_PRE_DEC:
                        zend_compile_pre_incdec(result, ast TSRMLS_CC);
                        return;
-               case ZEND_AST_CAST_NULL:
-               case ZEND_AST_CAST_BOOL:
-               case ZEND_AST_CAST_INT:
-               case ZEND_AST_CAST_DOUBLE:
-               case ZEND_AST_CAST_STRING:
-               case ZEND_AST_CAST_ARRAY:
-               case ZEND_AST_CAST_OBJECT:
+               case ZEND_AST_CAST:
                        zend_compile_cast(result, ast TSRMLS_CC);
                        return;
                case ZEND_AST_CONDITIONAL:
@@ -8069,11 +8400,52 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) {
                case ZEND_INSTANCEOF:
                        zend_compile_instanceof(result, ast TSRMLS_CC);
                        return;
+               case ZEND_INCLUDE_OR_EVAL:
+                       zend_compile_include_or_eval(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_ISSET:
+               case ZEND_AST_EMPTY:
+                       zend_compile_isset_or_empty(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_SILENCE:
+                       zend_compile_silence(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_SHELL_EXEC:
+                       zend_compile_shell_exec(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_ARRAY:
+                       zend_compile_array_maybe_ct(result, ast, 0 TSRMLS_CC);
+                       return;
+               case ZEND_AST_CONST:
+                       zend_compile_const(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_CLASS_CONST:
+                       zend_compile_class_const(result, ast TSRMLS_CC);
+                       return;
+               case ZEND_AST_RESOLVE_CLASS_NAME:
+                       zend_compile_resolve_class_name(result, ast TSRMLS_CC);
+                       return;
                default:
                        ZEND_ASSERT(0 /* not supported */);
        }
 }
 
+int zend_compile_expr_maybe_ct(znode *result, zend_ast *ast, zend_bool ct_required TSRMLS_DC) {
+       switch (ast->kind) {
+               case ZEND_CONST:
+                       ZVAL_COPY(&result->u.constant, zend_ast_get_zval(ast));
+                       result->op_type = IS_CONST;
+                       return SUCCESS;
+               case ZEND_AST_ARRAY:
+                       return zend_compile_array_maybe_ct(result, ast, ct_required TSRMLS_CC);
+               default:
+                       if (!ct_required) {
+                               zend_compile_expr(result, ast TSRMLS_CC);
+                       }
+                       return FAILURE;
+       }
+}
+
 void zend_compile_var(znode *result, zend_ast *ast, int type TSRMLS_DC) {
        switch (ast->kind) {
                case ZEND_AST_VAR:
@@ -8098,7 +8470,16 @@ void zend_compile_var(znode *result, zend_ast *ast, int type TSRMLS_DC) {
                        zend_compile_static_call(result, ast, type TSRMLS_CC);
                        return;
                default:
-                       // TODO.AST check writable
+                       if (type == BP_VAR_W || type == BP_VAR_REF
+                               || type == BP_VAR_RW || type == BP_VAR_UNSET
+                       ) {
+                               /* For BC reasons =& new Foo is allowed */
+                               if (type != BP_VAR_REF || ast->kind != ZEND_NEW) {
+                                       zend_error_noreturn(E_COMPILE_ERROR,
+                                               "Cannot use temporary expression in write context");
+                               }
+                       }
+
                        zend_compile_expr(result, ast TSRMLS_CC);
                        return;
        }
index d375cf7adde671e8e65cf9e63ba93915c907bd9b..86e552bc1a576c83aaf20a7154d5e985beacf681 100644 (file)
@@ -102,6 +102,7 @@ static inline znode *zend_ast_get_znode(zend_ast *ast) {
 void zend_ensure_writable_variable(const zend_ast *ast);
 void zend_compile_stmt(zend_ast *ast TSRMLS_DC);
 void zend_compile_expr(znode *node, zend_ast *ast TSRMLS_DC);
+int zend_compile_expr_maybe_ct(znode *node, zend_ast *ast, zend_bool ct_required TSRMLS_DC);
 void zend_compile_var(znode *node, zend_ast *ast, int type TSRMLS_DC);
 
 typedef struct _zend_execute_data zend_execute_data;
index 540bd205127a2ece02aef932ae94fd3596a2c05c..94fa29727be9d688dcfbab296910c381a57ecab1 100644 (file)
@@ -312,10 +312,10 @@ statement:
 
 unticked_statement:
                '{' inner_statement_list '}'
-       |       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_IF parenthesis_expr { AC($2); 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 ':' { AC($2); 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 { AC($3); 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 ';' { AC($6); zend_do_do_while_end(&$1, &$4, &$6 TSRMLS_CC); }
        |       T_FOR
                        '('
                                for_expr
@@ -325,7 +325,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 parenthesis_expr       { zend_do_switch_cond(&$2 TSRMLS_CC); } switch_case_list { zend_do_switch_end(&$4 TSRMLS_CC); }
+       |       T_SWITCH parenthesis_expr       { AC($2); 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 ';'                { AC($2); zend_do_brk_cont(ZEND_BRK, &$2 TSRMLS_CC); }
        |       T_CONTINUE ';'                  { zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); }
@@ -529,13 +529,13 @@ while_statement:
 
 elseif_list:
                /* empty */
-       |       elseif_list T_ELSEIF parenthesis_expr { zend_do_if_cond(&$3, &$2 TSRMLS_CC); } statement { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
+       |       elseif_list T_ELSEIF parenthesis_expr { AC($3); 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 parenthesis_expr ':' { zend_do_if_cond(&$3, &$2 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
+       |       new_elseif_list T_ELSEIF parenthesis_expr ':' { AC($3); zend_do_if_cond(&$3, &$2 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
 ;
 
 
@@ -593,7 +593,7 @@ non_empty_function_call_parameter_list:
 function_call_parameter:
                expr_without_variable   { $$.u.ast = $1.u.ast; }
        |       variable                                { $$.u.ast = $1.u.ast; }
-       |       '&' w_variable                  { /* ERROR */ ZEND_ASSERT(0); }
+       /*|     '&' variable                    { ZEND_ASSERT(0); } */
        |       T_ELLIPSIS expr                 { $$.u.ast = zend_ast_create_unary(ZEND_AST_UNPACK, $2.u.ast); }
 ;
 
@@ -764,29 +764,29 @@ expr_without_variable:
                              zend_ast_create_binary(ZEND_NEW, $5.u.ast, $6.u.ast)); }
        |       T_CLONE expr { $$.u.ast = zend_ast_create_unary(ZEND_CLONE, $2.u.ast); }
        |       variable T_PLUS_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_ADD, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_ADD, $1.u.ast, $3.u.ast); }
        |       variable T_MINUS_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SUB, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_SUB, $1.u.ast, $3.u.ast); }
        |       variable T_MUL_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_MUL, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_MUL, $1.u.ast, $3.u.ast); }
        |       variable T_POW_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_POW, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_POW, $1.u.ast, $3.u.ast); }
        |       variable T_DIV_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_DIV, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_DIV, $1.u.ast, $3.u.ast); }
        |       variable T_CONCAT_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_CONCAT, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_CONCAT, $1.u.ast, $3.u.ast); }
        |       variable T_MOD_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_MOD, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_MOD, $1.u.ast, $3.u.ast); }
        |       variable T_AND_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_AND, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_BW_AND, $1.u.ast, $3.u.ast); }
        |       variable T_OR_EQUAL expr 
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_OR, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_BW_OR, $1.u.ast, $3.u.ast); }
        |       variable T_XOR_EQUAL expr 
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_XOR, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_BW_XOR, $1.u.ast, $3.u.ast); }
        |       variable T_SL_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SL, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_SL, $1.u.ast, $3.u.ast); }
        |       variable T_SR_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SR, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_SR, $1.u.ast, $3.u.ast); }
        |       variable T_INC { $$.u.ast = zend_ast_create_unary(ZEND_POST_INC, $1.u.ast); }
        |       T_INC variable { $$.u.ast = zend_ast_create_unary(ZEND_PRE_INC, $2.u.ast); }
        |       variable T_DEC { $$.u.ast = zend_ast_create_unary(ZEND_POST_DEC, $1.u.ast); }
@@ -801,59 +801,66 @@ expr_without_variable:
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_AND, $1.u.ast, $3.u.ast); }
        |       expr T_LOGICAL_XOR expr
                        { $$.u.ast = zend_ast_create_binary(ZEND_BOOL_XOR, $1.u.ast, $3.u.ast); }
-       |       expr '|' expr   { $$.u.ast = zend_ast_create_binary(ZEND_BW_OR, $1.u.ast, $3.u.ast); }
-       |       expr '&' expr   { $$.u.ast = zend_ast_create_binary(ZEND_BW_AND, $1.u.ast, $3.u.ast); }
-       |       expr '^' expr   { $$.u.ast = zend_ast_create_binary(ZEND_BW_XOR, $1.u.ast, $3.u.ast); }
-       |       expr '.' expr   { $$.u.ast = zend_ast_create_binary(ZEND_CONCAT, $1.u.ast, $3.u.ast); }
-       |       expr '+' expr   { $$.u.ast = zend_ast_create_binary(ZEND_ADD, $1.u.ast, $3.u.ast); }
-       |       expr '-' expr   { $$.u.ast = zend_ast_create_binary(ZEND_SUB, $1.u.ast, $3.u.ast); }
-       |       expr '*' expr   { $$.u.ast = zend_ast_create_binary(ZEND_MUL, $1.u.ast, $3.u.ast); }
-       |       expr T_POW expr { $$.u.ast = zend_ast_create_binary(ZEND_POW, $1.u.ast, $3.u.ast); }
-       |       expr '/' expr   { $$.u.ast = zend_ast_create_binary(ZEND_DIV, $1.u.ast, $3.u.ast); }
-       |       expr '%' expr   { $$.u.ast = zend_ast_create_binary(ZEND_MOD, $1.u.ast, $3.u.ast); }
-       |       expr T_SL expr  { $$.u.ast = zend_ast_create_binary(ZEND_SL, $1.u.ast, $3.u.ast); }
-       |       expr T_SR expr  { $$.u.ast = zend_ast_create_binary(ZEND_SR, $1.u.ast, $3.u.ast); }
+       |       expr '|' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_BW_OR, $1.u.ast, $3.u.ast); }
+       |       expr '&' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_BW_AND, $1.u.ast, $3.u.ast); }
+       |       expr '^' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_BW_XOR, $1.u.ast, $3.u.ast); }
+       |       expr '.' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_CONCAT, $1.u.ast, $3.u.ast); }
+       |       expr '+' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_ADD, $1.u.ast, $3.u.ast); }
+       |       expr '-' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_SUB, $1.u.ast, $3.u.ast); }
+       |       expr '*' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_MUL, $1.u.ast, $3.u.ast); }
+       |       expr T_POW expr { $$.u.ast = zend_ast_create_binary_op(ZEND_POW, $1.u.ast, $3.u.ast); }
+       |       expr '/' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_DIV, $1.u.ast, $3.u.ast); }
+       |       expr '%' expr   { $$.u.ast = zend_ast_create_binary_op(ZEND_MOD, $1.u.ast, $3.u.ast); }
+       |       expr T_SL expr  { $$.u.ast = zend_ast_create_binary_op(ZEND_SL, $1.u.ast, $3.u.ast); }
+       |       expr T_SR expr  { $$.u.ast = zend_ast_create_binary_op(ZEND_SR, $1.u.ast, $3.u.ast); }
        |       '+' expr %prec T_INC { $$.u.ast = zend_ast_create_unary(ZEND_UNARY_PLUS, $2.u.ast); }
        |       '-' expr %prec T_INC { $$.u.ast = zend_ast_create_unary(ZEND_UNARY_MINUS, $2.u.ast); }
        |       '!' expr { $$.u.ast = zend_ast_create_unary(ZEND_BOOL_NOT, $2.u.ast); }
        |       '~' expr { $$.u.ast = zend_ast_create_unary(ZEND_BW_NOT, $2.u.ast); }
        |       expr T_IS_IDENTICAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_IDENTICAL, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_IDENTICAL, $1.u.ast, $3.u.ast); }
        |       expr T_IS_NOT_IDENTICAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_NOT_IDENTICAL, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_NOT_IDENTICAL, $1.u.ast, $3.u.ast); }
        |       expr T_IS_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_EQUAL, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_EQUAL, $1.u.ast, $3.u.ast); }
        |       expr T_IS_NOT_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_NOT_EQUAL, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_NOT_EQUAL, $1.u.ast, $3.u.ast); }
        |       expr '<' expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_SMALLER, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_SMALLER, $1.u.ast, $3.u.ast); }
        |       expr T_IS_SMALLER_OR_EQUAL expr
-                       { $$.u.ast = zend_ast_create_binary(ZEND_IS_SMALLER_OR_EQUAL, $1.u.ast, $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_SMALLER_OR_EQUAL, $1.u.ast, $3.u.ast); }
        |       expr '>' expr
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_GREATER, $1.u.ast, $3.u.ast); }
        |       expr T_IS_GREATER_OR_EQUAL expr
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_GREATER_EQUAL, $1.u.ast, $3.u.ast); }
        |       expr T_INSTANCEOF class_name_reference
                        { $$.u.ast = zend_ast_create_binary(ZEND_INSTANCEOF, $1.u.ast, $3.u.ast); }
-       |       parenthesis_expr        { $$.u.ast = AST_ZNODE(&$1); }
+       |       parenthesis_expr { $$.u.ast = $1.u.ast; }
        |       new_expr { $$.u.ast = $1.u.ast; }
        |       expr '?' expr ':' expr
                        { $$.u.ast = zend_ast_create_ternary(
                              ZEND_AST_CONDITIONAL, $1.u.ast, $3.u.ast, $5.u.ast); }
        |       expr '?' ':' expr
                        { $$.u.ast = zend_ast_create_ternary(ZEND_AST_CONDITIONAL, $1.u.ast, NULL, $4.u.ast); }
-       |       internal_functions_in_yacc { $$.u.ast = AST_ZNODE(&$1); }
-       |       T_INT_CAST expr         { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_INT, $2.u.ast); }
-       |       T_DOUBLE_CAST expr      { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_DOUBLE, $2.u.ast); }
-       |       T_STRING_CAST expr      { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_STRING, $2.u.ast); }
-       |       T_ARRAY_CAST expr       { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_ARRAY, $2.u.ast); }
-       |       T_OBJECT_CAST expr      { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_OBJECT, $2.u.ast); }
-       |       T_BOOL_CAST expr        { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_BOOL, $2.u.ast); }
-       |       T_UNSET_CAST expr       { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_NULL, $2.u.ast); }
-       |       T_EXIT exit_expr        { $$.u.ast = zend_ast_create_unary(ZEND_EXIT, $2.u.ast); }
-       |       '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { AC($3); zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; AZ($$); }
-       |       scalar                          { $$.u.ast = AST_ZNODE(&$1); }
-       |       '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); AZ($$); }
+       |       internal_functions_in_yacc { $$.u.ast = $1.u.ast; }
+       |       T_INT_CAST expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_LONG, $2.u.ast); }
+       |       T_DOUBLE_CAST expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_DOUBLE, $2.u.ast); }
+       |       T_STRING_CAST expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_STRING, $2.u.ast); }
+       |       T_ARRAY_CAST expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_ARRAY, $2.u.ast); }
+       |       T_OBJECT_CAST expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_OBJECT, $2.u.ast); }
+       |       T_BOOL_CAST expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, _IS_BOOL, $2.u.ast); }
+       |       T_UNSET_CAST expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_NULL, $2.u.ast); }
+       |       T_EXIT exit_expr { $$.u.ast = zend_ast_create_unary(ZEND_EXIT, $2.u.ast); }
+       |       '@' expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_SILENCE, $2.u.ast); }
+       |       scalar { $$.u.ast = $1.u.ast; }
+       |       '`' backticks_expr '`' { $$.u.ast = zend_ast_create_unary(ZEND_AST_SHELL_EXEC, $2.u.ast); }
        |       T_PRINT expr { $$.u.ast = zend_ast_create_unary(ZEND_PRINT, $2.u.ast); }
        |       T_YIELD { $$.u.ast = zend_ast_create_binary(ZEND_YIELD, NULL, NULL); }
        |       T_YIELD expr { $$.u.ast = zend_ast_create_binary(ZEND_YIELD, $2.u.ast, NULL); }
@@ -861,10 +868,10 @@ expr_without_variable:
                        { $$.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 '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $3; AZ($$); }
+               '{' inner_statement_list '}' { 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 '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $4; AZ($$); }
+               '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$4); }
 ;
 
 function:
@@ -886,21 +893,19 @@ lexical_var_list:
 function_call:
                namespace_name function_call_parameter_list
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
-                                 zend_ast_create_unary(ZEND_AST_NAME, AST_ZVAL(&$1)), $2.u.ast); }
+                                 zend_ast_create_zval_ex(&$1.u.constant, 1), $2.u.ast); }
        |       T_NAMESPACE T_NS_SEPARATOR namespace_name function_call_parameter_list
                        { ZVAL_EMPTY_STRING(&$1.u.constant);
                          zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC);
-                         $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
-                                 zend_ast_create_unary(ZEND_AST_NAME_FQ, AST_ZVAL(&$1)), $4.u.ast); }
+                         $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL, AST_ZVAL(&$1), $4.u.ast); }
        |       T_NS_SEPARATOR namespace_name function_call_parameter_list
-                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
-                                 zend_ast_create_unary(ZEND_AST_NAME_FQ, AST_ZVAL(&$2)), $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL, AST_ZVAL(&$2), $3.u.ast); }
        |       class_name T_PAAMAYIM_NEKUDOTAYIM member_name function_call_parameter_list
                        { $$.u.ast = zend_ast_create_ternary(ZEND_AST_STATIC_CALL,
                              AST_ZVAL(&$1), $3.u.ast, $4.u.ast); }
        |       variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name function_call_parameter_list
                        { $$.u.ast = zend_ast_create_ternary(ZEND_AST_STATIC_CALL,
-                             AST_ZNODE(&$1), $3.u.ast, $4.u.ast); }
+                             $1.u.ast, $3.u.ast, $4.u.ast); }
        |       callable_expr function_call_parameter_list
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL, $1.u.ast, $2.u.ast); }
 ;
@@ -928,13 +933,15 @@ class_name_reference:
 exit_expr:
                /* empty */                     { $$.u.ast = NULL; }
        |       '(' ')'                         { $$.u.ast = NULL; }
-       |       parenthesis_expr        { $$.u.ast = AST_ZNODE(&$1); }
+       |       parenthesis_expr        { $$.u.ast = $1.u.ast; }
 ;
 
 backticks_expr:
-               /* empty */     { ZVAL_EMPTY_STRING(&$$.u.constant); $$.op_type = IS_CONST; }
-       |       T_ENCAPSED_AND_WHITESPACE       { $$ = $1; }
-       |       encaps_list     { $$ = $1; }
+               /* empty */
+                       { 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); }
 ;
 
 
@@ -945,23 +952,25 @@ ctor_arguments:
 
 
 dereferencable_scalar:
-               T_ARRAY '(' array_pair_list ')' { $$ = $3; }
-       |       '[' array_pair_list ']'                 { $$ = $2; }
-       |       T_CONSTANT_ENCAPSED_STRING              { $$ = $1; }
+               T_ARRAY '(' array_pair_list ')' { $$.u.ast = $3.u.ast; }
+       |       '[' array_pair_list ']'                 { $$.u.ast = $2.u.ast; }
+       |       T_CONSTANT_ENCAPSED_STRING              { $$.u.ast = AST_ZVAL(&$1); }
 ;
 
 common_scalar:
-               T_LNUMBER                                       { $$ = $1; }
-       |       T_DNUMBER                                       { $$ = $1; }
-       |       T_LINE                                          { $$ = $1; }
-       |       T_FILE                                          { $$ = $1; }
-       |       T_DIR                                           { $$ = $1; }
-       |       T_TRAIT_C                                       { $$ = $1; }
-       |       T_METHOD_C                                      { $$ = $1; }
-       |       T_FUNC_C                                        { $$ = $1; }
-       |       T_NS_C                                          { $$ = $1; }
-       |       T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC { $$ = $2; }
-       |       T_START_HEREDOC T_END_HEREDOC { ZVAL_EMPTY_STRING(&$$.u.constant); $$.op_type = IS_CONST; }
+               T_LNUMBER                                       { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_DNUMBER                                       { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_LINE                                          { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_FILE                                          { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_DIR                                           { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_TRAIT_C                                       { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_METHOD_C                                      { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_FUNC_C                                        { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_NS_C                                          { $$.u.ast = AST_ZVAL(&$1); }
+       |       T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC { $$.u.ast = AST_ZVAL(&$2); }
+       |       T_START_HEREDOC T_END_HEREDOC
+                       { zval empty_str; ZVAL_EMPTY_STRING(&empty_str);
+                         $$.u.ast = zend_ast_create_constant(&empty_str); }
 ;
 
 static_class_constant:
@@ -973,8 +982,7 @@ static_scalar: /* compile-time evaluated scalars */
 ;
 
 static_scalar_base:
-               common_scalar                           { $$ = $1; }
-       |       T_CONSTANT_ENCAPSED_STRING      { $$ = $1; }
+               T_CONSTANT_ENCAPSED_STRING      { $$ = $1; }
        |       T_CLASS_C                                       { $$ = $1; }
        |       static_class_name_scalar        { $$ = $1; }
        |       static_class_constant           { $$ = $1; }
@@ -985,6 +993,7 @@ static_scalar_base:
 
 static_scalar_value:
                static_scalar_base { $$.u.ast = zend_ast_create_constant(&$1.u.constant); }
+       |       common_scalar { $$.u.ast = $1.u.ast; }
        |       T_ARRAY '(' static_array_pair_list ')' { $$ = $3; }
        |       '[' static_array_pair_list ']' { $$ = $2; }
        |       static_operation { $$ = $1; }
@@ -1027,17 +1036,26 @@ static_operation:
 
 
 scalar:
-               T_STRING_VARNAME                { $$ = $1; }
-       |       class_name_scalar       { $$ = $1; }
-       |       class_constant          { $$ = $1; }
-       |       namespace_name  { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC); }
-       |       T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant);  zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_RT, 0 TSRMLS_CC); }
-       |       T_NS_SEPARATOR namespace_name { zval tmp; ZVAL_NEW_STR(&tmp, STR_ALLOC(Z_STRLEN($2.u.constant)+1, 0)); Z_STRVAL(tmp)[0] = '\\'; memcpy(Z_STRVAL(tmp) + 1, Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); if (Z_DELREF($2.u.constant) == 0) {efree(Z_STR($2.u.constant));} Z_STR($2.u.constant) = Z_STR(tmp); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_RT, 0 TSRMLS_CC); }
-       |       common_scalar                   { $$ = $1; }
-       |       '"' encaps_list '"'     { $$ = $2; }
-       |       T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; }
-       |       T_CLASS_C                               { if (Z_TYPE($1.u.constant) == IS_CONSTANT) {zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC);} else {$$ = $1;} }
-       |       dereferencable_scalar   { $$ = $1; }
+               T_STRING_VARNAME                { $$ = $1; AZ($$); }
+       |       class_name_scalar       { $$.u.ast = $1.u.ast; }
+       |       class_constant          { $$.u.ast = $1.u.ast; }
+       |       namespace_name
+                       { $$.u.ast = zend_ast_create_unary(
+                             ZEND_AST_CONST, zend_ast_create_zval_ex(&$1.u.constant, 1)); }
+       |       T_NAMESPACE T_NS_SEPARATOR namespace_name
+                       { ZVAL_EMPTY_STRING(&$1.u.constant);
+                         zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC);
+                         $$.u.ast = zend_ast_create_unary(ZEND_AST_CONST, AST_ZVAL(&$1)); }
+       |       T_NS_SEPARATOR namespace_name
+                       { zval tmp; ZVAL_NEW_STR(&tmp, STR_ALLOC(Z_STRLEN($2.u.constant)+1, 0)); Z_STRVAL(tmp)[0] = '\\'; memcpy(Z_STRVAL(tmp) + 1, Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1);
+                         if (Z_DELREF($2.u.constant) == 0) { efree(Z_STR($2.u.constant)); }
+                         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($$); }
+       |       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; }
 ;
 
 
@@ -1064,27 +1082,23 @@ expr:
 ;
 
 parenthesis_expr:
-               '(' expr ')'            { AST_COMPILE(&$$, $2.u.ast); }
-;
-
-w_variable:
-       variable        { zend_ensure_writable_variable($1.u.ast); AST_COMPILE_VAR(&$$, $1.u.ast, BP_VAR_W); }
+               '(' expr ')' { $$.u.ast = $2.u.ast; }
 ;
 
 variable_class_name:
-       dereferencable { zend_compile_expr(&$$, $1.u.ast TSRMLS_CC); zend_ast_destroy($1.u.ast); }
+       dereferencable { $$.u.ast = $1.u.ast; }
 ;
 
 dereferencable:
                variable                                { $$.u.ast = $1.u.ast; }
        |       '(' expr ')'                    { $$.u.ast = $2.u.ast; }
-       |       dereferencable_scalar   { $$.u.ast = AST_ZNODE(&$1); }
+       |       dereferencable_scalar   { $$.u.ast = $1.u.ast; }
 ;
 
 callable_expr:
                callable_variable               { $$.u.ast = $1.u.ast; }
        |       '(' expr ')'                    { $$.u.ast = $2.u.ast; }
-       |       dereferencable_scalar   { $$.u.ast = AST_ZNODE(&$1); }
+       |       dereferencable_scalar   { $$.u.ast = $1.u.ast; }
 ;
 
 callable_variable:
@@ -1121,7 +1135,7 @@ static_member:
                class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable
                        { $$.u.ast = zend_ast_create_binary(ZEND_AST_STATIC_PROP, AST_ZVAL(&$1), $3.u.ast); }
        |       variable_class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable
-                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_STATIC_PROP, AST_ZNODE(&$1), $3.u.ast); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_STATIC_PROP, $1.u.ast, $3.u.ast); }
 ;
 
 new_variable:
@@ -1166,19 +1180,26 @@ assignment_list_element:
 
 
 array_pair_list:
-               /* empty */ { zend_do_init_array(&$$, NULL, NULL, 0 TSRMLS_CC); zend_do_end_array(&$$, &$$ TSRMLS_CC); }
-       |       non_empty_array_pair_list possible_comma        { zend_do_end_array(&$$, &$1 TSRMLS_CC); }
+               /* empty */ { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_ARRAY); }
+       |       non_empty_array_pair_list possible_comma { $$.u.ast = $1.u.ast; }
 ;
 
 non_empty_array_pair_list:
-               non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr  { AC($3); AC($5); zend_do_add_array_element(&$$, &$5, &$3, 0 TSRMLS_CC); }
-       |       non_empty_array_pair_list ',' expr                      { AC($3); zend_do_add_array_element(&$$, &$3, NULL, 0 TSRMLS_CC); }
-       |       expr T_DOUBLE_ARROW expr        { AC($1); AC($3); zend_do_init_array(&$$, &$3, &$1, 0 TSRMLS_CC); }
-       |       expr                            { AC($1); zend_do_init_array(&$$, &$1, NULL, 0 TSRMLS_CC); }
-       |       non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable { AC($3); zend_do_add_array_element(&$$, &$6, &$3, 1 TSRMLS_CC); }
-       |       non_empty_array_pair_list ',' '&' w_variable { zend_do_add_array_element(&$$, &$4, NULL, 1 TSRMLS_CC); }
-       |       expr T_DOUBLE_ARROW '&' w_variable      { AC($1); zend_do_init_array(&$$, &$4, &$1, 1 TSRMLS_CC); }
-       |       '&' w_variable                  { zend_do_init_array(&$$, &$2, NULL, 1 TSRMLS_CC); }
+               non_empty_array_pair_list ',' array_pair
+                       { zend_ast_dynamic_add(&$1.u.ast, $3.u.ast); $$.u.ast = $1.u.ast; }
+       |       array_pair
+                       { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_ARRAY);
+                         zend_ast_dynamic_add(&$$.u.ast, $1.u.ast); }
+;
+
+array_pair:
+               expr T_DOUBLE_ARROW expr
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_ARRAY_ELEM, $3.u.ast, $1.u.ast); }
+       |       expr { $$.u.ast = zend_ast_create_binary(ZEND_AST_ARRAY_ELEM, $1.u.ast, NULL); }
+       |       expr T_DOUBLE_ARROW '&' variable
+                       { $$.u.ast = zend_ast_create_binary_ex(ZEND_AST_ARRAY_ELEM, 1, $4.u.ast, $1.u.ast); }
+       |       '&' variable
+                       { $$.u.ast = zend_ast_create_binary_ex(ZEND_AST_ARRAY_ELEM, 1, $2.u.ast, NULL); }
 ;
 
 encaps_list:
@@ -1216,29 +1237,39 @@ encaps_var_offset:
 
 
 internal_functions_in_yacc:
-               T_ISSET '(' isset_variables ')' { $$ = $3; }
-       |       T_EMPTY '(' variable ')' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); }
-       |       T_EMPTY '(' expr_without_variable ')' { AC($3); zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$3 TSRMLS_CC); }
-       |       T_INCLUDE expr                  { AC($2); zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }
-       |       T_INCLUDE_ONCE expr     { AC($2); zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }
-       |       T_EVAL '(' expr ')'     { AC($3); zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }
-       |       T_REQUIRE expr                  { AC($2); zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }
-       |       T_REQUIRE_ONCE expr             { AC($2); zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); }
+               T_ISSET '(' isset_variables ')' { $$.u.ast  = $3.u.ast; }
+       |       T_EMPTY '(' expr ')' { $$.u.ast = zend_ast_create_unary(ZEND_AST_EMPTY, $3.u.ast); }
+       |       T_INCLUDE expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_INCLUDE_OR_EVAL, ZEND_INCLUDE, $2.u.ast); }
+       |       T_INCLUDE_ONCE expr
+                       { $$.u.ast = zend_ast_create_unary_ex(
+                             ZEND_INCLUDE_OR_EVAL, ZEND_INCLUDE_ONCE, $2.u.ast); }
+       |       T_EVAL '(' expr ')'
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_INCLUDE_OR_EVAL, ZEND_EVAL, $3.u.ast); }
+       |       T_REQUIRE expr
+                       { $$.u.ast = zend_ast_create_unary_ex(ZEND_INCLUDE_OR_EVAL, ZEND_REQUIRE, $2.u.ast); }
+       |       T_REQUIRE_ONCE expr
+                       { $$.u.ast = zend_ast_create_unary_ex(
+                             ZEND_INCLUDE_OR_EVAL, ZEND_REQUIRE_ONCE, $2.u.ast); }
 ;
 
 isset_variables:
-               isset_variable                  { $$ = $1; }
-       |       isset_variables ',' { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } isset_variable { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
+               isset_variable { $$.u.ast = $1.u.ast; }
+       |       isset_variables ',' isset_variable
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_AND, $1.u.ast, $3.u.ast); }
 ;
 
 isset_variable:
-               variable { zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$1 TSRMLS_CC); }
-       |       expr_without_variable   { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use isset() on the result of an expression (you can use \"null !== expression\" instead)"); }
+               expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_ISSET, $1.u.ast); }
 ;
 
 class_constant:
-               class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); }
-       |       variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); }
+               class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING
+                       { $$.u.ast = zend_ast_create_binary(
+                             ZEND_AST_CLASS_CONST, AST_ZVAL(&$1), AST_ZVAL(&$3)); }
+       |       variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING
+                       { $$.u.ast = zend_ast_create_binary(
+                             ZEND_AST_CLASS_CONST, $1.u.ast, AST_ZVAL(&$3)); }
 ;
 
 static_class_name_scalar:
@@ -1246,7 +1277,8 @@ static_class_name_scalar:
 ;
 
 class_name_scalar:
-       class_name T_PAAMAYIM_NEKUDOTAYIM T_CLASS { zend_do_resolve_class_name(&$$, &$1, 0 TSRMLS_CC); }
+       class_name T_PAAMAYIM_NEKUDOTAYIM T_CLASS
+               { $$.u.ast = zend_ast_create_unary(ZEND_AST_RESOLVE_CLASS_NAME, AST_ZVAL(&$1)); }
 ;
 
 %%
index 37875dca5784ff33068f8c160402e893112a6b0a..e524645e4e4c841ef5cd1fec6728ab21061cf791 100644 (file)
@@ -733,13 +733,10 @@ ZEND_API unary_op_type get_unary_op(int opcode)
        switch (opcode) {
                case ZEND_BW_NOT:
                        return (unary_op_type) bitwise_not_function;
-                       break;
                case ZEND_BOOL_NOT:
                        return (unary_op_type) boolean_not_function;
-                       break;
                default:
                        return (unary_op_type) NULL;
-                       break;
        }
 }
 
@@ -749,74 +746,54 @@ ZEND_API binary_op_type get_binary_op(int opcode)
                case ZEND_ADD:
                case ZEND_ASSIGN_ADD:
                        return (binary_op_type) add_function;
-                       break;
                case ZEND_SUB:
                case ZEND_ASSIGN_SUB:
                        return (binary_op_type) sub_function;
-                       break;
                case ZEND_MUL:
                case ZEND_ASSIGN_MUL:
                        return (binary_op_type) mul_function;
-                       break;
                case ZEND_POW:
                        return (binary_op_type) pow_function;
-                       break;
                case ZEND_DIV:
                case ZEND_ASSIGN_DIV:
                        return (binary_op_type) div_function;
-                       break;
                case ZEND_MOD:
                case ZEND_ASSIGN_MOD:
                        return (binary_op_type) mod_function;
-                       break;
                case ZEND_SL:
                case ZEND_ASSIGN_SL:
                        return (binary_op_type) shift_left_function;
-                       break;
                case ZEND_SR:
                case ZEND_ASSIGN_SR:
                        return (binary_op_type) shift_right_function;
-                       break;
                case ZEND_CONCAT:
                case ZEND_ASSIGN_CONCAT:
                        return (binary_op_type) concat_function;
-                       break;
                case ZEND_IS_IDENTICAL:
                        return (binary_op_type) is_identical_function;
-                       break;
                case ZEND_IS_NOT_IDENTICAL:
                        return (binary_op_type) is_not_identical_function;
-                       break;
                case ZEND_IS_EQUAL:
                        return (binary_op_type) is_equal_function;
-                       break;
                case ZEND_IS_NOT_EQUAL:
                        return (binary_op_type) is_not_equal_function;
-                       break;
                case ZEND_IS_SMALLER:
                        return (binary_op_type) is_smaller_function;
-                       break;
                case ZEND_IS_SMALLER_OR_EQUAL:
                        return (binary_op_type) is_smaller_or_equal_function;
-                       break;
                case ZEND_BW_OR:
                case ZEND_ASSIGN_BW_OR:
                        return (binary_op_type) bitwise_or_function;
-                       break;
                case ZEND_BW_AND:
                case ZEND_ASSIGN_BW_AND:
                        return (binary_op_type) bitwise_and_function;
-                       break;
                case ZEND_BW_XOR:
                case ZEND_ASSIGN_BW_XOR:
                        return (binary_op_type) bitwise_xor_function;
-                       break;
                case ZEND_BOOL_XOR:
                        return (binary_op_type) boolean_xor_function;
-                       break;
                default:
                        return (binary_op_type) NULL;
-                       break;
        }
 }