]> granicus.if.org Git - php/commitdiff
- Initial support for exceptions.
authorAndi Gutmans <andi@php.net>
Thu, 30 Aug 2001 15:26:30 +0000 (15:26 +0000)
committerAndi Gutmans <andi@php.net>
Thu, 30 Aug 2001 15:26:30 +0000 (15:26 +0000)
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_language_parser.y
Zend/zend_language_scanner.l

index a50ebc773a3fb85c1f62e6b2e314c7d91d557312..7e13063159415d39b4f14ae2b7c8f65ea0e5397a 100644 (file)
@@ -81,6 +81,7 @@ void zend_init_compiler_data_structures(TSRMLS_D)
        CG(handle_op_arrays) = 1;
        CG(in_compilation) = 0;
        init_compiler_declarables(TSRMLS_C);
+       CG(throw_list) = NULL;
 }
 
 
@@ -758,6 +759,8 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
 
                zend_stack_push(&CG(foreach_copy_stack), (void *) &switch_entry.cond, sizeof(znode));
        }
+       function_token->throw_list = CG(throw_list);
+       CG(throw_list) = NULL;  
 }
 
 
@@ -771,6 +774,8 @@ void zend_do_end_function_declaration(znode *function_token TSRMLS_DC)
        /* Pop the switch and foreach seperators */
        zend_stack_del_top(&CG(switch_cond_stack));
        zend_stack_del_top(&CG(foreach_copy_stack));
+
+       CG(throw_list) = function_token->throw_list;
 }
 
 
@@ -919,7 +924,16 @@ void zend_do_end_function_call(znode *function_name, znode *result, znode *argum
        opline->result.op_type = IS_VAR;
        *result = opline->result;
        SET_UNUSED(opline->op2);
-       opline->op2.u.constant.value.lval = is_method;
+
+       // Check how much this is really needed
+       //opline->op2.u.constant.value.lval = is_method;
+       if (CG(throw_list) != NULL) {
+               long op_number = get_next_op_number(CG(active_op_array))-1;
+               zend_llist_add_element(CG(throw_list), &op_number);
+       } else {
+               opline->op2.u.opline_num = -1;
+       }
+
        zend_stack_del_top(&CG(function_call_stack));
        opline->extended_value = argument_list->u.constant.value.lval;
 }
@@ -1089,6 +1103,74 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC)
 }
 
 
+void zend_do_try(znode *try_token CLS_DC)
+{
+       try_token->throw_list = (void *) CG(throw_list);
+       CG(throw_list) = (zend_llist *) emalloc(sizeof(zend_llist));
+       zend_llist_init(CG(throw_list), sizeof(long), NULL, 0);
+       // Initialize try backpatch list used to backpatch throw, do_fcall
+}
+
+static void throw_list_applier(long *opline_num, long *catch_opline)
+{
+       zend_op *opline;
+       CLS_FETCH(); // Pass this by argument
+
+       opline = &CG(active_op_array)->opcodes[*opline_num];
+
+       // Backpatch the opline of the catch statement
+       switch (opline->opcode) {
+               case ZEND_DO_FCALL:
+               case ZEND_DO_FCALL_BY_NAME:
+               case ZEND_THROW:
+                       opline->op2.u.opline_num = *catch_opline;
+                       break;
+               default:
+                       zend_error(E_ERROR, "Bad opcode in throw list");
+                       break;
+       }
+}
+
+void zend_do_begin_catch(znode *try_token, znode *catch_var CLS_DC)
+{
+       long catch_op_number = get_next_op_number(CG(active_op_array));
+       zend_op *opline;
+       
+       opline = get_next_op(CG(active_op_array) CLS_CC);
+       opline->opcode = ZEND_CATCH;
+       opline->op1 = *catch_var;
+       SET_UNUSED(opline->op2);
+
+       zend_llist_apply_with_argument(CG(throw_list), throw_list_applier, &catch_op_number);
+       zend_llist_destroy(CG(throw_list));
+       efree(CG(throw_list));
+       CG(throw_list) = (void *) try_token->throw_list;
+
+       try_token->u.opline_num = catch_op_number;
+}
+
+void zend_do_end_catch(znode *try_token CLS_DC)
+{
+       CG(active_op_array)->opcodes[try_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+}
+
+void zend_do_throw(znode *expr CLS_DC)
+{
+       zend_op *opline;
+       long throw_op_number = get_next_op_number(CG(active_op_array));
+       
+       opline = get_next_op(CG(active_op_array) CLS_CC);
+       opline->opcode = ZEND_THROW;
+       opline->op1 = *expr;
+       SET_UNUSED(opline->op2);
+       
+       if (CG(throw_list) != NULL) {
+               zend_llist_add_element(CG(throw_list), &throw_op_number);
+       } else {
+               opline->op2.u.opline_num = -1;
+       }
+}
+
 ZEND_API void function_add_ref(zend_function *function)
 {
        if (function->type == ZEND_USER_FUNCTION) {
@@ -1778,6 +1860,7 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC)
        opline->extended_value = ZEND_DO_FCALL;
        SET_UNUSED(opline->op2);
 
+       // FIXME: exception support not added to this op2
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
        opline->opcode = ZEND_DO_FCALL;
        opline->result.u.var = get_temporary_variable(CG(active_op_array));
index 914c7d458dbbff5a8108db2375f99f741e3ee15a..658dfed51eb722ae4c7ff352ca8995e086a74056 100644 (file)
@@ -48,6 +48,7 @@ typedef struct _zend_op_array zend_op_array;
 
 typedef struct _znode {
        int op_type;
+       zend_llist *throw_list; // Try and save this space later on
        union {
                zval constant;
 
@@ -280,6 +281,12 @@ void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC);
 void zend_do_begin_class_member_function_call(znode *class_name, znode *function_name TSRMLS_DC);
 void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC);
 void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC);
+
+void zend_do_try(znode *try_token CLS_DC);
+void zend_do_begin_catch(znode *try_token, znode *catch_var CLS_DC);
+void zend_do_end_catch(znode *try_token CLS_DC);
+void zend_do_throw(znode *expr CLS_DC);
+
 ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time);
 void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce);
 void zend_do_early_binding(TSRMLS_D);
