forked from aniani/vim
patch 9.1.0335: String interpolation fails for List type
Problem: String interpolation fails for List type Solution: use implicit string(list) for string interpolation and :put = (Yegappan Lakshmanan) related: #14529 closes: #14556 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
a59e031aa0
commit
bce51d9005
29
src/eval.c
29
src/eval.c
@ -575,17 +575,16 @@ skip_expr_concatenate(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert "tv" to a string.
|
* Convert "tv" to a string.
|
||||||
* When "convert" is TRUE convert a List into a sequence of lines and a Dict
|
* When "join_list" is TRUE convert a List into a sequence of lines.
|
||||||
* into a textual representation of the Dict.
|
|
||||||
* Returns an allocated string (NULL when out of memory).
|
* Returns an allocated string (NULL when out of memory).
|
||||||
*/
|
*/
|
||||||
char_u *
|
char_u *
|
||||||
typval2string(typval_T *tv, int convert)
|
typval2string(typval_T *tv, int join_list)
|
||||||
{
|
{
|
||||||
garray_T ga;
|
garray_T ga;
|
||||||
char_u *retval;
|
char_u *retval;
|
||||||
|
|
||||||
if (convert && tv->v_type == VAR_LIST)
|
if (join_list && tv->v_type == VAR_LIST)
|
||||||
{
|
{
|
||||||
ga_init2(&ga, sizeof(char), 80);
|
ga_init2(&ga, sizeof(char), 80);
|
||||||
if (tv->vval.v_list != NULL)
|
if (tv->vval.v_list != NULL)
|
||||||
@ -597,8 +596,16 @@ typval2string(typval_T *tv, int convert)
|
|||||||
ga_append(&ga, NUL);
|
ga_append(&ga, NUL);
|
||||||
retval = (char_u *)ga.ga_data;
|
retval = (char_u *)ga.ga_data;
|
||||||
}
|
}
|
||||||
else if (convert && tv->v_type == VAR_DICT)
|
else if (tv->v_type == VAR_LIST || tv->v_type == VAR_DICT)
|
||||||
retval = dict2string(tv, get_copyID(), FALSE);
|
{
|
||||||
|
char_u *tofree;
|
||||||
|
char_u numbuf[NUMBUFLEN];
|
||||||
|
|
||||||
|
retval = tv2string(tv, &tofree, numbuf, 0);
|
||||||
|
// Make a copy if we have a value but it's not in allocated memory.
|
||||||
|
if (retval != NULL && tofree == NULL)
|
||||||
|
retval = vim_strsave(retval);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
retval = vim_strsave(tv_get_string(tv));
|
retval = vim_strsave(tv_get_string(tv));
|
||||||
return retval;
|
return retval;
|
||||||
@ -607,13 +614,13 @@ typval2string(typval_T *tv, int convert)
|
|||||||
/*
|
/*
|
||||||
* Top level evaluation function, returning a string. Does not handle line
|
* Top level evaluation function, returning a string. Does not handle line
|
||||||
* breaks.
|
* breaks.
|
||||||
* When "convert" is TRUE convert a List into a sequence of lines.
|
* When "join_list" is TRUE convert a List into a sequence of lines.
|
||||||
* Return pointer to allocated memory, or NULL for failure.
|
* Return pointer to allocated memory, or NULL for failure.
|
||||||
*/
|
*/
|
||||||
char_u *
|
char_u *
|
||||||
eval_to_string_eap(
|
eval_to_string_eap(
|
||||||
char_u *arg,
|
char_u *arg,
|
||||||
int convert,
|
int join_list,
|
||||||
exarg_T *eap,
|
exarg_T *eap,
|
||||||
int use_simple_function)
|
int use_simple_function)
|
||||||
{
|
{
|
||||||
@ -631,7 +638,7 @@ eval_to_string_eap(
|
|||||||
retval = NULL;
|
retval = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
retval = typval2string(&tv, convert);
|
retval = typval2string(&tv, join_list);
|
||||||
clear_tv(&tv);
|
clear_tv(&tv);
|
||||||
}
|
}
|
||||||
clear_evalarg(&evalarg, NULL);
|
clear_evalarg(&evalarg, NULL);
|
||||||
@ -642,10 +649,10 @@ eval_to_string_eap(
|
|||||||
char_u *
|
char_u *
|
||||||
eval_to_string(
|
eval_to_string(
|
||||||
char_u *arg,
|
char_u *arg,
|
||||||
int convert,
|
int join_list,
|
||||||
int use_simple_function)
|
int use_simple_function)
|
||||||
{
|
{
|
||||||
return eval_to_string_eap(arg, convert, NULL, use_simple_function);
|
return eval_to_string_eap(arg, join_list, NULL, use_simple_function);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -662,7 +662,7 @@ eval_one_expr_in_str(char_u *p, garray_T *gap, int evaluate)
|
|||||||
if (evaluate)
|
if (evaluate)
|
||||||
{
|
{
|
||||||
*block_end = NUL;
|
*block_end = NUL;
|
||||||
expr_val = eval_to_string(block_start, TRUE, FALSE);
|
expr_val = eval_to_string(block_start, FALSE, FALSE);
|
||||||
*block_end = '}';
|
*block_end = '}';
|
||||||
if (expr_val == NULL)
|
if (expr_val == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -14,9 +14,9 @@ void init_evalarg(evalarg_T *evalarg);
|
|||||||
void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
|
void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
|
||||||
int skip_expr(char_u **pp, evalarg_T *evalarg);
|
int skip_expr(char_u **pp, evalarg_T *evalarg);
|
||||||
int skip_expr_concatenate(char_u **arg, char_u **start, char_u **end, evalarg_T *evalarg);
|
int skip_expr_concatenate(char_u **arg, char_u **start, char_u **end, evalarg_T *evalarg);
|
||||||
char_u *typval2string(typval_T *tv, int convert);
|
char_u *typval2string(typval_T *tv, int join_list);
|
||||||
char_u *eval_to_string_eap(char_u *arg, int convert, exarg_T *eap, int use_simple_function);
|
char_u *eval_to_string_eap(char_u *arg, int join_list, exarg_T *eap, int use_simple_function);
|
||||||
char_u *eval_to_string(char_u *arg, int convert, int use_simple_function);
|
char_u *eval_to_string(char_u *arg, int join_list, int use_simple_function);
|
||||||
char_u *eval_to_string_safe(char_u *arg, int use_sandbox, int keep_script_version, int use_simple_function);
|
char_u *eval_to_string_safe(char_u *arg, int use_sandbox, int keep_script_version, int use_simple_function);
|
||||||
varnumber_T eval_to_number(char_u *expr, int use_simple_function);
|
varnumber_T eval_to_number(char_u *expr, int use_simple_function);
|
||||||
typval_T *eval_expr(char_u *arg, exarg_T *eap);
|
typval_T *eval_expr(char_u *arg, exarg_T *eap);
|
||||||
|
@ -7,7 +7,7 @@ int generate_CONSTRUCT(cctx_T *cctx, class_T *cl);
|
|||||||
int generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type);
|
int generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type);
|
||||||
int generate_GET_ITF_MEMBER(cctx_T *cctx, class_T *itf, int idx, type_T *type);
|
int generate_GET_ITF_MEMBER(cctx_T *cctx, class_T *itf, int idx, type_T *type);
|
||||||
int generate_STORE_THIS(cctx_T *cctx, int idx);
|
int generate_STORE_THIS(cctx_T *cctx, int idx);
|
||||||
int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
|
int may_generate_2STRING(int offset, int tostring_flags, cctx_T *cctx);
|
||||||
int generate_add_instr(cctx_T *cctx, vartype_T vartype, type_T *type1, type_T *type2, exprtype_T expr_type);
|
int generate_add_instr(cctx_T *cctx, vartype_T vartype, type_T *type1, type_T *type2, exprtype_T expr_type);
|
||||||
vartype_T operator_type(type_T *type1, type_T *type2);
|
vartype_T operator_type(type_T *type1, type_T *type2);
|
||||||
int generate_two_op(cctx_T *cctx, char_u *op);
|
int generate_two_op(cctx_T *cctx, char_u *op);
|
||||||
|
@ -953,6 +953,18 @@ func Test_string_interp()
|
|||||||
#" Dict interpolation
|
#" Dict interpolation
|
||||||
VAR d = {'a': 10, 'b': [1, 2]}
|
VAR d = {'a': 10, 'b': [1, 2]}
|
||||||
call assert_equal("{'a': 10, 'b': [1, 2]}", $'{d}')
|
call assert_equal("{'a': 10, 'b': [1, 2]}", $'{d}')
|
||||||
|
VAR emptydict = {}
|
||||||
|
call assert_equal("a{}b", $'a{emptydict}b')
|
||||||
|
VAR nulldict = test_null_dict()
|
||||||
|
call assert_equal("a{}b", $'a{nulldict}b')
|
||||||
|
|
||||||
|
#" List interpolation
|
||||||
|
VAR l = ['a', 'b', 'c']
|
||||||
|
call assert_equal("['a', 'b', 'c']", $'{l}')
|
||||||
|
VAR emptylist = []
|
||||||
|
call assert_equal("a[]b", $'a{emptylist}b')
|
||||||
|
VAR nulllist = test_null_list()
|
||||||
|
call assert_equal("a[]b", $'a{nulllist}b')
|
||||||
|
|
||||||
#" Stray closing brace.
|
#" Stray closing brace.
|
||||||
call assert_fails('echo $"moo}"', 'E1278:')
|
call assert_fails('echo $"moo}"', 'E1278:')
|
||||||
|
@ -696,6 +696,41 @@ END
|
|||||||
END
|
END
|
||||||
call assert_equal(["let d2 = {'a': 10, 'b': 'ss', 'c': {}}"], code)
|
call assert_equal(["let d2 = {'a': 10, 'b': 'ss', 'c': {}}"], code)
|
||||||
|
|
||||||
|
" Empty dictionary
|
||||||
|
let d1 = {}
|
||||||
|
let code =<< eval trim END
|
||||||
|
let d2 = {d1}
|
||||||
|
END
|
||||||
|
call assert_equal(["let d2 = {}"], code)
|
||||||
|
|
||||||
|
" null dictionary
|
||||||
|
let d1 = test_null_dict()
|
||||||
|
let code =<< eval trim END
|
||||||
|
let d2 = {d1}
|
||||||
|
END
|
||||||
|
call assert_equal(["let d2 = {}"], code)
|
||||||
|
|
||||||
|
" Evaluate a List
|
||||||
|
let l1 = ['a', 'b', 'c']
|
||||||
|
let code =<< eval trim END
|
||||||
|
let l2 = {l1}
|
||||||
|
END
|
||||||
|
call assert_equal(["let l2 = ['a', 'b', 'c']"], code)
|
||||||
|
|
||||||
|
" Empty List
|
||||||
|
let l1 = []
|
||||||
|
let code =<< eval trim END
|
||||||
|
let l2 = {l1}
|
||||||
|
END
|
||||||
|
call assert_equal(["let l2 = []"], code)
|
||||||
|
|
||||||
|
" Null List
|
||||||
|
let l1 = test_null_list()
|
||||||
|
let code =<< eval trim END
|
||||||
|
let l2 = {l1}
|
||||||
|
END
|
||||||
|
call assert_equal(["let l2 = []"], code)
|
||||||
|
|
||||||
let code = 'xxx'
|
let code = 'xxx'
|
||||||
let code =<< eval trim END
|
let code =<< eval trim END
|
||||||
let n = {5 +
|
let n = {5 +
|
||||||
|
@ -328,4 +328,12 @@ func Test_put_dict()
|
|||||||
bw!
|
bw!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_put_list()
|
||||||
|
new
|
||||||
|
let l = ['a', 'b', 'c']
|
||||||
|
put! =l
|
||||||
|
call assert_equal(['a', 'b', 'c', ''], getline(1, '$'))
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -2994,6 +2994,56 @@ def Test_heredoc_expr()
|
|||||||
CODE
|
CODE
|
||||||
v9.CheckDefAndScriptSuccess(lines)
|
v9.CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
|
# Evaluate an empty dictionary
|
||||||
|
lines =<< trim CODE
|
||||||
|
var d1 = {}
|
||||||
|
var code =<< trim eval END
|
||||||
|
var d2 = {d1}
|
||||||
|
END
|
||||||
|
assert_equal(["var d2 = {}"], code)
|
||||||
|
CODE
|
||||||
|
v9.CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
|
# Evaluate a null dictionary
|
||||||
|
lines =<< trim CODE
|
||||||
|
var d1 = test_null_dict()
|
||||||
|
var code =<< trim eval END
|
||||||
|
var d2 = {d1}
|
||||||
|
END
|
||||||
|
assert_equal(["var d2 = {}"], code)
|
||||||
|
CODE
|
||||||
|
v9.CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
|
# Evaluate a List
|
||||||
|
lines =<< trim CODE
|
||||||
|
var l1 = ['a', 'b', 'c']
|
||||||
|
var code =<< trim eval END
|
||||||
|
var l2 = {l1}
|
||||||
|
END
|
||||||
|
assert_equal(["var l2 = ['a', 'b', 'c']"], code)
|
||||||
|
CODE
|
||||||
|
v9.CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
|
# Evaluate an empty List
|
||||||
|
lines =<< trim CODE
|
||||||
|
var l1 = []
|
||||||
|
var code =<< trim eval END
|
||||||
|
var l2 = {l1}
|
||||||
|
END
|
||||||
|
assert_equal(["var l2 = []"], code)
|
||||||
|
CODE
|
||||||
|
v9.CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
|
# Evaluate a null List
|
||||||
|
lines =<< trim CODE
|
||||||
|
var l1 = test_null_list()
|
||||||
|
var code =<< trim eval END
|
||||||
|
var l2 = {l1}
|
||||||
|
END
|
||||||
|
assert_equal(["var l2 = []"], code)
|
||||||
|
CODE
|
||||||
|
v9.CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
lines =<< trim CODE
|
lines =<< trim CODE
|
||||||
var code =<< eval trim END
|
var code =<< eval trim END
|
||||||
var s = "{$SOME_ENV_VAR}"
|
var s = "{$SOME_ENV_VAR}"
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
335,
|
||||||
/**/
|
/**/
|
||||||
334,
|
334,
|
||||||
/**/
|
/**/
|
||||||
|
@ -460,7 +460,7 @@ typedef struct {
|
|||||||
// arguments to ISN_2STRING and ISN_2STRING_ANY
|
// arguments to ISN_2STRING and ISN_2STRING_ANY
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int offset;
|
int offset;
|
||||||
int tolerant;
|
int flags;
|
||||||
} tostring_T;
|
} tostring_T;
|
||||||
|
|
||||||
// arguments to ISN_2BOOL
|
// arguments to ISN_2BOOL
|
||||||
@ -880,3 +880,10 @@ typedef enum {
|
|||||||
|
|
||||||
// flags for call_def_function()
|
// flags for call_def_function()
|
||||||
#define DEF_USE_PT_ARGV 1 // use the partial arguments
|
#define DEF_USE_PT_ARGV 1 // use the partial arguments
|
||||||
|
|
||||||
|
// Flag used for conversion to string by may_generate_2STRING()
|
||||||
|
#define TOSTRING_NONE 0x0
|
||||||
|
// Convert a List to series of values separated by newline
|
||||||
|
#define TOSTRING_INTERPOLATE 0x1
|
||||||
|
// Convert a List to a textual representation of the list "[...]"
|
||||||
|
#define TOSTRING_TOLERANT 0x2
|
||||||
|
@ -1931,7 +1931,7 @@ compile_throw(char_u *arg, cctx_T *cctx UNUSED)
|
|||||||
return NULL;
|
return NULL;
|
||||||
if (cctx->ctx_skip == SKIP_YES)
|
if (cctx->ctx_skip == SKIP_YES)
|
||||||
return p;
|
return p;
|
||||||
if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
|
if (may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (generate_instr_drop(cctx, ISN_THROW, 1) == NULL)
|
if (generate_instr_drop(cctx, ISN_THROW, 1) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2359,7 +2359,7 @@ compile_exec(char_u *line_arg, exarg_T *eap, cctx_T *cctx)
|
|||||||
p += 2;
|
p += 2;
|
||||||
if (compile_expr0(&p, cctx) == FAIL)
|
if (compile_expr0(&p, cctx) == FAIL)
|
||||||
return NULL;
|
return NULL;
|
||||||
may_generate_2STRING(-1, TRUE, cctx);
|
may_generate_2STRING(-1, TOSTRING_TOLERANT, cctx);
|
||||||
++count;
|
++count;
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
if (*p != '`')
|
if (*p != '`')
|
||||||
|
@ -1222,7 +1222,7 @@ compile_one_expr_in_str(char_u *p, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
if (compile_expr0(&block_start, cctx) == FAIL)
|
if (compile_expr0(&block_start, cctx) == FAIL)
|
||||||
return NULL;
|
return NULL;
|
||||||
may_generate_2STRING(-1, TRUE, cctx);
|
may_generate_2STRING(-1, TOSTRING_INTERPOLATE, cctx);
|
||||||
|
|
||||||
return block_end + 1;
|
return block_end + 1;
|
||||||
}
|
}
|
||||||
@ -2421,7 +2421,7 @@ compile_assign_unlet(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (dest_type == VAR_DICT
|
if (dest_type == VAR_DICT
|
||||||
&& may_generate_2STRING(-1, FALSE, cctx) == FAIL)
|
&& may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (dest_type == VAR_LIST || dest_type == VAR_BLOB)
|
if (dest_type == VAR_LIST || dest_type == VAR_BLOB)
|
||||||
{
|
{
|
||||||
@ -2975,7 +2975,7 @@ compile_assignment(
|
|||||||
|
|
||||||
if (*op == '.')
|
if (*op == '.')
|
||||||
{
|
{
|
||||||
if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
|
if (may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1638,7 +1638,7 @@ store_var(char_u *name, typval_T *tv)
|
|||||||
* Return FAIL if not allowed.
|
* Return FAIL if not allowed.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
do_2string(typval_T *tv, int is_2string_any, int tolerant)
|
do_2string(typval_T *tv, int is_2string_any, int tostring_flags)
|
||||||
{
|
{
|
||||||
if (tv->v_type == VAR_STRING)
|
if (tv->v_type == VAR_STRING)
|
||||||
return OK;
|
return OK;
|
||||||
@ -1657,7 +1657,7 @@ do_2string(typval_T *tv, int is_2string_any, int tolerant)
|
|||||||
case VAR_BLOB: break;
|
case VAR_BLOB: break;
|
||||||
|
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
if (tolerant)
|
if (tostring_flags & TOSTRING_TOLERANT)
|
||||||
{
|
{
|
||||||
char_u *s, *e, *p;
|
char_u *s, *e, *p;
|
||||||
garray_T ga;
|
garray_T ga;
|
||||||
@ -1690,6 +1690,8 @@ do_2string(typval_T *tv, int is_2string_any, int tolerant)
|
|||||||
tv->vval.v_string = ga.ga_data;
|
tv->vval.v_string = ga.ga_data;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
if (tostring_flags & TOSTRING_INTERPOLATE)
|
||||||
|
break;
|
||||||
// FALLTHROUGH
|
// FALLTHROUGH
|
||||||
default: to_string_error(tv->v_type);
|
default: to_string_error(tv->v_type);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -5685,7 +5687,7 @@ exec_instructions(ectx_T *ectx)
|
|||||||
SOURCING_LNUM = iptr->isn_lnum;
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
if (do_2string(STACK_TV_BOT(iptr->isn_arg.tostring.offset),
|
if (do_2string(STACK_TV_BOT(iptr->isn_arg.tostring.offset),
|
||||||
iptr->isn_type == ISN_2STRING_ANY,
|
iptr->isn_type == ISN_2STRING_ANY,
|
||||||
iptr->isn_arg.tostring.tolerant) == FAIL)
|
iptr->isn_arg.tostring.flags) == FAIL)
|
||||||
goto on_error;
|
goto on_error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
|||||||
typep->type_curr = &t_any;
|
typep->type_curr = &t_any;
|
||||||
typep->type_decl = &t_any;
|
typep->type_decl = &t_any;
|
||||||
}
|
}
|
||||||
if (may_generate_2STRING(-1, FALSE, cctx) == FAIL
|
if (may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL
|
||||||
|| generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
|
|| generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (keeping_dict != NULL)
|
if (keeping_dict != NULL)
|
||||||
@ -1598,7 +1598,7 @@ compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
}
|
}
|
||||||
if (isn->isn_type == ISN_PUSHS)
|
if (isn->isn_type == ISN_PUSHS)
|
||||||
key = isn->isn_arg.string;
|
key = isn->isn_arg.string;
|
||||||
else if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
|
else if (may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
*arg = skipwhite(*arg);
|
*arg = skipwhite(*arg);
|
||||||
if (**arg != ']')
|
if (**arg != ']')
|
||||||
@ -3014,8 +3014,8 @@ compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
ppconst->pp_is_const = FALSE;
|
ppconst->pp_is_const = FALSE;
|
||||||
if (*op == '.')
|
if (*op == '.')
|
||||||
{
|
{
|
||||||
if (may_generate_2STRING(-2, FALSE, cctx) == FAIL
|
if (may_generate_2STRING(-2, TOSTRING_NONE, cctx) == FAIL
|
||||||
|| may_generate_2STRING(-1, FALSE, cctx) == FAIL)
|
|| may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (generate_CONCAT(cctx, 2) == FAIL)
|
if (generate_CONCAT(cctx, 2) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
@ -191,10 +191,12 @@ generate_STORE_THIS(cctx_T *cctx, int idx)
|
|||||||
/*
|
/*
|
||||||
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
|
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
|
||||||
* But only for simple types.
|
* But only for simple types.
|
||||||
* When "tolerant" is TRUE convert most types to string, e.g. a List.
|
* When tostring_flags has TOSTRING_TOLERANT, convert a List to a series of
|
||||||
|
* strings. When tostring_flags has TOSTRING_INTERPOLATE, convert a List or a
|
||||||
|
* Dict to the corresponding textual representation.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
|
may_generate_2STRING(int offset, int tostring_flags, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
isntype_T isntype = ISN_2STRING;
|
isntype_T isntype = ISN_2STRING;
|
||||||
@ -223,11 +225,13 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
|
|||||||
// conversion possible when tolerant
|
// conversion possible when tolerant
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
case VAR_DICT:
|
case VAR_DICT:
|
||||||
if (tolerant)
|
if (tostring_flags & TOSTRING_TOLERANT)
|
||||||
{
|
{
|
||||||
isntype = ISN_2STRING_ANY;
|
isntype = ISN_2STRING_ANY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (tostring_flags & TOSTRING_INTERPOLATE)
|
||||||
|
break;
|
||||||
// FALLTHROUGH
|
// FALLTHROUGH
|
||||||
|
|
||||||
// conversion not possible
|
// conversion not possible
|
||||||
@ -249,7 +253,7 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
|
|||||||
if ((isn = generate_instr(cctx, isntype)) == NULL)
|
if ((isn = generate_instr(cctx, isntype)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.tostring.offset = offset;
|
isn->isn_arg.tostring.offset = offset;
|
||||||
isn->isn_arg.tostring.tolerant = tolerant;
|
isn->isn_arg.tostring.flags = tostring_flags;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user