From: Nikita Popov Date: Thu, 19 Jun 2014 11:57:29 +0000 (+0200) Subject: AST stage 2.4 X-Git-Tag: POST_AST_MERGE^2~196 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=657762ee2b32fc9bd2145b8cfa4b3d174783bf41;p=php AST stage 2.4 --- diff --git a/Zend/tests/isset_func_error.phpt b/Zend/tests/isset_func_error.phpt index 7d1036def8..7d6616b96d 100644 --- a/Zend/tests/isset_func_error.phpt +++ b/Zend/tests/isset_func_error.phpt @@ -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 diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 98aca3c6af..84243c2793 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -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)); diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 83e1f64bd9..cfe0ffae14 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -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 { \ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 4972ecc15c..9fc035e0d6 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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(¶ms_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; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index d375cf7add..86e552bc1a 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -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; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 540bd20512..94fa29727b 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -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)); } ; %% diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 37875dca57..e524645e4e 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -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; } }