/*
* Convert "tv" to a string.
- * When "convert" is TRUE convert a List into a sequence of lines and a Dict
- * into a textual representation of the Dict.
+ * When "join_list" is TRUE convert a List into a sequence of lines.
* Returns an allocated string (NULL when out of memory).
*/
char_u *
-typval2string(typval_T *tv, int convert)
+typval2string(typval_T *tv, int join_list)
{
garray_T ga;
char_u *retval;
- if (convert && tv->v_type == VAR_LIST)
+ if (join_list && tv->v_type == VAR_LIST)
{
ga_init2(&ga, sizeof(char), 80);
if (tv->vval.v_list != NULL)
ga_append(&ga, NUL);
retval = (char_u *)ga.ga_data;
}
- else if (convert && tv->v_type == VAR_DICT)
- retval = dict2string(tv, get_copyID(), FALSE);
+ else if (tv->v_type == VAR_LIST || tv->v_type == VAR_DICT)
+ {
+ 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
retval = vim_strsave(tv_get_string(tv));
return retval;
/*
* Top level evaluation function, returning a string. Does not handle line
* 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.
*/
char_u *
eval_to_string_eap(
char_u *arg,
- int convert,
+ int join_list,
exarg_T *eap,
int use_simple_function)
{
retval = NULL;
else
{
- retval = typval2string(&tv, convert);
+ retval = typval2string(&tv, join_list);
clear_tv(&tv);
}
clear_evalarg(&evalarg, NULL);
char_u *
eval_to_string(
char_u *arg,
- int convert,
+ int join_list,
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);
}
/*
if (evaluate)
{
*block_end = NUL;
- expr_val = eval_to_string(block_start, TRUE, FALSE);
+ expr_val = eval_to_string(block_start, FALSE, FALSE);
*block_end = '}';
if (expr_val == NULL)
return NULL;
void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
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);
-char_u *typval2string(typval_T *tv, int convert);
-char_u *eval_to_string_eap(char_u *arg, int convert, exarg_T *eap, int use_simple_function);
-char_u *eval_to_string(char_u *arg, int convert, int use_simple_function);
+char_u *typval2string(typval_T *tv, int join_list);
+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 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);
varnumber_T eval_to_number(char_u *expr, int use_simple_function);
typval_T *eval_expr(char_u *arg, exarg_T *eap);
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_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);
vartype_T operator_type(type_T *type1, type_T *type2);
int generate_two_op(cctx_T *cctx, char_u *op);
#" Dict interpolation
VAR d = {'a': 10, 'b': [1, 2]}
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.
call assert_fails('echo $"moo}"', 'E1278:')
END
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 =<< eval trim END
let n = {5 +
bw!
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
CODE
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
var code =<< eval trim END
var s = "{$SOME_ENV_VAR}"
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 335,
/**/
334,
/**/
// arguments to ISN_2STRING and ISN_2STRING_ANY
typedef struct {
int offset;
- int tolerant;
+ int flags;
} tostring_T;
// arguments to ISN_2BOOL
// flags for call_def_function()
#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
return NULL;
if (cctx->ctx_skip == SKIP_YES)
return p;
- if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
+ if (may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
return NULL;
if (generate_instr_drop(cctx, ISN_THROW, 1) == NULL)
return NULL;
p += 2;
if (compile_expr0(&p, cctx) == FAIL)
return NULL;
- may_generate_2STRING(-1, TRUE, cctx);
+ may_generate_2STRING(-1, TOSTRING_TOLERANT, cctx);
++count;
p = skipwhite(p);
if (*p != '`')
}
if (compile_expr0(&block_start, cctx) == FAIL)
return NULL;
- may_generate_2STRING(-1, TRUE, cctx);
+ may_generate_2STRING(-1, TOSTRING_INTERPOLATE, cctx);
return block_end + 1;
}
return FAIL;
}
if (dest_type == VAR_DICT
- && may_generate_2STRING(-1, FALSE, cctx) == FAIL)
+ && may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
return FAIL;
if (dest_type == VAR_LIST || dest_type == VAR_BLOB)
{
if (*op == '.')
{
- if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
+ if (may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
goto theend;
}
else
* Return FAIL if not allowed.
*/
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)
return OK;
case VAR_BLOB: break;
case VAR_LIST:
- if (tolerant)
+ if (tostring_flags & TOSTRING_TOLERANT)
{
char_u *s, *e, *p;
garray_T ga;
tv->vval.v_string = ga.ga_data;
return OK;
}
+ if (tostring_flags & TOSTRING_INTERPOLATE)
+ break;
// FALLTHROUGH
default: to_string_error(tv->v_type);
return FAIL;
SOURCING_LNUM = iptr->isn_lnum;
if (do_2string(STACK_TV_BOT(iptr->isn_arg.tostring.offset),
iptr->isn_type == ISN_2STRING_ANY,
- iptr->isn_arg.tostring.tolerant) == FAIL)
+ iptr->isn_arg.tostring.flags) == FAIL)
goto on_error;
break;
typep->type_curr = &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)
return FAIL;
if (keeping_dict != NULL)
}
if (isn->isn_type == ISN_PUSHS)
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;
*arg = skipwhite(*arg);
if (**arg != ']')
ppconst->pp_is_const = FALSE;
if (*op == '.')
{
- if (may_generate_2STRING(-2, FALSE, cctx) == FAIL
- || may_generate_2STRING(-1, FALSE, cctx) == FAIL)
+ if (may_generate_2STRING(-2, TOSTRING_NONE, cctx) == FAIL
+ || may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
return FAIL;
if (generate_CONCAT(cctx, 2) == FAIL)
return FAIL;
/*
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
* 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
-may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
+may_generate_2STRING(int offset, int tostring_flags, cctx_T *cctx)
{
isn_T *isn;
isntype_T isntype = ISN_2STRING;
// conversion possible when tolerant
case VAR_LIST:
case VAR_DICT:
- if (tolerant)
+ if (tostring_flags & TOSTRING_TOLERANT)
{
isntype = ISN_2STRING_ANY;
break;
}
+ if (tostring_flags & TOSTRING_INTERPOLATE)
+ break;
// FALLTHROUGH
// conversion not possible
if ((isn = generate_instr(cctx, isntype)) == NULL)
return FAIL;
isn->isn_arg.tostring.offset = offset;
- isn->isn_arg.tostring.tolerant = tolerant;
+ isn->isn_arg.tostring.flags = tostring_flags;
return OK;
}