summaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c452
1 files changed, 292 insertions, 160 deletions
diff --git a/src/eval.c b/src/eval.c
index 8cc6ed1ed5..833a230f9d 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -6450,10 +6450,291 @@ set_ref_in_item(
}
/*
+ * Return a textual representation of a string in "tv".
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * When both "echo_style" and "composite_val" are FALSE, put quotes around
+ * strings as "string()", otherwise does not put quotes around strings.
+ * May return NULL.
+ */
+ static char_u *
+string_tv2string(
+ typval_T *tv,
+ char_u **tofree,
+ int echo_style,
+ int composite_val)
+{
+ char_u *r = NULL;
+
+ if (echo_style && !composite_val)
+ {
+ *tofree = NULL;
+ r = tv->vval.v_string;
+ if (r == NULL)
+ r = (char_u *)"";
+ }
+ else
+ {
+ *tofree = string_quote(tv->vval.v_string, FALSE);
+ r = *tofree;
+ }
+
+ return r;
+}
+
+/*
+ * Return a textual representation of a function in "tv".
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * When "echo_style" is FALSE, put quotes around the function name as
+ * "function()", otherwise does not put quotes around function name.
+ * May return NULL.
+ */
+ static char_u *
+func_tv2string(typval_T *tv, char_u **tofree, int echo_style)
+{
+ char_u *r = NULL;
+ char_u buf[MAX_FUNC_NAME_LEN];
+
+ if (echo_style)
+ {
+ r = tv->vval.v_string == NULL ? (char_u *)"function()"
+ : make_ufunc_name_readable(tv->vval.v_string,
+ buf, MAX_FUNC_NAME_LEN);
+ if (r == buf)
+ {
+ r = vim_strsave(buf);
+ *tofree = r;
+ }
+ else
+ *tofree = NULL;
+ }
+ else
+ {
+ *tofree = string_quote(tv->vval.v_string == NULL ? NULL
+ : make_ufunc_name_readable(tv->vval.v_string,
+ buf, MAX_FUNC_NAME_LEN), TRUE);
+ r = *tofree;
+ }
+
+ return r;
+}
+
+/*
+ * Return a textual representation of a partial in "tv".
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * "numbuf" is used for a number. May return NULL.
+ */
+ static char_u *
+partial_tv2string(
+ typval_T *tv,
+ char_u **tofree,
+ char_u *numbuf,
+ int copyID)
+{
+ char_u *r = NULL;
+ partial_T *pt;
+ char_u *fname;
+ garray_T ga;
+ int i;
+ char_u *tf;
+
+ pt = tv->vval.v_partial;
+ fname = string_quote(pt == NULL ? NULL : partial_name(pt), FALSE);
+
+ ga_init2(&ga, 1, 100);
+ ga_concat(&ga, (char_u *)"function(");
+ if (fname != NULL)
+ {
+ // When using uf_name prepend "g:" for a global function.
+ if (pt != NULL && pt->pt_name == NULL && fname[0] == '\''
+ && vim_isupper(fname[1]))
+ {
+ ga_concat(&ga, (char_u *)"'g:");
+ ga_concat(&ga, fname + 1);
+ }
+ else
+ ga_concat(&ga, fname);
+ vim_free(fname);
+ }
+ if (pt != NULL && pt->pt_argc > 0)
+ {
+ ga_concat(&ga, (char_u *)", [");
+ for (i = 0; i < pt->pt_argc; ++i)
+ {
+ if (i > 0)
+ ga_concat(&ga, (char_u *)", ");
+ ga_concat(&ga, tv2string(&pt->pt_argv[i], &tf, numbuf, copyID));
+ vim_free(tf);
+ }
+ ga_concat(&ga, (char_u *)"]");
+ }
+ if (pt != NULL && pt->pt_dict != NULL)
+ {
+ typval_T dtv;
+
+ ga_concat(&ga, (char_u *)", ");
+ dtv.v_type = VAR_DICT;
+ dtv.vval.v_dict = pt->pt_dict;
+ ga_concat(&ga, tv2string(&dtv, &tf, numbuf, copyID));
+ vim_free(tf);
+ }
+ // terminate with ')' and a NUL
+ ga_concat_len(&ga, (char_u *)")", 2);
+
+ *tofree = ga.ga_data;
+ r = *tofree;
+
+ return r;
+}
+
+/*
+ * Return a textual representation of a List in "tv".
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * When "copyID" is not zero replace recursive lists with "...". When
+ * "restore_copyID" is FALSE, repeated items in lists are replaced with "...".
+ * May return NULL.
+ */
+ static char_u *
+list_tv2string(
+ typval_T *tv,
+ char_u **tofree,
+ int copyID,
+ int restore_copyID)
+{
+ char_u *r = NULL;
+
+ if (tv->vval.v_list == NULL)
+ {
+ // NULL list is equivalent to empty list.
+ *tofree = NULL;
+ r = (char_u *)"[]";
+ }
+ else if (copyID != 0 && tv->vval.v_list->lv_copyID == copyID
+ && tv->vval.v_list->lv_len > 0)
+ {
+ *tofree = NULL;
+ r = (char_u *)"[...]";
+ }
+ else
+ {
+ int old_copyID = tv->vval.v_list->lv_copyID;
+
+ tv->vval.v_list->lv_copyID = copyID;
+ *tofree = list2string(tv, copyID, restore_copyID);
+ if (restore_copyID)
+ tv->vval.v_list->lv_copyID = old_copyID;
+ r = *tofree;
+ }
+
+ return r;
+}
+
+/*
+ * Return a textual representation of a Dict in "tv".
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * When "copyID" is not zero replace recursive dicts with "...".
+ * When "restore_copyID" is FALSE, repeated items in the dictionary are
+ * replaced with "...". May return NULL.
+ */
+ static char_u *
+dict_tv2string(
+ typval_T *tv,
+ char_u **tofree,
+ int copyID,
+ int restore_copyID)
+{
+ char_u *r = NULL;
+
+ if (tv->vval.v_dict == NULL)
+ {
+ // NULL dict is equivalent to empty dict.
+ *tofree = NULL;
+ r = (char_u *)"{}";
+ }
+ else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID
+ && tv->vval.v_dict->dv_hashtab.ht_used != 0)
+ {
+ *tofree = NULL;
+ r = (char_u *)"{...}";
+ }
+ else
+ {
+ int old_copyID = tv->vval.v_dict->dv_copyID;
+
+ tv->vval.v_dict->dv_copyID = copyID;
+ *tofree = dict2string(tv, copyID, restore_copyID);
+ if (restore_copyID)
+ tv->vval.v_dict->dv_copyID = old_copyID;
+ r = *tofree;
+ }
+
+ return r;
+}
+
+/*
+ * Return a textual representation of a job or a channel in "tv".
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * "numbuf" is used for a number.
+ * When "composite_val" is FALSE, put quotes around strings as "string()",
+ * otherwise does not put quotes around strings.
+ * May return NULL.
+ */
+ static char_u *
+jobchan_tv2string(
+ typval_T *tv,
+ char_u **tofree,
+ char_u *numbuf,
+ int composite_val)
+{
+ char_u *r = NULL;
+
+#ifdef FEAT_JOB_CHANNEL
+ *tofree = NULL;
+
+ if (tv->v_type == VAR_JOB)
+ r = job_to_string_buf(tv, numbuf);
+ else
+ r = channel_to_string_buf(tv, numbuf);
+
+ if (composite_val)
+ {
+ *tofree = string_quote(r, FALSE);
+ r = *tofree;
+ }
+#endif
+
+ return r;
+}
+
+/*
+ * Return a textual representation of a class in "tv".
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * May return NULL.
+ */
+ static char_u *
+class_tv2string(typval_T *tv, char_u **tofree)
+{
+ char_u *r = NULL;
+ class_T *cl = tv->vval.v_class;
+ char *s = "class";
+
+ if (cl != NULL && IS_INTERFACE(cl))
+ s = "interface";
+ else if (cl != NULL && IS_ENUM(cl))
+ s = "enum";
+ size_t len = STRLEN(s) + 1 +
+ (cl == NULL ? 9 : STRLEN(cl->class_name)) + 1;
+ r = *tofree = alloc(len);
+ vim_snprintf((char *)r, len, "%s %s", s,
+ cl == NULL ? "[unknown]" : (char *)cl->class_name);
+
+ return r;
+}
+
+/*
* Return a string with the string representation of a variable.
* If the memory is allocated "tofree" is set to it, otherwise NULL.
* "numbuf" is used for a number.
- * When "copyID" is not NULL replace recursive lists and dicts with "...".
+ * When "copyID" is not zero replace recursive lists and dicts with "...".
* When both "echo_style" and "composite_val" are FALSE, put quotes around
* strings as "string()", otherwise does not put quotes around strings, as
* ":echo" displays values.
@@ -6492,155 +6773,27 @@ echo_string_core(
switch (tv->v_type)
{
case VAR_STRING:
- if (echo_style && !composite_val)
- {
- *tofree = NULL;
- r = tv->vval.v_string;
- if (r == NULL)
- r = (char_u *)"";
- }
- else
- {
- *tofree = string_quote(tv->vval.v_string, FALSE);
- r = *tofree;
- }
+ r = string_tv2string(tv, tofree, echo_style, composite_val);
break;
case VAR_FUNC:
- {
- char_u buf[MAX_FUNC_NAME_LEN];
-
- if (echo_style)
- {
- r = tv->vval.v_string == NULL ? (char_u *)"function()"
- : make_ufunc_name_readable(tv->vval.v_string,
- buf, MAX_FUNC_NAME_LEN);
- if (r == buf)
- {
- r = vim_strsave(buf);
- *tofree = r;
- }
- else
- *tofree = NULL;
- }
- else
- {
- *tofree = string_quote(tv->vval.v_string == NULL ? NULL
- : make_ufunc_name_readable(
- tv->vval.v_string, buf, MAX_FUNC_NAME_LEN),
- TRUE);
- r = *tofree;
- }
- }
+ r = func_tv2string(tv, tofree, echo_style);
break;
case VAR_PARTIAL:
- {
- partial_T *pt = tv->vval.v_partial;
- char_u *fname = string_quote(pt == NULL ? NULL
- : partial_name(pt), FALSE);
- garray_T ga;
- int i;
- char_u *tf;
-
- ga_init2(&ga, 1, 100);
- ga_concat(&ga, (char_u *)"function(");
- if (fname != NULL)
- {
- // When using uf_name prepend "g:" for a global function.
- if (pt != NULL && pt->pt_name == NULL && fname[0] == '\''
- && vim_isupper(fname[1]))
- {
- ga_concat(&ga, (char_u *)"'g:");
- ga_concat(&ga, fname + 1);
- }
- else
- ga_concat(&ga, fname);
- vim_free(fname);
- }
- if (pt != NULL && pt->pt_argc > 0)
- {
- ga_concat(&ga, (char_u *)", [");
- for (i = 0; i < pt->pt_argc; ++i)
- {
- if (i > 0)
- ga_concat(&ga, (char_u *)", ");
- ga_concat(&ga,
- tv2string(&pt->pt_argv[i], &tf, numbuf, copyID));
- vim_free(tf);
- }
- ga_concat(&ga, (char_u *)"]");
- }
- if (pt != NULL && pt->pt_dict != NULL)
- {
- typval_T dtv;
-
- ga_concat(&ga, (char_u *)", ");
- dtv.v_type = VAR_DICT;
- dtv.vval.v_dict = pt->pt_dict;
- ga_concat(&ga, tv2string(&dtv, &tf, numbuf, copyID));
- vim_free(tf);
- }
- // terminate with ')' and a NUL
- ga_concat_len(&ga, (char_u *)")", 2);
-
- *tofree = ga.ga_data;
- r = *tofree;
- break;
- }
+ r = partial_tv2string(tv, tofree, numbuf, copyID);
+ break;
case VAR_BLOB:
r = blob2string(tv->vval.v_blob, tofree, numbuf);
break;
case VAR_LIST:
- if (tv->vval.v_list == NULL)
- {
- // NULL list is equivalent to empty list.
- *tofree = NULL;
- r = (char_u *)"[]";
- }
- else if (copyID != 0 && tv->vval.v_list->lv_copyID == copyID
- && tv->vval.v_list->lv_len > 0)
- {
- *tofree = NULL;
- r = (char_u *)"[...]";
- }
- else
- {
- int old_copyID = tv->vval.v_list->lv_copyID;
-
- tv->vval.v_list->lv_copyID = copyID;
- *tofree = list2string(tv, copyID, restore_copyID);
- if (restore_copyID)
- tv->vval.v_list->lv_copyID = old_copyID;
- r = *tofree;
- }
+ r = list_tv2string(tv, tofree, copyID, restore_copyID);
break;
case VAR_DICT:
- if (tv->vval.v_dict == NULL)
- {
- // NULL dict is equivalent to empty dict.
- *tofree = NULL;
- r = (char_u *)"{}";
- }
- else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID
- && tv->vval.v_dict->dv_hashtab.ht_used != 0)
- {
- *tofree = NULL;
- r = (char_u *)"{...}";
- }
- else
- {
- int old_copyID = tv->vval.v_dict->dv_copyID;
-
- tv->vval.v_dict->dv_copyID = copyID;
- *tofree = dict2string(tv, copyID, restore_copyID);
- if (restore_copyID)
- tv->vval.v_dict->dv_copyID = old_copyID;
- r = *tofree;
- }
+ r = dict_tv2string(tv, tofree, copyID, restore_copyID);
break;
case VAR_NUMBER:
@@ -6653,16 +6806,7 @@ echo_string_core(
case VAR_JOB:
case VAR_CHANNEL:
-#ifdef FEAT_JOB_CHANNEL
- *tofree = NULL;
- r = tv->v_type == VAR_JOB ? job_to_string_buf(tv, numbuf)
- : channel_to_string_buf(tv, numbuf);
- if (composite_val)
- {
- *tofree = string_quote(r, FALSE);
- r = *tofree;
- }
-#endif
+ r = jobchan_tv2string(tv, tofree, numbuf, composite_val);
break;
case VAR_INSTR:
@@ -6671,23 +6815,11 @@ echo_string_core(
break;
case VAR_CLASS:
- {
- class_T *cl = tv->vval.v_class;
- char *s = "class";
- if (cl != NULL && IS_INTERFACE(cl))
- s = "interface";
- else if (cl != NULL && IS_ENUM(cl))
- s = "enum";
- size_t len = STRLEN(s) + 1 +
- (cl == NULL ? 9 : STRLEN(cl->class_name)) + 1;
- r = *tofree = alloc(len);
- vim_snprintf((char *)r, len, "%s %s", s,
- cl == NULL ? "[unknown]" : (char *)cl->class_name);
- }
+ r = class_tv2string(tv, tofree);
break;
case VAR_OBJECT:
- *tofree = r = object_string(tv->vval.v_object, numbuf, copyID,
+ *tofree = r = object2string(tv->vval.v_object, numbuf, copyID,
echo_style, restore_copyID,
composite_val);
break;
@@ -6722,7 +6854,7 @@ echo_string_core(
* If the memory is allocated "tofree" is set to it, otherwise NULL.
* "numbuf" is used for a number.
* Does not put quotes around strings, as ":echo" displays values.
- * When "copyID" is not NULL replace recursive lists and dicts with "...".
+ * When "copyID" is not zero replace recursive lists and dicts with "...".
* May return NULL.
*/
char_u *