diff options
-rw-r--r-- | src/eval.c | 149 | ||||
-rw-r--r-- | src/testdir/test_partial.vim | 23 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 105 insertions, 69 deletions
diff --git a/src/eval.c b/src/eval.c index 891cbad73..6280323aa 100644 --- a/src/eval.c +++ b/src/eval.c @@ -110,7 +110,6 @@ static char *e_illvar = N_("E461: Illegal variable name: %s"); #ifdef FEAT_FLOAT static char *e_float_as_string = N_("E806: using Float as a String"); #endif -static char *e_dict_both = N_("E924: can't have both a \"self\" dict and a partial: %s"); #define NAMESPACE_CHAR (char_u *)"abglstvw" @@ -8678,28 +8677,6 @@ get_func_tv( return ret; } - -/* - * Call a function with its resolved parameters - * Return FAIL when the function can't be called, OK otherwise. - * Also returns OK when an error was encountered while executing the function. - */ - int -call_func( - char_u *funcname, /* name of the function */ - int len, /* length of "name" */ - typval_T *rettv, /* return value goes here */ - int argcount_in, /* number of "argvars" */ - typval_T *argvars_in, /* vars for arguments, must have "argcount" - PLUS ONE elements! */ - linenr_T firstline, /* first line of range */ - linenr_T lastline, /* last line of range */ - int *doesrange, /* return: function handled range */ - int evaluate, - partial_T *partial, /* optional, can be NULL */ - dict_T *selfdict_in) /* Dictionary for "self" */ -{ - int ret = FAIL; #define ERROR_UNKNOWN 0 #define ERROR_TOOMANY 1 #define ERROR_TOOFEW 2 @@ -8707,32 +8684,21 @@ call_func( #define ERROR_DICT 4 #define ERROR_NONE 5 #define ERROR_OTHER 6 -#define ERROR_BOTH 7 - int error = ERROR_NONE; - int i; - int llen; - ufunc_T *fp; #define FLEN_FIXED 40 - char_u fname_buf[FLEN_FIXED + 1]; - char_u *fname; - char_u *name; - int argcount = argcount_in; - typval_T *argvars = argvars_in; - dict_T *selfdict = selfdict_in; - typval_T argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */ - int argv_clear = 0; - /* Make a copy of the name, if it comes from a funcref variable it could - * be changed or deleted in the called function. */ - name = vim_strnsave(funcname, len); - if (name == NULL) - return ret; +/* + * In a script change <SID>name() and s:name() to K_SNR 123_name(). + * Change <SNR>123_name() to K_SNR 123_name(). + * Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory + * (slow). + */ + static char_u * +fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error) +{ + int llen; + char_u *fname; + int i; - /* - * In a script change <SID>name() and s:name() to K_SNR 123_name(). - * Change <SNR>123_name() to K_SNR 123_name(). - * Use fname_buf[] when it fits, otherwise allocate memory (slow). - */ llen = eval_fname_script(name); if (llen > 0) { @@ -8743,7 +8709,7 @@ call_func( if (eval_fname_sid(name)) /* "<SID>" or "s:" */ { if (current_SID <= 0) - error = ERROR_SCRIPT; + *error = ERROR_SCRIPT; else { sprintf((char *)fname_buf + 3, "%ld_", (long)current_SID); @@ -8759,9 +8725,10 @@ call_func( { fname = alloc((unsigned)(i + STRLEN(name + llen) + 1)); if (fname == NULL) - error = ERROR_OTHER; + *error = ERROR_OTHER; else { + *tofree = fname; mch_memmove(fname, fname_buf, (size_t)i); STRCPY(fname + i, name + llen); } @@ -8769,6 +8736,50 @@ call_func( } else fname = name; + return fname; +} + +/* + * Call a function with its resolved parameters + * Return FAIL when the function can't be called, OK otherwise. + * Also returns OK when an error was encountered while executing the function. + */ + int +call_func( + char_u *funcname, /* name of the function */ + int len, /* length of "name" */ + typval_T *rettv, /* return value goes here */ + int argcount_in, /* number of "argvars" */ + typval_T *argvars_in, /* vars for arguments, must have "argcount" + PLUS ONE elements! */ + linenr_T firstline, /* first line of range */ + linenr_T lastline, /* last line of range */ + int *doesrange, /* return: function handled range */ + int evaluate, + partial_T *partial, /* optional, can be NULL */ + dict_T *selfdict_in) /* Dictionary for "self" */ +{ + int ret = FAIL; + int error = ERROR_NONE; + int i; + ufunc_T *fp; + char_u fname_buf[FLEN_FIXED + 1]; + char_u *tofree = NULL; + char_u *fname; + char_u *name; + int argcount = argcount_in; + typval_T *argvars = argvars_in; + dict_T *selfdict = selfdict_in; + typval_T argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */ + int argv_clear = 0; + + /* Make a copy of the name, if it comes from a funcref variable it could + * be changed or deleted in the called function. */ + name = vim_strnsave(funcname, len); + if (name == NULL) + return ret; + + fname = fname_trans_sid(name, fname_buf, &tofree, &error); *doesrange = FALSE; @@ -8776,9 +8787,11 @@ call_func( { if (partial->pt_dict != NULL) { - if (selfdict_in != NULL) - error = ERROR_BOTH; - selfdict = partial->pt_dict; + /* When the function has a partial with a dict and there is a dict + * argument, use the dict argument. That is backwards compatible. + */ + if (selfdict_in == NULL) + selfdict = partial->pt_dict; } if (error == ERROR_NONE && partial->pt_argc > 0) { @@ -8934,16 +8947,12 @@ call_func( emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"), name); break; - case ERROR_BOTH: - emsg_funcname(e_dict_both, name); - break; } } while (argv_clear > 0) clear_tv(&argv[--argv_clear]); - if (fname != name && fname != fname_buf) - vim_free(fname); + vim_free(tofree); vim_free(name); return ret; @@ -11876,12 +11885,6 @@ f_function(typval_T *argvars, typval_T *rettv) vim_free(name); return; } - if (argvars[0].v_type == VAR_PARTIAL) - { - EMSG2(_(e_dict_both), name); - vim_free(name); - return; - } if (argvars[dict_idx].vval.v_dict == NULL) dict_idx = 0; } @@ -11925,14 +11928,16 @@ f_function(typval_T *argvars, typval_T *rettv) } } - if (argvars[0].v_type == VAR_PARTIAL) + /* For "function(dict.func, [], dict)" and "func" is a partial + * use "dict". That is backwards compatible. */ + if (dict_idx > 0) { - pt->pt_dict = argvars[0].vval.v_partial->pt_dict; + pt->pt_dict = argvars[dict_idx].vval.v_dict; ++pt->pt_dict->dv_refcount; } - else if (dict_idx > 0) + else if (argvars[0].v_type == VAR_PARTIAL) { - pt->pt_dict = argvars[dict_idx].vval.v_dict; + pt->pt_dict = argvars[0].vval.v_partial->pt_dict; ++pt->pt_dict->dv_refcount; } @@ -21714,7 +21719,17 @@ handle_subscript( if (rettv->v_type == VAR_FUNC && selfdict != NULL) { - ufunc_T *fp = find_func(rettv->vval.v_string); + char_u *fname; + char_u *tofree = NULL; + ufunc_T *fp; + char_u fname_buf[FLEN_FIXED + 1]; + int error; + + /* Translate "s:func" to the stored function name. */ + fname = fname_trans_sid(rettv->vval.v_string, fname_buf, + &tofree, &error); + fp = find_func(fname); + vim_free(tofree); /* Turn "dict.Func" into a partial for "Func" with "dict". */ if (fp != NULL && (fp->uf_flags & FC_DICT)) diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim index e9d9a3226..fe451cd8b 100644 --- a/src/testdir/test_partial.vim +++ b/src/testdir/test_partial.vim @@ -70,8 +70,6 @@ func Test_partial_implicit() let Func = function(dict.MyFunc, ['bbb']) call assert_equal('foo/bbb', Func()) - - call assert_fails('call function(dict.MyFunc, ["bbb"], dict)', 'E924:') endfunc fun InnerCall(funcref) @@ -87,3 +85,24 @@ func Test_function_in_dict() call OuterCall() endfunc +function! s:cache_clear() dict + return self.name +endfunction + +func Test_script_function_in_dict() + let s:obj = {'name': 'foo'} + let s:obj2 = {'name': 'bar'} + + let s:obj['clear'] = function('s:cache_clear') + + call assert_equal('foo', s:obj.clear()) + let F = s:obj.clear + call assert_equal('foo', F()) + call assert_equal('foo', call(s:obj.clear, [], s:obj)) + call assert_equal('bar', call(s:obj.clear, [], s:obj2)) + + let s:obj2['clear'] = function('s:cache_clear') + call assert_equal('bar', s:obj2.clear()) + let B = s:obj2.clear + call assert_equal('bar', B()) +endfunc diff --git a/src/version.c b/src/version.c index 8af175ef1..6e195360f 100644 --- a/src/version.c +++ b/src/version.c @@ -749,6 +749,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1582, +/**/ 1581, /**/ 1580, |