To: vim_dev@googlegroups.com Subject: Patch 7.4.1581 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1581 Problem: Using ":call dict.func()" where the function is a partial does not work. Using "dict.func()" where the function does not take a Dictionary does not work. Solution: Handle partial properly in ":call". (Yasuhiro Matsumoto) Files: src/eval.c, src/testdir/test_partial.vim, src/testdir/test55.ok *** ../vim-7.4.1580/src/eval.c 2016-03-16 20:41:16.489091037 +0100 --- src/eval.c 2016-03-16 21:34:38.811937117 +0100 *************** *** 867,873 **** static int tv_check_lock(int lock, char_u *name, int use_gettext); static int item_copy(typval_T *from, typval_T *to, int deep, int copyID); static char_u *find_option_end(char_u **arg, int *opt_flags); ! static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd); static int eval_fname_script(char_u *p); static int eval_fname_sid(char_u *p); static void list_func_head(ufunc_T *fp, int indent); --- 867,873 ---- static int tv_check_lock(int lock, char_u *name, int use_gettext); static int item_copy(typval_T *from, typval_T *to, int deep, int copyID); static char_u *find_option_end(char_u **arg, int *opt_flags); ! static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd, partial_T **partial); static int eval_fname_script(char_u *p); static int eval_fname_sid(char_u *p); static void list_func_head(ufunc_T *fp, int indent); *************** *** 3476,3482 **** return; } ! tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi); if (fudi.fd_newkey != NULL) { /* Still need to give an error message for missing key. */ --- 3476,3482 ---- return; } ! tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial); if (fudi.fd_newkey != NULL) { /* Still need to give an error message for missing key. */ *************** *** 3491,3499 **** if (fudi.fd_dict != NULL) ++fudi.fd_dict->dv_refcount; ! /* If it is the name of a variable of type VAR_FUNC use its contents. */ len = (int)STRLEN(tofree); ! name = deref_func_name(tofree, &len, &partial, FALSE); /* Skip white space to allow ":call func ()". Not good, but required for * backward compatibility. */ --- 3491,3508 ---- if (fudi.fd_dict != NULL) ++fudi.fd_dict->dv_refcount; ! /* If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its ! * contents. For VAR_PARTIAL get its partial, unless we already have one ! * from trans_function_name(). */ len = (int)STRLEN(tofree); ! name = deref_func_name(tofree, &len, ! partial != NULL ? NULL : &partial, FALSE); ! ! /* When calling fdict.func(), where "func" is a partial, use "fdict" ! * instead of the dict in the partial, for backwards compatibility. ! * TODO: Do use the arguments in the partial? */ ! if (fudi.fd_dict != NULL) ! partial = NULL; /* Skip white space to allow ":call func ()". Not good, but required for * backward compatibility. */ *************** *** 8561,8575 **** /* * Check if "name" is a variable of type VAR_FUNC. If so, return the function * name it contains, otherwise return "name". ! * If "name" is of type VAR_PARTIAL also return "partial" */ static char_u * ! deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload) { dictitem_T *v; int cc; ! *partial = NULL; cc = name[*lenp]; name[*lenp] = NUL; --- 8570,8586 ---- /* * Check if "name" is a variable of type VAR_FUNC. If so, return the function * name it contains, otherwise return "name". ! * If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set ! * "partialp". */ static char_u * ! deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload) { dictitem_T *v; int cc; ! if (partialp != NULL) ! *partialp = NULL; cc = name[*lenp]; name[*lenp] = NUL; *************** *** 8588,8601 **** if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) { ! *partial = v->di_tv.vval.v_partial; ! if (*partial == NULL) { *lenp = 0; return (char_u *)""; /* just in case */ } ! *lenp = (int)STRLEN((*partial)->pt_name); ! return (*partial)->pt_name; } return name; --- 8599,8615 ---- if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) { ! partial_T *pt = v->di_tv.vval.v_partial; ! ! if (pt == NULL) { *lenp = 0; return (char_u *)""; /* just in case */ } ! if (partialp != NULL) ! *partialp = pt; ! *lenp = (int)STRLEN(pt->pt_name); ! return pt->pt_name; } return name; *************** *** 21700,21717 **** if (rettv->v_type == VAR_FUNC && selfdict != NULL) { ! partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); /* Turn "dict.Func" into a partial for "Func" with "dict". */ ! if (pt != NULL) { ! pt->pt_refcount = 1; ! pt->pt_dict = selfdict; ! selfdict = NULL; ! pt->pt_name = rettv->vval.v_string; ! func_ref(pt->pt_name); ! rettv->v_type = VAR_PARTIAL; ! rettv->vval.v_partial = pt; } } --- 21714,21736 ---- if (rettv->v_type == VAR_FUNC && selfdict != NULL) { ! ufunc_T *fp = find_func(rettv->vval.v_string); /* Turn "dict.Func" into a partial for "Func" with "dict". */ ! if (fp != NULL && (fp->uf_flags & FC_DICT)) { ! partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); ! ! if (pt != NULL) ! { ! pt->pt_refcount = 1; ! pt->pt_dict = selfdict; ! selfdict = NULL; ! pt->pt_name = rettv->vval.v_string; ! func_ref(pt->pt_name); ! rettv->v_type = VAR_PARTIAL; ! rettv->vval.v_partial = pt; ! } } } *************** *** 23220,23226 **** * g:func global function name, same as "func" */ p = eap->arg; ! name = trans_function_name(&p, eap->skip, 0, &fudi); paren = (vim_strchr(p, '(') != NULL); if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { --- 23239,23245 ---- * g:func global function name, same as "func" */ p = eap->arg; ! name = trans_function_name(&p, eap->skip, 0, &fudi, NULL); paren = (vim_strchr(p, '(') != NULL); if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { *************** *** 23533,23539 **** if (*p == '!') p = skipwhite(p + 1); p += eval_fname_script(p); ! vim_free(trans_function_name(&p, TRUE, 0, NULL)); if (*skipwhite(p) == '(') { ++nesting; --- 23552,23558 ---- if (*p == '!') p = skipwhite(p + 1); p += eval_fname_script(p); ! vim_free(trans_function_name(&p, TRUE, 0, NULL, NULL)); if (*skipwhite(p) == '(') { ++nesting; *************** *** 23788,23794 **** char_u **pp, int skip, /* only find the end, don't evaluate */ int flags, ! funcdict_T *fdp) /* return: info about dictionary used */ { char_u *name = NULL; char_u *start; --- 23807,23814 ---- char_u **pp, int skip, /* only find the end, don't evaluate */ int flags, ! funcdict_T *fdp, /* return: info about dictionary used */ ! partial_T **partial) /* return: partial of a FuncRef */ { char_u *name = NULL; char_u *start; *************** *** 23797,23803 **** char_u sid_buf[20]; int len; lval_T lv; - partial_T *partial; if (fdp != NULL) vim_memset(fdp, 0, sizeof(funcdict_T)); --- 23817,23822 ---- *************** *** 23882,23888 **** if (lv.ll_exp_name != NULL) { len = (int)STRLEN(lv.ll_exp_name); ! name = deref_func_name(lv.ll_exp_name, &len, &partial, flags & TFN_NO_AUTOLOAD); if (name == lv.ll_exp_name) name = NULL; --- 23901,23907 ---- if (lv.ll_exp_name != NULL) { len = (int)STRLEN(lv.ll_exp_name); ! name = deref_func_name(lv.ll_exp_name, &len, partial, flags & TFN_NO_AUTOLOAD); if (name == lv.ll_exp_name) name = NULL; *************** *** 23890,23896 **** else { len = (int)(end - *pp); ! name = deref_func_name(*pp, &len, &partial, flags & TFN_NO_AUTOLOAD); if (name == *pp) name = NULL; } --- 23909,23915 ---- else { len = (int)(end - *pp); ! name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD); if (name == *pp) name = NULL; } *************** *** 24115,24121 **** int n = FALSE; p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD, ! NULL); nm = skipwhite(nm); /* Only accept "funcname", "funcname ", "funcname (..." and --- 24134,24140 ---- int n = FALSE; p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD, ! NULL, NULL); nm = skipwhite(nm); /* Only accept "funcname", "funcname ", "funcname (..." and *************** *** 24132,24138 **** char_u *nm = name; char_u *p; ! p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL); if (p != NULL && *nm == NUL) if (!check || translated_function_exists(p)) --- 24151,24157 ---- char_u *nm = name; char_u *p; ! p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL, NULL); if (p != NULL && *nm == NUL) if (!check || translated_function_exists(p)) *************** *** 24488,24494 **** funcdict_T fudi; p = eap->arg; ! name = trans_function_name(&p, eap->skip, 0, &fudi); vim_free(fudi.fd_newkey); if (name == NULL) { --- 24507,24513 ---- funcdict_T fudi; p = eap->arg; ! name = trans_function_name(&p, eap->skip, 0, &fudi, NULL); vim_free(fudi.fd_newkey); if (name == NULL) { *** ../vim-7.4.1580/src/testdir/test_partial.vim 2016-03-16 20:41:16.489091037 +0100 --- src/testdir/test_partial.vim 2016-03-16 20:43:29.567712656 +0100 *************** *** 16,21 **** --- 16,23 ---- func Test_partial_args() let Cb = function('MyFunc', ["foo", "bar"]) + + call Cb("zzz") call assert_equal("foo/bar/xxx", Cb("xxx")) call assert_equal("foo/bar/yyy", call(Cb, ["yyy"])) *************** *** 49,54 **** --- 51,59 ---- let Cb = function('MyDictFunc', dict) call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy")) call assert_fails('Cb("fff")', 'E492:') + + let dict = {"tr": function('tr', ['hello', 'h', 'H'])} + call assert_equal("Hello", dict.tr()) endfunc func Test_partial_implicit() *** ../vim-7.4.1580/src/testdir/test55.ok 2016-03-12 19:33:43.430403350 +0100 --- src/testdir/test55.ok 2016-03-16 21:28:32.627735123 +0100 *************** *** 44,50 **** {'33': 999} len: 3 again: 3 ! Vim(call):E725: g:dict.func-4 a:function('3') Vim(let):E698: --- 44,50 ---- {'33': 999} len: 3 again: 3 ! xxx3 g:dict.func-4 a:function('3') Vim(let):E698: *** ../vim-7.4.1580/src/version.c 2016-03-16 20:41:16.489091037 +0100 --- src/version.c 2016-03-16 20:44:15.699234847 +0100 *************** *** 750,751 **** --- 750,753 ---- { /* Add new patch number below this line */ + /**/ + 1581, /**/ -- "I don’t know how to make a screenshot" - Richard Stallman, July 2002 (when asked to send a screenshot of his desktop for unix.se) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///