Permalink
Browse files

patch 7.4.2137

Problem:    Using function() with a name will find another function when it is
            redefined.
Solution:   Add funcref().  Refer to lambda using a partial.  Fix several
            reference counting issues.
  • Loading branch information...
1 parent 5801644 commit 437bafe4c8a83ed71ee006eda7f54b65a90f0d4c @brammool brammool committed Aug 1, 2016
Showing with 447 additions and 231 deletions.
  1. +24 −5 runtime/doc/eval.txt
  2. +22 −3 src/channel.c
  3. +25 −9 src/eval.c
  4. +77 −30 src/evalfunc.c
  5. +1 −1 src/if_mzsch.c
  6. +1 −1 src/if_py_both.h
  7. +8 −4 src/misc2.c
  8. +1 −0 src/proto/eval.pro
  9. +5 −1 src/proto/userfunc.pro
  10. +1 −1 src/regexp.c
  11. +91 −1 src/structs.h
  12. +15 −0 src/testdir/test_expr.vim
  13. +1 −1 src/testdir/test_lambda.vim
  14. +172 −174 src/userfunc.c
  15. +2 −0 src/version.c
  16. +1 −0 src/vim.h
View
@@ -1,4 +1,4 @@
-*eval.txt* For Vim version 7.4. Last change: 2016 Jul 29
+*eval.txt* For Vim version 7.4. Last change: 2016 Jul 31
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1240,7 +1240,9 @@ function returns: >
:let Bar = Foo(4)
:echo Bar(6)
< 5
-See also |:func-closure|.
+
+See also |:func-closure|. Lambda and closure support can be checked with: >
+ if has('lambda')
Examples for using a lambda expression with |sort()|, |map()| and |filter()|: >
:echo map([1, 2, 3], {idx, val -> val + 1})
@@ -2071,8 +2073,10 @@ foldlevel({lnum}) Number fold level at {lnum}
foldtext() String line displayed for closed fold
foldtextresult({lnum}) String text for closed fold at {lnum}
foreground() Number bring the Vim window to the foreground
-function({name} [, {arglist}] [, {dict}])
+funcref({name} [, {arglist}] [, {dict}])
Funcref reference to function {name}
+function({name} [, {arglist}] [, {dict}])
+ Funcref named reference to function {name}
garbagecollect([{atexit}]) none free memory, breaking cyclic references
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
@@ -3850,19 +3854,32 @@ foreground() Move the Vim window to the foreground. Useful when sent from
{only in the Win32, Athena, Motif and GTK GUI versions and the
Win32 console version}
+ *funcref()*
+funcref({name} [, {arglist}] [, {dict}])
+ Just like |function()|, but the returned Funcref will lookup
+ the function by reference, not by name. This matters when the
+ function {name} is redefined later.
+
+ Unlike |function()|, {name} must be an existing user function.
+ Also for autoloaded functions. {name} cannot be a builtin
+ function.
*function()* *E700* *E922* *E923*
function({name} [, {arglist}] [, {dict}])
Return a |Funcref| variable that refers to function {name}.
{name} can be the name of a user defined function or an
internal function.
- {name} can also be a Funcref, also a partial. When it is a
+ {name} can also be a Funcref or a partial. When it is a
partial the dict stored in it will be used and the {dict}
argument is not allowed. E.g.: >
let FuncWithArg = function(dict.Func, [arg])
let Broken = function(dict.Func, [arg], dict)
<
+ When using the Funcref the function will be found by {name},
+ also when it was redefined later. Use |funcref()| to keep the
+ same function.
+
When {arglist} or {dict} is present this creates a partial.
That means the argument list and/or the dictionary is stored in
the Funcref and will be used when the Funcref is called.
@@ -6191,6 +6208,7 @@ screenrow() *screenrow()*
The result is a Number, which is the current screen row of the
cursor. The top line has number one.
This function is mainly used for testing.
+ Alternatively you can use |winline()|.
Note: Same restrictions as with |screencol()|.
@@ -8039,6 +8057,7 @@ insert_expand Compiled with support for CTRL-X expansion commands in
Insert mode.
jumplist Compiled with |jumplist| support.
keymap Compiled with 'keymap' support.
+lambda Compiled with |lambda| support.
langmap Compiled with 'langmap' support.
libcall Compiled with |libcall()| support.
linebreak Compiled with 'linebreak', 'breakat', 'showbreak' and
@@ -8294,7 +8313,7 @@ See |:verbose-cmd| for more information.
:endf[unction] The end of a function definition. Must be on a line
by its own, without other commands.
- *:delf* *:delfunction* *E130* *E131*
+ *:delf* *:delfunction* *E130* *E131* *E933*
:delf[unction] {name} Delete function {name}.
{name} can also be a |Dictionary| entry that is a
|Funcref|: >
View
@@ -1124,15 +1124,18 @@ set_callback(
if (callback != NULL && *callback != NUL)
{
if (partial != NULL)
- *cbp = partial->pt_name;
+ *cbp = partial_name(partial);
else
+ {
*cbp = vim_strsave(callback);
+ func_ref(*cbp);
+ }
}
else
*cbp = NULL;
*pp = partial;
- if (*pp != NULL)
- ++(*pp)->pt_refcount;
+ if (partial != NULL)
+ ++partial->pt_refcount;
}
/*
@@ -1279,7 +1282,10 @@ channel_set_req_callback(
item->cq_callback = callback;
}
else
+ {
item->cq_callback = vim_strsave(callback);
+ func_ref(item->cq_callback);
+ }
item->cq_seq_nr = id;
item->cq_prev = head->cq_prev;
head->cq_prev = item;
@@ -3923,14 +3929,24 @@ free_job_options(jobopt_T *opt)
{
if (opt->jo_partial != NULL)
partial_unref(opt->jo_partial);
+ else if (opt->jo_callback != NULL)
+ func_unref(opt->jo_callback);
if (opt->jo_out_partial != NULL)
partial_unref(opt->jo_out_partial);
+ else if (opt->jo_out_cb != NULL)
+ func_unref(opt->jo_out_cb);
if (opt->jo_err_partial != NULL)
partial_unref(opt->jo_err_partial);
+ else if (opt->jo_err_cb != NULL)
+ func_unref(opt->jo_err_cb);
if (opt->jo_close_partial != NULL)
partial_unref(opt->jo_close_partial);
+ else if (opt->jo_close_cb != NULL)
+ func_unref(opt->jo_close_cb);
if (opt->jo_exit_partial != NULL)
partial_unref(opt->jo_exit_partial);
+ else if (opt->jo_exit_cb != NULL)
+ func_unref(opt->jo_exit_cb);
}
/*
@@ -4476,7 +4492,10 @@ job_set_options(job_T *job, jobopt_T *opt)
++job->jv_exit_partial->pt_refcount;
}
else
+ {
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+ func_ref(job->jv_exit_cb);
+ }
}
}
}
View
@@ -5011,6 +5011,17 @@ get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
return OK;
}
+/*
+ * Return the function name of the partial.
+ */
+ char_u *
+partial_name(partial_T *pt)
+{
+ if (pt->pt_name != NULL)
+ return pt->pt_name;
+ return pt->pt_func->uf_name;
+}
+
static void
partial_free(partial_T *pt)
{
@@ -5020,8 +5031,13 @@ partial_free(partial_T *pt)
clear_tv(&pt->pt_argv[i]);
vim_free(pt->pt_argv);
dict_unref(pt->pt_dict);
- func_unref(pt->pt_name);
- vim_free(pt->pt_name);
+ if (pt->pt_name != NULL)
+ {
+ func_unref(pt->pt_name);
+ vim_free(pt->pt_name);
+ }
+ else
+ func_ptr_unref(pt->pt_func);
vim_free(pt);
}
@@ -5051,11 +5067,11 @@ func_equal(
/* empty and NULL function name considered the same */
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
- : tv1->vval.v_partial->pt_name;
+ : partial_name(tv1->vval.v_partial);
if (s1 != NULL && *s1 == NUL)
s1 = NULL;
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
- : tv2->vval.v_partial->pt_name;
+ : partial_name(tv2->vval.v_partial);
if (s2 != NULL && *s2 == NUL)
s2 = NULL;
if (s1 == NULL || s2 == NULL)
@@ -5550,7 +5566,7 @@ set_ref_in_item(
}
else if (tv->v_type == VAR_FUNC)
{
- abort = set_ref_in_func(tv->vval.v_string, copyID);
+ abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
}
else if (tv->v_type == VAR_PARTIAL)
{
@@ -5561,7 +5577,7 @@ set_ref_in_item(
*/
if (pt != NULL)
{
- abort = set_ref_in_func(pt->pt_name, copyID);
+ abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
if (pt->pt_dict != NULL)
{
@@ -5735,7 +5751,7 @@ echo_string_core(
{
partial_T *pt = tv->vval.v_partial;
char_u *fname = string_quote(pt == NULL ? NULL
- : pt->pt_name, FALSE);
+ : partial_name(pt), FALSE);
garray_T ga;
int i;
char_u *tf;
@@ -6871,7 +6887,7 @@ handle_subscript(
if (functv.v_type == VAR_PARTIAL)
{
pt = functv.vval.v_partial;
- s = pt->pt_name;
+ s = partial_name(pt);
}
else
s = functv.vval.v_string;
@@ -10025,7 +10041,7 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
{
partial_T *partial = expr->vval.v_partial;
- s = partial->pt_name;
+ s = partial_name(partial);
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
goto theend;
Oops, something went wrong.

0 comments on commit 437bafe

Please sign in to comment.