Commit:    3823321c5cef053319872ae07d726f0ef29c90b1
Author:    Nikita Popov <ni...@php.net>         Mon, 17 Jun 2013 17:48:13 +0200
Parents:   1143f58a7094ed9a4960bfb714fa2773dda7c704
Branches:  master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=3823321c5cef053319872ae07d726f0ef29c90b1

Log:
Implement internal operator overloading

As pre RFC https://wiki.php.net/rfc/operator_overloading_gmp

Changed paths:
  M  Zend/zend_object_handlers.c
  M  Zend/zend_object_handlers.h
  M  Zend/zend_operators.c
  M  Zend/zend_operators.h

diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index f7be370..921e0d7 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -1651,6 +1651,8 @@ ZEND_API zend_object_handlers std_object_handlers = {
        NULL,                                                                   
/* get_debug_info */
        zend_std_get_closure,                                   /* get_closure 
*/
        zend_std_get_gc,                                                /* 
get_gc */
+       NULL,                                                                   
/* do_operation */
+       NULL,                                                                   
/* compare */
 };
 
 /*
diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h
index 3ea6008..0742873 100644
--- a/Zend/zend_object_handlers.h
+++ b/Zend/zend_object_handlers.h
@@ -100,6 +100,7 @@ typedef zend_object_value (*zend_object_clone_obj_t)(zval 
*object TSRMLS_DC);
 typedef zend_class_entry *(*zend_object_get_class_entry_t)(const zval *object 
TSRMLS_DC);
 typedef int (*zend_object_get_class_name_t)(const zval *object, const char 
**class_name, zend_uint *class_name_len, int parent TSRMLS_DC);
 typedef int (*zend_object_compare_t)(zval *object1, zval *object2 TSRMLS_DC);
+typedef int (*zend_object_compare_zvals_t)(zval *resul, zval *op1, zval *op2 
TSRMLS_DC);
 
 /* Cast an object to some other type
  */
