Mercurial > vim
comparison src/vim9execute.c @ 30065:6cf788ab844c v9.0.0370
patch 9.0.0370: cleaning up afterwards can make a function messy
Commit: https://github.com/vim/vim/commit/1d84f7608f1e41dad03b8cc7925895437775f7c0
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Sep 3 21:35:53 2022 +0100
patch 9.0.0370: cleaning up afterwards can make a function messy
Problem: Cleaning up afterwards can make a function messy.
Solution: Add the :defer command.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 03 Sep 2022 22:45:03 +0200 |
parents | d269dd3cd31d |
children | 6a8c2ff5b2ef |
comparison
equal
deleted
inserted
replaced
30064:a8f1fbaa43c8 | 30065:6cf788ab844c |
---|---|
99 #ifdef FEAT_PROFILE | 99 #ifdef FEAT_PROFILE |
100 // stack of profinfo_T used when profiling. | 100 // stack of profinfo_T used when profiling. |
101 static garray_T profile_info_ga = {0, 0, sizeof(profinfo_T), 20, NULL}; | 101 static garray_T profile_info_ga = {0, 0, sizeof(profinfo_T), 20, NULL}; |
102 #endif | 102 #endif |
103 | 103 |
104 // Get pointer to item in the stack. | |
105 #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx) | |
106 | |
104 // Get pointer to item relative to the bottom of the stack, -1 is the last one. | 107 // Get pointer to item relative to the bottom of the stack, -1 is the last one. |
105 #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + (idx)) | 108 #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + (idx)) |
109 | |
110 // Get pointer to a local variable on the stack. Negative for arguments. | |
111 #define STACK_TV_VAR(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx + STACK_FRAME_SIZE + idx) | |
106 | 112 |
107 void | 113 void |
108 to_string_error(vartype_T vartype) | 114 to_string_error(vartype_T vartype) |
109 { | 115 { |
110 semsg(_(e_cannot_convert_str_to_string), vartype_name(vartype)); | 116 semsg(_(e_cannot_convert_str_to_string), vartype_name(vartype)); |
608 ectx->ec_iidx = 0; | 614 ectx->ec_iidx = 0; |
609 | 615 |
610 return OK; | 616 return OK; |
611 } | 617 } |
612 | 618 |
613 // Get pointer to item in the stack. | |
614 #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx) | |
615 | |
616 // Double linked list of funcstack_T in use. | 619 // Double linked list of funcstack_T in use. |
617 static funcstack_T *first_funcstack = NULL; | 620 static funcstack_T *first_funcstack = NULL; |
618 | 621 |
619 static void | 622 static void |
620 add_funcstack_to_list(funcstack_T *funcstack) | 623 add_funcstack_to_list(funcstack_T *funcstack) |
841 } | 844 } |
842 return FALSE; | 845 return FALSE; |
843 } | 846 } |
844 | 847 |
845 /* | 848 /* |
849 * Handle ISN_DEFER. Stack has a function reference and "argcount" arguments. | |
850 * The local variable that lists deferred functions is "var_idx". | |
851 * Returns OK or FAIL. | |
852 */ | |
853 static int | |
854 add_defer_func(int var_idx, int argcount, ectx_T *ectx) | |
855 { | |
856 typval_T *defer_tv = STACK_TV_VAR(var_idx); | |
857 list_T *defer_l; | |
858 typval_T *func_tv; | |
859 list_T *l; | |
860 int i; | |
861 typval_T listval; | |
862 | |
863 if (defer_tv->v_type != VAR_LIST) | |
864 { | |
865 // first one, allocate the list | |
866 if (rettv_list_alloc(defer_tv) == FAIL) | |
867 return FAIL; | |
868 } | |
869 defer_l = defer_tv->vval.v_list; | |
870 | |
871 l = list_alloc_with_items(argcount + 1); | |
872 if (l == NULL) | |
873 return FAIL; | |
874 listval.v_type = VAR_LIST; | |
875 listval.vval.v_list = l; | |
876 listval.v_lock = 0; | |
877 if (list_insert_tv(defer_l, &listval, | |
878 defer_l == NULL ? NULL : defer_l->lv_first) == FAIL) | |
879 { | |
880 vim_free(l); | |
881 return FAIL; | |
882 } | |
883 | |
884 func_tv = STACK_TV_BOT(-argcount - 1); | |
885 // TODO: check type is a funcref | |
886 list_set_item(l, 0, func_tv); | |
887 | |
888 for (i = 1; i <= argcount; ++i) | |
889 list_set_item(l, i, STACK_TV_BOT(-argcount + i - 1)); | |
890 ectx->ec_stack.ga_len -= argcount + 1; | |
891 return OK; | |
892 } | |
893 | |
894 /* | |
895 * Invoked when returning from a function: Invoke any deferred calls. | |
896 */ | |
897 static void | |
898 invoke_defer_funcs(ectx_T *ectx) | |
899 { | |
900 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) | |
901 + ectx->ec_dfunc_idx; | |
902 typval_T *defer_tv = STACK_TV_VAR(dfunc->df_defer_var_idx - 1); | |
903 listitem_T *li; | |
904 | |
905 if (defer_tv->v_type != VAR_LIST) | |
906 return; // no function added | |
907 for (li = defer_tv->vval.v_list->lv_first; li != NULL; li = li->li_next) | |
908 { | |
909 list_T *l = li->li_tv.vval.v_list; | |
910 typval_T rettv; | |
911 typval_T argvars[MAX_FUNC_ARGS]; | |
912 int i; | |
913 listitem_T *arg_li = l->lv_first; | |
914 funcexe_T funcexe; | |
915 | |
916 for (i = 0; i < l->lv_len - 1; ++i) | |
917 { | |
918 arg_li = arg_li->li_next; | |
919 argvars[i] = arg_li->li_tv; | |
920 } | |
921 | |
922 CLEAR_FIELD(funcexe); | |
923 funcexe.fe_evaluate = TRUE; | |
924 rettv.v_type = VAR_UNKNOWN; | |
925 (void)call_func(l->lv_first->li_tv.vval.v_string, -1, | |
926 &rettv, l->lv_len - 1, argvars, &funcexe); | |
927 clear_tv(&rettv); | |
928 } | |
929 } | |
930 | |
931 /* | |
846 * Return from the current function. | 932 * Return from the current function. |
847 */ | 933 */ |
848 static int | 934 static int |
849 func_return(ectx_T *ectx) | 935 func_return(ectx_T *ectx) |
850 { | 936 { |
874 --profile_info_ga.ga_len; | 960 --profile_info_ga.ga_len; |
875 } | 961 } |
876 } | 962 } |
877 #endif | 963 #endif |
878 | 964 |
965 if (dfunc->df_defer_var_idx > 0) | |
966 invoke_defer_funcs(ectx); | |
967 | |
879 // No check for uf_refcount being zero, cannot think of a way that would | 968 // No check for uf_refcount being zero, cannot think of a way that would |
880 // happen. | 969 // happen. |
881 --dfunc->df_ufunc->uf_calls; | 970 --dfunc->df_ufunc->uf_calls; |
882 | 971 |
883 // execution context goes one level up | 972 // execution context goes one level up |
946 | 1035 |
947 funcdepth_decrement(); | 1036 funcdepth_decrement(); |
948 --ex_nesting_level; | 1037 --ex_nesting_level; |
949 return OK; | 1038 return OK; |
950 } | 1039 } |
951 | |
952 #undef STACK_TV | |
953 | 1040 |
954 /* | 1041 /* |
955 * Prepare arguments and rettv for calling a builtin or user function. | 1042 * Prepare arguments and rettv for calling a builtin or user function. |
956 */ | 1043 */ |
957 static int | 1044 static int |
1729 typedef struct subs_expr_S { | 1816 typedef struct subs_expr_S { |
1730 ectx_T *subs_ectx; | 1817 ectx_T *subs_ectx; |
1731 isn_T *subs_instr; | 1818 isn_T *subs_instr; |
1732 int subs_status; | 1819 int subs_status; |
1733 } subs_expr_T; | 1820 } subs_expr_T; |
1734 | |
1735 // Get pointer to item in the stack. | |
1736 #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx) | |
1737 | |
1738 // Get pointer to item at the bottom of the stack, -1 is the bottom. | |
1739 #undef STACK_TV_BOT | |
1740 #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx) | |
1741 | |
1742 // Get pointer to a local variable on the stack. Negative for arguments. | |
1743 #define STACK_TV_VAR(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx + STACK_FRAME_SIZE + idx) | |
1744 | 1821 |
1745 // Set when calling do_debug(). | 1822 // Set when calling do_debug(). |
1746 static ectx_T *debug_context = NULL; | 1823 static ectx_T *debug_context = NULL; |
1747 static int debug_var_count; | 1824 static int debug_var_count; |
1748 | 1825 |
3668 ectx, iptr) == FAIL) | 3745 ectx, iptr) == FAIL) |
3669 goto on_error; | 3746 goto on_error; |
3670 } | 3747 } |
3671 break; | 3748 break; |
3672 | 3749 |
3750 // :defer func(arg) | |
3751 case ISN_DEFER: | |
3752 if (add_defer_func(iptr->isn_arg.defer.defer_var_idx, | |
3753 iptr->isn_arg.defer.defer_argcount, ectx) == FAIL) | |
3754 goto on_error; | |
3755 break; | |
3756 | |
3673 // return from a :def function call without a value | 3757 // return from a :def function call without a value |
3674 case ISN_RETURN_VOID: | 3758 case ISN_RETURN_VOID: |
3675 if (GA_GROW_FAILS(&ectx->ec_stack, 1)) | 3759 if (GA_GROW_FAILS(&ectx->ec_stack, 1)) |
3676 goto theend; | 3760 goto theend; |
3677 tv = STACK_TV_BOT(0); | 3761 tv = STACK_TV_BOT(0); |
5022 } | 5106 } |
5023 | 5107 |
5024 done: | 5108 done: |
5025 ret = OK; | 5109 ret = OK; |
5026 theend: | 5110 theend: |
5111 { | |
5112 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) | |
5113 + ectx->ec_dfunc_idx; | |
5114 | |
5115 if (dfunc->df_defer_var_idx > 0) | |
5116 invoke_defer_funcs(ectx); | |
5117 } | |
5118 | |
5027 dict_stack_clear(dict_stack_len_at_start); | 5119 dict_stack_clear(dict_stack_len_at_start); |
5028 ectx->ec_trylevel_at_start = save_trylevel_at_start; | 5120 ectx->ec_trylevel_at_start = save_trylevel_at_start; |
5029 return ret; | 5121 return ret; |
5030 } | 5122 } |
5031 | 5123 |
5900 cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount); | 5992 cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount); |
5901 } | 5993 } |
5902 break; | 5994 break; |
5903 case ISN_PCALL_END: | 5995 case ISN_PCALL_END: |
5904 smsg("%s%4d PCALL end", pfx, current); | 5996 smsg("%s%4d PCALL end", pfx, current); |
5997 break; | |
5998 case ISN_DEFER: | |
5999 smsg("%s%4d DEFER %d args", pfx, current, | |
6000 (int)iptr->isn_arg.defer.defer_argcount); | |
5905 break; | 6001 break; |
5906 case ISN_RETURN: | 6002 case ISN_RETURN: |
5907 smsg("%s%4d RETURN", pfx, current); | 6003 smsg("%s%4d RETURN", pfx, current); |
5908 break; | 6004 break; |
5909 case ISN_RETURN_VOID: | 6005 case ISN_RETURN_VOID: |