@@ -530,6 +537,9 @@ int zendlex(znode *zendlval TSRMLS_DC);
 
 #define ZEND_SEND_VAR_NO_REF           106
 
+#define ZEND_CATCH                                     107
+#define ZEND_THROW                                     108
+
 /* end of block */
 
 
index 226af584c52547b5ef8902b30854f2c22f27105c..5a6ea6023e13b202ebd23040fd9bed75172375e2 100644 (file)
@@ -989,6 +989,11 @@ static int zend_check_symbol(zval **pz TSRMLS_DC)
        opline++;                               \
        continue;
 
+#define RETURN_FROM_EXECUTE_LOOP()                                                                     \
+       free_alloca(Ts);                                                                                                \
+       EG(in_execution) = original_in_execution;                                               \
+       return;
+
 typedef struct _object_info {
        zval *ptr;
 } object_info;
@@ -1633,11 +1638,14 @@ do_fcall_common:
                                                zend_execute(EG(active_op_array) TSRMLS_CC);
 
                                                if (return_value_used && !Ts[opline->result.u.var].var.ptr) {
-                                                       ALLOC_ZVAL(Ts[opline->result.u.var].var.ptr);
-                                                       INIT_ZVAL(*Ts[opline->result.u.var].var.ptr);
+                                                       if (!EG(exception)) {
+                                                               ALLOC_ZVAL(Ts[opline->result.u.var].var.ptr);
+                                                               INIT_ZVAL(*Ts[opline->result.u.var].var.ptr);
+                                                       }
                                                } else if (!return_value_used && Ts[opline->result.u.var].var.ptr) {
                                                        zval_ptr_dtor(&Ts[opline->result.u.var].var.ptr);
                                                }
+
                                                EG(opline_ptr) = &opline;
                                                EG(active_op_array) = op_array;
                                                EG(return_value_ptr_ptr)=original_return_value;
@@ -1666,7 +1674,16 @@ do_fcall_common:
                                        function_state.function = (zend_function *) op_array;
                                        EG(function_state_ptr) = &function_state;
                                        zend_ptr_stack_clear_multiple(TSRMLS_C);
-                               }
+
+                                       if (EG(exception)) {
+                                               if (opline->op2.u.opline_num == -1) {
+                                                       RETURN_FROM_EXECUTE_LOOP();
+                                               } else {
+                                                       opline = &op_array->opcodes[opline->op2.u.opline_num];
+                                                       continue;
+                                               }
+                                       }
+                               }
                                NEXT_OPCODE();
                        case ZEND_RETURN: {
                                        zval *retval_ptr;
@@ -1703,11 +1720,43 @@ do_fcall_common:
                                                        (*EG(return_value_ptr_ptr))->is_ref = 0;
                                                }
                                        }
-                                       free_alloca(Ts);
-                                       EG(in_execution) = original_in_execution;
-                                       return;
+                                       RETURN_FROM_EXECUTE_LOOP();
                                }
                                break;