@@ -113,6 +114,8 @@ typedef int (*zend_object_get_closure_t)(zval *obj, 
zend_class_entry **ce_ptr, u
 
 typedef HashTable *(*zend_object_get_gc_t)(zval *object, zval ***table, int *n 
TSRMLS_DC);
 
+typedef int (*zend_object_do_operation_t)(zend_uchar opcode, zval *result, 
zval *op1, zval *op2 TSRMLS_DC);
+
 struct _zend_object_handlers {
        /* general object functions */
        zend_object_add_ref_t                                   add_ref;
@@ -142,6 +145,8 @@ struct _zend_object_handlers {
        zend_object_get_debug_info_t                    get_debug_info;
        zend_object_get_closure_t                               get_closure;
        zend_object_get_gc_t                                    get_gc;
+       zend_object_do_operation_t                              do_operation;
+       zend_object_compare_zvals_t                             compare;
 };
 
 extern ZEND_API zend_object_handlers std_object_handlers;
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index 88995c4..6073012 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -857,6 +857,8 @@ ZEND_API int add_function(zval *result, zval *op1, zval 
*op2 TSRMLS_DC) /* {{{ *
 
                        default:
                                if (!converted) {
+                                       
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD);
+
                                        zendi_convert_scalar_to_number(op1, 
op1_copy, result);
                                        zendi_convert_scalar_to_number(op2, 
op2_copy, result);
                                        converted = 1;
@@ -904,6 +906,8 @@ ZEND_API int sub_function(zval *result, zval *op1, zval 
*op2 TSRMLS_DC) /* {{{ *
 
                        default:
                                if (!converted) {
+                                       
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB);
+
                                        zendi_convert_scalar_to_number(op1, 
op1_copy, result);
                                        zendi_convert_scalar_to_number(op2, 
op2_copy, result);
                                        converted = 1;
@@ -945,6 +949,8 @@ ZEND_API int mul_function(zval *result, zval *op1, zval 
*op2 TSRMLS_DC) /* {{{ *
 
                        default:
                                if (!converted) {
+                                       
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL);
+
                                        zendi_convert_scalar_to_number(op1, 
op1_copy, result);
                                        zendi_convert_scalar_to_number(op2, 
op2_copy, result);
                                        converted = 1;
@@ -1010,6 +1016,8 @@ ZEND_API int div_function(zval *result, zval *op1, zval 
*op2 TSRMLS_DC) /* {{{ *
 
                        default:
                                if (!converted) {
+                                       
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
+
                                        zendi_convert_scalar_to_number(op1, 
op1_copy, result);
                                        zendi_convert_scalar_to_number(op2, 
op2_copy, result);
                                        converted = 1;
@@ -1027,9 +1035,15 @@ ZEND_API int mod_function(zval *result, zval *op1, zval 
*op2 TSRMLS_DC) /* {{{ *
        zval op1_copy, op2_copy;
        long op1_lval;
 
-       zendi_convert_to_long(op1, op1_copy, result);
-       op1_lval = Z_LVAL_P(op1);
-       zendi_convert_to_long(op2, op2_copy, result);
+       if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
+               ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD);
+
+               zendi_convert_to_long(op1, op1_copy, result);
+               op1_lval = Z_LVAL_P(op1);
+               zendi_convert_to_long(op2, op2_copy, result);
+       } else {
+               op1_lval = Z_LVAL_P(op1);
+       }
 
        if (Z_LVAL_P(op2) == 0) {
                zend_error(E_WARNING, "Division by zero");
@@ -1053,9 +1067,16 @@ ZEND_API int boolean_xor_function(zval *result, zval 
*op1, zval *op2 TSRMLS_DC)
        zval op1_copy, op2_copy;
        long op1_lval;
 
-       zendi_convert_to_boolean(op1, op1_copy, result);
-       op1_lval = Z_LVAL_P(op1);
-       zendi_convert_to_boolean(op2, op2_copy, result);
+       if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) {
+               ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_XOR);
+
+               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;
 }
@@ -1065,7 +1086,12 @@ ZEND_API int boolean_not_function(zval *result, zval 
*op1 TSRMLS_DC) /* {{{ */
 {
        zval op1_copy;
 
-       zendi_convert_to_boolean(op1, op1_copy, result);
+       if (Z_TYPE_P(op1) != IS_BOOL) {
+               ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
+
+               zendi_convert_to_boolean(op1, op1_copy, result);
+       }
+
        ZVAL_BOOL(result, !Z_LVAL_P(op1));
        return SUCCESS;
 }
@@ -1073,29 +1099,32 @@ ZEND_API int boolean_not_function(zval *result, zval 
*op1 TSRMLS_DC) /* {{{ */
 
 ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
 {
-       zval op1_copy = *op1;
-
-       op1 = &op1_copy;
 
-       if (Z_TYPE_P(op1) == IS_LONG) {
-               ZVAL_LONG(result, ~Z_LVAL_P(op1));
-               return SUCCESS;
-       } else if (Z_TYPE_P(op1) == IS_DOUBLE) {
-               ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
-               return SUCCESS;
-       } else if (Z_TYPE_P(op1) == IS_STRING) {
-               int i;
-
-               Z_TYPE_P(result) = IS_STRING;
-               Z_STRVAL_P(result) = estrndup(Z_STRVAL_P(op1), Z_STRLEN_P(op1));
-               Z_STRLEN_P(result) = Z_STRLEN_P(op1);
-               for (i = 0; i < Z_STRLEN_P(op1); i++) {
-                       Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
+       switch (Z_TYPE_P(op1)) {
+               case IS_LONG:
+                       ZVAL_LONG(result, ~Z_LVAL_P(op1));
+                       return SUCCESS;
+               case IS_DOUBLE:
+                       ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
+                       return SUCCESS;
+               case IS_STRING: {
+                       int i;
+                       zval op1_copy = *op1;
+
+                       Z_TYPE_P(result) = IS_STRING;
+                       Z_STRVAL_P(result) = estrndup(Z_STRVAL(op1_copy), 
Z_STRLEN(op1_copy));
+                       Z_STRLEN_P(result) = Z_STRLEN(op1_copy);
+                       for (i = 0; i < Z_STRLEN(op1_copy); i++) {
+                               Z_STRVAL_P(result)[i] = ~Z_STRVAL(op1_copy)[i];
+                       }
+                       return SUCCESS;
                }
-               return SUCCESS;
+               default:
+                       ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
+
+                       zend_error(E_ERROR, "Unsupported operand types");
+                       return FAILURE;
        }
-       zend_error(E_ERROR, "Unsupported operand types");
-       return FAILURE;                         /* unknown datatype */
 }
 /* }}} */
 
@@ -1130,9 +1159,16 @@ ZEND_API int bitwise_or_function(zval *result, zval 
*op1, zval *op2 TSRMLS_DC) /
                Z_STRLEN_P(result) = result_len;
                return SUCCESS;
        }
-       zendi_convert_to_long(op1, op1_copy, result);
-       op1_lval = Z_LVAL_P(op1);
-       zendi_convert_to_long(op2, op2_copy, result);
+
+       if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
+               ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR);
+
+               zendi_convert_to_long(op1, op1_copy, result);
+               op1_lval = Z_LVAL_P(op1);
+               zendi_convert_to_long(op2, op2_copy, result);
+       } else {
+               op1_lval = Z_LVAL_P(op1);
+       }
 
        ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
        return SUCCESS;
@@ -1171,10 +1207,15 @@ ZEND_API int bitwise_and_function(zval *result, zval 
*op1, zval *op2 TSRMLS_DC)
                return SUCCESS;
        }
 
