Mercurial > vim
changeset 26470:ff0310e6f889 v8.2.3765
patch 8.2.3765: Vim9: cannot use a lambda for 'opfunc' and others
Commit: https://github.com/vim/vim/commit/dcb53be4418fe263a71c7738315241031df6c986
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Dec 9 14:23:43 2021 +0000
patch 8.2.3765: Vim9: cannot use a lambda for 'opfunc' and others
Problem: Vim9: cannot use a lambda for 'opfunc' and others.
Solution: Convert the lambda to a string.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 09 Dec 2021 15:30:04 +0100 |
parents | 8e3d1d2500bb |
children | d76f275bc6dc |
files | src/testdir/test_vim9_disassemble.vim src/testdir/test_vim9_func.vim src/version.c src/vim9.h src/vim9compile.c src/vim9execute.c |
diffstat | 6 files changed, 92 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -316,6 +316,7 @@ def s:ScriptFuncStore() w:windowvar = 'wv' t:tabpagevar = 'tv' &tabstop = 8 + &opfunc = (t) => len(t) $ENVVAR = 'ev' @z = 'rv' enddef @@ -343,12 +344,17 @@ def Test_disassemble_store() ' STOREW w:windowvar.*' .. 't:tabpagevar = ''tv''.*' .. ' STORET t:tabpagevar.*' .. - '&tabstop = 8.*' .. - ' STOREOPT &tabstop.*' .. - '$ENVVAR = ''ev''.*' .. - ' STOREENV $ENVVAR.*' .. + '&tabstop = 8\_s*' .. + '\d\+ PUSHNR 8\_s*' .. + '\d\+ STOREOPT &tabstop\_s*' .. + '&opfunc = (t) => len(t)\_s*' .. + '\d\+ FUNCREF <lambda>\d\+\_s*' .. + '\d\+ STOREFUNCOPT &opfunc\_s*' .. + '$ENVVAR = ''ev''\_s*' .. + '\d\+ PUSHS "ev"\_s*' .. + '\d\+ STOREENV $ENVVAR\_s*' .. '@z = ''rv''.*' .. - ' STOREREG @z.*', + '\d\+ STOREREG @z.*', res) enddef
--- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -1202,6 +1202,28 @@ def Test_lambda_in_reduce_line_break() CheckScriptSuccess(lines) enddef +def Test_set_opfunc_to_lambda() + var lines =<< trim END + vim9script + nnoremap <expr> <F4> <SID>CountSpaces() .. '_' + def CountSpaces(type = ''): string + if type == '' + &operatorfunc = (t) => CountSpaces(t) + return 'g@' + endif + normal! '[V']y + g:result = getreg('"')->count(' ') + return '' + enddef + new + 'a b c d e'->setline(1) + feedkeys("\<F4>", 'x') + assert_equal(4, g:result) + bwipe! + END + CheckScriptSuccess(lines) +enddef + " Default arg and varargs def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string var res = one .. ',' .. two
--- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3765, +/**/ 3764, /**/ 3763,
--- a/src/vim9.h +++ b/src/vim9.h @@ -55,7 +55,8 @@ typedef enum { ISN_STORES, // pop into script variable isn_arg.loadstore ISN_STOREOUTER, // pop variable into outer scope isn_arg.outer ISN_STORESCRIPT, // pop into script variable isn_arg.script - ISN_STOREOPT, // pop into option isn_arg.string + ISN_STOREOPT, // pop into option isn_arg.storeopt + ISN_STOREFUNCOPT, // pop into option isn_arg.storeopt ISN_STOREENV, // pop into environment variable isn_arg.string ISN_STOREREG, // pop into register isn_arg.number // ISN_STOREOTHER, // pop into other script variable isn_arg.other. @@ -291,7 +292,7 @@ typedef struct { varnumber_T stnr_val; } storenr_T; -// arguments to ISN_STOREOPT +// arguments to ISN_STOREOPT and ISN_STOREFUNCOPT typedef struct { char_u *so_name; int so_flags;
--- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -118,6 +118,7 @@ typedef struct { typedef enum { dest_local, dest_option, + dest_func_option, dest_env, dest_global, dest_buffer, @@ -1412,15 +1413,19 @@ generate_STORENR(cctx_T *cctx, int idx, } /* - * Generate an ISN_STOREOPT instruction - */ - static int -generate_STOREOPT(cctx_T *cctx, char_u *name, int opt_flags) + * Generate an ISN_STOREOPT or ISN_STOREFUNCOPT instruction + */ + static int +generate_STOREOPT( + cctx_T *cctx, + isntype_T isn_type, + char_u *name, + int opt_flags) { isn_T *isn; RETURN_OK_IF_SKIP(cctx); - if ((isn = generate_instr_drop(cctx, ISN_STOREOPT, 1)) == NULL) + if ((isn = generate_instr_drop(cctx, isn_type, 1)) == NULL) return FAIL; isn->isn_arg.storeopt.so_name = vim_strsave(name); isn->isn_arg.storeopt.so_flags = opt_flags; @@ -5980,6 +5985,7 @@ generate_loadvar( switch (dest) { case dest_option: + case dest_func_option: generate_LOAD(cctx, ISN_LOADOPT, 0, name, type); break; case dest_global: @@ -6094,6 +6100,7 @@ get_var_dest( int cc; long numval; getoption_T opt_type; + int opt_p_flags; *dest = dest_option; if (cmdidx == CMD_final || cmdidx == CMD_const) @@ -6112,7 +6119,7 @@ get_var_dest( cc = *p; *p = NUL; opt_type = get_option_value(skip_option_env_lead(name), - &numval, NULL, NULL, *option_scope); + &numval, NULL, &opt_p_flags, *option_scope); *p = cc; switch (opt_type) { @@ -6121,7 +6128,16 @@ get_var_dest( return FAIL; case gov_string: case gov_hidden_string: - *type = &t_string; + if (opt_p_flags & P_FUNC) + { + // might be a Funcref, check the type later + *type = &t_any; + *dest = dest_func_option; + } + else + { + *type = &t_string; + } break; case gov_bool: case gov_hidden_bool: @@ -6204,8 +6220,11 @@ generate_store_var( switch (dest) { case dest_option: - return generate_STOREOPT(cctx, skip_option_env_lead(name), - opt_flags); + return generate_STOREOPT(cctx, ISN_STOREOPT, + skip_option_env_lead(name), opt_flags); + case dest_func_option: + return generate_STOREOPT(cctx, ISN_STOREFUNCOPT, + skip_option_env_lead(name), opt_flags); case dest_global: // include g: with the name, easier to execute that way return generate_STORE(cctx, vim_strchr(name, AUTOLOAD_CHAR) == NULL @@ -6468,7 +6487,7 @@ compile_lhs( if (lhs->lhs_varlen > 1 || var_start[lhs->lhs_varlen] != ':') var_end = lhs->lhs_dest_end; - if (lhs->lhs_dest != dest_option) + if (lhs->lhs_dest != dest_option && lhs->lhs_dest != dest_func_option) { if (is_decl && *var_end == ':') { @@ -7223,7 +7242,8 @@ compile_assignment(char_u *arg, exarg_T emsg(_(e_const_requires_a_value)); goto theend; } - else if (!lhs.lhs_has_type || lhs.lhs_dest == dest_option) + else if (!lhs.lhs_has_type || lhs.lhs_dest == dest_option + || lhs.lhs_dest == dest_func_option) { emsg(_(e_type_or_initialization_required)); goto theend; @@ -10454,6 +10474,7 @@ delete_instr(isn_T *isn) break; case ISN_STOREOPT: + case ISN_STOREFUNCOPT: vim_free(isn->isn_arg.storeopt.so_name); break;
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2336,10 +2336,14 @@ exec_instructions(ectx_T *ectx) // store option case ISN_STOREOPT: + case ISN_STOREFUNCOPT: { + char_u *opt_name = iptr->isn_arg.storeopt.so_name; + int opt_flags = iptr->isn_arg.storeopt.so_flags; long n = 0; char_u *s = NULL; char *msg; + callback_T cb = {NULL, NULL, 0}; --ectx->ec_stack.ga_len; tv = STACK_TV_BOT(0); @@ -2349,11 +2353,22 @@ exec_instructions(ectx_T *ectx) if (s == NULL) s = (char_u *)""; } + else if (iptr->isn_type == ISN_STOREFUNCOPT) + { + SOURCING_LNUM = iptr->isn_lnum; + cb = get_callback(tv); + if (cb.cb_name == NULL || *cb.cb_name == NUL) + { + clear_tv(tv); + free_callback(&cb); + goto on_error; + } + s = cb.cb_name; + } else // must be VAR_NUMBER, CHECKTYPE makes sure n = tv->vval.v_number; - msg = set_option_value(iptr->isn_arg.storeopt.so_name, - n, s, iptr->isn_arg.storeopt.so_flags); + msg = set_option_value(opt_name, n, s, opt_flags); clear_tv(tv); if (msg != NULL) { @@ -2361,6 +2376,8 @@ exec_instructions(ectx_T *ectx) emsg(_(msg)); goto on_error; } + if (cb.cb_name != NULL) + free_callback(&cb); } break; @@ -5335,7 +5352,9 @@ list_instructions(char *pfx, isn_T *inst } break; case ISN_STOREOPT: - smsg("%s%4d STOREOPT &%s", pfx, current, + case ISN_STOREFUNCOPT: + smsg("%s%4d %s &%s", pfx, current, + iptr->isn_type == ISN_STOREOPT ? "STOREOPT" : "STOREFUNCOPT", iptr->isn_arg.storeopt.so_name); break; case ISN_STOREENV: