summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/Makefile.am2
-rw-r--r--Zend/Zend.dsp4
-rw-r--r--Zend/ZendTS.dsp4
-rw-r--r--Zend/tests/class_properties_dynamic.phpt13
-rw-r--r--Zend/tests/class_properties_static.phpt20
-rw-r--r--Zend/tests/constant_expressions.phpt91
-rw-r--r--Zend/tests/constant_expressions_dynamic.phpt11
-rw-r--r--Zend/tests/function_arguments_003.phpt17
-rw-r--r--Zend/tests/static_variable.phpt29
-rw-r--r--Zend/zend.h25
-rw-r--r--Zend/zend_API.c5
-rw-r--r--Zend/zend_ast.c130
-rw-r--r--Zend/zend_ast.h60
-rw-r--r--Zend/zend_builtin_functions.c2
-rw-r--r--Zend/zend_compile.c25
-rw-r--r--Zend/zend_compile.h5
-rw-r--r--Zend/zend_execute_API.c331
-rw-r--r--Zend/zend_language_parser.y53
-rw-r--r--Zend/zend_operators.c62
-rw-r--r--Zend/zend_operators.h7
-rw-r--r--Zend/zend_variables.c10
-rw-r--r--Zend/zend_vm_def.h9
-rw-r--r--Zend/zend_vm_execute.h15
-rw-r--r--configure.in2
-rw-r--r--ext/reflection/php_reflection.c5
-rw-r--r--win32/build/config.w322
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);