diff --git a/Zend/tests/class_properties_dynamic.phpt b/Zend/tests/class_properties_dynamic.phpt new file mode 100644 index 00000000000..8a1fc6f0297 --- /dev/null +++ b/Zend/tests/class_properties_dynamic.phpt @@ -0,0 +1,13 @@ +--TEST-- +Class Property Expressions +--FILE-- +bar; +?> +--EXPECTF-- +3 diff --git a/Zend/tests/class_properties_static.phpt b/Zend/tests/class_properties_static.phpt new file mode 100644 index 00000000000..9a56466340c --- /dev/null +++ b/Zend/tests/class_properties_static.phpt @@ -0,0 +1,20 @@ +--TEST-- +Static Class Property Expressions +--FILE-- +b1, + $f->b2, + $f->b3 +); +?> +--EXPECT-- +int(2) +int(4) +string(13) "foo bar baz" diff --git a/Zend/tests/constant_expressions.phpt b/Zend/tests/constant_expressions.phpt new file mode 100644 index 00000000000..441b9a6f2a8 --- /dev/null +++ b/Zend/tests/constant_expressions.phpt @@ -0,0 +1,49 @@ +--TEST-- +Constant Expressions +--FILE-- + +--EXPECT-- +int(2) +float(0.5) +float(3) +string(6) "foobar" +float(6) +string(6) "foo234" +int(8) +string(21) "This is a test string" +int(0) +int(2) +int(7) +int(6) diff --git a/Zend/tests/constant_expressions_dynamic.phpt b/Zend/tests/constant_expressions_dynamic.phpt new file mode 100644 index 00000000000..21c9216cc19 --- /dev/null +++ b/Zend/tests/constant_expressions_dynamic.phpt @@ -0,0 +1,11 @@ +--TEST-- +Dynamic Constant Expressions +--FILE-- + +--EXPECTF-- +3 diff --git a/Zend/tests/function_arguments_003.phpt b/Zend/tests/function_arguments_003.phpt new file mode 100644 index 00000000000..b882476d1d9 --- /dev/null +++ b/Zend/tests/function_arguments_003.phpt @@ -0,0 +1,17 @@ +--TEST-- +Function Argument Parsing #003 +--FILE-- + +--EXPECT-- +int(2) +int(4) +string(6) "foobar" +int(100) diff --git a/Zend/tests/static_variable.phpt b/Zend/tests/static_variable.phpt new file mode 100644 index 00000000000..ea69a8f86b0 --- /dev/null +++ b/Zend/tests/static_variable.phpt @@ -0,0 +1,29 @@ +--TEST-- +Static Variable Expressions +--FILE-- + 1 + 1, baz * 2 => 1 << 2]; + static $c = [1 => bar] + [3 => baz]; + var_dump($a, $b, $c); +} + +foo(); +?> +--EXPECT-- +int(2) +array(2) { + [2]=> + int(2) + [6]=> + int(4) +} +array(2) { + [1]=> + int(2) + [3]=> + int(3) +} diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 705c4df465b..7d85e241061 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -22,7 +22,8 @@ #include "zend_execute.h" #define OP_IS_CONST_THEN(op, do_code) \ - switch (Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK) { \ + switch (op?Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK:-1) { \ + case -1: \ case IS_CONSTANT: \ case IS_CONSTANT_ARRAY: \ case IS_CONSTANT_AST: { \ @@ -31,20 +32,26 @@ } #define OP_IS_NOT_CONST_THEN(op, do_code) \ - switch (Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK) { \ - case IS_CONSTANT: \ - case IS_CONSTANT_ARRAY: \ - case IS_CONSTANT_AST: \ - break; \ + if (op) { \ + switch (Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK) { \ + case IS_CONSTANT: \ + case IS_CONSTANT_ARRAY: \ + case IS_CONSTANT_AST: \ + break; \ \ - default: { \ - do_code \ + default: { \ + do_code \ + } \ } \ } #define COPY_ZVAL_TO_OP(nr) \ - Z_AST_P(result)->ops[nr] = emalloc(sizeof(zval)); \ - *Z_AST_P(result)->ops[nr] = *op##nr; + if (op##nr) { \ + Z_AST_P(result)->ops[nr] = emalloc(sizeof(zval)); \ + *Z_AST_P(result)->ops[nr] = *op##nr; \ + } else { \ + Z_AST_P(result)->ops[nr] = NULL; \ + } void zend_ast_add(zval *result, intermediary_ast_function_type func, char op_count) { zend_ast *ast = emalloc(sizeof(zend_ast)); @@ -58,9 +65,10 @@ void zend_ast_add(zval *result, intermediary_ast_function_type func, char op_cou /* Do operations on constant operators at compile time (AST building time) */ -void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0) { +void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 TSRMLS_DC) { OP_IS_NOT_CONST_THEN(op0, - func(result, op0); + func(result, op0 TSRMLS_CC); + zval_dtor(op0); return; ) @@ -68,9 +76,11 @@ void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0) { COPY_ZVAL_TO_OP(0) } -void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1) { +void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1 TSRMLS_DC) { OP_IS_NOT_CONST_THEN(op0, OP_IS_NOT_CONST_THEN(op1, - func(result, op0, op1); + func(result, op0, op1 TSRMLS_CC); + zval_dtor(op0); + zval_dtor(op1); return; )) @@ -79,9 +89,12 @@ void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op COPY_ZVAL_TO_OP(1) } -void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2) { +void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2 TSRMLS_DC) { OP_IS_NOT_CONST_THEN(op0, OP_IS_NOT_CONST_THEN(op1, OP_IS_NOT_CONST_THEN(op2, - func(result, op0, op1, op2); + func(result, op0, op1, op2 TSRMLS_CC); + zval_dtor(op0); + zval_dtor(op1); + zval_dtor(op2); return; ))) @@ -95,20 +108,22 @@ void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC) { int i; for (i = ast->op_count; i--;) { - OP_IS_CONST_THEN(ast->ops[i], - zval_update_constant_ex(&ast->ops[i], (void *)1, NULL TSRMLS_CC); - ) + if (ast->ops[i]) { + OP_IS_CONST_THEN(ast->ops[i], + zval_update_constant_ex(&ast->ops[i], (void *)1, NULL TSRMLS_CC); + ) + } } switch (ast->op_count) { case 1: - ((unary_ast_func)ast->func)(result, ast->ops[0]); + ((unary_ast_func)ast->func)(result, ast->ops[0] TSRMLS_CC); break; case 2: - ((binary_ast_func)ast->func)(result, ast->ops[0], ast->ops[1]); + ((binary_ast_func)ast->func)(result, ast->ops[0], ast->ops[1] TSRMLS_CC); break; case 3: - ((ternary_ast_func)ast->func)(result, ast->ops[0], ast->ops[1], ast->ops[2]); + ((ternary_ast_func)ast->func)(result, ast->ops[0], ast->ops[1], ast->ops[2] TSRMLS_CC); break; } } @@ -117,7 +132,7 @@ void zend_ast_destroy(zend_ast *ast TSRMLS_DC) { int i; for (i = ast->op_count; i--;) { - if (!Z_DELREF_P(ast->ops[i])) { + if (ast->ops[i] && !Z_DELREF_P(ast->ops[i])) { zval_dtor(ast->ops[i]); efree(ast->ops[i]); } diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 9841c3463e4..218f2c02e05 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -26,9 +26,9 @@ typedef struct _zend_ast zend_ast; #include "zend.h" typedef void(*intermediary_ast_function_type)(zval *, ...); -typedef int(*unary_ast_func)(zval *result, zval *op0); -typedef int(*binary_ast_func)(zval *result, zval *op0, zval *op1); -typedef int(*ternary_ast_func)(zval *result, zval *op0, zval *op1, zval *op2); +typedef int(*unary_ast_func)(zval *result, zval *op0 TSRMLS_DC); +typedef int(*binary_ast_func)(zval *result, zval *op0, zval *op1 TSRMLS_DC); +typedef int(*ternary_ast_func)(zval *result, zval *op0, zval *op1, zval *op2 TSRMLS_DC); struct _zend_ast { char op_count; @@ -37,9 +37,9 @@ struct _zend_ast { int refcount; }; -void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0); -void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1); -void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2); +void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 TSRMLS_DC); +void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1 TSRMLS_DC); +void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2 TSRMLS_DC); void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index eabebacce46..a66cdeea922 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -599,7 +599,7 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco continue; } if (str_index[str_index_len - 2] == IS_CONSTANT_AST) { - zend_ast_evaluate(&const_value, *(zend_ast **)str_index); + zend_ast_evaluate(&const_value, *(zend_ast **)str_index TSRMLS_CC); ZEND_AST_DEL_REF(*(zend_ast **)str_index); } else if (!zend_get_constant_ex(str_index, str_index_len - 3, &const_value, scope, str_index[str_index_len - 2] TSRMLS_CC)) { char *actual; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 517ae56e41e..af00f2ef4a8 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -982,6 +982,8 @@ static_operation: | static_scalar_value T_SL static_scalar_value { zend_ast_add_binary(&$$.u.constant, shift_left_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } | static_scalar_value T_SR static_scalar_value { zend_ast_add_binary(&$$.u.constant, shift_right_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } | static_scalar_value '.' static_scalar_value { zend_ast_add_binary(&$$.u.constant, concat_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '?' ':' static_scalar_value { zend_ast_add_ternary(&$$.u.constant, ternary_function, &$1.u.constant, NULL, &$4.u.constant TSRMLS_CC); } + | static_scalar_value '?' static_scalar_value ':' static_scalar_value { zend_ast_add_ternary(&$$.u.constant, ternary_function, &$1.u.constant, &$3.u.constant, &$5.u.constant TSRMLS_CC); } | '+' static_scalar_value { ZVAL_LONG(&$1.u.constant, 0); zend_ast_add_binary(&$$.u.constant, add_function, &$1.u.constant, &$2.u.constant TSRMLS_CC); } | '-' static_scalar_value { ZVAL_LONG(&$1.u.constant, 0); zend_ast_add_binary(&$$.u.constant, sub_function, &$1.u.constant, &$2.u.constant TSRMLS_CC); } | '(' static_scalar_value ')' { $$ = $2; } diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index e8629291e54..53a84de155e 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2323,6 +2323,28 @@ ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */ } /* }}} */ +#define PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(var) \ + *result = *var; \ + if (Z_REFCOUNT_P(var) == 1) { \ + Z_TYPE_P(var) = IS_NULL; \ + } + +ZEND_API int ternary_function(zval *result, zval *condition, zval *then, zval *if_not TSRMLS_DC) /* {{{ */ +{ + if (i_zend_is_true(condition)) { + if (then) { + PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(then); + } else { + PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(condition); + } + } else { + PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(if_not); + } + + return SUCCESS; +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index ce21af3d2e7..79ede573205 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -376,6 +376,8 @@ ZEND_API int zend_atoi(const char *str, int str_len); ZEND_API long zend_atol(const char *str, int str_len); ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC); + +ZEND_API int ternary_function(zval *result, zval *condition, zval *then, zval *if_not TSRMLS_DC); END_EXTERN_C() #define convert_to_ex_master(ppzv, lower_type, upper_type) \