diff options
author | Bram Moolenaar <Bram@vim.org> | 2005-01-14 21:53:12 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2005-01-14 21:53:12 +0000 |
commit | 8c711458a6affdad1cbae635694ff0a014850a27 (patch) | |
tree | 1645457d30b263a5eb31ea79bd62230a1cb4caa0 /src | |
parent | d8b0273231d69a2a6c24844c1acc938330acf035 (diff) |
updated for version 7.0038v7.0038
Diffstat (limited to 'src')
-rw-r--r-- | src/eval.c | 1369 | ||||
-rw-r--r-- | src/ex_cmds.c | 4 | ||||
-rw-r--r-- | src/gui_gtk_x11.c | 2 |
3 files changed, 1028 insertions, 347 deletions
diff --git a/src/eval.c b/src/eval.c index 54215198d2..100bc80a99 100644 --- a/src/eval.c +++ b/src/eval.c @@ -47,6 +47,7 @@ typedef struct varnumber_T v_number; /* number value */ char_u *v_string; /* string value (can be NULL!) */ struct listvar_S *v_list; /* list value (can be NULL!) */ + struct dictvar_S *v_dict; /* dict value (can be NULL!) */ } vval; } typeval; @@ -56,6 +57,7 @@ typedef struct #define VAR_STRING 2 /* "v_string" is used */ #define VAR_FUNC 3 /* "v_string" is function name */ #define VAR_LIST 4 /* "v_list" is used */ +#define VAR_DICT 5 /* "v_dict" is used */ /* * Structure to hold an internal variable with a name. @@ -104,12 +106,43 @@ struct listvar_S typedef struct listvar_S listvar; #define VAR_LIST_MAXNEST 100 /* maximum nesting of lists */ + +/* + * Structure to hold an item of a Dictionary. + */ +struct dictitem_S +{ + struct dictitem_S *di_next; /* next item in list */ + char_u *di_key; /* key string */ + typeval di_tv; /* type and value of the variable */ +}; + +typedef struct dictitem_S dictitem; + +/* + * Structure to hold info about a Dictionary. + */ +struct dictvar_S +{ + int dv_refcount; /* reference count */ + dictitem *dv_first; /* first item, NULL if none */ +}; + +typedef struct dictvar_S dictvar; + + static char *e_letunexp = N_("E18: Unexpected characters in :let"); static char *e_listidx = N_("E684: list index out of range: %ld"); static char *e_undefvar = N_("E121: Undefined variable: %s"); static char *e_missbrac = N_("E111: Missing ']'"); static char *e_intern2 = N_("E685: Internal error: %s"); -static char *e_listarg = N_("E686: Argument of %s must be a list"); +static char *e_listarg = N_("E686: Argument of %s must be a List"); +static char *e_listdictarg = N_("E999: Argument of %s must be a List or Dictionaary"); +static char *e_emptykey = N_("E999: Empty key in Dictionary"); +static char *e_listreq = N_("E999: List required"); +static char *e_dictreq = N_("E999: Dictionary required"); +static char *e_toomanyarg = N_("E118: Too many arguments for function: %s"); +static char *e_dictkey = N_("E999: key not found in Dictionary: %s"); /* * All user-defined global variables are stored in "variables". @@ -316,7 +349,6 @@ static int eval_index __ARGS((char_u **arg, typeval *rettv, int evaluate)); static int get_option_tv __ARGS((char_u **arg, typeval *rettv, int evaluate)); static int get_string_tv __ARGS((char_u **arg, typeval *rettv, int evaluate)); static int get_lit_string_tv __ARGS((char_u **arg, typeval *rettv, int evaluate)); -static int get_sharp_string_tv __ARGS((char_u **arg, typeval *rettv, int evaluate)); static int get_list_tv __ARGS((char_u **arg, typeval *rettv, int evaluate)); static listvar *list_alloc __ARGS((void)); static void list_unref __ARGS((listvar *l)); @@ -340,6 +372,16 @@ static void list_getrem __ARGS((listvar *l, listitem *item, listitem *item2)); static char_u *list2string __ARGS((typeval *tv)); static void list_join __ARGS((garray_T *gap, listvar *l, char_u *sep, int echo)); +static dictvar *dict_alloc __ARGS((void)); +static void dict_unref __ARGS((dictvar *d)); +static void dict_free __ARGS((dictvar *d)); +static dictitem *dictitem_alloc __ARGS((void)); +static void dictitem_free __ARGS((dictitem *item)); +static void dict_add __ARGS((dictvar *d, dictitem *item)); +static dictitem *dict_find __ARGS((dictvar *d, char_u *key, int len)); +static char_u *dict2string __ARGS((typeval *tv)); +static int get_dict_tv __ARGS((char_u **arg, typeval *rettv, int evaluate)); + static char_u *echo_string __ARGS((typeval *tv, char_u **tofree, char_u *numbuf)); static char_u *tv2string __ARGS((typeval *tv, char_u **tofree, char_u *numbuf)); static char_u *string_quote __ARGS((char_u *str, int function)); @@ -438,7 +480,9 @@ static void f_inputsave __ARGS((typeval *argvars, typeval *rettv)); static void f_inputsecret __ARGS((typeval *argvars, typeval *rettv)); static void f_insert __ARGS((typeval *argvars, typeval *rettv)); static void f_isdirectory __ARGS((typeval *argvars, typeval *rettv)); +static void f_items __ARGS((typeval *argvars, typeval *rettv)); static void f_join __ARGS((typeval *argvars, typeval *rettv)); +static void f_keys __ARGS((typeval *argvars, typeval *rettv)); static void f_last_buffer_nr __ARGS((typeval *argvars, typeval *rettv)); static void f_len __ARGS((typeval *argvars, typeval *rettv)); static void f_libcall __ARGS((typeval *argvars, typeval *rettv)); @@ -459,6 +503,7 @@ static void f_mode __ARGS((typeval *argvars, typeval *rettv)); static void f_nextnonblank __ARGS((typeval *argvars, typeval *rettv)); static void f_nr2char __ARGS((typeval *argvars, typeval *rettv)); static void f_prevnonblank __ARGS((typeval *argvars, typeval *rettv)); +static void f_range __ARGS((typeval *argvars, typeval *rettv)); static void f_remote_expr __ARGS((typeval *argvars, typeval *rettv)); static void f_remote_foreground __ARGS((typeval *argvars, typeval *rettv)); static void f_remote_peek __ARGS((typeval *argvars, typeval *rettv)); @@ -501,6 +546,7 @@ static void f_tolower __ARGS((typeval *argvars, typeval *rettv)); static void f_toupper __ARGS((typeval *argvars, typeval *rettv)); static void f_tr __ARGS((typeval *argvars, typeval *rettv)); static void f_type __ARGS((typeval *argvars, typeval *rettv)); +static void f_values __ARGS((typeval *argvars, typeval *rettv)); static void f_virtcol __ARGS((typeval *argvars, typeval *rettv)); static void f_visualmode __ARGS((typeval *argvars, typeval *rettv)); static void f_winbufnr __ARGS((typeval *argvars, typeval *rettv)); @@ -561,8 +607,12 @@ static char_u *skip_var_one __ARGS((char_u *arg)); static void list_all_vars __ARGS((void)); static char_u *list_arg_vars __ARGS((exarg_T *eap, char_u *arg)); static char_u *ex_let_one __ARGS((char_u *arg, typeval *tv, int copy, char_u *endchars)); +static int check_changedtick __ARGS((char_u *arg)); static char_u *set_var_idx __ARGS((char_u *name, char_u *ip, typeval *rettv, int copy, char_u *endchars)); static void list_add_watch __ARGS((listvar *l, listwatch *lw)); +static void list_rem_watch __ARGS((listvar *l, listwatch *lwrem)); +static void list_fix_watch __ARGS((listvar *l, listitem *item)); +static int do_unlet_var __ARGS((char_u *name, int forceit)); /* * Set an internal variable to a string value. Creates the variable if it does @@ -1529,15 +1579,12 @@ ex_let_one(arg, tv, copy, endchars) if (!aborting()) EMSG2(_(e_invarg2), arg); } - else if (*p == '[') + else if (*p == '[' || *p == '.') arg_end = set_var_idx(arg, p, tv, copy, endchars); else if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) EMSG(_(e_letunexp)); - else if (STRNCMP(arg, "b:changedtick", 13) == 0 - && !eval_isnamec(arg[13])) - EMSG2(_(e_readonlyvar), arg); - else + else if (!check_changedtick(arg)) { c1 = *p; *p = NUL; @@ -1556,8 +1603,24 @@ ex_let_one(arg, tv, copy, endchars) } /* + * If "arg" is equal to "b:changedtick" give an error and return TRUE. + */ + static int +check_changedtick(arg) + char_u *arg; +{ + if (STRNCMP(arg, "b:changedtick", 13) == 0 && !eval_isnamec(arg[13])) + { + EMSG2(_(e_readonlyvar), arg); + return TRUE; + } + return FALSE; +} + +/* * Set a variable with an index: "name[expr]", "name[expr:expr]", - * "name[expr][expr]", etc. Only works if "name" is an existing List. + * "name[expr][expr]", "name.key", "name.key[expr]" etc. + * Only works if "name" is an existing List or Dictionary. * "ip" points to the first '['. * Returns a pointer to just after the last used ']'; NULL for error. */ @@ -1577,11 +1640,15 @@ set_var_idx(name, ip, rettv, copy, endchars) int range = FALSE; typeval *tv; long n1 = 0, n2 = 0; - int empty1, empty2 = FALSE; - listitem *item = NULL; + int empty1 = FALSE, empty2 = FALSE; + listitem *li = NULL; listitem *ni; listitem *ri; listvar *l = NULL; + dictitem *di; + char_u *key = NULL; + char_u *newkey = NULL; + int len; c1 = *ip; *ip = NUL; @@ -1593,11 +1660,12 @@ set_var_idx(name, ip, rettv, copy, endchars) return NULL; tv = &v->tv; - for (p = ip; *p == '['; p = skipwhite(p + 1)) + for (p = ip; *p == '[' || (*p == '.' && tv->v_type == VAR_DICT); ) { - if (tv->v_type != VAR_LIST || tv->vval.v_list == NULL) + if (!(tv->v_type == VAR_LIST && tv->vval.v_list != NULL) + && !(tv->v_type == VAR_DICT && tv->vval.v_dict != NULL)) { - EMSG(_("E689: Can only index a List")); + EMSG(_("E689: Can only index a List or Dictionary")); p = NULL; break; } @@ -1608,120 +1676,191 @@ set_var_idx(name, ip, rettv, copy, endchars) break; } - /* Get the index [expr] or the first index [expr: ]. */ - p = skipwhite(p + 1); - if (*p == ':') - empty1 = TRUE; - else + len = -1; + if (*p == '.') { - empty1 = FALSE; - if (eval1(&p, &var1, TRUE) == FAIL) /* recursive! */ + key = p + 1; + for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len) + ; + if (len == 0) { + EMSG(_(e_emptykey)); p = NULL; break; } + p = key + len; } - - /* Optionally get the second index [ :expr]. */ - if (*p == ':') + else { - if (rettv->v_type != VAR_LIST || rettv->vval.v_list == NULL) - { - EMSG(_("E709: [:] requires a List value")); - p = NULL; - if (!empty1) - clear_tv(&var1); - break; - } + /* Get the index [expr] or the first index [expr: ]. */ p = skipwhite(p + 1); - if (*p == ']') - empty2 = TRUE; + if (*p == ':') + empty1 = TRUE; else { - empty2 = FALSE; - if (eval1(&p, &var2, TRUE) == FAIL) /* recursive! */ + empty1 = FALSE; + if (eval1(&p, &var1, TRUE) == FAIL) /* recursive! */ { p = NULL; + break; + } + } + + /* Optionally get the second index [ :expr]. */ + if (*p == ':') + { + if (tv->v_type == VAR_DICT) + { + EMSG(_("E999: Cannot use [:] with a Dictionary")); + p = NULL; if (!empty1) clear_tv(&var1); break; } + if (rettv->v_type != VAR_LIST || rettv->vval.v_list == NULL) + { + EMSG(_("E709: [:] requires a List value")); + p = NULL; + if (!empty1) + clear_tv(&var1); + break; + } + p = skipwhite(p + 1); + if (*p == ']') + empty2 = TRUE; + else + { + empty2 = FALSE; + if (eval1(&p, &var2, TRUE) == FAIL) /* recursive! */ + { + p = NULL; + if (!empty1) + clear_tv(&var1); + break; + } + } + range = TRUE; } - range = TRUE; + else + range = FALSE; + + if (*p != ']') + { + EMSG(_(e_missbrac)); + if (!empty1) + clear_tv(&var1); + if (range && !empty2) + clear_tv(&var2); + p = NULL; + break; + } + + /* Skip to past ']'. */ + ++p; } - else - range = FALSE; - if (*p != ']') + if (tv->v_type == VAR_DICT) { - EMSG(_(e_missbrac)); - if (!empty1) + if (len == -1) + { + key = get_tv_string(&var1); + if (*key == NUL) + { + EMSG(_(e_emptykey)); + clear_tv(&var1); + p = NULL; + break; + } + } + di = dict_find(tv->vval.v_dict, key, len); + if (di == NULL) + { + /* Key does not exist in dict: may need toadd it. */ + if (*p == '[' || *p == '.') + { + EMSG2(_("E999: Key does not exist in Dictionary: %s"), key); + p = NULL; + if (len == -1) + clear_tv(&var1); + break; + } + if (len == -1) + newkey = vim_strsave(key); + else + newkey = vim_strnsave(key, len); + if (len == -1) + clear_tv(&var1); + if (newkey == NULL) + p = NULL; + break; + } + if (len == -1) clear_tv(&var1); - if (range && !empty2) - clear_tv(&var2); - p = NULL; - break; + tv = &di->di_tv; } - - /* - * Get the number and item for the only or first index. - */ - if (empty1) - n1 = 0; else { - n1 = get_tv_number(&var1); - clear_tv(&var1); - } - l = tv->vval.v_list; - item = list_find(l, n1); - if (item == NULL) - { - EMSGN(_(e_listidx), n1); - p = NULL; + /* + * Get the number and item for the only or first index of the List. + */ + if (empty1) + n1 = 0; + else + { + n1 = get_tv_number(&var1); + clear_tv(&var1); + } + l = tv->vval.v_list; + li = list_find(l, n1); + if (li == NULL) + { + EMSGN(_(e_listidx), n1); + p = NULL; + if (range && !empty2) + clear_tv(&var2); + break; + } + + /* + * May need to find the item or absolute index for the second + * index of a range. + * When no index given: "empty2" is TRUE. + * Otherwise "n2" is set to the second index. + */ if (range && !empty2) + { + n2 = get_tv_number(&var2); clear_tv(&var2); - break; - } + if (n2 < 0) + { + ni = list_find(l, n2); + if (ni == NULL) + { + EMSGN(_(e_listidx), n2); + p = NULL; + break; + } + n2 = list_idx_of_item(l, ni); + } - /* - * May need to find the item or absolute index for the second index of - * a range. - * When no index given: "empty2" is TRUE. - * Otherwise "n2" is set to the second index. - */ - if (range && !empty2) - { - n2 = get_tv_number(&var2); - clear_tv(&var2); - if (n2 < 0) - { - ni = list_find(l, n2); - if (ni == NULL) + /* Check that n2 isn't before n1. */ + if (n1 < 0) + n1 = list_idx_of_item(l, li); + if (n2 < n1) { EMSGN(_(e_listidx), n2); p = NULL; break; } - n2 = list_idx_of_item(l, ni); } - /* Check that n2 isn't before n1. */ - if (n1 < 0) - n1 = list_idx_of_item(l, item); - if (n2 < n1) - { - EMSGN(_(e_listidx), n2); - p = NULL; - break; - } + tv = &li->li_tv; } - - tv = &item->li_tv; } if (p != NULL) { + p = skipwhite(p); if (endchars != NULL && vim_strchr(endchars, *p) == NULL) { EMSG(_(e_letunexp)); @@ -1734,12 +1873,12 @@ set_var_idx(name, ip, rettv, copy, endchars) */ for (ri = rettv->vval.v_list->lv_first; ri != NULL; ) { - clear_tv(&item->li_tv); - copy_tv(&ri->li_tv, &item->li_tv); + clear_tv(&li->li_tv); + copy_tv(&ri->li_tv, &li->li_tv); ri = ri->li_next; if (ri == NULL || (!empty2 && n2 == n1)) break; - if (item->li_next == NULL) + if (li->li_next == NULL) { /* Need to add an empty item. */ ni = listitem_alloc(); @@ -1752,29 +1891,49 @@ set_var_idx(name, ip, rettv, copy, endchars) ni->li_tv.vval.v_number = 0; list_append(l, ni); } - item = item->li_next; + li = li->li_next; ++n1; } if (ri != NULL) EMSG(_("E710: List value has more items than target")); - else if (empty2 ? item != NULL && item->li_next != NULL : n1 != n2) + else if (empty2 ? li != NULL && li->li_next != NULL : n1 != n2) EMSG(_("E711: List value has not enough items")); } else { + if (newkey != NULL) + { + /* Need to add the item to the dictionary. */ + di = dictitem_alloc(); + if (di == NULL) + p = NULL; + else + { + di->di_key = newkey; + newkey = NULL; + dict_add(tv->vval.v_dict, di); + tv = &di->di_tv; + } + } + else + clear_tv(tv); + /* * Assign the value to the variable or list item. */ - clear_tv(tv); - if (copy) - copy_tv(rettv, tv); - else + if (p != NULL) { - *tv = *rettv; - init_tv(rettv); + if (copy) + copy_tv(rettv, tv); + else + { + *tv = *rettv; + init_tv(rettv); + } } } } + vim_free(newkey); return p; } @@ -2004,17 +2163,11 @@ set_context_for_expression(xp, arg, cmdidx) } else if (c == '\'') /* literal string */ { + /* Trick: '' is like stopping and starting a literal string. */ while ((c = *++xp->xp_pattern) != NUL && c != '\'') /* skip */ ; xp->xp_context = EXPAND_NOTHING; } - else if (c == '#') /* sharp string */ - { - /* Trick: ## is like stopping and starting a sharp string. */ - while ((c = *++xp->xp_pattern) != NUL && c != '#') - /* skip */ ; - xp->xp_context = EXPAND_NOTHING; - } else if (c == '|') { if (xp->xp_pattern[1] == '|') @@ -2149,7 +2302,7 @@ ex_unlet(eap) do { /* Find the end of the name. */ - name_end = find_name_end(arg, &expr_start, &expr_end, FALSE); + name_end = find_name_end(arg, &expr_start, &expr_end, TRUE); if (!vim_iswhite(*name_end) && !ends_excmd(*name_end)) { @@ -2183,11 +2336,8 @@ ex_unlet(eap) } else { - if (do_unlet(temp_string) == FAIL && !eap->forceit) - { - EMSG2(_("E108: No such variable: \"%s\""), temp_string); + if (do_unlet_var(temp_string, eap->forceit) == FAIL) error = TRUE; - } vim_free(temp_string); } } @@ -2195,13 +2345,8 @@ ex_unlet(eap) { cc = *name_end; *name_end = NUL; - - if (do_unlet(arg) == FAIL && !eap->forceit) - { - EMSG2(_("E108: No such variable: \"%s\""), arg); + if (do_unlet_var(arg, eap->forceit) == FAIL) error = TRUE; - } - *name_end = cc; } } @@ -2211,6 +2356,21 @@ ex_unlet(eap) eap->nextcmd = check_nextcmd(arg); } + static int +do_unlet_var(name, forceit) + char_u *name; + int forceit; +{ + if (check_changedtick(name)) + return FAIL; + if (do_unlet(name) == FAIL && !forceit) + { + EMSG2(_("E108: No such variable: \"%s\""), name); + return FAIL; + } + return OK; +} + /* * "unlet" a variable. Return OK if it existed, FAIL if not. */ @@ -3061,7 +3221,8 @@ eval6(arg, rettv, evaluate) * ! in front logical NOT * - in front unary minus * + in front unary plus (ignored) - * trailing [] subscript in String + * trailing [] subscript in String or List + * trailing .name entry in Dictionary * * "arg" must point to the first non-white of the expression. * "arg" is advanced to the next non-white after the recognized expression. @@ -3127,21 +3288,21 @@ eval7(arg, rettv, evaluate) break; /* - * Literal string constant: 'string'. + * Literal string constant: 'str''ing'. */ case '\'': ret = get_lit_string_tv(arg, rettv, evaluate); break; /* - * Sharp string constant: #str##ing#. + * List: [expr, expr] */ - case '#': ret = get_sharp_string_tv(arg, rettv, evaluate); + case '[': ret = get_list_tv(arg, rettv, evaluate); break; /* - * List: [expr, expr] + * Dictionary: {key: val, key: val} */ - case '[': ret = get_list_tv(arg, rettv, evaluate); + case '{': ret = get_dict_tv(arg, rettv, evaluate); break; /* @@ -3191,53 +3352,60 @@ eval7(arg, rettv, evaluate) } break; - /* - * Must be a variable or function name then. - */ - default: s = *arg; - len = get_func_len(arg, &alias, evaluate); - if (alias != NULL) - s = alias; + default: ret = NOTDONE; + break; + } - if (len == 0) - ret = FAIL; - else + if (ret == NOTDONE) + { + /* + * Must be a variable or function name. + * Can also be a curly-braces kind of name: {expr}. + */ + s = *arg; + len = get_func_len(arg, &alias, evaluate); + if (alias != NULL) + s = alias; + + if (len == 0) + ret = FAIL; + else + { + if (**arg == '(') /* recursive! */ + { + /* If "s" is the name of a variable of type VAR_FUNC + * use its contents. */ + s = deref_func_name(s, &len); + + /* Invoke the function. */ + ret = get_func_tv(s, len, rettv, arg, + curwin->w_cursor.lnum, curwin->w_cursor.lnum, + &len, evaluate); + /* Stop the expression evaluation when immediately + * aborting on error, or when an interrupt occurred or + * an exception was thrown but not caught. */ + if (aborting()) { - if (**arg == '(') /* recursive! */ - { - /* If "s" is the name of a variable of type VAR_FUNC - * use its contents. */ - s = deref_func_name(s, &len); - - /* Invoke the function. */ - ret = get_func_tv(s, len, rettv, arg, - curwin->w_cursor.lnum, curwin->w_cursor.lnum, - &len, evaluate); - /* Stop the expression evaluation when immediately - * aborting on error, or when an interrupt occurred or - * an exception was thrown but not caught. */ - if (aborting()) - { - if (ret == OK) - clear_tv(rettv); - ret = FAIL; - } - } - else if (evaluate) - ret = get_var_tv(s, len, rettv); + if (ret == OK) + clear_tv(rettv); + ret = FAIL; } + } + else if (evaluate) + ret = get_var_tv(s, len, rettv); + } - if (alias != NULL) - vim_free(alias); - - break; + if (alias != NULL) + vim_free(alias); } + *arg = skipwhite(*arg); /* - * Handle expr[expr] and expr[expr:expr] subscript. + * Handle expr[expr], expr[expr:expr] subscript and .name lookup. */ - while (**arg == '[' && ret == OK) + while ((**arg == '[' || (**arg == '.' && rettv->v_type == VAR_DICT)) + && !vim_iswhite(*(*arg - 1)) && ret == OK) { if (eval_index(arg, rettv, evaluate) == FAIL) { @@ -3282,9 +3450,10 @@ eval_index(arg, rettv, evaluate) int empty1 = FALSE, empty2 = FALSE; typeval var1, var2; long n1, n2 = 0; - long len; - int range; + long len = -1; + int range = FALSE; char_u *s; + char_u *key = NULL; if (rettv->v_type == VAR_FUNC) { @@ -3292,48 +3461,63 @@ eval_index(arg, rettv, evaluate) return FAIL; } - /* - * Get the (first) variable from inside the []. - */ - *arg = skipwhite(*arg + 1); - if (**arg == ':') - empty1 = TRUE; - else if (eval1(arg, &var1, evaluate) == FAIL) /* recursive! */ - return FAIL; - - /* - * Get the second variable from inside the [:]. - */ - if (**arg == ':') + if (**arg == '.') { - range = TRUE; + /* + * dict.name + */ + key = *arg + 1; + for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len) + ; + if (len == 0) + return FAIL; + *arg = skipwhite(key + len); + } + else + { + /* + * something[idx] + * + * Get the (first) variable from inside the []. + */ *arg = skipwhite(*arg + 1); - if (**arg == ']') - empty2 = TRUE; - else if (eval1(arg, &var2, evaluate) == FAIL) /* recursive! */ + if (**arg == ':') + empty1 = TRUE; + else if (eval1(arg, &var1, evaluate) == FAIL) /* recursive! */ + return FAIL; + + /* + * Get the second variable from inside the [:]. + */ + if (**arg == ':') { + range = TRUE; + *arg = skipwhite(*arg + 1); + if (**arg == ']') + empty2 = TRUE; + else if (eval1(arg, &var2, evaluate) == FAIL) /* recursive! */ + { + clear_tv(&var1); + return FAIL; + } + } + + /* Check for the ']'. */ + if (**arg != ']') + { + EMSG(_(e_missbrac)); clear_tv(&var1); + if (range) + clear_tv(&var2); return FAIL; } - } - else - range = FALSE; - - /* Check for the ']'. */ - if (**arg != ']') - { - EMSG(_(e_missbrac)); - clear_tv(&var1); - if (range) - clear_tv(&var2); - return FAIL; + *arg = skipwhite(*arg + 1); /* skip the ']' */ } if (evaluate) { - if (empty1) - n1 = 0; - else + n1 = 0; + if (!empty1 && rettv->v_type != VAR_DICT) { n1 = get_tv_number(&var1); clear_tv(&var1); @@ -3405,7 +3589,7 @@ eval_index(arg, rettv, evaluate) if (n2 < 0) n2 = len + n2; - if (!empty2 && (n2 < 0 || n2 >= len || n2 < n1)) + if (!empty2 && (n2 < 0 || n2 >= len || n2 + 1 < n1)) { EMSGN(_(e_listidx), n2); return FAIL; @@ -3436,10 +3620,46 @@ eval_index(arg, rettv, evaluate) *rettv = var1; } break; + + case VAR_DICT: + if (range) + { + EMSG(_("E999: Using range with Dictionary")); + if (len == -1) + clear_tv(&var1); + return FAIL; + } + { + dictitem *item; + + if (len == -1) + { + key = get_tv_string(&var1); + if (*key == NUL) + { + EMSG(_("E999: Empty key for Dictionary")); + clear_tv(&var1); + return FAIL; + } + } + + item = dict_find(rettv->vval.v_dict, key, (int)len); + + if (item == NULL) + EMSG2(_("E999: Key not found in Dictionary: %s"), key); + if (len == -1) + clear_tv(&var1); + if (item == NULL) + return FAIL; + + copy_tv(&item->di_tv, &var1); + clear_tv(rettv); + *rettv = var1; + } + break; } } - *arg = skipwhite(*arg + 1); /* skip the ']' */ return OK; } @@ -3536,7 +3756,6 @@ get_string_tv(arg, rettv, evaluate) { char_u *p; char_u *name; - int i; int extra = 0; /* @@ -3574,20 +3793,21 @@ get_string_tv(arg, rettv, evaluate) name = alloc((unsigned)(p - *arg + extra)); if (name == NULL) return FAIL; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = name; - i = 0; - for (p = *arg + 1; *p != NUL && *p != '"'; ++p) + for (p = *arg + 1; *p != NUL && *p != '"'; ) { if (*p == '\\') { switch (*++p) { - case 'b': name[i++] = BS; break; - case 'e': name[i++] = ESC; break; - case 'f': name[i++] = FF; break; - case 'n': name[i++] = NL; break; - case 'r': name[i++] = CAR; break; - case 't': name[i++] = TAB; break; + case 'b': *name++ = BS; ++p; break; + case 'e': *name++ = ESC; ++p; break; + case 'f': *name++ = FF; ++p; break; + case 'n': *name++ = NL; ++p; break; + case 'r': *name++ = CAR; ++p; break; + case 't': *name++ = TAB; ++p; break; case 'X': /* hex: "\x1", "\x12" */ case 'x': @@ -3608,17 +3828,16 @@ get_string_tv(arg, rettv, evaluate) ++p; nr = (nr << 4) + hex2nr(*p); } + ++p; #ifdef FEAT_MBYTE /* For "\u" store the number according to * 'encoding'. */ if (c != 'X') - i += (*mb_char2bytes)(nr, name + i); + name += (*mb_char2bytes)(nr, name); else #endif - name[i++] = nr; + *name++ = nr; } - else - name[i++] = *p; break; /* octal: "\1", "\12", "\123" */ @@ -3629,59 +3848,41 @@ get_string_tv(arg, rettv, evaluate) case '4': case '5': case '6': - case '7': name[i] = *p - '0'; - if (p[1] >= '0' && p[1] <= '7') + case '7': *name = *p++ - '0'; + if (*p >= '0' && *p <= '7') { - ++p; - name[i] = (name[i] << 3) + *p - '0'; - if (p[1] >= '0' && p[1] <= '7') - { - ++p; - name[i] = (name[i] << 3) + *p - '0'; - } + *name = (*name << 3) + *p++ - '0'; + if (*p >= '0' && *p <= '7') + *name = (*name << 3) + *p++ - '0'; } - ++i; + ++name; break; /* Special key, e.g.: "\<C-W>" */ - case '<': extra = trans_special(&p, name + i, TRUE); + case '<': extra = trans_special(&p, name, TRUE); if (extra != 0) { - i += extra; - --p; + name += extra; break; } /* FALLTHROUGH */ - default: name[i++] = *p; + default: MB_COPY_CHAR(p, name); break; } } else - name[i++] = *p; - -#ifdef FEAT_MBYTE - /* For a multi-byte character copy the bytes after the first one. */ - if (has_mbyte) - { - int l = (*mb_ptr2len_check)(p); + MB_COPY_CHAR(p, name); - while (--l > 0) - name[i++] = *++p; - } -#endif } - name[i] = NUL; + *name = NUL; *arg = p + 1; - rettv->v_type = VAR_STRING; - rettv->vval.v_string = name; - return OK; } /* - * Allocate a variable for an backtick-string constant. + * Allocate a variable for a 'str''ing' constant. * Return OK or FAIL. */ static int @@ -3691,72 +3892,30 @@ get_lit_string_tv(arg, rettv, evaluate) int evaluate; { char_u *p; - char_u *name; - - /* - * Find the end of the string. - */ - p = vim_strchr(*arg + 1, '\''); - if (p == NULL) - { - EMSG2(_("E115: Missing quote: %s"), *arg); - return FAIL; - } - - if (evaluate) - { - /* - * Copy the string into allocated memory. - */ - name = vim_strnsave(*arg + 1, (int)(p - (*arg + 1))); - if (name == NULL) - return FAIL; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = name; - } - - *arg = p + 1; - - return OK; -} - -/* - * Allocate a variable for a #string# constant. - * Return OK or FAIL. - */ - static int -get_sharp_string_tv(arg, rettv, evaluate) - char_u **arg; - typeval *rettv; - int evaluate; -{ - char_u *p; char_u *str; - int i; int reduce = 0; /* - * Find the end of the string, skipping ##. + * Find the end of the string, skipping ''. */ for (p = *arg + 1; *p != NUL; mb_ptr_adv(p)) { - if (*p == '#') + if (*p == '\'') { - if (p[1] != '#') + if (p[1] != '\'') break; ++reduce; ++p; } } - if (*p != '#') + if (*p != '\'') { - EMSG2(_("E999: Missing #: %s"), *arg); + EMSG2(_("E115: Missing quote: %s"), *arg); return FAIL; } - /* If only parsing, set *arg and return here */ + /* If only parsing return after setting "*arg" */ if (!evaluate) { *arg = p + 1; @@ -3764,40 +3923,27 @@ get_sharp_string_tv(arg, rettv, evaluate) } /* - * Copy the string into allocated memory, handling ## to # reduction. + * Copy the string into allocated memory, handling '' to ' reduction. */ str = alloc((unsigned)((p - *arg) - reduce)); if (str == NULL) return FAIL; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = str; - i = 0; - for (p = *arg + 1; *p != NUL; ++p) + for (p = *arg + 1; *p != NUL; ) { - if (*p == '#') + if (*p == '\'') { - if (p[1] != '#') + if (p[1] != '\'') break; ++p; } - str[i++] = *p; - -#ifdef FEAT_MBYTE - /* For a multi-byte character copy the bytes after the first one. */ - if (has_mbyte) - { - int l = (*mb_ptr2len_check)(p); - - while (--l > 0) - str[i++] = *++p; - } -#endif + MB_COPY_CHAR(p, str); } - str[i] = NUL; + *str = NUL; *arg = p + 1; - rettv->v_type = VAR_STRING; - rettv->vval.v_string = str; - return OK; } @@ -3841,7 +3987,7 @@ get_list_tv(arg, rettv, evaluate) break; if (**arg != ',') { - EMSG2(_("E696: Missing comma in list: %s"), *arg); + EMSG2(_("E696: Missing comma in List: %s"), *arg); goto failret; } *arg = skipwhite(*arg + 1); @@ -3849,7 +3995,7 @@ get_list_tv(arg, rettv, evaluate) if (**arg != ']') { - EMSG2(_("E697: Missing end of list ']': %s"), *arg); + EMSG2(_("E697: Missing end of List ']': %s"), *arg); failret: if (evaluate) list_free(l); @@ -4366,6 +4512,314 @@ list_join(gap, l, sep, echo) } /* + * Allocate an empty header for a dictionary. + */ + static dictvar * +dict_alloc() +{ + return (dictvar *)alloc_clear(sizeof(dictvar)); +} + +/* + * Unreference a Dictionary: decrement the reference count and free it when it < |