+       if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
+               ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND);
 
-       zendi_convert_to_long(op1, op1_copy, result);
-       op1_lval = Z_LVAL_P(op1);
-       zendi_convert_to_long(op2, op2_copy, result);
+               zendi_convert_to_long(op1, op1_copy, result);
+               op1_lval = Z_LVAL_P(op1);
+               zendi_convert_to_long(op2, op2_copy, result);
+       } else {
+               op1_lval = Z_LVAL_P(op1);
+       }
 
        ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
        return SUCCESS;
@@ -1213,9 +1254,15 @@ ZEND_API int bitwise_xor_function(zval *result, zval 
*op1, zval *op2 TSRMLS_DC)
                return SUCCESS;
        }
 
-       zendi_convert_to_long(op1, op1_copy, result);
-       op1_lval = Z_LVAL_P(op1);
-       zendi_convert_to_long(op2, op2_copy, result);
+       if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
+               ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR);
+
+               zendi_convert_to_long(op1, op1_copy, result);
+               op1_lval = Z_LVAL_P(op1);
+               zendi_convert_to_long(op2, op2_copy, result);
+       } else {
+               op1_lval = Z_LVAL_P(op1);
+       }
 
        ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
        return SUCCESS;
@@ -1227,9 +1274,16 @@ ZEND_API int shift_left_function(zval *result, zval 
*op1, zval *op2 TSRMLS_DC) /
        zval op1_copy, op2_copy;
        long op1_lval;
 
-       zendi_convert_to_long(op1, op1_copy, result);
-       op1_lval = Z_LVAL_P(op1);
-       zendi_convert_to_long(op2, op2_copy, result);
+       if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
+               ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL);
+
+               zendi_convert_to_long(op1, op1_copy, result);
+               op1_lval = Z_LVAL_P(op1);
+               zendi_convert_to_long(op2, op2_copy, result);
+       } else {
+               op1_lval = Z_LVAL_P(op1);
+       }
+
        ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
        return SUCCESS;
 }
@@ -1240,9 +1294,16 @@ ZEND_API int shift_right_function(zval *result, zval 
*op1, zval *op2 TSRMLS_DC)
        zval op1_copy, op2_copy;
        long op1_lval;
 
-       zendi_convert_to_long(op1, op1_copy, result);
-       op1_lval = Z_LVAL_P(op1);
-       zendi_convert_to_long(op2, op2_copy, result);
+       if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
+               ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR);
+
+               zendi_convert_to_long(op1, op1_copy, result);
+               op1_lval = Z_LVAL_P(op1);
+               zendi_convert_to_long(op2, op2_copy, result);
+       } else {
+               op1_lval = Z_LVAL_P(op1);
+       }
+
        ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
        return SUCCESS;
 }
