diff options
| -rw-r--r-- | Zend/Makefile.am | 2 | ||||
| -rw-r--r-- | Zend/Zend.dsp | 4 | ||||
| -rw-r--r-- | Zend/ZendTS.dsp | 4 | ||||
| -rw-r--r-- | Zend/tests/class_properties_dynamic.phpt | 13 | ||||
| -rw-r--r-- | Zend/tests/class_properties_static.phpt | 20 | ||||
| -rw-r--r-- | Zend/tests/constant_expressions.phpt | 91 | ||||
| -rw-r--r-- | Zend/tests/constant_expressions_dynamic.phpt | 11 | ||||
| -rw-r--r-- | Zend/tests/function_arguments_003.phpt | 17 | ||||
| -rw-r--r-- | Zend/tests/static_variable.phpt | 29 | ||||
| -rw-r--r-- | Zend/zend.h | 25 | ||||
| -rw-r--r-- | Zend/zend_API.c | 5 | ||||
| -rw-r--r-- | Zend/zend_ast.c | 130 | ||||
| -rw-r--r-- | Zend/zend_ast.h | 60 | ||||
| -rw-r--r-- | Zend/zend_builtin_functions.c | 2 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 25 | ||||
| -rw-r--r-- | Zend/zend_compile.h | 5 | ||||
| -rw-r--r-- | Zend/zend_execute_API.c | 331 | ||||
| -rw-r--r-- | Zend/zend_language_parser.y | 53 | ||||
| -rw-r--r-- | Zend/zend_operators.c | 62 | ||||
| -rw-r--r-- | Zend/zend_operators.h | 7 | ||||
| -rw-r--r-- | Zend/zend_variables.c | 10 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 9 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 15 | ||||
| -rw-r--r-- | configure.in | 2 | ||||
| -rw-r--r-- | ext/reflection/php_reflection.c | 5 | ||||
| -rw-r--r-- | win32/build/config.w32 | 2 |
26 files changed, 734 insertions, 205 deletions
diff --git a/Zend/Makefile.am b/Zend/Makefile.am index 924a00daeb..d9ce4c61ba 100644 --- a/Zend/Makefile.am +++ b/Zend/Makefile.am @@ -18,7 +18,7 @@ libZend_la_SOURCES=\ zend_default_classes.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c \ zend_strtod.c zend_closures.c zend_float.c zend_string.c zend_signal.c \ - zend_generators.c zend_virtual_cwd.c + zend_generators.c zend_virtual_cwd.c zend_ast.c libZend_la_LDFLAGS = libZend_la_LIBADD = @ZEND_EXTRA_LIBS@ diff --git a/Zend/Zend.dsp b/Zend/Zend.dsp index d1b3b89030..d8bb03b9e8 100644 --- a/Zend/Zend.dsp +++ b/Zend/Zend.dsp @@ -119,6 +119,10 @@ SOURCE=.\zend_API.c # End Source File
# Begin Source File
+SOURCE=.\zend_ast.c
+# End Source File
+# Begin Source File
+
SOURCE=.\zend_builtin_functions.c
# End Source File
# Begin Source File
diff --git a/Zend/ZendTS.dsp b/Zend/ZendTS.dsp index 3be2c58bed..5dfa24d5b9 100644 --- a/Zend/ZendTS.dsp +++ b/Zend/ZendTS.dsp @@ -140,6 +140,10 @@ SOURCE=.\zend_alloc.c # End Source File
# Begin Source File
+SOURCE=.\zend_ast.c
+# End Source File
+# Begin Source File
+
SOURCE=.\zend_API.c
# End Source File
# Begin Source File
diff --git a/Zend/tests/class_properties_dynamic.phpt b/Zend/tests/class_properties_dynamic.phpt new file mode 100644 index 0000000000..8a1fc6f029 --- /dev/null +++ b/Zend/tests/class_properties_dynamic.phpt @@ -0,0 +1,13 @@ +--TEST-- +Class Property Expressions +--FILE-- +<?php +class Foo { + const BAR = 1 << 0; + const BAZ = 1 << 1; + public $bar = self::BAR | self::BAZ; +} +echo (new Foo)->bar; +?> +--EXPECTF-- +3 diff --git a/Zend/tests/class_properties_static.phpt b/Zend/tests/class_properties_static.phpt new file mode 100644 index 0000000000..9a56466340 --- /dev/null +++ b/Zend/tests/class_properties_static.phpt @@ -0,0 +1,20 @@ +--TEST-- +Static Class Property Expressions +--FILE-- +<?php +class Foo { + public $b1 = 1 + 1; + public $b2 = 1 << 2; + public $b3 = "foo " . " bar " . " baz"; +} +$f = new Foo; +var_dump( + $f->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 0000000000..7dea0d83f7 --- /dev/null +++ b/Zend/tests/constant_expressions.phpt @@ -0,0 +1,91 @@ +--TEST-- +Constant Expressions +--FILE-- +<?php +const T_1 = 1 << 1; +const T_2 = 1 / 2; +const T_3 = 1.5 + 1.5; +const T_4 = "foo" . "bar"; +const T_5 = (1.5 + 1.5) * 2; +const T_6 = "foo" . 2 . 3 . 4.0; +const T_7 = __LINE__; +const T_8 = <<<ENDOFSTRING +This is a test string +ENDOFSTRING; +const T_9 = ~-1; +const T_10 = (-1?:1) + (0?2:3); +const T_11 = 1 && 0; +const T_12 = 1 and 1; +const T_13 = 0 || 0; +const T_14 = 1 or 0; +const T_15 = 1 xor 1; +const T_16 = 1 xor 0; +const T_17 = 1 < 0; +const T_18 = 0 <= 0; +const T_19 = 1 > 0; +const T_20 = 1 >= 0; +const T_21 = 1 === 1; +const T_22 = 1 !== 1; +const T_23 = 0 != "0"; +const T_24 = 1 == "1"; + +// Test order of operations +const T_25 = 1 + 2 * 3; + +// Test for memory leaks +const T_26 = "1" + 2 + "3"; + +var_dump(T_1); +var_dump(T_2); +var_dump(T_3); +var_dump(T_4); +var_dump(T_5); +var_dump(T_6); +var_dump(T_7); +var_dump(T_8); +var_dump(T_9); +var_dump(T_10); +var_dump(T_11); +var_dump(T_12); +var_dump(T_13); +var_dump(T_14); +var_dump(T_15); +var_dump(T_16); +var_dump(T_17); +var_dump(T_18); +var_dump(T_19); +var_dump(T_20); +var_dump(T_21); +var_dump(T_22); +var_dump(T_23); +var_dump(T_24); +var_dump(T_25); +var_dump(T_26); +?> +--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) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(false) +bool(true) +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 0000000000..21c9216cc1 --- /dev/null +++ b/Zend/tests/constant_expressions_dynamic.phpt @@ -0,0 +1,11 @@ +--TEST-- +Dynamic Constant Expressions +--FILE-- +<?php +const FOO = 1; +const BAR = FOO | 2; + +echo BAR; +?> +--EXPECTF-- +3 diff --git a/Zend/tests/function_arguments_003.phpt b/Zend/tests/function_arguments_003.phpt new file mode 100644 index 0000000000..b882476d1d --- /dev/null +++ b/Zend/tests/function_arguments_003.phpt @@ -0,0 +1,17 @@ +--TEST-- +Function Argument Parsing #003 +--FILE-- +<?php +const a = 10; + +function t1($a = 1 + 1, $b = 1 << 2, $c = "foo" . "bar", $d = a * 10) { + var_dump($a, $b, $c, $d); +} + +t1(); +?> +--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 0000000000..ea69a8f86b --- /dev/null +++ b/Zend/tests/static_variable.phpt @@ -0,0 +1,29 @@ +--TEST-- +Static Variable Expressions +--FILE-- +<?php +const bar = 2, baz = bar + 1; + +function foo() { + static $a = 1 + 1; + static $b = [bar => 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.h b/Zend/zend.h index 5ac884455d..a949c5b0b6 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -317,6 +317,7 @@ typedef struct _zend_object { } zend_object; #include "zend_object_handlers.h" +#include "zend_ast.h" typedef union _zvalue_value { long lval; /* long value */ @@ -327,6 +328,7 @@ typedef union _zvalue_value { } str; HashTable *ht; /* hash table value */ zend_object_value obj; + zend_ast *ast; } zvalue_value; struct _zval_struct { @@ -577,17 +579,18 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length); /* data types */ /* All data types <= IS_BOOL have their constructor/destructors skipped */ -#define IS_NULL 0 -#define IS_LONG 1 -#define IS_DOUBLE 2 -#define IS_BOOL 3 -#define IS_ARRAY 4 -#define IS_OBJECT 5 -#define IS_STRING 6 -#define IS_RESOURCE 7 -#define IS_CONSTANT 8 +#define IS_NULL 0 +#define IS_LONG 1 +#define IS_DOUBLE 2 +#define IS_BOOL 3 +#define IS_ARRAY 4 +#define IS_OBJECT 5 +#define IS_STRING 6 +#define IS_RESOURCE 7 +#define IS_CONSTANT 8 #define IS_CONSTANT_ARRAY 9 -#define IS_CALLABLE 10 +#define IS_CONSTANT_AST 10 +#define IS_CALLABLE 11 /* Ugly hack to support constants as static array indices */ #define IS_CONSTANT_TYPE_MASK 0x00f @@ -597,6 +600,8 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length); #define IS_LEXICAL_REF 0x040 #define IS_CONSTANT_IN_NAMESPACE 0x100 +#define IS_CONSTANT_TYPE(type) (((type) & IS_CONSTANT_TYPE_MASK) >= IS_CONSTANT && ((type) & IS_CONSTANT_TYPE_MASK) <= IS_CONSTANT_AST) + /* overloaded elements data types */ #define OE_IS_ARRAY (1<<0) #define OE_IS_OBJECT (1<<1) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 5fa7fb908e..3687b6a67b 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1053,8 +1053,7 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destro static int zval_update_class_constant(zval **pp, int is_static, int offset TSRMLS_DC) /* {{{ */ { - if ((Z_TYPE_PP(pp) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || - (Z_TYPE_PP(pp) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT_ARRAY) { + if (IS_CONSTANT_TYPE(Z_TYPE_PP(pp))) { zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry); if ((*scope)->parent) { @@ -1078,7 +1077,7 @@ static int zval_update_class_constant(zval **pp, int is_static, int offset TSRML } ce = ce->parent; } while (ce); - + } return zval_update_constant(pp, (void*)1 TSRMLS_CC); } diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c new file mode 100644 index 0000000000..21c08da510 --- /dev/null +++ b/Zend/zend_ast.c @@ -0,0 +1,130 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "zend_ast.h" +#include "zend_execute.h" + +#define COPY_ZVAL_TO_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) + op_count * sizeof(zval *)); + ast->op_count = op_count; + ast->ops = (zval **)(ast + 1); + ast->refcount = 1; + ast->func = func; + Z_AST_P(result) = ast; + Z_TYPE_P(result) = IS_CONSTANT_AST; +} + +/* Do operations on constant operators at compile time (AST building time) */ + +void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 TSRMLS_DC) { + if (!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) { + func(result, op0 TSRMLS_CC); + if (op0) zval_dtor(op0); + return; + } + + zend_ast_add(result, (intermediary_ast_function_type)func, 1); + COPY_ZVAL_TO_OP(0) +} + +void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1 TSRMLS_DC) { + if ((!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) && (!op1 || !IS_CONSTANT_TYPE(Z_TYPE_P(op1)))) { + func(result, op0, op1 TSRMLS_CC); + if (op0) zval_dtor(op0); + if (op1) zval_dtor(op1); + return; + } + + zend_ast_add(result, (intermediary_ast_function_type)func, 2); + COPY_ZVAL_TO_OP(0) + COPY_ZVAL_TO_OP(1) +} + +void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2 TSRMLS_DC) { + if ((!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) && (!op1 || !IS_CONSTANT_TYPE(Z_TYPE_P(op1))) && (!op2 || !IS_CONSTANT_TYPE(Z_TYPE_P(op2)))) { + func(result, op0, op1, op2 TSRMLS_CC); + if (op0) zval_dtor(op0); + if (op1) zval_dtor(op1); + if (op2) zval_dtor(op2); + return; + } + + zend_ast_add(result, (intermediary_ast_function_type)func, 3); + COPY_ZVAL_TO_OP(0) + COPY_ZVAL_TO_OP(1) + COPY_ZVAL_TO_OP(2) +} + +void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC) { + int i; + zval **ops = emalloc((sizeof(zval *) + sizeof(zval)) * ast->op_count); + + for (i = ast->op_count; i--;) { + if (ast->ops[i] && IS_CONSTANT_TYPE(Z_TYPE_P(ast->ops[i]))) { + ops[i] = ((zval *)(ops + ast->op_count)) + i; + *ops[i] = *ast->ops[i]; + zval_copy_ctor(ops[i]); + zval_update_constant_ex(&ops[i], (void *)1, NULL TSRMLS_CC); + } else { + ops[i] = ast->ops[i]; + } + } + + switch (ast->op_count) { + case 1: + ((unary_ast_func)ast->func)(result, ops[0] TSRMLS_CC); + break; + case 2: + ((binary_ast_func)ast->func)(result, ops[0], ops[1] TSRMLS_CC); + break; + case 3: + ((ternary_ast_func)ast->func)(result, ops[0], ops[1], ops[2] TSRMLS_CC); + break; + } + + for (i = ast->op_count; i--;) { + if (ast->ops[i] != ops[i]) { + zval_dtor(ops[i]); + } + } + + efree(ops); +} + +void zend_ast_destroy(zend_ast *ast TSRMLS_DC) { + int i; + + for (i = ast->op_count; i--;) { + if (ast->ops[i] && !Z_DELREF_P(ast->ops[i])) { + zval_dtor(ast->ops[i]); + efree(ast->ops[i]); + } + } + + efree(ast); +} diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h new file mode 100644 index 0000000000..218f2c02e0 --- /dev/null +++ b/Zend/zend_ast.h @@ -0,0 +1,60 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef ZEND_AST_H +#define ZEND_AST_H + +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 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; + zval **ops; + intermediary_ast_function_type func; + int refcount; +}; + +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); + +void zend_ast_destroy(zend_ast *ast TSRMLS_DC); + +#define ZEND_AST_ADD_REF(ast) ++ast->refcount + +static inline int ZEND_AST_DEL_REF(zend_ast *ast) { + if (ast->refcount == 1) { + TSRMLS_FETCH(); + + zend_ast_destroy(ast TSRMLS_CC); + return 0; + } + return --ast->refcount; +} + +#endif diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 55e5f34e83..049864c54a 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -946,7 +946,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value /* this is necessary to make it able to work with default array * properties, returned to user */ - if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || (Z_TYPE_P(prop_copy) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + switch (IS_CONSTANT_TYPE(Z_TYPE_P(prop_copy))) { zval_update_constant(&prop_copy, 0 TSRMLS_CC); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 7132c3e5fc..77da945153 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1891,7 +1891,7 @@ void zend_do_receive_param(zend_uchar op, znode *varname, const znode *initializ if (class_type->u.constant.type == IS_ARRAY) { cur_arg_info->type_hint = IS_ARRAY; if (op == ZEND_RECV_INIT) { - if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { + if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) || Z_TYPE(initialization->u.constant) == IS_CONSTANT_AST) { cur_arg_info->allow_null = 1; } else if (Z_TYPE(initialization->u.constant) != IS_ARRAY && Z_TYPE(initialization->u.constant) != IS_CONSTANT_ARRAY) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with array type hint can only be an array or NULL"); @@ -1900,7 +1900,7 @@ void zend_do_receive_param(zend_uchar op, znode *varname, const znode *initializ } else if (class_type->u.constant.type == IS_CALLABLE) { cur_arg_info->type_hint = IS_CALLABLE; if (op == ZEND_RECV_INIT) { - if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { + if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) || Z_TYPE(initialization->u.constant) == IS_CONSTANT_AST) { cur_arg_info->allow_null = 1; } else { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with callable type hint can only be NULL"); @@ -1915,7 +1915,7 @@ void zend_do_receive_param(zend_uchar op, znode *varname, const znode *initializ cur_arg_info->class_name = Z_STRVAL(class_type->u.constant); cur_arg_info->class_name_len = Z_STRLEN(class_type->u.constant); if (op == ZEND_RECV_INIT) { - if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { + if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) || Z_TYPE(initialization->u.constant) == IS_CONSTANT_AST) { cur_arg_info->allow_null = 1; } else { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL"); @@ -5529,8 +5529,7 @@ static zend_constant* zend_get_ct_const(const zval *const_name, int all_internal if (all_internal_constants_substitution && (c->flags & CONST_PERSISTENT) && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) && - Z_TYPE(c->value) != IS_CONSTANT && - Z_TYPE(c->value) != IS_CONSTANT_ARRAY) { + !IS_CONSTANT_TYPE(Z_TYPE(c->value))) { return c; } return NULL; @@ -5772,7 +5771,7 @@ void zend_do_add_static_array_element(znode *result, znode *offset, const znode ALLOC_ZVAL(element); *element = expr->u.constant; if (offset) { - switch (offset->u.constant.type & IS_CONSTANT_TYPE_MASK) { + switch (Z_TYPE(offset->u.constant) & IS_CONSTANT_TYPE_MASK) { case IS_CONSTANT: /* Ugly hack to denote that this value has a constant index */ Z_TYPE_P(element) |= IS_CONSTANT_INDEX; @@ -5782,6 +5781,20 @@ void zend_do_add_static_array_element(znode *result, znode *offset, const znode zend_symtable_update(Z_ARRVAL(result->u.constant), Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+3, &element, sizeof(zval *), NULL); zval_dtor(&offset->u.constant); break; + case IS_CONSTANT_AST: { + /* Another ugly hack to store the data about the AST in the array */ + char* key; + int len = sizeof(zend_ast *); + Z_TYPE_P(element) |= IS_CONSTANT_INDEX; + + key = emalloc(len + 2); + *(zend_ast **)key = Z_AST(offset->u.constant); + key[len] = Z_TYPE(offset->u.constant); + key[len + 1] = 0; + zend_symtable_update(Z_ARRVAL(result->u.constant), key, len + 2, &element, sizeof(zval *), NULL); + efree(key); + } + break; case IS_STRING: zend_symtable_update(Z_ARRVAL(result->u.constant), Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+1, &element, sizeof(zval *), NULL); zval_dtor(&offset->u.constant); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index f9520c98ea..b80a7cb84f 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -23,6 +23,7 @@ #define ZEND_COMPILE_H #include "zend.h" +#include "zend_ast.h" #ifdef HAVE_STDARG_H # include <stdarg.h> @@ -721,6 +722,10 @@ int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC); #define ZEND_OP_DATA 137 +/* Pseudo-opcodes for internal object overloading */ +#define ZEND_BOOL_AND -1 +#define ZEND_BOOL_OR -2 + /* END: OPCODES */ /* class fetches */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 779e6d886f..12047f0518 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -478,188 +478,205 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco if (IS_CONSTANT_VISITED(p)) { zend_error(E_ERROR, "Cannot declare self-referencing constant '%s'", Z_STRVAL_P(p)); - } else if ((Z_TYPE_P(p) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { - int refcount; - zend_uchar is_ref; + return FAILURE; + } + switch (Z_TYPE_P(p) & IS_CONSTANT_TYPE_MASK) { + case IS_CONSTANT: { + int refcount; + zend_uchar is_ref; - SEPARATE_ZVAL_IF_NOT_REF(pp); - p = *pp; + SEPARATE_ZVAL_IF_NOT_REF(pp); + p = *pp; - MARK_CONSTANT_VISITED(p); + MARK_CONSTANT_VISITED(p); - refcount = Z_REFCOUNT_P(p); - is_ref = Z_ISREF_P(p); + refcount = Z_REFCOUNT_P(p); + is_ref = Z_ISREF_P(p); - if (!zend_get_constant_ex(p->value.str.val, p->value.str.len, &const_value, scope, Z_REAL_TYPE_P(p) TSRMLS_CC)) { - char *actual = Z_STRVAL_P(p); + if (!zend_get_constant_ex(p->value.str.val, p->value.str.len, &const_value, scope, Z_REAL_TYPE_P(p) TSRMLS_CC)) { + char *actual = Z_STRVAL_P(p); - if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) { - zend_error(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(p)); - Z_STRLEN_P(p) -= ((colon - Z_STRVAL_P(p)) + 1); - if (inline_change) { - colon = estrndup(colon, Z_STRLEN_P(p)); - str_efree(Z_STRVAL_P(p)); - Z_STRVAL_P(p) = colon; - } else { - Z_STRVAL_P(p) = colon + 1; - } - } else { - char *save = actual, *slash; - int actual_len = Z_STRLEN_P(p); - if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) && (slash = (char *)zend_memrchr(actual, '\\', actual_len))) { - actual = slash + 1; - actual_len -= (actual - Z_STRVAL_P(p)); + if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) { + zend_error(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(p)); + Z_STRLEN_P(p) -= ((colon - Z_STRVAL_P(p)) + 1); if (inline_change) { - actual = estrndup(actual, actual_len); - Z_STRVAL_P(p) = actual; - Z_STRLEN_P(p) = actual_len; - } - } - if (actual[0] == '\\') { - if (inline_change) { - memmove(Z_STRVAL_P(p), Z_STRVAL_P(p)+1, Z_STRLEN_P(p)); - --Z_STRLEN_P(p); + colon = estrndup(colon, Z_STRLEN_P(p)); + str_efree(Z_STRVAL_P(p)); + Z_STRVAL_P(p) = colon; } else { - ++actual; + Z_STRVAL_P(p) = colon + 1; } - --actual_len; - } - if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) { - int fix_save = 0; - if (save[0] == '\\') { - save++; - fix_save = 1; + } else { + char *save = actual, *slash; + int actual_len = Z_STRLEN_P(p); + if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) && (slash = (char *)zend_memrchr(actual, '\\', actual_len))) { + actual = slash + 1; + actual_len -= (actual - Z_STRVAL_P(p)); + if (inline_change) { + actual = estrndup(actual, actual_len); + Z_STRVAL_P(p) = actual; + Z_STRLEN_P(p) = actual_len; + } } - zend_error(E_ERROR, "Undefined constant '%s'", save); - if (fix_save) { - save--; + if (actual[0] == '\\') { + if (inline_change) { + memmove(Z_STRVAL_P(p), Z_STRVAL_P(p)+1, Z_STRLEN_P(p)--); + } else { + ++actual; + } + --actual_len; } - if (inline_change) { + if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) { + int fix_save = 0; + if (save[0] == '\\') { + save++; + fix_save = 1; + } + zend_error(E_ERROR, "Undefined constant '%s'", save); + if (fix_save) { + save--; + } + if (inline_change) { + str_efree(save); + } + save = NULL; + } + if (inline_change && save && save != actual) { str_efree(save); } - save = NULL; - } - if (inline_change && save && save != actual) { - str_efree(save); + zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual); + p->type = IS_STRING; + if (!inline_change) { + Z_STRVAL_P(p) = actual; + Z_STRLEN_P(p) = actual_len; + zval_copy_ctor(p); + } } - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual); - p->type = IS_STRING; - if (!inline_change) { - Z_STRVAL_P(p) = actual; - Z_STRLEN_P(p) = actual_len; - zval_copy_ctor(p); + } else { + if (inline_change) { + str_efree(Z_STRVAL_P(p)); } + *p = const_value; } - } else { - if (inline_change) { - str_efree(Z_STRVAL_P(p)); - } - *p = const_value; - } - Z_SET_REFCOUNT_P(p, refcount); - Z_SET_ISREF_TO_P(p, is_ref); - } else if (Z_TYPE_P(p) == IS_CONSTANT_ARRAY) { - zval **element, *new_val; - char *str_index; - uint str_index_len; - ulong num_index; - int ret; - - SEPARATE_ZVAL_IF_NOT_REF(pp); - p = *pp; - Z_TYPE_P(p) = IS_ARRAY; - - if (!inline_change) { - zval *tmp; - HashTable *tmp_ht = NULL; - - ALLOC_HASHTABLE(tmp_ht); - zend_hash_init(tmp_ht, zend_hash_num_elements(Z_ARRVAL_P(p)), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(tmp_ht, Z_ARRVAL_P(p), (copy_ctor_func_t) zval_deep_copy, (void *) &tmp, sizeof(zval *)); - Z_ARRVAL_P(p) = tmp_ht; + Z_SET_REFCOUNT_P(p, refcount); + Z_SET_ISREF_TO_P(p, is_ref); } - - /* First go over the array and see if there are any constant indices */ - zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); - while (zend_hash_get_current_data(Z_ARRVAL_P(p), (void **) &element) == SUCCESS) { - if (!(Z_TYPE_PP(element) & IS_CONSTANT_INDEX)) { - zend_hash_move_forward(Z_ARRVAL_P(p)); - continue; + break; + + case IS_CONSTANT_ARRAY: { + zval **element, *new_val; + char *str_index; + uint str_index_len; + ulong num_index; + int ret; + + SEPARATE_ZVAL_IF_NOT_REF(pp); + p = *pp; + Z_TYPE_P(p) = IS_ARRAY; + + if (!inline_change) { + zval *tmp; + HashTable *tmp_ht = NULL; + + ALLOC_HASHTABLE(tmp_ht); + zend_hash_init(tmp_ht, zend_hash_num_elements(Z_ARRVAL_P(p)), NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(tmp_ht, Z_ARRVAL_P(p), (copy_ctor_func_t) zval_deep_copy, (void *) &tmp, sizeof(zval *)); + Z_ARRVAL_P(p) = tmp_ht; } - Z_TYPE_PP(element) &= ~IS_CONSTANT_INDEX; - if (zend_hash_get_current_key_ex(Z_ARRVAL_P(p), &str_index, &str_index_len, &num_index, 0, NULL) != HASH_KEY_IS_STRING) { - zend_hash_move_forward(Z_ARRVAL_P(p)); - continue; - } - if (!zend_get_constant_ex(str_index, str_index_len - 3, &const_value, scope, str_index[str_index_len - 2] TSRMLS_CC)) { - char *actual; - const char *save = str_index; - if ((colon = (char*)zend_memrchr(str_index, ':', str_index_len - 3))) { - zend_error(E_ERROR, "Undefined class constant '%s'", str_index); - str_index_len -= ((colon - str_index) + 1); - str_index = colon; - } else { - if (str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) { - if ((actual = (char *)zend_memrchr(str_index, '\\', str_index_len - 3))) { - actual++; - str_index_len -= (actual - str_index); - str_index = actual; + + /* First go over the array and see if there are any constant indices */ + zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); + while (zend_hash_get_current_data(Z_ARRVAL_P(p), (void **) &element) == SUCCESS) { + if (!(Z_TYPE_PP(element) & IS_CONSTANT_INDEX)) { + zend_hash_move_forward(Z_ARRVAL_P(p)); + continue; + } + Z_TYPE_PP(element) &= ~IS_CONSTANT_INDEX; + if (zend_hash_get_current_key_ex(Z_ARRVAL_P(p), &str_index, &str_index_len, &num_index, 0, NULL) != HASH_KEY_IS_STRING) { + zend_hash_move_forward(Z_ARRVAL_P(p)); + continue; + } + if (str_index[str_index_len - 2] == IS_CONSTANT_AST) { + 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; + const char *save = str_index; + if ((colon = (char*)zend_memrchr(str_index, ':', str_index_len - 3))) { + zend_error(E_ERROR, "Undefined class constant '%s'", str_index); + str_index_len -= ((colon - str_index) + 1); + str_index = colon; + } else { + if (str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) { + if ((actual = (char *)zend_memrchr(str_index, '\\', str_index_len - 3))) { + actual++; + str_index_len -= (actual - str_index); + str_index = actual; + } } + if (str_index[0] == '\\') { + ++str_index; + --str_index_len; + } + if (save[0] == '\\') { + ++save; + } + if ((str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) == 0) { + zend_error(E_ERROR, "Undefined constant '%s'", save); + } + zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", str_index, str_index); } - if (str_index[0] == '\\') { - ++str_index; - --str_index_len; - } - if (save[0] == '\\') { - ++save; - } - if ((str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) == 0) { - zend_error(E_ERROR, "Undefined constant '%s'", save); - } - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", str_index, str_index); + ZVAL_STRINGL(&const_value, str_index, str_index_len-3, 1); } - ZVAL_STRINGL(&const_value, str_index, str_index_len-3, 1); - } - if (Z_REFCOUNT_PP(element) > 1) { - ALLOC_ZVAL(new_val); - *new_val = **element; - zval_copy_ctor(new_val); - Z_SET_REFCOUNT_P(new_val, 1); - Z_UNSET_ISREF_P(new_val); - - /* preserve this bit for inheritance */ - Z_TYPE_PP(element) |= IS_CONSTANT_INDEX; - zval_ptr_dtor(element); - *element = new_val; - } + if (Z_REFCOUNT_PP(element) > 1) { + ALLOC_ZVAL(new_val); + *new_val = **element; + zval_copy_ctor(new_val); + Z_SET_REFCOUNT_P(new_val, 1); + Z_UNSET_ISREF_P(new_val); + + /* preserve this bit for inheritance */ + Z_TYPE_PP(element) |= IS_CONSTANT_INDEX; + zval_ptr_dtor(element); + *element = new_val; + } - switch (Z_TYPE(const_value)) { - case IS_STRING: - ret = zend_symtable_update_current_key(Z_ARRVAL_P(p), Z_STRVAL(const_value), Z_STRLEN(const_value) + 1, HASH_UPDATE_KEY_IF_BEFORE); - break; - case IS_BOOL: - case IS_LONG: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - case IS_DOUBLE: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, zend_dval_to_lval(Z_DVAL(const_value)), HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - case IS_NULL: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, "", 1, 0, HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - default: - ret = SUCCESS; - break; - } - if (ret == SUCCESS) { - zend_hash_move_forward(Z_ARRVAL_P(p)); + switch (Z_TYPE(const_value)) { + case IS_STRING: + ret = zend_symtable_update_current_key(Z_ARRVAL_P(p), Z_STRVAL(const_value), Z_STRLEN(const_value) + 1, HASH_UPDATE_KEY_IF_BEFORE); + break; + case IS_BOOL: + case IS_LONG: + ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL); + break; + case IS_DOUBLE: + ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, zend_dval_to_lval(Z_DVAL(const_value)), HASH_UPDATE_KEY_IF_BEFORE, NULL); + break; + case IS_NULL: + ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, "", 1, 0, HASH_UPDATE_KEY_IF_BEFORE, NULL); + break; + default: + ret = SUCCESS; + break; + } + if (ret == SUCCESS) { + zend_hash_move_forward(Z_ARRVAL_P(p)); + } + zval_dtor(&const_value); } - zval_dtor(&const_value); + zend_hash_apply_with_argument(Z_ARRVAL_P(p), (apply_func_arg_t) zval_update_constant_inline_change, (void *) scope TSRMLS_CC); + zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); + } + break; + + case IS_CONSTANT_AST: { + zend_ast *ast = Z_AST_P(p); + + zend_ast_evaluate(p, ast TSRMLS_CC); + ZEND_AST_DEL_REF(ast); } - zend_hash_apply_with_argument(Z_ARRVAL_P(p), (apply_func_arg_t) zval_update_constant_inline_change, (void *) scope TSRMLS_CC); - zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); } return 0; } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index f76b77b555..19d6d839a2 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -947,24 +947,61 @@ common_scalar: | T_START_HEREDOC T_END_HEREDOC { ZVAL_EMPTY_STRING(&$$.u.constant); INIT_PZVAL(&$$.u.constant); $$.op_type = IS_CONST; } ; +static_class_constant: + class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT, 0 TSRMLS_CC); } +; static_scalar: /* compile-time evaluated scalars */ - common_scalar { $$ = $1; } + static_scalar_value { $$ = $1; } + | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; } + | '[' static_array_pair_list ']' { $$ = $2; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; } +; + +static_scalar_value: + common_scalar { $$ = $1; } | static_class_name_scalar { $$ = $1; } | namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 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_CT, 0 TSRMLS_CC); } | T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); } - | '+' static_scalar { ZVAL_LONG(&$1.u.constant, 0); add_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } - | '-' static_scalar { ZVAL_LONG(&$1.u.constant, 0); sub_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } - | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; } - | '[' static_array_pair_list ']' { $$ = $2; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; } | static_class_constant { $$ = $1; } | T_CLASS_C { $$ = $1; } + | static_operation { $$ = $1; } +; + +static_operation: + static_scalar_value '+' static_scalar_value { zend_ast_add_binary(&$$.u.constant, add_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '-' static_scalar_value { zend_ast_add_binary(&$$.u.constant, sub_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '*' static_scalar_value { zend_ast_add_binary(&$$.u.constant, mul_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '/' static_scalar_value { zend_ast_add_binary(&$$.u.constant, div_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '%' static_scalar_value { zend_ast_add_binary(&$$.u.constant, mod_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | '!' static_scalar_value { zend_ast_add_unary(&$$.u.constant, boolean_not_function, &$2.u.constant TSRMLS_CC); } + | '~' static_scalar_value { zend_ast_add_unary(&$$.u.constant, bitwise_not_function, &$2.u.constant TSRMLS_CC); } + | static_scalar_value '|' static_scalar_value { zend_ast_add_binary(&$$.u.constant, bitwise_or_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '&' static_scalar_value { zend_ast_add_binary(&$$.u.constant, bitwise_and_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '^' static_scalar_value { zend_ast_add_binary(&$$.u.constant, bitwise_xor_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | 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 T_LOGICAL_XOR static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_xor_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_LOGICAL_AND static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_and_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_LOGICAL_OR static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_or_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_BOOLEAN_AND static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_and_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_BOOLEAN_OR static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_or_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_IS_IDENTICAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_identical_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_IS_NOT_IDENTICAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_not_identical_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_IS_EQUAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_equal_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_IS_NOT_EQUAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_not_equal_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '<' static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_smaller_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value '>' static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_smaller_function, &$3.u.constant, &$1.u.constant TSRMLS_CC); } + | static_scalar_value T_IS_SMALLER_OR_EQUAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_smaller_or_equal_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } + | static_scalar_value T_IS_GREATER_OR_EQUAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_smaller_or_equal_function, &$3.u.constant, &$1.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; } ; -static_class_constant: - class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT, 0 TSRMLS_CC); } -; scalar: T_STRING_VARNAME { $$ = $1; } diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index e8629291e5..8c083542f0 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1082,6 +1082,46 @@ ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) } /* }}} */ +ZEND_API int boolean_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + zval op1_copy, op2_copy; + long op1_lval; + + if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_AND); + + zendi_convert_to_boolean(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_boolean(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } + + ZVAL_BOOL(result, op1_lval & Z_LVAL_P(op2)); + return SUCCESS; +} +/* }}} */ + +ZEND_API int boolean_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + zval op1_copy, op2_copy; + long op1_lval; + + if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_OR); + + zendi_convert_to_boolean(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_boolean(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } + + ZVAL_BOOL(result, op1_lval | Z_LVAL_P(op2)); + return SUCCESS; +} +/* }}} */ + ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { zval op1_copy; @@ -2323,6 +2363,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 15ad79e4db..3f0fc2ef6a 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -50,6 +50,8 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); +ZEND_API int boolean_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); +ZEND_API int boolean_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC); ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC); ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); @@ -376,6 +378,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) \ @@ -443,6 +447,7 @@ END_EXTERN_C() #define Z_STRVAL(zval) (zval).value.str.val #define Z_STRLEN(zval) (zval).value.str.len #define Z_ARRVAL(zval) (zval).value.ht +#define Z_AST(zval) (zval).value.ast #define Z_OBJVAL(zval) (zval).value.obj #define Z_OBJ_HANDLE(zval) Z_OBJVAL(zval).handle #define Z_OBJ_HT(zval) Z_OBJVAL(zval).handlers @@ -458,6 +463,7 @@ END_EXTERN_C() #define Z_STRVAL_P(zval_p) Z_STRVAL(*zval_p) #define Z_STRLEN_P(zval_p) Z_STRLEN(*zval_p) #define Z_ARRVAL_P(zval_p) Z_ARRVAL(*zval_p) +#define Z_AST_P(zval_p) Z_AST(*zval_p) #define Z_OBJPROP_P(zval_p) Z_OBJPROP(*zval_p) #define Z_OBJCE_P(zval_p) Z_OBJCE(*zval_p) #define Z_RESVAL_P(zval_p) Z_RESVAL(*zval_p) @@ -473,6 +479,7 @@ END_EXTERN_C() #define Z_STRVAL_PP(zval_pp) Z_STRVAL(**zval_pp) #define Z_STRLEN_PP(zval_pp) Z_STRLEN(**zval_pp) #define Z_ARRVAL_PP(zval_pp) Z_ARRVAL(**zval_pp) +#define Z_AST_PP(zval_p) Z_AST(**zval_p) #define Z_OBJPROP_PP(zval_pp) Z_OBJPROP(**zval_pp) #define Z_OBJCE_PP(zval_pp) Z_OBJCE(**zval_pp) #define Z_RESVAL_PP(zval_pp) Z_RESVAL(**zval_pp) diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c index d82e1642e7..095c16ca91 100644 --- a/Zend/zend_variables.c +++ b/Zend/zend_variables.c @@ -22,6 +22,7 @@ #include <stdio.h> #include "zend.h" #include "zend_API.h" +#include "zend_ast.h" #include "zend_globals.h" #include "zend_constants.h" #include "zend_list.h" @@ -47,6 +48,9 @@ ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC) } } break; + case IS_CONSTANT_AST: + ZEND_AST_DEL_REF(Z_AST_P(zvalue)); + break; case IS_OBJECT: { TSRMLS_FETCH(); @@ -81,6 +85,9 @@ ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC) CHECK_ZVAL_STRING_REL(zvalue); str_free(zvalue->value.str.val); break; + case IS_CONSTANT_AST: + ZEND_AST_DEL_REF(Z_AST_P(zvalue)); + break; case IS_ARRAY: case IS_CONSTANT_ARRAY: case IS_OBJECT: @@ -139,6 +146,9 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) zvalue->value.ht = tmp_ht; } break; + case IS_CONSTANT_AST: + ZEND_AST_ADD_REF(Z_AST_P(zvalue)); + break; case IS_OBJECT: { TSRMLS_FETCH(); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 572aac5a20..006f2ec729 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3252,8 +3252,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) if (param == NULL) { ALLOC_ZVAL(assignment_value); *assignment_value = *opline->op2.zv; - if ((Z_TYPE_P(assignment_value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || - Z_TYPE_P(assignment_value)==IS_CONSTANT_ARRAY) { + if (IS_CONSTANT_TYPE(Z_TYPE_P(assignment_value))) { Z_SET_REFCOUNT_P(assignment_value, 1); zval_update_constant(&assignment_value, 0 TSRMLS_CC); } else { @@ -3580,8 +3579,7 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST) } if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { - if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || - (Z_TYPE_PP(value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + if (IS_CONSTANT_TYPE(Z_TYPE_PP(value))) { zend_class_entry *old_scope = EG(scope); EG(scope) = ce; @@ -5187,7 +5185,7 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST) name = GET_OP1_ZVAL_PTR(BP_VAR_R); val = GET_OP2_ZVAL_PTR(BP_VAR_R); - if ((Z_TYPE_P(val) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE_P(val) == IS_CONSTANT_ARRAY) { + if (IS_CONSTANT_TYPE(Z_TYPE_P(val))) { zval tmp; zval *tmp_ptr = &tmp; @@ -5202,6 +5200,7 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST) INIT_PZVAL_COPY(&c.value, val); zval_copy_ctor(&c.value); } + c.flags = CONST_CS; /* non persistent, case sensetive */ c.name = str_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); c.name_len = Z_STRLEN_P(name)+1; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 7ad7dcf463..4f850c2978 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1435,8 +1435,7 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ if (param == NULL) { ALLOC_ZVAL(assignment_value); *assignment_value = *opline->op2.zv; - if ((Z_TYPE_P(assignment_value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || - Z_TYPE_P(assignment_value)==IS_CONSTANT_ARRAY) { + if (IS_CONSTANT_TYPE(Z_TYPE_P(assignment_value))) { Z_SET_REFCOUNT_P(assignment_value, 1); zval_update_constant(&assignment_value, 0 TSRMLS_CC); } else { @@ -3792,8 +3791,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO } if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { - if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || - (Z_TYPE_PP(value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + if (IS_CONSTANT_TYPE(Z_TYPE_PP(value))) { zend_class_entry *old_scope = EG(scope); EG(scope) = ce; @@ -4089,7 +4087,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCOD name = opline->op1.zv; val = opline->op2.zv; - if ((Z_TYPE_P(val) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE_P(val) == IS_CONSTANT_ARRAY) { + if (IS_CONSTANT_TYPE(Z_TYPE_P(val))) { zval tmp; zval *tmp_ptr = &tmp; @@ -4104,6 +4102,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCOD INIT_PZVAL_COPY(&c.value, val); zval_copy_ctor(&c.value); } + c.flags = CONST_CS; /* non persistent, case sensetive */ c.name = str_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); c.name_len = Z_STRLEN_P(name)+1; @@ -15635,8 +15634,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE } if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { - if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || - (Z_TYPE_PP(value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + if (IS_CONSTANT_TYPE(Z_TYPE_PP(value))) { zend_class_entry *old_scope = EG(scope); EG(scope) = ce; @@ -25171,8 +25169,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC } if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { - if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || - (Z_TYPE_PP(value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + if (IS_CONSTANT_TYPE(Z_TYPE_PP(value))) { zend_class_entry *old_scope = EG(scope); EG(scope) = ce; diff --git a/configure.in b/configure.in index 805aa48f59..29358b1c88 100644 --- a/configure.in +++ b/configure.in @@ -1476,7 +1476,7 @@ PHP_ADD_SOURCES(Zend, \ zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \ zend_closures.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ - zend_virtual_cwd.c) + zend_virtual_cwd.c zend_ast.c) if test -r "$abs_srcdir/Zend/zend_objects.c"; then PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_default_classes.c) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index cc148b39c5..bff5e66472 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2599,8 +2599,7 @@ ZEND_METHOD(reflection_parameter, getDefaultValue) *return_value = *precv->op2.zv; INIT_PZVAL(return_value); - if ((Z_TYPE_P(return_value) & IS_CONSTANT_TYPE_MASK) != IS_CONSTANT - && (Z_TYPE_P(return_value) & IS_CONSTANT_TYPE_MASK) != IS_CONSTANT_ARRAY) { + if (!IS_CONSTANT_TYPE(Z_TYPE_P(return_value))) { zval_copy_ctor(return_value); } zval_update_constant_ex(&return_value, (void*)0, param->fptr->common.scope TSRMLS_CC); @@ -3414,7 +3413,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value /* this is necessary to make it able to work with default array * properties, returned to user */ - if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || (Z_TYPE_P(prop_copy) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + if (IS_CONSTANT_TYPE(Z_TYPE_P(prop_copy))) { zval_update_constant(&prop_copy, (void *) 1 TSRMLS_CC); } diff --git a/win32/build/config.w32 b/win32/build/config.w32 index af92eb0d4c..6e19c48967 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -364,7 +364,7 @@ ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ zend_stream.c zend_iterators.c zend_interfaces.c zend_objects.c \ zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c \ - zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c"); + zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c"); if (VCVERS == 1200) { AC_DEFINE('ZEND_DVAL_TO_LVAL_CAST_OK', 1); |
