This commit is contained in:
Michael Ennen
2016-10-29 14:55:53 -07:00
committed by James McCoy
parent 2c4e92abea
commit a21c687661
6 changed files with 71 additions and 62 deletions

View File

@@ -154,9 +154,6 @@ passed to the function. Example: >
This will invoke the function as if using: > This will invoke the function as if using: >
call myDict.Callback('foo') call myDict.Callback('foo')
This is very useful when passing a function around, e.g. in the arguments of
|ch_open()|.
Note that binding a function to a Dictionary also happens when the function is Note that binding a function to a Dictionary also happens when the function is
a member of the Dictionary: > a member of the Dictionary: >
@@ -164,8 +161,8 @@ a member of the Dictionary: >
call myDict.myFunction() call myDict.myFunction()
Here MyFunction() will get myDict passed as "self". This happens when the Here MyFunction() will get myDict passed as "self". This happens when the
"myFunction" member is accessed. When making assigning "myFunction" to "myFunction" member is accessed. When assigning "myFunction" to otherDict
otherDict and calling it, it will be bound to otherDict: > and calling it, it will be bound to otherDict: >
let otherDict.myFunction = myDict.myFunction let otherDict.myFunction = myDict.myFunction
call otherDict.myFunction() call otherDict.myFunction()
@@ -3588,7 +3585,7 @@ get({dict}, {key} [, {default}])
item is not available return {default}. Return zero when item is not available return {default}. Return zero when
{default} is omitted. {default} is omitted.
get({func}, {what}) get({func}, {what})
Get an item with from Funcref {func}. Possible values for Get item {what} from Funcref {func}. Possible values for
{what} are: {what} are:
'name' The function name 'name' The function name
'func' The function 'func' The function

View File

