# HG changeset patch # User Bram Moolenaar # Date 1606066205 -3600 # Node ID 4c97c074701751ea529f56ca5b823bba54bf1cd6 # Parent d2b36acb42dd19eadf710ff895e8147b5f00ead6 patch 8.2.2033: Vim9: :def without argument gives compilation error Commit: https://github.com/vim/vim/commit/6abdcf82859e158713a3d5aa6b1012748ea5c2a0 Author: Bram Moolenaar Date: Sun Nov 22 18:15:44 2020 +0100 patch 8.2.2033: Vim9: :def without argument gives compilation error Problem: Vim9: :def without argument gives compilation error. Solution: Add the DEF instruction. (closes https://github.com/vim/vim/issues/7344) diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -274,7 +274,6 @@ static void ex_tag_cmd(exarg_T *eap, cha # define ex_continue ex_ni # define ex_debug ex_ni # define ex_debuggreedy ex_ni -# define ex_def ex_ni # define ex_defcompile ex_ni # define ex_delfunction ex_ni # define ex_disassemble ex_ni diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -33,6 +33,7 @@ int call_func(char_u *funcname, int len, char_u *printable_func_name(ufunc_T *fp); char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial); char_u *untrans_function_name(char_u *name); +void list_functions(regmatch_T *regmatch); ufunc_T *define_function(exarg_T *eap, char_u *name_arg); void ex_function(exarg_T *eap); void ex_defcompile(exarg_T *eap); diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -905,6 +905,29 @@ def Test_nested_func() instr) enddef +def NestedDefList() + def + def Info + def /Info + def /Info/ +enddef + +def Test_nested_def_list() + var instr = execute('disassemble NestedDefList') + assert_match('NestedDefList\_s*' .. + 'def\_s*' .. + '\d DEF \_s*' .. + 'def Info\_s*' .. + '\d DEF Info\_s*' .. + 'def /Info\_s*' .. + '\d DEF /Info\_s*' .. + 'def /Info/\_s*' .. + '\d DEF /Info/\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d RETURN', + instr) +enddef + def AndOr(arg: any): string if arg == 1 && arg != 2 || arg == 4 return 'yes' diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -288,6 +288,33 @@ def Test_nested_global_function() CheckScriptFailure(lines, "E1073:") enddef +def DefListAll() + def +enddef + +def DefListOne() + def DefListOne +enddef + +def DefListMatches() + def /DefList +enddef + +def Test_nested_def_list() + var funcs = split(execute('call DefListAll()'), "\n") + assert_true(len(funcs) > 10) + assert_true(funcs->index('def DefListAll()') >= 0) + + funcs = split(execute('call DefListOne()'), "\n") + assert_equal([' def DefListOne()', '1 def DefListOne', ' enddef'], funcs) + + funcs = split(execute('call DefListMatches()'), "\n") + assert_true(len(funcs) >= 3) + assert_true(funcs->index('def DefListAll()') >= 0) + assert_true(funcs->index('def DefListOne()') >= 0) + assert_true(funcs->index('def DefListMatches()') >= 0) +enddef + def Test_global_local_function() var lines =<< trim END vim9script diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2748,7 +2748,7 @@ untrans_function_name(char_u *name) * List functions. When "regmatch" is NULL all of then. * Otherwise functions matching "regmatch". */ - static void + void list_functions(regmatch_T *regmatch) { int changed = func_hashtab.ht_changed; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2033, +/**/ 2032, /**/ 2031, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -82,6 +82,7 @@ typedef enum { ISN_RETURN, // return, result is on top of stack ISN_FUNCREF, // push a function ref to dfunc isn_arg.funcref ISN_NEWFUNC, // create a global function from a lambda function + ISN_DEF, // list functions // expression operations ISN_JUMP, // jump if condition is matched isn_arg.jump diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1433,6 +1433,26 @@ generate_NEWFUNC(cctx_T *cctx, char_u *l } /* + * Generate an ISN_DEF instruction: list functions + */ + static int +generate_DEF(cctx_T *cctx, char_u *name, size_t len) +{ + isn_T *isn; + + RETURN_OK_IF_SKIP(cctx); + if ((isn = generate_instr(cctx, ISN_DEF)) == NULL) + return FAIL; + if (len > 0) + { + isn->isn_arg.string = vim_strnsave(name, len); + if (isn->isn_arg.string == NULL) + return FAIL; + } + return OK; +} + +/* * Generate an ISN_JUMP instruction. */ static int @@ -4801,6 +4821,27 @@ compile_nested_function(exarg_T *eap, cc return NULL; } + if (*name_start == '/') + { + name_end = skip_regexp(name_start + 1, '/', TRUE); + if (*name_end == '/') + ++name_end; + eap->nextcmd = check_nextcmd(name_end); + } + if (name_end == name_start || *skipwhite(name_end) != '(') + { + if (!ends_excmd2(name_start, name_end)) + { + semsg(_(e_invalid_command_str), eap->cmd); + return NULL; + } + + // "def" or "def Name": list functions + if (generate_DEF(cctx, name_start, name_end - name_start) == FAIL) + return NULL; + return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd; + } + // Only g:Func() can use a namespace. if (name_start[1] == ':' && !is_global) { @@ -7736,22 +7777,23 @@ delete_instr(isn_T *isn) { switch (isn->isn_type) { + case ISN_DEF: case ISN_EXEC: + case ISN_LOADB: case ISN_LOADENV: case ISN_LOADG: - case ISN_LOADB: - case ISN_LOADW: + case ISN_LOADOPT: case ISN_LOADT: - case ISN_LOADOPT: - case ISN_STRINGMEMBER: + case ISN_LOADW: case ISN_PUSHEXC: + case ISN_PUSHFUNC: case ISN_PUSHS: + case ISN_STOREB: case ISN_STOREENV: case ISN_STOREG: - case ISN_STOREB: + case ISN_STORET: case ISN_STOREW: - case ISN_STORET: - case ISN_PUSHFUNC: + case ISN_STRINGMEMBER: vim_free(isn->isn_arg.string); break; diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1970,6 +1970,20 @@ call_def_function( } break; + // List functions + case ISN_DEF: + if (iptr->isn_arg.string == NULL) + list_functions(NULL); + else + { + exarg_T ea; + + CLEAR_FIELD(ea); + ea.cmd = ea.arg = iptr->isn_arg.string; + define_function(&ea, NULL); + } + break; + // jump if a condition is met case ISN_JUMP: { @@ -3371,6 +3385,15 @@ ex_disassemble(exarg_T *eap) } break; + case ISN_DEF: + { + char_u *name = iptr->isn_arg.string; + + smsg("%4d DEF %s", current, + name == NULL ? (char_u *)"" : name); + } + break; + case ISN_JUMP: { char *when = "?";