@@ -1291,11 +1352,15 @@ ZEND_API int concat_function(zval *result, zval *op1, 
zval *op2 TSRMLS_DC) /* {{
        zval op1_copy, op2_copy;
        int use_copy1 = 0, use_copy2 = 0;
 
-       if (Z_TYPE_P(op1) != IS_STRING) {
-               zend_make_printable_zval(op1, &op1_copy, &use_copy1);
-       }
-       if (Z_TYPE_P(op2) != IS_STRING) {
-               zend_make_printable_zval(op2, &op2_copy, &use_copy2);
+       if (Z_TYPE_P(op1) != IS_STRING || Z_TYPE_P(op2) != IS_STRING) {
+               ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT);
+
+               if (Z_TYPE_P(op1) != IS_STRING) {
+                       zend_make_printable_zval(op1, &op1_copy, &use_copy1);
+               }
+               if (Z_TYPE_P(op2) != IS_STRING) {
+                       zend_make_printable_zval(op2, &op2_copy, &use_copy2);
+               }
        }
 
        if (use_copy1) {
@@ -1526,20 +1591,24 @@ ZEND_API int compare_function(zval *result, zval *op1, 
zval *op2 TSRMLS_DC) /* {
                                ZVAL_LONG(result, -1);
                                return SUCCESS;
 
-                       case TYPE_PAIR(IS_OBJECT, IS_OBJECT):
-                               /* If both are objects sharing the same 
comparision handler then use is */
-                               if (Z_OBJ_HANDLER_P(op1,compare_objects) == 
Z_OBJ_HANDLER_P(op2,compare_objects)) {
+                       default:
+                               if (Z_TYPE_P(op1) == IS_OBJECT && 
Z_OBJ_HANDLER_P(op1, compare)) {
+                                       return Z_OBJ_HANDLER_P(op1, 
compare)(result, op1, op2 TSRMLS_CC);
+                               } else if (Z_TYPE_P(op2) == IS_OBJECT && 
Z_OBJ_HANDLER_P(op2, compare)) {
+                                       return Z_OBJ_HANDLER_P(op2, 
compare)(result, op1, op2 TSRMLS_CC);
+                               }
+
+                               if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) 
== IS_OBJECT) {
                                        if (Z_OBJ_HANDLE_P(op1) == 
Z_OBJ_HANDLE_P(op2)) {
                                                /* object handles are 
identical, apparently this is the same object */
                                                ZVAL_LONG(result, 0);
                                                return SUCCESS;
                                        }
-                                       ZVAL_LONG(result, 
Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC));
-                                       return SUCCESS;
+                                       if (Z_OBJ_HANDLER_P(op1, 
compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
+                                               ZVAL_LONG(result, 
Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC));
+                                               return SUCCESS;
+                                       }
                                }
-                               /* break missing intentionally */
-
-                       default:
                                if (Z_TYPE_P(op1) == IS_OBJECT) {
                                        if (Z_OBJ_HT_P(op1)->get) {
                                                op_free = 
Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
@@ -1890,6 +1959,20 @@ ZEND_API int increment_function(zval *op1) /* {{{ */
                                }
                        }
                        break;
+               case IS_OBJECT:
+                       if (Z_OBJ_HANDLER_P(op1, do_operation)) {
+                               zval *op2;
+                               int res;
+                               TSRMLS_FETCH();
+
+                               MAKE_STD_ZVAL(op2);
+                               ZVAL_LONG(op2, 1);
+                               res = Z_OBJ_HANDLER_P(op1, 
do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC);
+                               zval_ptr_dtor(&op2);
+
+                               return res;
+                       }
+                       return FAILURE;
                default:
                        return FAILURE;
        }
@@ -1936,6 +2019,20 @@ ZEND_API int decrement_function(zval *op1) /* {{{ */
                                        break;
                        }
                        break;
+               case IS_OBJECT:
+                       if (Z_OBJ_HANDLER_P(op1, do_operation)) {
+                               zval *op2;
+                               int res;
+                               TSRMLS_FETCH();
+
+                               MAKE_STD_ZVAL(op2);
+                               ZVAL_LONG(op2, 1);
+                               res = Z_OBJ_HANDLER_P(op1, 
do_operation)(ZEND_SUB, op1, op1, op2 TSRMLS_CC);
+                               zval_ptr_dtor(&op2);
+
+                               return res;
+                       }
+                       return FAILURE;
                default:
                        return FAILURE;
        }
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index 0b890ff..e7ab9bb 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -945,6 +945,24 @@ static zend_always_inline int 
fast_is_smaller_or_equal_function(zval *result, zv
        return Z_LVAL_P(result) <= 0;
 }
 
+#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode)                               
                   \
+       if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) { 
                      \
+               if (SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, 
result, op1, op2 TSRMLS_CC)) {  \
+                       return SUCCESS;                                         
                              \
+               }                                                               
                          \
+       } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, 
do_operation)) {                \
+               if (SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, 
result, op1, op2 TSRMLS_CC)) {  \
+                       return SUCCESS;                                         
                              \
+               }                                                               
                          \
+       }
+
+#define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode)                                
                   \
+       if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)    
                      \
+        && SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, 
NULL TSRMLS_CC)        \
+       ) {                                                                     
                      \
+               return SUCCESS;                                                 
                          \
+       }
+
 #endif
 
 /*
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to