@@ -2759,7 +2759,7 @@ void ex_call(exarg_T *eap)
typval_T rettv; typval_T rettv;
linenr_T lnum; linenr_T lnum;
int doesrange; int doesrange;
int failed = false; bool failed = false;
funcdict_T fudi; funcdict_T fudi;
partial_T *partial = NULL; partial_T *partial = NULL;
@@ -4915,9 +4915,7 @@ static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
static void partial_free(partial_T *pt) static void partial_free(partial_T *pt)
{ {
int i; for (int i = 0; i < pt->pt_argc; i++) {
for (i = 0; i < pt->pt_argc; i++) {
clear_tv(&pt->pt_argv[i]); clear_tv(&pt->pt_argv[i]);
} }
xfree(pt->pt_argv); xfree(pt->pt_argv);
@@ -5170,15 +5168,14 @@ dict_equal (
static int tv_equal_recurse_limit; static int tv_equal_recurse_limit;
static int func_equal( static bool func_equal(
typval_T *tv1, typval_T *tv1,
typval_T *tv2, typval_T *tv2,
int ic // ignore case bool ic // ignore case
) { ) {
char_u *s1, *s2; char_u *s1, *s2;
dict_T *d1, *d2; dict_T *d1, *d2;
int a1, a2; int a1, a2;
int i;
// empty and NULL function name considered the same // empty and NULL function name considered the same
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
@@ -5216,7 +5213,7 @@ static int func_equal(
if (a1 != a2) { if (a1 != a2) {
return false; return false;
} }
for (i = 0; i < a1; i++) { for (int i = 0; i < a1; i++) {
if (!tv_equal(tv1->vval.v_partial->pt_argv + i, if (!tv_equal(tv1->vval.v_partial->pt_argv + i,
tv2->vval.v_partial->pt_argv + i, ic, true)) { tv2->vval.v_partial->pt_argv + i, ic, true)) {
return false; return false;
@@ -6147,7 +6144,6 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
switch (tv->v_type) { switch (tv->v_type) {
case VAR_DICT: { case VAR_DICT: {
dict_T *dd = tv->vval.v_dict; dict_T *dd = tv->vval.v_dict;
if (dd != NULL && dd->dv_copyID != copyID) { if (dd != NULL && dd->dv_copyID != copyID) {
// Didn't see this dict yet. // Didn't see this dict yet.
dd->dv_copyID = copyID; dd->dv_copyID = copyID;
@@ -6201,7 +6197,6 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
case VAR_PARTIAL: { case VAR_PARTIAL: {
partial_T *pt = tv->vval.v_partial; partial_T *pt = tv->vval.v_partial;
int i;
// A partial does not have a copyID, because it cannot contain itself. // A partial does not have a copyID, because it cannot contain itself.
if (pt != NULL) { if (pt != NULL) {
@@ -6213,7 +6208,7 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
abort = abort || set_ref_in_item(&dtv, copyID, ht_stack, list_stack); abort = abort || set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
} }
for (i = 0; i < pt->pt_argc; i++) { for (int i = 0; i < pt->pt_argc; i++) {
abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID, abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
ht_stack, list_stack); ht_stack, list_stack);
} }
@@ -6356,7 +6351,6 @@ static void dict_free_contents(dict_T *d) {
dictitem_T *di; dictitem_T *di;
/* Lock the hashtab, we don't want it to resize while freeing items. */ /* Lock the hashtab, we don't want it to resize while freeing items. */
hash_lock(&d->dv_hashtab); hash_lock(&d->dv_hashtab);
assert(d->dv_hashtab.ht_locked > 0); assert(d->dv_hashtab.ht_locked > 0);
@@ -6969,7 +6963,7 @@ static VimLFuncDef *find_internal_func(const char *const name)
/// "partialp". /// "partialp".
static char_u *deref_func_name( static char_u *deref_func_name(
char_u *name, int *lenp, char_u *name, int *lenp,
partial_T **partialp, int no_autoload partial_T **partialp, bool no_autoload
) )
{ {
dictitem_T *v; dictitem_T *v;
@@ -7102,17 +7096,16 @@ fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error) {
if (current_SID <= 0) { if (current_SID <= 0) {
*error = ERROR_SCRIPT; *error = ERROR_SCRIPT;
} else { } else {
vim_snprintf((char *)fname_buf + 3, ARRAY_SIZE(fname_buf) - 3, snprintf((char *)fname_buf + 3, FLEN_FIXED + 1, "%" PRId64 "_",
"%" PRId64 "_", (int64_t)current_SID); (int64_t)current_SID);
i = (int)STRLEN(fname_buf); i = (int)STRLEN(fname_buf);
} }
} }
if (i + STRLEN(name + llen) < FLEN_FIXED) { if (i + STRLEN(name + llen) < FLEN_FIXED) {
STRCPY(fname_buf + i, name + llen); STRCPY(fname_buf + i, name + llen);
fname = fname_buf; fname = fname_buf;
} else { } else {
fname = xmalloc((unsigned)(i + STRLEN(name + llen) + 1)); fname = xmalloc(i + STRLEN(name + llen) + 1);
if (fname == NULL) { if (fname == NULL) {
*error = ERROR_OTHER; *error = ERROR_OTHER;
} else { } else {
@@ -7142,7 +7135,7 @@ call_func(
linenr_T firstline, // first line of range linenr_T firstline, // first line of range
linenr_T lastline, // last line of range linenr_T lastline, // last line of range
int *doesrange, // return: function handled range int *doesrange, // return: function handled range
int evaluate, bool evaluate,
partial_T *partial, // optional, can be NULL partial_T *partial, // optional, can be NULL
dict_T *selfdict_in // Dictionary for "self" dict_T *selfdict_in // Dictionary for "self"
) )
@@ -7169,7 +7162,7 @@ call_func(
fname = fname_trans_sid(name, fname_buf, &tofree, &error); fname = fname_trans_sid(name, fname_buf, &tofree, &error);
*doesrange = FALSE; *doesrange = false;
if (partial != NULL) { if (partial != NULL) {
// When the function has a partial with a dict and there is a dict // When the function has a partial with a dict and there is a dict
@@ -7180,12 +7173,10 @@ call_func(
selfdict = partial->pt_dict; selfdict = partial->pt_dict;
} }
if (error == ERROR_NONE && partial->pt_argc > 0) { if (error == ERROR_NONE && partial->pt_argc > 0) {
int i;
for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) { for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) {
copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]); copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]);
} }
for (i = 0; i < argcount_in; i++) { for (int i = 0; i < argcount_in; i++) {
argv[i + argv_clear] = argvars_in[i]; argv[i + argv_clear] = argvars_in[i];
} }
argvars = argv; argvars = argv;
@@ -8133,7 +8124,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
selfdict = argvars[2].vval.v_dict; selfdict = argvars[2].vval.v_dict;
} }
(void)func_call(func, &argvars[1], partial, selfdict, rettv); func_call(func, &argvars[1], partial, selfdict, rettv);
} }
/* /*
@@ -9611,7 +9602,6 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
use_string = true; use_string = true;
} }
s = get_tv_string(&argvars[0]);
if (s == NULL || *s == NUL || (use_string && ascii_isdigit(*s))) { if (s == NULL || *s == NUL || (use_string && ascii_isdigit(*s))) {
EMSG2(_(e_invarg2), s); EMSG2(_(e_invarg2), s);
} else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL } else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
@@ -9622,7 +9612,6 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int dict_idx = 0; int dict_idx = 0;
int arg_idx = 0; int arg_idx = 0;
list_T *list = NULL; list_T *list = NULL;
if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) { if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) {
char sid_buf[25]; char sid_buf[25];
int off = *s == 's' ? 2 : 5; int off = *s == 's' ? 2 : 5;
@@ -9633,7 +9622,7 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// printable text. // printable text.
snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_", snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
(int64_t)current_SID); (int64_t)current_SID);
name = xmalloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1)); name = xmalloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
if (name != NULL) { if (name != NULL) {
STRCPY(name, sid_buf); STRCPY(name, sid_buf);
STRCAT(name, s + off); STRCAT(name, s + off);
@@ -15574,7 +15563,6 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
} else { } else {
func_name = partial->pt_name; func_name = partial->pt_name;
} }
// Copy the values. This is needed to be able to set v_lock to VAR_FIXED // Copy the values. This is needed to be able to set v_lock to VAR_FIXED
// in the copy without changing the original list items. // in the copy without changing the original list items.
copy_tv(&si1->item->li_tv, &argv[0]); copy_tv(&si1->item->li_tv, &argv[0]);
@@ -18573,8 +18561,7 @@ handle_subscript (
pt->pt_auto = true; pt->pt_auto = true;
selfdict = NULL; selfdict = NULL;
if (rettv->v_type == VAR_FUNC) { if (rettv->v_type == VAR_FUNC) {
// Just a function: Take over the function name and use // Just a function: Take over the function name and use selfdict.
// selfdict.
pt->pt_name = rettv->vval.v_string; pt->pt_name = rettv->vval.v_string;
} else { } else {
partial_T *ret_pt = rettv->vval.v_partial; partial_T *ret_pt = rettv->vval.v_partial;
@@ -18692,6 +18679,8 @@ void free_tv(typval_T *varp)
#define TYPVAL_ENCODE_CONV_PARTIAL(pt) \ #define TYPVAL_ENCODE_CONV_PARTIAL(pt) \
do { \ do { \
partial_unref(pt); \
pt = NULL; \
tv->v_lock = VAR_UNLOCKED; \ tv->v_lock = VAR_UNLOCKED; \
} while (0) } while (0)
@@ -19020,11 +19009,10 @@ static dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload)
return find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL); return find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
} }
/* /// Find variable "varname" in hashtab "ht" with name "htname".
* Find variable "varname" in hashtab "ht" with name "htname". /// Returns NULL if not found.
* Returns NULL if not found. static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname,
*/ char_u *varname, bool no_autoload)
static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload)
{ {
hashitem_T *hi; hashitem_T *hi;

View File

@@ -315,34 +315,58 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
ga_append(gap, ')'); \ ga_append(gap, ')'); \
} while (0) } while (0)
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \ #define TYPVAL_ENCODE_CONV_PARTIAL(pt) \
do { \ do { \
partial_T *pt = tv->vval.v_partial; \
garray_T ga; \
int i; \ int i; \
ga_init(&ga, 1, 100); \ ga_concat(gap, "function("); \
ga_concat(&ga, (char_u *)"function("); \
if (&pt->pt_name != NULL) { \ if (&pt->pt_name != NULL) { \
TYPVAL_ENCODE_CONV_STRING((char *)pt->pt_name, sizeof(pt->pt_name)); \ size_t len; \
char_u *p; \
len = 3; \
len += STRLEN(pt->pt_name); \
for (p = pt->pt_name; *p != NUL; mb_ptr_adv(p)) { \
if (*p == '\'') { \
len++; \
} \ } \
if (pt != NULL && pt->pt_argc > 0) { \ } \
ga_concat(&ga, (char_u *)", ["); \ char_u *r, *s; \
s = r = xmalloc(len); \
if (r != NULL) { \
*r++ = '\''; \
for (p = pt->pt_name; *p != NUL; ) { \
if (*p == '\'') { \
*r++ = '\''; \
} \
MB_COPY_CHAR(p, r); \
} \
*r++ = '\''; \
*r++ = NUL; \
} \
ga_concat(gap, s); \
xfree(s); \
} \
if (pt->pt_argc > 0) { \
ga_concat(gap, ", ["); \
for (i = 0; i < pt->pt_argc; i++) { \ for (i = 0; i < pt->pt_argc; i++) { \
if (i > 0) { \ if (i > 0) { \
ga_concat(&ga, (char_u *)", "); \ ga_concat(gap, ", "); \
} \ } \
ga_concat(&ga, encode_tv2string(&pt->pt_argv[i], NULL)); \ char *tofree = encode_tv2string(&pt->pt_argv[i], NULL); \
ga_concat(gap, tofree); \
xfree(tofree); \
} \ } \
ga_concat(&ga, (char_u *)"]"); \ ga_append(gap, ']'); \
} \ } \
if (pt != NULL && pt->pt_dict != NULL) { \ if (pt->pt_dict != NULL) { \
typval_T dtv; \ typval_T dtv; \
ga_concat(&ga, (char_u *)", "); \ ga_concat(gap, ", "); \
dtv.v_type = VAR_DICT; \ dtv.v_type = VAR_DICT; \
dtv.vval.v_dict = pt->pt_dict; \ dtv.vval.v_dict = pt->pt_dict; \
ga_concat(&ga, encode_tv2string(&dtv, NULL)); \ char *tofree = encode_tv2string(&dtv, NULL); \
ga_concat(gap, tofree); \
xfree(tofree); \
} \ } \
ga_concat(&ga, (char_u *)")"); \ ga_append(gap, ')'); \
} while (0) } while (0)
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ #define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
@@ -692,7 +716,7 @@ static inline int convert_to_json_string(garray_T *const gap,
mpstack, objname) mpstack, objname)
#undef TYPVAL_ENCODE_CONV_PARTIAL #undef TYPVAL_ENCODE_CONV_PARTIAL
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \ #define TYPVAL_ENCODE_CONV_PARTIAL(pt) \
return conv_error(_("E474: Error while dumping %s, %s: " \ return conv_error(_("E474: Error while dumping %s, %s: " \
"attempt to dump partial"), \ "attempt to dump partial"), \
mpstack, objname) mpstack, objname)

View File

@@ -72,7 +72,7 @@
/// @def TYPVAL_ENCODE_CONV_PARTIAL /// @def TYPVAL_ENCODE_CONV_PARTIAL
/// @brief Macros used to convert a partial /// @brief Macros used to convert a partial
/// ///
/// @param partial Partial name. /// @param pt Partial name.
/// @def TYPVAL_ENCODE_CONV_EMPTY_LIST /// @def TYPVAL_ENCODE_CONV_EMPTY_LIST
/// @brief Macros used to convert an empty list /// @brief Macros used to convert an empty list

View File

@@ -37,12 +37,12 @@ typedef enum {
VAR_NUMBER, ///< Number, .v_number is used. VAR_NUMBER, ///< Number, .v_number is used.
VAR_STRING, ///< String, .v_string is used. VAR_STRING, ///< String, .v_string is used.
VAR_FUNC, ///< Function reference, .v_string is used as function name. VAR_FUNC, ///< Function reference, .v_string is used as function name.
VAR_PARTIAL, ///< Partial, .v_partial is used.
VAR_LIST, ///< List, .v_list is used. VAR_LIST, ///< List, .v_list is used.
VAR_DICT, ///< Dictionary, .v_dict is used. VAR_DICT, ///< Dictionary, .v_dict is used.
VAR_FLOAT, ///< Floating-point value, .v_float is used. VAR_FLOAT, ///< Floating-point value, .v_float is used.
VAR_SPECIAL, ///< Special value (true, false, null), .v_special VAR_SPECIAL, ///< Special value (true, false, null), .v_special
///< is used. ///< is used.
VAR_PARTIAL, ///< Partial, .v_partial is used.
} VarType; } VarType;
/// Structure that holds an internal variable value /// Structure that holds an internal variable value

View File

@@ -1235,7 +1235,7 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
EXTERN int ignored; EXTERN int ignored;
EXTERN char *ignoredp; EXTERN char *ignoredp;
EXTERN int in_free_unref_items INIT(= false); EXTERN bool in_free_unref_items INIT(= false);
// If a msgpack-rpc channel should be started over stdin/stdout // If a msgpack-rpc channel should be started over stdin/stdout
EXTERN bool embedded_mode INIT(= false); EXTERN bool embedded_mode INIT(= false);