To: vim_dev@googlegroups.com Subject: Patch 8.2.3692 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3692 Problem: Vim9: cannot use :func inside a :def function. Solution: Make it work. Files: src/vim9compile.c, src/vim9.h, src/vim9execute.c, src/errors.h, src/structs.h, src/userfunc.c, src/testdir/test_vim9_func.vim *** ../vim-8.2.3691/src/vim9compile.c 2021-11-23 12:35:54.350064548 +0000 --- src/vim9compile.c 2021-11-28 21:54:52.784775660 +0000 *************** *** 1675,1681 **** RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) return FAIL; ! isn->isn_arg.funcref.fr_func = ufunc->uf_dfunc_idx; cctx->ctx_has_closure = 1; // If the referenced function is a closure, it may use items further up in --- 1675,1684 ---- RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) return FAIL; ! if (ufunc->uf_def_status == UF_NOT_COMPILED) ! isn->isn_arg.funcref.fr_func_name = vim_strsave(ufunc->uf_name); ! else ! isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx; cctx->ctx_has_closure = 1; // If the referenced function is a closure, it may use items further up in *************** *** 5835,5840 **** --- 5838,5844 ---- fill_exarg_from_cctx(eap, cctx); eap->forceit = FALSE; + // We use the special 99 name, but it's not really a lambda. lambda_name = vim_strsave(get_lambda_name()); if (lambda_name == NULL) return NULL; *************** *** 9976,9991 **** switch (ea.cmdidx) { case CMD_def: ea.arg = p; line = compile_nested_function(&ea, &cctx); break; - case CMD_function: - // TODO: should we allow this, e.g. to declare a global - // function? - emsg(_(e_cannot_use_function_inside_def)); - goto erret; - case CMD_return: line = compile_return(p, check_return_type, local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx); --- 9980,9990 ---- switch (ea.cmdidx) { case CMD_def: + case CMD_function: ea.arg = p; line = compile_nested_function(&ea, &cctx); break; case CMD_return: line = compile_return(p, check_return_type, local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx); *************** *** 10442,10453 **** case ISN_FUNCREF: { ! dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) ! + isn->isn_arg.funcref.fr_func; ! ufunc_T *ufunc = dfunc->df_ufunc; ! if (ufunc != NULL && func_name_refcount(ufunc->uf_name)) ! func_ptr_unref(ufunc); } break; --- 10441,10463 ---- case ISN_FUNCREF: { ! if (isn->isn_arg.funcref.fr_func_name == NULL) ! { ! dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) ! + isn->isn_arg.funcref.fr_dfunc_idx; ! ufunc_T *ufunc = dfunc->df_ufunc; ! if (ufunc != NULL && func_name_refcount(ufunc->uf_name)) ! func_ptr_unref(ufunc); ! } ! else ! { ! char_u *name = isn->isn_arg.funcref.fr_func_name; ! ! if (name != NULL) ! func_unref(name); ! vim_free(isn->isn_arg.funcref.fr_func_name); ! } } break; *** ../vim-8.2.3691/src/vim9.h 2021-09-16 15:15:00.204224417 +0100 --- src/vim9.h 2021-11-28 21:01:31.606756591 +0000 *************** *** 322,328 **** // arguments to ISN_FUNCREF typedef struct { ! int fr_func; // function index } funcref_T; // arguments to ISN_NEWFUNC --- 322,329 ---- // arguments to ISN_FUNCREF typedef struct { ! int fr_dfunc_idx; // function index for :def function ! char_u *fr_func_name; // function name for legacy function } funcref_T; // arguments to ISN_NEWFUNC *** ../vim-8.2.3691/src/vim9execute.c 2021-11-23 22:16:30.522773542 +0000 --- src/vim9execute.c 2021-11-28 21:16:49.706158909 +0000 *************** *** 3168,3175 **** case ISN_FUNCREF: { partial_T *pt = ALLOC_CLEAR_ONE(partial_T); ! dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data) ! + iptr->isn_arg.funcref.fr_func; if (pt == NULL) goto theend; --- 3168,3175 ---- case ISN_FUNCREF: { partial_T *pt = ALLOC_CLEAR_ONE(partial_T); ! ufunc_T *ufunc; ! funcref_T *funcref = &iptr->isn_arg.funcref; if (pt == NULL) goto theend; *************** *** 3178,3185 **** vim_free(pt); goto theend; } ! if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc, ! ectx) == FAIL) goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; --- 3178,3195 ---- vim_free(pt); goto theend; } ! if (funcref->fr_func_name == NULL) ! { ! dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data) ! + funcref->fr_dfunc_idx; ! ! ufunc = pt_dfunc->df_ufunc; ! } ! else ! { ! ufunc = find_func(funcref->fr_func_name, FALSE, NULL); ! } ! if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL) goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; *************** *** 5454,5463 **** case ISN_FUNCREF: { funcref_T *funcref = &iptr->isn_arg.funcref; ! dfunc_T *df = ((dfunc_T *)def_functions.ga_data) ! + funcref->fr_func; ! smsg("%s%4d FUNCREF %s", pfx, current, df->df_ufunc->uf_name); } break; --- 5464,5480 ---- case ISN_FUNCREF: { funcref_T *funcref = &iptr->isn_arg.funcref; ! char_u *name; ! if (funcref->fr_func_name == NULL) ! { ! dfunc_T *df = ((dfunc_T *)def_functions.ga_data) ! + funcref->fr_dfunc_idx; ! name = df->df_ufunc->uf_name; ! } ! else ! name = funcref->fr_func_name; ! smsg("%s%4d FUNCREF %s", pfx, current, name); } break; *** ../vim-8.2.3691/src/errors.h 2021-11-24 12:17:49.168449919 +0000 --- src/errors.h 2021-11-28 21:54:43.836795171 +0000 *************** *** 355,362 **** INIT(= N_("E1084: Cannot delete Vim9 script function %s")); EXTERN char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); ! EXTERN char e_cannot_use_function_inside_def[] ! INIT(= N_("E1086: Cannot use :function inside :def")); EXTERN char e_cannot_use_index_when_declaring_variable[] INIT(= N_("E1087: Cannot use an index when declaring a variable")); // E1088 unused --- 355,361 ---- INIT(= N_("E1084: Cannot delete Vim9 script function %s")); EXTERN char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); ! // E1086 unused EXTERN char e_cannot_use_index_when_declaring_variable[] INIT(= N_("E1087: Cannot use an index when declaring a variable")); // E1088 unused *** ../vim-8.2.3691/src/structs.h 2021-11-24 16:32:50.720422469 +0000 --- src/structs.h 2021-11-28 21:44:06.182134663 +0000 *************** *** 1699,1704 **** --- 1699,1705 ---- #define FC_VIM9 0x400 // defined in vim9 script file #define FC_CFUNC 0x800 // defined as Lua C func #define FC_COPY 0x1000 // copy of another function by copy_func() + #define FC_LAMBDA 0x2000 // one line "return {expr}" #define MAX_FUNC_ARGS 20 // maximum number of function arguments #define VAR_SHORT_LEN 20 // short variable name length *** ../vim-8.2.3691/src/userfunc.c 2021-11-20 21:46:16.088614817 +0000 --- src/userfunc.c 2021-11-28 21:47:12.133757952 +0000 *************** *** 523,529 **** fp->uf_def_status = UF_NOT_COMPILED; fp->uf_refcount = 1; fp->uf_varargs = TRUE; ! fp->uf_flags = FC_CFUNC; fp->uf_calls = 0; fp->uf_script_ctx = current_sctx; fp->uf_cb = cb; --- 523,529 ---- fp->uf_def_status = UF_NOT_COMPILED; fp->uf_refcount = 1; fp->uf_varargs = TRUE; ! fp->uf_flags = FC_CFUNC | FC_LAMBDA; fp->uf_calls = 0; fp->uf_script_ctx = current_sctx; fp->uf_cb = cb; *************** *** 1205,1210 **** --- 1205,1211 ---- set_ufunc_name(ufunc, name); if (hash_add(&func_hashtab, UF2HIKEY(ufunc)) == FAIL) goto erret; + ufunc->uf_flags = FC_LAMBDA; ufunc->uf_refcount = 1; ufunc->uf_args = *newargs; newargs->ga_data = NULL; *************** *** 1399,1405 **** if (evaluate) { int len; ! int flags = 0; char_u *p; char_u *line_end; char_u *name = get_lambda_name(); --- 1400,1406 ---- if (evaluate) { int len; ! int flags = FC_LAMBDA; char_u *p; char_u *line_end; char_u *name = get_lambda_name(); *************** *** 2506,2513 **** return; } ! if (STRNCMP(fp->uf_name, "", 8) == 0) ! islambda = TRUE; /* * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables --- 2507,2513 ---- return; } ! islambda = fp->uf_flags & FC_LAMBDA; /* * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables *** ../vim-8.2.3691/src/testdir/test_vim9_func.vim 2021-11-20 21:46:16.088614817 +0000 --- src/testdir/test_vim9_func.vim 2021-11-28 21:52:25.885094272 +0000 *************** *** 586,600 **** enddef def Test_nested_function() ! def Nested(arg: string): string return 'nested ' .. arg enddef ! Nested('function')->assert_equal('nested function') CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:') CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:') - CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:') CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:') CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:') --- 586,604 ---- enddef def Test_nested_function() ! def NestedDef(arg: string): string return 'nested ' .. arg enddef ! NestedDef(':def')->assert_equal('nested :def') ! ! func NestedFunc(arg) ! return 'nested ' .. a:arg ! endfunc ! NestedFunc(':func')->assert_equal('nested :func') CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:') CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:') CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:') CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:') *************** *** 691,696 **** --- 695,720 ---- enddef defcompile Outer() + g:Inner()->assert_equal('inner') + delfunc g:Inner + Outer() + g:Inner()->assert_equal('inner') + delfunc g:Inner + Outer() + g:Inner()->assert_equal('inner') + delfunc g:Inner + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + def Outer() + func g:Inner() + return 'inner' + endfunc + enddef + defcompile + Outer() g:Inner()->assert_equal('inner') delfunc g:Inner Outer() *** ../vim-8.2.3691/src/version.c 2021-11-28 21:33:32.307336723 +0000 --- src/version.c 2021-11-28 21:58:58.072236602 +0000 *************** *** 759,760 **** --- 759,762 ---- { /* Add new patch number below this line */ + /**/ + 3692, /**/ -- Wi n0t trei a h0liday in Sweden thi yer? "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///