*: Hide list implementation in other files as well

This commit is contained in:
ZyX 2017-12-10 22:04:43 +03:00
parent 5c1ddb5078
commit ac4bbf55f6
17 changed files with 278 additions and 235 deletions

View File

@ -789,7 +789,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
Object item = obj.data.array.items[i];
listitem_T *li = tv_list_item_alloc();
if (!object_to_vim(item, &li->li_tv, err)) {
if (!object_to_vim(item, TV_LIST_ITEM_TV(li), err)) {
// cleanup
tv_list_item_free(li);
tv_list_free(list);

View File

@ -3536,19 +3536,19 @@ theend:
/*
* Add completions from a list.
*/
static void ins_compl_add_list(list_T *list)
static void ins_compl_add_list(list_T *const list)
{
listitem_T *li;
int dir = compl_direction;
/* Go through the List with matches and add each of them. */
for (li = list->lv_first; li != NULL; li = li->li_next) {
if (ins_compl_add_tv(&li->li_tv, dir) == OK)
/* if dir was BACKWARD then honor it just once */
// Go through the List with matches and add each of them.
TV_LIST_ITER(list, li, {
if (ins_compl_add_tv(TV_LIST_ITEM_TV(li), dir) == OK) {
// If dir was BACKWARD then honor it just once.
dir = FORWARD;
else if (did_emsg)
} else if (did_emsg) {
break;
}
}
});
}
/*

View File

@ -120,7 +120,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
last_container = kv_last(*container_stack);
}
if (last_container.container.v_type == VAR_LIST) {
if (last_container.container.vval.v_list->lv_len != 0
if (tv_list_len(last_container.container.vval.v_list) != 0
&& !obj.didcomma) {
EMSG2(_("E474: Expected comma before list item: %s"), val_location);
tv_clear(&obj.val);
@ -128,7 +128,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
}
assert(last_container.special_val == NULL);
listitem_T *obj_li = tv_list_item_alloc();
obj_li->li_tv = obj.val;
*TV_LIST_ITEM_TV(obj_li) = obj.val;
tv_list_append(last_container.container.vval.v_list, obj_li);
} else if (last_container.stack_index == kv_size(*stack) - 2) {
if (!obj.didcolon) {
@ -155,10 +155,10 @@ static inline int json_decoder_pop(ValuesStackItem obj,
list_T *const kv_pair = tv_list_alloc();
tv_list_append_list(last_container.special_val, kv_pair);
listitem_T *const key_li = tv_list_item_alloc();
key_li->li_tv = key.val;
*TV_LIST_ITEM_TV(key_li) = key.val;
tv_list_append(kv_pair, key_li);
listitem_T *const val_li = tv_list_item_alloc();
val_li->li_tv = obj.val;
*TV_LIST_ITEM_TV(val_li) = obj.val;
tv_list_append(kv_pair, val_li);
}
} else {
@ -738,8 +738,9 @@ json_decode_string_cycle_start:
} else if (last_container.special_val == NULL
? (last_container.container.v_type == VAR_DICT
? (DICT_LEN(last_container.container.vval.v_dict) == 0)
: (last_container.container.vval.v_list->lv_len == 0))
: (last_container.special_val->lv_len == 0)) {
: (tv_list_len(last_container.container.vval.v_list)
== 0))
: (tv_list_len(last_container.special_val) == 0)) {
emsgf(_("E474: Leading comma: %.*s"), LENP(p, e));
goto json_decode_string_fail;
}
@ -1047,9 +1048,10 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
};
for (size_t i = 0; i < mobj.via.array.size; i++) {
listitem_T *const li = tv_list_item_alloc();
li->li_tv.v_type = VAR_UNKNOWN;
TV_LIST_ITEM_TV(li)->v_type = VAR_UNKNOWN;
tv_list_append(list, li);
if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) {
if (msgpack_to_vim(mobj.via.array.ptr[i], TV_LIST_ITEM_TV(li))
== FAIL) {
return FAIL;
}
}
@ -1094,15 +1096,17 @@ msgpack_to_vim_generic_map: {}
list_T *const kv_pair = tv_list_alloc();
tv_list_append_list(list, kv_pair);
listitem_T *const key_li = tv_list_item_alloc();
key_li->li_tv.v_type = VAR_UNKNOWN;
TV_LIST_ITEM_TV(key_li)->v_type = VAR_UNKNOWN;
tv_list_append(kv_pair, key_li);
listitem_T *const val_li = tv_list_item_alloc();
val_li->li_tv.v_type = VAR_UNKNOWN;
TV_LIST_ITEM_TV(val_li)->v_type = VAR_UNKNOWN;
tv_list_append(kv_pair, val_li);
if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) {
if (msgpack_to_vim(mobj.via.map.ptr[i].key, TV_LIST_ITEM_TV(key_li))
== FAIL) {
return FAIL;
}
if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_li->li_tv) == FAIL) {
if (msgpack_to_vim(mobj.via.map.ptr[i].val, TV_LIST_ITEM_TV(val_li))
== FAIL) {
return FAIL;
}
}

View File

@ -53,17 +53,18 @@ int encode_list_write(void *const data, const char *const buf, const size_t len)
list_T *const list = (list_T *) data;
const char *const end = buf + len;
const char *line_end = buf;
listitem_T *li = list->lv_last;
listitem_T *li = tv_list_last(list);
// Continue the last list element
if (li != NULL) {
line_end = xmemscan(buf, NL, len);
if (line_end != buf) {
const size_t line_length = (size_t)(line_end - buf);
char *str = (char *)li->li_tv.vval.v_string;
char *str = (char *)TV_LIST_ITEM_TV(li)->vval.v_string;
const size_t li_len = (str == NULL ? 0 : strlen(str));
li->li_tv.vval.v_string = xrealloc(str, li_len + line_length + 1);
str = (char *)li->li_tv.vval.v_string + li_len;
TV_LIST_ITEM_TV(li)->vval.v_string = xrealloc(
str, li_len + line_length + 1);
str = (char *)TV_LIST_ITEM_TV(li)->vval.v_string + li_len;
memcpy(str, buf, line_length);
str[line_length] = 0;
memchrsub(str, NUL, NL, line_length);
@ -135,21 +136,18 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
}
case kMPConvPairs:
case kMPConvList: {
int idx = 0;
const listitem_T *li;
for (li = v.data.l.list->lv_first;
li != NULL && li->li_next != v.data.l.li;
li = li->li_next) {
idx++;
}
const listitem_T *const li = TV_LIST_ITEM_PREV(v.data.l.list,
v.data.l.li);
int idx = (int)tv_list_idx_of_item(v.data.l.list, li);
if (v.type == kMPConvList
|| li == NULL
|| (li->li_tv.v_type != VAR_LIST
&& li->li_tv.vval.v_list->lv_len <= 0)) {
vim_snprintf((char *) IObuff, IOSIZE, idx_msg, idx);
|| (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST
&& tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) <= 0)) {
vim_snprintf((char *)IObuff, IOSIZE, idx_msg, idx);
ga_concat(&msg_ga, IObuff);
} else {
typval_T key_tv = li->li_tv.vval.v_list->lv_first->li_tv;
typval_T key_tv = *TV_LIST_ITEM_TV(
tv_list_first(TV_LIST_ITEM_TV(li)->vval.v_list));
char *const key = encode_tv2echo(&key_tv, NULL);
vim_snprintf((char *) IObuff, IOSIZE, key_pair_msg, key, idx);
xfree(key);
@ -202,21 +200,17 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len,
FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
size_t len = 0;
if (list != NULL) {
for (const listitem_T *li = list->lv_first;
li != NULL;
li = li->li_next) {
if (li->li_tv.v_type != VAR_STRING) {
return false;
}
len++;
if (li->li_tv.vval.v_string != 0) {
len += STRLEN(li->li_tv.vval.v_string);
}
TV_LIST_ITER_CONST(list, li, {
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
return false;
}
if (len) {
len--;
len++;
if (TV_LIST_ITEM_TV(li)->vval.v_string != 0) {
len += STRLEN(TV_LIST_ITEM_TV(li)->vval.v_string);
}
});
if (len) {
len--;
}
*ret_len = len;
if (len == 0) {
@ -253,31 +247,34 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
char *const buf_end = buf + nbuf;
char *p = buf;
while (p < buf_end) {
assert(state->li_length == 0 || state->li->li_tv.vval.v_string != NULL);
assert(state->li_length == 0
|| TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL);
for (size_t i = state->offset; i < state->li_length && p < buf_end; i++) {
assert(state->li->li_tv.vval.v_string != NULL);
const char ch = (char)state->li->li_tv.vval.v_string[state->offset++];
assert(TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL);
const char ch = (char)(
TV_LIST_ITEM_TV(state->li)->vval.v_string[state->offset++]);
*p++ = (char)((char)ch == (char)NL ? (char)NUL : (char)ch);
}
if (p < buf_end) {
state->li = state->li->li_next;
state->li = TV_LIST_ITEM_NEXT(state->list, state->li);
if (state->li == NULL) {
*read_bytes = (size_t) (p - buf);
return OK;
}
*p++ = NL;
if (state->li->li_tv.v_type != VAR_STRING) {
if (TV_LIST_ITEM_TV(state->li)->v_type != VAR_STRING) {
*read_bytes = (size_t) (p - buf);
return FAIL;
}
state->offset = 0;
state->li_length = (state->li->li_tv.vval.v_string == NULL
state->li_length = (TV_LIST_ITEM_TV(state->li)->vval.v_string == NULL
? 0
: STRLEN(state->li->li_tv.vval.v_string));
: STRLEN(TV_LIST_ITEM_TV(state->li)->vval.v_string));
}
}
*read_bytes = nbuf;
return (state->offset < state->li_length || state->li->li_next != NULL
return ((state->offset < state->li_length
|| TV_LIST_ITEM_NEXT(state->list, state->li) != NULL)
? NOTDONE
: OK);
}
@ -727,12 +724,11 @@ bool encode_check_json_key(const typval_T *const tv)
if (val_di->di_tv.vval.v_list == NULL) {
return true;
}
for (const listitem_T *li = val_di->di_tv.vval.v_list->lv_first;
li != NULL; li = li->li_next) {
if (li->li_tv.v_type != VAR_STRING) {
TV_LIST_ITER_CONST(val_di->di_tv.vval.v_list, li, {
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
return false;
}
}
});
return true;
}

View File

@ -33,9 +33,10 @@ int encode_vim_to_echo(garray_T *const packer,
/// Structure defining state for read_from_list()
typedef struct {
const list_T *const list; ///< List being currently read.
const listitem_T *li; ///< Item currently read.
size_t offset; ///< Byte offset inside the read item.
size_t li_length; ///< Length of the string inside the read item.
size_t offset; ///< Byte offset inside the read item.
size_t li_length; ///< Length of the string inside the read item.
} ListReaderState;
/// Initialize ListReaderState structure
@ -43,11 +44,13 @@ static inline ListReaderState encode_init_lrstate(const list_T *const list)
FUNC_ATTR_NONNULL_ALL
{
return (ListReaderState) {
.li = list->lv_first,
.list = list,
.li = tv_list_first(list),
.offset = 0,
.li_length = (list->lv_first->li_tv.vval.v_string == NULL
.li_length = (TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string == NULL
? 0
: STRLEN(list->lv_first->li_tv.vval.v_string)),
: STRLEN(TV_LIST_ITEM_TV(
tv_list_first(list))->vval.v_string)),
};
}

View File

@ -383,6 +383,22 @@ static inline listitem_T *tv_list_first(const list_T *const l)
return l->lv_first;
}
static inline listitem_T *tv_list_last(const list_T *const l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get last list item
///
/// @param[in] l List to get item from.
///
/// @return List item or NULL in case of an empty list.
static inline listitem_T *tv_list_last(const list_T *const l)
{
if (l == NULL) {
return NULL;
}
return l->lv_last;
}
static inline long tv_dict_len(const dict_T *const d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;

View File

@ -355,14 +355,14 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
break;
}
case VAR_LIST: {
if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) {
if (tv->vval.v_list == NULL || tv_list_len(tv->vval.v_list) == 0) {
TYPVAL_ENCODE_CONV_EMPTY_LIST(tv);
break;
}
const int saved_copyID = tv->vval.v_list->lv_copyID;
_TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, copyID,
kMPConvList);
TYPVAL_ENCODE_CONV_LIST_START(tv, tv->vval.v_list->lv_len);
TYPVAL_ENCODE_CONV_LIST_START(tv, tv_list_len(tv->vval.v_list));
assert(saved_copyID != copyID && saved_copyID != copyID - 1);
_mp_push(*mpstack, ((MPConvStackVal) {
.type = kMPConvList,
@ -371,7 +371,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.data = {
.l = {
.list = tv->vval.v_list,
.li = tv->vval.v_list->lv_first,
.li = tv_list_first(tv->vval.v_list),
},
},
}));
@ -440,23 +440,43 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
// bits is not checked), other unsigned and have at most 31
// non-zero bits (number of bits is not checked).
if (val_di->di_tv.v_type != VAR_LIST
|| (val_list = val_di->di_tv.vval.v_list) == NULL
|| val_list->lv_len != 4
|| val_list->lv_first->li_tv.v_type != VAR_NUMBER
|| (sign = val_list->lv_first->li_tv.vval.v_number) == 0
|| val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER
|| (highest_bits =
val_list->lv_first->li_next->li_tv.vval.v_number) < 0
|| val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER
|| (high_bits =
val_list->lv_last->li_prev->li_tv.vval.v_number) < 0
|| val_list->lv_last->li_tv.v_type != VAR_NUMBER
|| (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) {
|| tv_list_len(val_list = val_di->di_tv.vval.v_list) != 4) {
goto _convert_one_value_regular_dict;
}
uint64_t number = ((uint64_t)(((uint64_t)highest_bits) << 62)
| (uint64_t)(((uint64_t)high_bits) << 31)
| (uint64_t)low_bits);
const listitem_T *const sign_li = tv_list_first(val_list);
if (TV_LIST_ITEM_TV(sign_li)->v_type != VAR_NUMBER
|| (sign = TV_LIST_ITEM_TV(sign_li)->vval.v_number) == 0) {
goto _convert_one_value_regular_dict;
}
const listitem_T *const highest_bits_li = (
TV_LIST_ITEM_NEXT(val_list, sign_li));
if (TV_LIST_ITEM_TV(highest_bits_li)->v_type != VAR_NUMBER
|| ((highest_bits
= TV_LIST_ITEM_TV(highest_bits_li)->vval.v_number)
< 0)) {
goto _convert_one_value_regular_dict;
}
const listitem_T *const high_bits_li = (
TV_LIST_ITEM_NEXT(val_list, highest_bits_li));
if (TV_LIST_ITEM_TV(high_bits_li)->v_type != VAR_NUMBER
|| ((high_bits = TV_LIST_ITEM_TV(high_bits_li)->vval.v_number)
< 0)) {
goto _convert_one_value_regular_dict;
}
const listitem_T *const low_bits_li = tv_list_last(val_list);
if (TV_LIST_ITEM_TV(low_bits_li)->v_type != VAR_NUMBER
|| ((low_bits = TV_LIST_ITEM_TV(low_bits_li)->vval.v_number)
< 0)) {
goto _convert_one_value_regular_dict;
}
const uint64_t number = ((uint64_t)(((uint64_t)highest_bits) << 62)
| (uint64_t)(((uint64_t)high_bits) << 31)
| (uint64_t)low_bits);
if (sign > 0) {
TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, number);
} else {
@ -499,8 +519,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
_TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list,
lv_copyID, copyID,
kMPConvList);
TYPVAL_ENCODE_CONV_LIST_START(tv,
val_di->di_tv.vval.v_list->lv_len);
TYPVAL_ENCODE_CONV_LIST_START(
tv, tv_list_len(val_di->di_tv.vval.v_list));
assert(saved_copyID != copyID && saved_copyID != copyID - 1);
_mp_push(*mpstack, ((MPConvStackVal) {
.tv = tv,
@ -509,7 +529,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.data = {
.l = {
.list = val_di->di_tv.vval.v_list,
.li = val_di->di_tv.vval.v_list->lv_first,
.li = tv_list_first(val_di->di_tv.vval.v_list),
},
},
}));
@ -520,22 +540,21 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
goto _convert_one_value_regular_dict;
}
list_T *const val_list = val_di->di_tv.vval.v_list;
if (val_list == NULL || val_list->lv_len == 0) {
if (val_list == NULL || tv_list_len(val_list) == 0) {
TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, TYPVAL_ENCODE_NODICT_VAR);
break;
}
for (const listitem_T *li = val_list->lv_first; li != NULL;
li = li->li_next) {
if (li->li_tv.v_type != VAR_LIST
|| li->li_tv.vval.v_list->lv_len != 2) {
TV_LIST_ITER_CONST(val_list, li, {
if (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST
|| tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) != 2) {
goto _convert_one_value_regular_dict;
}
}
});
const int saved_copyID = val_di->di_tv.vval.v_list->lv_copyID;
_TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_list, lv_copyID, copyID,
kMPConvPairs);
TYPVAL_ENCODE_CONV_DICT_START(tv, TYPVAL_ENCODE_NODICT_VAR,
val_list->lv_len);
tv_list_len(val_list));
assert(saved_copyID != copyID && saved_copyID != copyID - 1);
_mp_push(*mpstack, ((MPConvStackVal) {
.tv = tv,
@ -544,7 +563,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.data = {
.l = {
.list = val_list,
.li = val_list->lv_first,
.li = tv_list_first(val_list),
},
},
}));
@ -554,18 +573,22 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
const list_T *val_list;
varnumber_T type;
if (val_di->di_tv.v_type != VAR_LIST
|| (val_list = val_di->di_tv.vval.v_list) == NULL
|| val_list->lv_len != 2
|| (val_list->lv_first->li_tv.v_type != VAR_NUMBER)
|| (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX
|| tv_list_len((val_list = val_di->di_tv.vval.v_list)) != 2
|| (TV_LIST_ITEM_TV(tv_list_first(val_list))->v_type
!= VAR_NUMBER)
|| ((type
= TV_LIST_ITEM_TV(tv_list_first(val_list))->vval.v_number)
> INT8_MAX)
|| type < INT8_MIN
|| (val_list->lv_last->li_tv.v_type != VAR_LIST)) {
|| (TV_LIST_ITEM_TV(tv_list_last(val_list))->v_type
!= VAR_LIST)) {
goto _convert_one_value_regular_dict;
}
size_t len;
char *buf;
if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list,
&len, &buf)) {
if (!encode_vim_list_to_buf(
TV_LIST_ITEM_TV(tv_list_last(val_list))->vval.v_list, &len,
&buf)) {
goto _convert_one_value_regular_dict;
}
TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type);
@ -674,11 +697,13 @@ typval_encode_stop_converting_one_item:
cur_mpsv->data.l.list->lv_copyID = cur_mpsv->saved_copyID;
TYPVAL_ENCODE_CONV_LIST_END(cur_mpsv->tv);
continue;
} else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) {
} else if (cur_mpsv->data.l.li
!= tv_list_first(cur_mpsv->data.l.list)) {
TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(cur_mpsv->tv);
}
tv = &cur_mpsv->data.l.li->li_tv;
cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next;
tv = TV_LIST_ITEM_TV(cur_mpsv->data.l.li);
cur_mpsv->data.l.li = TV_LIST_ITEM_NEXT(cur_mpsv->data.l.list,
cur_mpsv->data.l.li);
break;
}
case kMPConvPairs: {
@ -687,24 +712,26 @@ typval_encode_stop_converting_one_item:
cur_mpsv->data.l.list->lv_copyID = cur_mpsv->saved_copyID;
TYPVAL_ENCODE_CONV_DICT_END(cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR);
continue;
} else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) {
} else if (cur_mpsv->data.l.li
!= tv_list_first(cur_mpsv->data.l.list)) {
TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(
cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR);
}
const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list;
const list_T *const kv_pair = (
TV_LIST_ITEM_TV(cur_mpsv->data.l.li)->vval.v_list);
TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(
encode_vim_to__error_ret, kv_pair->lv_first->li_tv);
if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME,
&mpstack, cur_mpsv,
&kv_pair->lv_first->li_tv,
copyID,
objname) == FAIL) {
encode_vim_to__error_ret, *TV_LIST_ITEM_TV(tv_list_first(kv_pair)));
if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(
TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, cur_mpsv,
TV_LIST_ITEM_TV(tv_list_first(kv_pair)), copyID, objname)
== FAIL) {
goto encode_vim_to__error_ret;
}
TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(cur_mpsv->tv,
TYPVAL_ENCODE_NODICT_VAR);
tv = &kv_pair->lv_last->li_tv;
cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next;
tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair));
cur_mpsv->data.l.li = TV_LIST_ITEM_NEXT(cur_mpsv->data.l.list,
cur_mpsv->data.l.li);
break;
}
case kMPConvPartial: {

View File

@ -6334,7 +6334,6 @@ char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
void ex_oldfiles(exarg_T *eap)
{
list_T *l = get_vim_var_list(VV_OLDFILES);
listitem_T *li;
long nr = 0;
if (l == NULL) {
@ -6342,19 +6341,22 @@ void ex_oldfiles(exarg_T *eap)
} else {
msg_start();
msg_scroll = true;
for (li = l->lv_first; li != NULL && !got_int; li = li->li_next) {
TV_LIST_ITER(l, li, {
if (got_int) {
break;
}
nr++;
const char *fname = tv_get_string(&li->li_tv);
const char *fname = tv_get_string(TV_LIST_ITEM_TV(li));
if (!message_filtered((char_u *)fname)) {
msg_outnum(nr);
MSG_PUTS(": ");
msg_outtrans((char_u *)tv_get_string(&li->li_tv));
msg_outtrans((char_u *)tv_get_string(TV_LIST_ITEM_TV(li)));
msg_clr_eos();
msg_putchar('\n');
ui_flush(); // output one line at a time
os_breakcheck();
}
}
});
// Assume "got_int" was set to truncate the listing.
got_int = false;
@ -6364,7 +6366,7 @@ void ex_oldfiles(exarg_T *eap)
quit_more = false;
nr = prompt_for_number(false);
msg_starthere();
if (nr > 0 && nr <= l->lv_len) {
if (nr > 0 && nr <= tv_list_len(l)) {
const char *const p = tv_list_find_str(l, nr - 1);
if (p == NULL) {
return;

View File

@ -2618,20 +2618,20 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
}
varnumber_T prev_end = 0;
int i = 0;
for (const listitem_T *li = tv.vval.v_list->lv_first;
li != NULL; li = li->li_next, i++) {
if (li->li_tv.v_type != VAR_LIST) {
TV_LIST_ITER_CONST(tv.vval.v_list, li, {
if (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST) {
PRINT_ERRMSG(_("E5401: List item %i is not a List"), i);
goto color_cmdline_error;
}
const list_T *const l = li->li_tv.vval.v_list;
const list_T *const l = TV_LIST_ITEM_TV(li)->vval.v_list;
if (tv_list_len(l) != 3) {
PRINT_ERRMSG(_("E5402: List item %i has incorrect length: %li /= 3"),
i, tv_list_len(l));
goto color_cmdline_error;
}
bool error = false;
const varnumber_T start = tv_get_number_chk(&l->lv_first->li_tv, &error);
const varnumber_T start = (
tv_get_number_chk(TV_LIST_ITEM_TV(tv_list_first(l)), &error));
if (error) {
goto color_cmdline_error;
} else if (!(prev_end <= start && start < colored_ccline->cmdlen)) {
@ -2651,8 +2651,8 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
.attr = 0,
}));
}
const varnumber_T end = tv_get_number_chk(&l->lv_first->li_next->li_tv,
&error);
const varnumber_T end = tv_get_number_chk(
TV_LIST_ITEM_TV(TV_LIST_ITEM_NEXT(l, tv_list_first(l))), &error);
if (error) {
goto color_cmdline_error;
} else if (!(start < end && end <= colored_ccline->cmdlen)) {
@ -2668,7 +2668,8 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
goto color_cmdline_error;
}
prev_end = end;
const char *const group = tv_get_string_chk(&l->lv_last->li_tv);
const char *const group = tv_get_string_chk(
TV_LIST_ITEM_TV(tv_list_last(l)));
if (group == NULL) {
goto color_cmdline_error;
}
@ -2679,7 +2680,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
.end = end,
.attr = attr,
}));
}
});
if (prev_end < colored_ccline->cmdlen) {
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
.start = prev_end,
@ -5021,24 +5022,24 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
*/
static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
{
list_T *retlist;
listitem_T *li;
garray_T ga;
retlist = call_user_expand_func((user_expand_func_T)call_func_retlist, xp,
num_file, file);
list_T *const retlist = call_user_expand_func(
(user_expand_func_T)call_func_retlist, xp, num_file, file);
if (retlist == NULL) {
return FAIL;
}
garray_T ga;
ga_init(&ga, (int)sizeof(char *), 3);
/* Loop over the items in the list. */
for (li = retlist->lv_first; li != NULL; li = li->li_next) {
if (li->li_tv.v_type != VAR_STRING || li->li_tv.vval.v_string == NULL)
continue; /* Skip non-string items and empty strings */
// Loop over the items in the list.
TV_LIST_ITER_CONST(retlist, li, {
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING
|| TV_LIST_ITEM_TV(li)->vval.v_string == NULL) {
continue; // Skip non-string items and empty strings.
}
GA_APPEND(char_u *, &ga, vim_strsave(li->li_tv.vval.v_string));
}
GA_APPEND(char *, &ga, xstrdup(
(const char *)TV_LIST_ITEM_TV(li)->vval.v_string));
});
tv_list_unref(retlist);
*file = ga.ga_data;

View File

@ -214,9 +214,9 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
list_T *const kv_pair = tv_list_alloc();
tv_list_append_list(cur.tv->vval.v_list, kv_pair);
listitem_T *const key = tv_list_item_alloc();
key->li_tv = decode_string(s, len, kTrue, false, false);
*TV_LIST_ITEM_TV(key) = decode_string(s, len, kTrue, false, false);
tv_list_append(kv_pair, key);
if (key->li_tv.v_type == VAR_UNKNOWN) {
if (TV_LIST_ITEM_TV(key)->v_type == VAR_UNKNOWN) {
ret = false;
tv_list_unref(kv_pair);
continue;
@ -224,7 +224,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
listitem_T *const val = tv_list_item_alloc();
tv_list_append(kv_pair, val);
kv_push(stack, cur);
cur = (TVPopStackItem) { &val->li_tv, false, false, 0 };
cur = (TVPopStackItem) { TV_LIST_ITEM_TV(val), false, false, 0 };
} else {
dictitem_T *const di = tv_dict_item_alloc_len(s, len);
if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) {
@ -239,7 +239,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
}
} else {
assert(cur.tv->v_type == VAR_LIST);
lua_rawgeti(lstate, -1, cur.tv->vval.v_list->lv_len + 1);
lua_rawgeti(lstate, -1, tv_list_len(cur.tv->vval.v_list) + 1);
if (lua_isnil(lstate, -1)) {
lua_pop(lstate, 2);
continue;
@ -247,7 +247,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
listitem_T *const li = tv_list_item_alloc();
tv_list_append(cur.tv->vval.v_list, li);
kv_push(stack, cur);
cur = (TVPopStackItem) { &li->li_tv, false, false, 0 };
cur = (TVPopStackItem) { TV_LIST_ITEM_TV(li), false, false, 0 };
}
}
assert(!cur.container);

View File

@ -4854,9 +4854,8 @@ static void *get_reg_wrap_one_line(char_u *s, int flags)
if (!(flags & kGRegList)) {
return s;
}
list_T *list = tv_list_alloc();
tv_list_append_string(list, NULL, 0);
list->lv_first->li_tv.vval.v_string = s;
list_T *const list = tv_list_alloc();
tv_list_append_allocated_string(list, (char *)s);
return list;
}
@ -5610,12 +5609,13 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
list_T *res = result.vval.v_list;
list_T *lines = NULL;
if (res->lv_len == 2 && res->lv_first->li_tv.v_type == VAR_LIST) {
lines = res->lv_first->li_tv.vval.v_list;
if (res->lv_last->li_tv.v_type != VAR_STRING) {
if (tv_list_len(res) == 2
&& TV_LIST_ITEM_TV(tv_list_first(res))->v_type == VAR_LIST) {
lines = TV_LIST_ITEM_TV(tv_list_first(res))->vval.v_list;
if (TV_LIST_ITEM_TV(tv_list_last(res))->v_type != VAR_STRING) {
goto err;
}
char_u *regtype = res->lv_last->li_tv.vval.v_string;
char_u *regtype = TV_LIST_ITEM_TV(tv_list_last(res))->vval.v_string;
if (regtype == NULL || strlen((char*)regtype) > 1) {
goto err;
}
@ -5641,20 +5641,21 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
reg->y_type = kMTUnknown;
}
reg->y_array = xcalloc((size_t)lines->lv_len, sizeof(uint8_t *));
reg->y_size = (size_t)lines->lv_len;
reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(char_u *));
reg->y_size = (size_t)tv_list_len(lines);
reg->additional_data = NULL;
reg->timestamp = 0;
// Timestamp is not saved for clipboard registers because clipboard registers
// are not saved in the ShaDa file.
int i = 0;
for (listitem_T *li = lines->lv_first; li != NULL; li = li->li_next) {
if (li->li_tv.v_type != VAR_STRING) {
TV_LIST_ITER_CONST(lines, li, {
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
goto err;
}
reg->y_array[i++] = (char_u *)xstrdupnul((char *)li->li_tv.vval.v_string);
}
reg->y_array[i++] = (char_u *)xstrdupnul(
(const char *)TV_LIST_ITEM_TV(li)->vval.v_string);
});
if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) {
// a known-to-be charwise yank might have a final linebreak

View File

@ -156,6 +156,7 @@ typedef struct {
FILE *fd;
typval_T *tv;
char_u *p_str;
list_T *p_list;
listitem_T *p_li;
buf_T *buf;
linenr_T buflnum;
@ -516,17 +517,17 @@ static int qf_get_next_list_line(qfstate_T *state)
// Get the next line from the supplied list
while (p_li != NULL
&& (p_li->li_tv.v_type != VAR_STRING
|| p_li->li_tv.vval.v_string == NULL)) {
p_li = p_li->li_next; // Skip non-string items
&& (TV_LIST_ITEM_TV(p_li)->v_type != VAR_STRING
|| TV_LIST_ITEM_TV(p_li)->vval.v_string == NULL)) {
p_li = TV_LIST_ITEM_NEXT(state->p_list, p_li); // Skip non-string items.
}
if (p_li == NULL) { // End of the list
if (p_li == NULL) { // End of the list.
state->p_li = NULL;
return QF_END_OF_INPUT;
}
len = STRLEN(p_li->li_tv.vval.v_string);
len = STRLEN(TV_LIST_ITEM_TV(p_li)->vval.v_string);
if (len > IOSIZE - 2) {
state->linebuf = qf_grow_linebuf(state, len);
} else {
@ -534,9 +535,10 @@ static int qf_get_next_list_line(qfstate_T *state)
state->linelen = len;
}
STRLCPY(state->linebuf, p_li->li_tv.vval.v_string, state->linelen + 1);
STRLCPY(state->linebuf, TV_LIST_ITEM_TV(p_li)->vval.v_string,
state->linelen + 1);
state->p_li = p_li->li_next; // next item
state->p_li = TV_LIST_ITEM_NEXT(state->p_list, p_li);
return QF_OK;
}
@ -983,7 +985,7 @@ qf_init_ext(
)
{
qfstate_T state = { NULL, 0, NULL, 0, NULL, NULL, NULL, NULL,
NULL, 0, 0 };
NULL, NULL, 0, 0 };
qffields_T fields = { NULL, NULL, 0, 0L, 0, false, NULL, 0, 0, 0 };
qfline_T *old_last = NULL;
bool adding = false;
@ -1064,7 +1066,8 @@ qf_init_ext(
if (tv->v_type == VAR_STRING) {
state.p_str = tv->vval.v_string;
} else if (tv->v_type == VAR_LIST) {
state.p_li = tv->vval.v_list->lv_first;
state.p_list = tv->vval.v_list;
state.p_li = tv_list_first(tv->vval.v_list);
}
state.tv = tv;
}
@ -4100,7 +4103,6 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
int action)
{
listitem_T *li;
dict_T *d;
qfline_T *old_last = NULL;
int retval = OK;
@ -4117,13 +4119,15 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
qf_store_title(qi, title);
}
for (li = list->lv_first; li != NULL; li = li->li_next) {
if (li->li_tv.v_type != VAR_DICT)
continue; /* Skip non-dict items */
TV_LIST_ITER_CONST(list, li, {
if (TV_LIST_ITEM_TV(li)->v_type != VAR_DICT) {
continue; // Skip non-dict items.
}
d = li->li_tv.vval.v_dict;
if (d == NULL)
d = TV_LIST_ITEM_TV(li)->vval.v_dict;
if (d == NULL) {
continue;
}
char *const filename = tv_dict_get_string(d, "filename", true);
int bufnum = (int)tv_dict_get_number(d, "bufnr");
@ -4175,7 +4179,7 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
retval = FAIL;
break;
}
}
});
if (qi->qf_lists[qi->qf_curlist].qf_index == 0) {
// no valid entry

View File

@ -6477,10 +6477,6 @@ static regsubmatch_T rsm; // can only be used when can_f_submatch is true
/// vim_regsub_both().
static int fill_submatch_list(int argc, typval_T *argv, int argcount)
{
listitem_T *li;
int i;
char_u *s;
if (argcount == 0) {
// called function doesn't take an argument
return 0;
@ -6490,28 +6486,26 @@ static int fill_submatch_list(int argc, typval_T *argv, int argcount)
init_static_list((staticList10_T *)(argv->vval.v_list));
// There are always 10 list items in staticList10_T.
li = argv->vval.v_list->lv_first;
for (i = 0; i < 10; i++) {
s = rsm.sm_match->startp[i];
listitem_T *li = tv_list_first(argv->vval.v_list);
for (int i = 0; i < 10; i++) {
char_u *s = rsm.sm_match->startp[i];
if (s == NULL || rsm.sm_match->endp[i] == NULL) {
s = NULL;
} else {
s = vim_strnsave(s, (int)(rsm.sm_match->endp[i] - s));
}
li->li_tv.v_type = VAR_STRING;
li->li_tv.vval.v_string = s;
li = li->li_next;
TV_LIST_ITEM_TV(li)->v_type = VAR_STRING;
TV_LIST_ITEM_TV(li)->vval.v_string = s;
li = TV_LIST_ITEM_NEXT(argv->vval.v_list, li);
}
return 1;
}
static void clear_submatch_list(staticList10_T *sl)
{
int i;
for (i = 0; i < 10; i++) {
xfree(sl->sl_items[i].li_tv.vval.v_string);
}
TV_LIST_ITER(&sl->sl_list, li, {
xfree(TV_LIST_ITEM_TV(li)->vval.v_string);
});
}
/// vim_regsub() - perform substitutions after a vim_regexec() or
@ -6651,6 +6645,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
rettv.vval.v_string = NULL;
argv[0].v_type = VAR_LIST;
argv[0].vval.v_list = &matchList.sl_list;
// FIXME: Abstract away
matchList.sl_list.lv_len = 0;
if (expr->v_type == VAR_FUNC) {
s = expr->vval.v_string;

View File

@ -1180,8 +1180,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES);
const bool force = flags & kShaDaForceit;
const bool get_old_files = (flags & (kShaDaGetOldfiles | kShaDaForceit)
&& (force || oldfiles_list == NULL
|| oldfiles_list->lv_len == 0));
&& (force || tv_list_len(oldfiles_list) == 0));
const bool want_marks = flags & kShaDaWantMarks;
const unsigned srni_flags = (unsigned) (
(flags & kShaDaWantInfo
@ -1599,13 +1598,13 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
#define DUMP_ADDITIONAL_ELEMENTS(src, what) \
do { \
if ((src) != NULL) { \
for (listitem_T *li = (src)->lv_first; li != NULL; li = li->li_next) { \
if (encode_vim_to_msgpack(spacker, &li->li_tv, \
TV_LIST_ITER((src), li, { \
if (encode_vim_to_msgpack(spacker, TV_LIST_ITEM_TV(li), \
_("additional elements of ShaDa " what)) \
== FAIL) { \
goto shada_pack_entry_error; \
} \
} \
}); \
} \
} while (0)
#define DUMP_ADDITIONAL_DATA(src, what) \
@ -1648,9 +1647,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
const bool is_hist_search =
entry.data.history_item.histtype == HIST_SEARCH;
const size_t arr_size = 2 + (size_t) is_hist_search + (size_t) (
entry.data.history_item.additional_elements == NULL
? 0
: entry.data.history_item.additional_elements->lv_len);
tv_list_len(entry.data.history_item.additional_elements));
msgpack_pack_array(spacker, arr_size);
msgpack_pack_uint8(spacker, entry.data.history_item.histtype);
PACK_BIN(cstr_as_string(entry.data.history_item.string));
@ -1663,9 +1660,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
}
case kSDItemVariable: {
const size_t arr_size = 2 + (size_t) (
entry.data.global_var.additional_elements == NULL
? 0
: entry.data.global_var.additional_elements->lv_len);
tv_list_len(entry.data.global_var.additional_elements));
msgpack_pack_array(spacker, arr_size);
const String varname = cstr_as_string(entry.data.global_var.name);
PACK_BIN(varname);
@ -1685,9 +1680,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
}
case kSDItemSubString: {
const size_t arr_size = 1 + (size_t) (
entry.data.sub_string.additional_elements == NULL
? 0
: entry.data.sub_string.additional_elements->lv_len);
tv_list_len(entry.data.sub_string.additional_elements));
msgpack_pack_array(spacker, arr_size);
PACK_BIN(cstr_as_string(entry.data.sub_string.sub));
DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,

View File

@ -3213,26 +3213,25 @@ spell_find_suggest (
// Find suggestions by evaluating expression "expr".
static void spell_suggest_expr(suginfo_T *su, char_u *expr)
{
list_T *list;
listitem_T *li;
int score;
const char *p;
// The work is split up in a few parts to avoid having to export
// suginfo_T.
// First evaluate the expression and get the resulting list.
list = eval_spell_expr(su->su_badword, expr);
list_T *const list = eval_spell_expr(su->su_badword, expr);
if (list != NULL) {
// Loop over the items in the list.
for (li = list->lv_first; li != NULL; li = li->li_next)
if (li->li_tv.v_type == VAR_LIST) {
TV_LIST_ITER(list, li, {
if (TV_LIST_ITEM_TV(li)->v_type == VAR_LIST) {
// Get the word and the score from the items.
score = get_spellword(li->li_tv.vval.v_list, &p);
score = get_spellword(TV_LIST_ITEM_TV(li)->vval.v_list, &p);
if (score >= 0 && score <= su->su_maxscore) {
add_suggestion(su, &su->su_ga, (const char_u *)p, su->su_badlen,
score, 0, true, su->su_sallang, false);
}
}
});
tv_list_unref(list);
}

View File

@ -5579,30 +5579,26 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
// Set up position matches
if (pos_list != NULL)
{
linenr_T toplnum = 0;
linenr_T botlnum = 0;
listitem_T *li;
int i;
linenr_T toplnum = 0;
linenr_T botlnum = 0;
for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
i++, li = li->li_next) {
linenr_T lnum = 0;
colnr_T col = 0;
int len = 1;
list_T *subl;
listitem_T *subli;
int i = 0;
TV_LIST_ITER(pos_list, li, {
linenr_T lnum = 0;
colnr_T col = 0;
int len = 1;
bool error = false;
if (li->li_tv.v_type == VAR_LIST) {
subl = li->li_tv.vval.v_list;
if (TV_LIST_ITEM_TV(li)->v_type == VAR_LIST) {
const list_T *const subl = TV_LIST_ITEM_TV(li)->vval.v_list;
if (subl == NULL) {
goto fail;
}
subli = subl->lv_first;
const listitem_T *subli = tv_list_first(subl);
if (subli == NULL) {
goto fail;
}
lnum = tv_get_number_chk(&subli->li_tv, &error);
lnum = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
if (error) {
goto fail;
}
@ -5611,15 +5607,15 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
continue;
}
m->pos.pos[i].lnum = lnum;
subli = subli->li_next;
subli = TV_LIST_ITEM_NEXT(subl, subli);
if (subli != NULL) {
col = tv_get_number_chk(&subli->li_tv, &error);
col = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
if (error) {
goto fail;
}
subli = subli->li_next;
subli = TV_LIST_ITEM_NEXT(subl, subli);
if (subli != NULL) {
len = tv_get_number_chk(&subli->li_tv, &error);
len = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
if (error) {
goto fail;
}
@ -5627,12 +5623,12 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
}
m->pos.pos[i].col = col;
m->pos.pos[i].len = len;
} else if (li->li_tv.v_type == VAR_NUMBER) {
if (li->li_tv.vval.v_number == 0) {
--i;
} else if (TV_LIST_ITEM_TV(li)->v_type == VAR_NUMBER) {
if (TV_LIST_ITEM_TV(li)->vval.v_number == 0) {
i--;
continue;
}
m->pos.pos[i].lnum = li->li_tv.vval.v_number;
m->pos.pos[i].lnum = TV_LIST_ITEM_TV(li)->vval.v_number;
m->pos.pos[i].col = 0;
m->pos.pos[i].len = 0;
} else {
@ -5645,7 +5641,11 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
if (botlnum == 0 || lnum >= botlnum) {
botlnum = lnum + 1;
}
}
i++;
if (i >= MAXPOSMATCH) {
break;
}
});
// Calculate top and bottom lines for redrawing area
if (toplnum != 0){

View File

@ -118,6 +118,8 @@ describe('NULL', function()
null_expr_test('does not crash setreg', 'setreg("x", L)', 0, 0)
null_expr_test('does not crash systemlist()', 'systemlist("cat", L)', 0, {})
null_expr_test('does not crash setline', 'setline(1, L)', 0, 0)
null_test('does not make Neovim crash when v:oldfiles gets assigned to that', ':let v:oldfiles = L|oldfiles', 0)
-- FIXME Add test for complete(, L)
end)
describe('dict', function()
it('does not crash when indexing NULL dict', function()