+                       case ZEND_THROW:
+                               {
+                                       zval *value;
+                                       zval *exception;
+
+                                       value = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
+                                       
+                                       // Not sure if a complete copy is what we want here
+                                       MAKE_STD_ZVAL(exception);
+                                       *exception = *value;
+                                       if (!EG(free_op1)) {
+                                               zval_copy_ctor(exception);
+                                       }
+                                       INIT_PZVAL(exception);
+                                       EG(exception) = exception;
+                                       
+                                       if (opline->op2.u.opline_num == -1) {
+                                               RETURN_FROM_EXECUTE_LOOP();
+                                       } else {
+                                               opline = &op_array->opcodes[opline->op2.u.opline_num];
+                                               continue;
+                                       }
+                               }
+                               NEXT_OPCODE();
+                       case ZEND_CATCH:
+                               // Check if this is really an exception, if not, jump over code
+                               if (EG(exception) == NULL) {
+                                               opline = &op_array->opcodes[opline->op2.u.opline_num];
+                                               continue;
+                               }
+                               zend_hash_update(EG(active_symbol_table), opline->op1.u.constant.value.str.val,
+                                       opline->op1.u.constant.value.str.len+1, &EG(exception), sizeof(zval *), (void **) NULL);
+                               EG(exception) = NULL;
+                               NEXT_OPCODE();
                        case ZEND_SEND_VAL: 
                                if (opline->extended_value==ZEND_DO_FCALL_BY_NAME
                                        && ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num, fbc, fbc->common.arg_types)) {
@@ -2490,7 +2539,6 @@ send_by_ref:
                        case ZEND_NOP:
                                NEXT_OPCODE();
                        EMPTY_SWITCH_DEFAULT_CASE()
-
                }
        }
        zend_error(E_ERROR, "Arrived at end of main loop which shouldn't happen");
index 714f322d0c342a8dc6d0a488b6bd06fdaa826493..2a0b042e034f73f9e94f3d2fe8e9744f7ea595ba 100644 (file)
@@ -155,6 +155,8 @@ void init_executor(TSRMLS_D)
 #ifdef ZEND_WIN32
        EG(timed_out) = 0;
 #endif
+
+       EG(exception) = NULL;
 }
 
 
index 24b1f0442eb87d2ee659e27bfa9ca0feb578dba9..814f65be770828ada7c120d759178a5a9d3431c0 100644 (file)
@@ -121,6 +121,8 @@ struct _zend_compiler_globals {
        void *ini_parser;
 #endif
 
+       zend_llist *throw_list;
+
        struct _zend_ini_parser_param *ini_parser_param;
 
        int interactive;
@@ -203,6 +205,7 @@ struct _zend_executor_globals {
 
        HashTable ini_directives;
        zend_objects objects;
+       zval *exception;
 
        void *reserved[ZEND_MAX_RESERVED_RESOURCES];
 };
index 97d418103219a05a4aafdc76dc75a44c01b15481..d02ef4f7a7e12756a52a6da8e75c815aa58cc80b 100644 (file)
 %token T_FUNCTION
 %token T_CONST
 %token T_RETURN
+%token T_TRY
+%token T_CATCH
+%token T_THROW
 %token T_USE
 %token T_GLOBAL
 %token T_STATIC
@@ -201,6 +204,9 @@ unticked_statement:
        |       T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 TSRMLS_CC); } w_cvar foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); }
        |       T_DECLARE { zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(TSRMLS_C); }
        |       ';'             /* empty statement */
+       |       T_TRY { zend_do_try(&$1 CLS_CC); } '{' inner_statement_list '}'
+                       T_CATCH '(' T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8 CLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 CLS_CC); }
+       |       T_THROW expr ';' { zend_do_throw(&$2 CLS_CC); }
        |       T_DELETE cvar   ';' { zend_do_end_variable_parse(BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1, ZEND_UNSET_OBJ TSRMLS_CC); }
 ;
 
index 2dd310d938274eda17de7b1c5899d7b2503b3456..096f3e2920395a6fa0e7d2057d788164d242eb22 100644 (file)
@@ -648,6 +648,18 @@ NEWLINE ("\r"|"\n"|"\r\n")
        return T_RETURN;
 }
 
+<ST_IN_SCRIPTING>"try" {
+       return T_TRY;
+}
+
+<ST_IN_SCRIPTING>"catch" {
+       return T_CATCH;
+}
+
+<ST_IN_SCRIPTING>"throw" {
+       return T_THROW;
+}
+
 <ST_IN_SCRIPTING>"if" {
        return T_IF;
 }