Patch 7.4.1279
Problem: jsonencode() is not producing strict JSON.
Solution: Add jsencode() and jsdecode(). Make jsonencode() and jsondecode()
strict.
Files: src/json.c, src/json_test.c, src/proto/json.pro, src/channel.c,
src/proto/channel.pro, src/eval.c, src/vim.h, src/structs.h,
runtime/doc/eval.txt, runtime/doc/channel.txt,
src/testdir/test_json.vim
*** ../vim-7.4.1278/src/json.c 2016-02-07 16:53:08.779395103 +0100
--- src/json.c 2016-02-07 18:43:33.130797605 +0100
***************
*** 16,37 ****
#include "vim.h"
#if defined(FEAT_EVAL) || defined(PROTO)
! static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int
allow_none);
! static int json_decode_item(js_read_T *reader, typval_T *res);
/*
* Encode "val" into a JSON format string.
* The result is in allocated memory.
* The result is empty when encoding fails.
*/
char_u *
! json_encode(typval_T *val)
{
garray_T ga;
/* Store bytes in the growarray. */
ga_init2(&ga, 1, 4000);
! if (json_encode_item(&ga, val, get_copyID(), TRUE) == FAIL)
{
vim_free(ga.ga_data);
return vim_strsave((char_u *)"");
--- 16,38 ----
#include "vim.h"
#if defined(FEAT_EVAL) || defined(PROTO)
! static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int
options);
! static int json_decode_item(js_read_T *reader, typval_T *res, int options);
/*
* Encode "val" into a JSON format string.
* The result is in allocated memory.
* The result is empty when encoding fails.
+ * "options" can be JSON_JS or zero;
*/
char_u *
! json_encode(typval_T *val, int options)
{
garray_T ga;
/* Store bytes in the growarray. */
ga_init2(&ga, 1, 4000);
! if (json_encode_item(&ga, val, get_copyID(), options) == FAIL)
{
vim_free(ga.ga_data);
return vim_strsave((char_u *)"");
***************
*** 41,50 ****
/*
* Encode ["nr", "val"] into a JSON format string in allocated memory.
* Returns NULL when out of memory.
*/
char_u *
! json_encode_nr_expr(int nr, typval_T *val)
{
typval_T listtv;
typval_T nrtv;
--- 42,52 ----
/*
* Encode ["nr", "val"] into a JSON format string in allocated memory.
+ * "options" can be JSON_JS or zero;
* Returns NULL when out of memory.
*/
char_u *
! json_encode_nr_expr(int nr, typval_T *val, int options)
{
typval_T listtv;
typval_T nrtv;
***************
*** 61,67 ****
return NULL;
}
! text = json_encode(&listtv);
list_unref(listtv.vval.v_list);
return text;
}
--- 63,69 ----
return NULL;
}
! text = json_encode(&listtv, options);
list_unref(listtv.vval.v_list);
return text;
}
***************
*** 123,133 ****
}
/*
* Encode "val" into "gap".
* Return FAIL or OK.
*/
static int
! json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
{
char_u numbuf[NUMBUFLEN];
char_u *res;
--- 125,153 ----
}
/*
+ * Return TRUE if "key" can be used without quotes.
+ * That is when it starts with a letter and only contains letters, digits and
+ * underscore.
+ */
+ static int
+ is_simple_key(char_u *key)
+ {
+ char_u *p;
+
+ if (!ASCII_ISALPHA(*key))
+ return FALSE;
+ for (p = key + 1; *p != NUL; ++p)
+ if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
+ return FALSE;
+ return TRUE;
+ }
+
+ /*
* Encode "val" into "gap".
* Return FAIL or OK.
*/
static int
! json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
{
char_u numbuf[NUMBUFLEN];
char_u *res;
***************
*** 141,153 ****
{
case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
! case VVAL_NONE: if (!allow_none)
! {
! /* TODO: better error */
! EMSG(_(e_invarg));
! return FAIL;
! }
! break;
case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
}
break;
--- 161,171 ----
{
case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
! case VVAL_NONE: if ((options & JSON_JS) != 0
! && (options & JSON_NO_NONE) == 0)
! /* empty item */
! break;
! /* FALLTHROUGH */
case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
}
break;
***************
*** 185,193 ****
ga_append(gap, '[');
for (li = l->lv_first; li != NULL && !got_int; )
{
! if (json_encode_item(gap, &li->li_tv, copyID, TRUE)
! == FAIL)
return FAIL;
li = li->li_next;
if (li != NULL)
ga_append(gap, ',');
--- 203,217 ----
ga_append(gap, '[');
for (li = l->lv_first; li != NULL && !got_int; )
{
! if (json_encode_item(gap, &li->li_tv, copyID,
! options & JSON_JS) == FAIL)
return FAIL;
+ if ((options & JSON_JS)
+ && li->li_next == NULL
+ && li->li_tv.v_type == VAR_SPECIAL
+ && li->li_tv.vval.v_number == VVAL_NONE)
+ /* add an extra comma if the last item is v:none */
+ ga_append(gap, ',');
li = li->li_next;
if (li != NULL)
ga_append(gap, ',');
***************
*** 224,233 ****
first = FALSE;
else
ga_append(gap, ',');
! write_string(gap, hi->hi_key);
ga_append(gap, ':');
if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
! copyID, FALSE) == FAIL)
return FAIL;
}
ga_append(gap, '}');
--- 248,261 ----
first = FALSE;
else
ga_append(gap, ',');
! if ((options & JSON_JS)
! && is_simple_key(hi->hi_key))
! ga_concat(gap, hi->hi_key);
! else
! write_string(gap, hi->hi_key);
ga_append(gap, ':');
if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
! copyID, options | JSON_NO_NONE) == FAIL)
return FAIL;
}
ga_append(gap, '}');
***************
*** 265,271 ****
}
/*
! * Skip white space in "reader".
* Also tops up readahead when needed.
*/
static void
--- 293,300 ----
}
/*
! * Skip white space in "reader". All characters <= space are considered white
! * space.
* Also tops up readahead when needed.
*/
static void
***************
*** 282,288 ****
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
continue;
}
! if (c != ' ' && c != TAB && c != NL && c != CAR)
break;
++reader->js_used;
}
--- 311,317 ----
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
continue;
}
! if (c == NUL || c > ' ')
break;
++reader->js_used;
}
***************
*** 290,296 ****
}
static int
! json_decode_array(js_read_T *reader, typval_T *res)
{
char_u *p;
typval_T item;
--- 319,325 ----
}
static int
! json_decode_array(js_read_T *reader, typval_T *res, int options)
{
char_u *p;
typval_T item;
***************
*** 317,323 ****
break;
}
! ret = json_decode_item(reader, res == NULL ? NULL : &item);
if (ret != OK)
return ret;
if (res != NULL)
--- 346,352 ----
break;
}
! ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
if (ret != OK)
return ret;
if (res != NULL)
***************
*** 347,353 ****
}
static int
! json_decode_object(js_read_T *reader, typval_T *res)
{
char_u *p;
typval_T tvkey;
--- 376,382 ----
}
static int
! json_decode_object(js_read_T *reader, typval_T *res, int options)
{
char_u *p;
typval_T tvkey;
***************
*** 377,392 ****
break;
}
! ret = json_decode_item(reader, res == NULL ? NULL : &tvkey);
! if (ret != OK)
! return ret;
! if (res != NULL)
{
! key = get_tv_string_buf_chk(&tvkey, buf);
! if (key == NULL || *key == NUL)
{
! clear_tv(&tvkey);
! return FAIL;
}
}
--- 406,436 ----
break;
}
! if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
! {
! /* accept a key that is not in quotes */
! key = p = reader->js_buf + reader->js_used;
! while (*p != NUL && *p != ':' && *p > ' ')
! ++p;
! tvkey.v_type = VAR_STRING;
! tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
! reader->js_used += (int)(p - key);
! key = tvkey.vval.v_string;
! }
! else
{
! ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
! options);
! if (ret != OK)
! return ret;
! if (res != NULL)
{
! key = get_tv_string_buf_chk(&tvkey, buf);
! if (key == NULL || *key == NUL)
! {
! clear_tv(&tvkey);
! return FAIL;
! }
}
}
***************
*** 403,409 ****
++reader->js_used;
json_skip_white(reader);
! ret = json_decode_item(reader, res == NULL ? NULL : &item);
if (ret != OK)
{
if (res != NULL)
--- 447,453 ----
++reader->js_used;
json_skip_white(reader);
! ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
if (ret != OK)
{
if (res != NULL)
***************
*** 569,575 ****
* Return MAYBE for an incomplete message.
*/
static int
! json_decode_item(js_read_T *reader, typval_T *res)
{
char_u *p;
int len;
--- 613,619 ----
* Return MAYBE for an incomplete message.
*/
static int
! json_decode_item(js_read_T *reader, typval_T *res, int options)
{
char_u *p;
int len;
***************
*** 579,593 ****
switch (*p)
{
case '[': /* array */
! return json_decode_array(reader, res);
case '{': /* object */
! return json_decode_object(reader, res);
case '"': /* string */
return json_decode_string(reader, res);
case ',': /* comma: empty item */
case NUL: /* empty */
if (res != NULL)
{
--- 623,640 ----
switch (*p)
{
case '[': /* array */
! return json_decode_array(reader, res, options);
case '{': /* object */
! return json_decode_object(reader, res, options);
case '"': /* string */
return json_decode_string(reader, res);
case ',': /* comma: empty item */
+ if ((options & JSON_JS) == 0)
+ return FAIL;
+ /* FALLTHROUGH */
case NUL: /* empty */
if (res != NULL)
{
***************
*** 691,707 ****
/*
* Decode the JSON from "reader" and store the result in "res".
* Return FAIL if not the whole message was consumed.
*/
int
! json_decode_all(js_read_T *reader, typval_T *res)
{
int ret;
! /* We get the end once, to avoid calling strlen() many times. */
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
json_skip_white(reader);
! ret = json_decode_item(reader, res);
if (ret != OK)
return FAIL;
json_skip_white(reader);
--- 738,755 ----
/*
* Decode the JSON from "reader" and store the result in "res".
+ * "options" can be JSON_JS or zero;
* Return FAIL if not the whole message was consumed.
*/
int
! json_decode_all(js_read_T *reader, typval_T *res, int options)
{
int ret;
! /* We find the end once, to avoid calling strlen() many times. */
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
json_skip_white(reader);
! ret = json_decode_item(reader, res, options);
if (ret != OK)
return FAIL;
json_skip_white(reader);
***************
*** 712,729 ****
/*
* Decode the JSON from "reader" and store the result in "res".
* Return FAIL if the message has a decoding error or the message is
* truncated. Consumes the message anyway.
*/
int
! json_decode(js_read_T *reader, typval_T *res)
{
int ret;
! /* We get the end once, to avoid calling strlen() many times. */
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
json_skip_white(reader);
! ret = json_decode_item(reader, res);
json_skip_white(reader);
return ret == OK ? OK : FAIL;
--- 760,778 ----
/*
* Decode the JSON from "reader" and store the result in "res".
+ * "options" can be JSON_JS or zero;
* Return FAIL if the message has a decoding error or the message is
* truncated. Consumes the message anyway.
*/
int
! json_decode(js_read_T *reader, typval_T *res, int options)
{
int ret;
! /* We find the end once, to avoid calling strlen() many times. */
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
json_skip_white(reader);
! ret = json_decode_item(reader, res, options);
json_skip_white(reader);
return ret == OK ? OK : FAIL;
***************
*** 731,736 ****
--- 780,786 ----
/*
* Decode the JSON from "reader" to find the end of the message.
+ * "options" can be JSON_JS or zero;
* Return FAIL if the message has a decoding error.
* Return MAYBE if the message is truncated, need to read more.
* This only works reliable if the message contains an object, array or
***************
*** 738,752 ****
* Does not advance the reader.
*/
int
! json_find_end(js_read_T *reader)
{
int used_save = reader->js_used;
int ret;
! /* We get the end once, to avoid calling strlen() many times. */
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
json_skip_white(reader);
! ret = json_decode_item(reader, NULL);
reader->js_used = used_save;
return ret;
}
--- 788,802 ----
* Does not advance the reader.
*/
int
! json_find_end(js_read_T *reader, int options)
{
int used_save = reader->js_used;
int ret;
! /* We find the end once, to avoid calling strlen() many times. */
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
json_skip_white(reader);
! ret = json_decode_item(reader, NULL, options);
reader->js_used = used_save;
return ret;
}
*** ../vim-7.4.1278/src/json_test.c 2016-02-02 19:15:33.252127718 +0100
--- src/json_test.c 2016-02-07 17:51:06.959400557 +0100
***************
*** 35,141 ****
/* string and incomplete string */
reader.js_buf = (char_u *)"\"hello\"";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)" \"hello\" ";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)"\"hello";
! assert(json_find_end(&reader) == MAYBE);
/* number and dash (incomplete number) */
reader.js_buf = (char_u *)"123";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)"-";
! assert(json_find_end(&reader) == MAYBE);
/* false, true and null, also incomplete */
reader.js_buf = (char_u *)"false";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)"f";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"fa";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"fal";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"fals";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"true";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)"t";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"tr";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"tru";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"null";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)"n";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"nu";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"nul";
! assert(json_find_end(&reader) == MAYBE);
/* object without white space */
reader.js_buf = (char_u *)"{\"a\":123}";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)"{\"a\":123";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"{\"a\":";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"{\"a\"";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"{\"a";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"{\"";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"{";
! assert(json_find_end(&reader) == MAYBE);
/* object with white space */
reader.js_buf = (char_u *)" { \"a\" : 123 } ";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)" { \"a\" : 123 ";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)" { \"a\" : ";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)" { \"a\" ";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)" { \"a ";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)" { ";
! assert(json_find_end(&reader) == MAYBE);
/* array without white space */
reader.js_buf = (char_u *)"[\"a\",123]";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)"[\"a\",123";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"[\"a\",";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"[\"a\"";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"[\"a";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"[\"";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)"[";
! assert(json_find_end(&reader) == MAYBE);
/* array with white space */
reader.js_buf = (char_u *)" [ \"a\" , 123 ] ";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)" [ \"a\" , ";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)" [ \"a\" ";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)" [ \"a ";
! assert(json_find_end(&reader) == MAYBE);
reader.js_buf = (char_u *)" [ ";
! assert(json_find_end(&reader) == MAYBE);
}
static int
--- 35,141 ----
/* string and incomplete string */
reader.js_buf = (char_u *)"\"hello\"";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)" \"hello\" ";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)"\"hello";
! assert(json_find_end(&reader, 0) == MAYBE);
/* number and dash (incomplete number) */
reader.js_buf = (char_u *)"123";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)"-";
! assert(json_find_end(&reader, 0) == MAYBE);
/* false, true and null, also incomplete */
reader.js_buf = (char_u *)"false";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)"f";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"fa";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"fal";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"fals";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"true";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)"t";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"tr";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"tru";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"null";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)"n";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"nu";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"nul";
! assert(json_find_end(&reader, 0) == MAYBE);
/* object without white space */
reader.js_buf = (char_u *)"{\"a\":123}";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)"{\"a\":123";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"{\"a\":";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"{\"a\"";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"{\"a";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"{\"";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"{";
! assert(json_find_end(&reader, 0) == MAYBE);
/* object with white space */
reader.js_buf = (char_u *)" { \"a\" : 123 } ";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)" { \"a\" : 123 ";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)" { \"a\" : ";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)" { \"a\" ";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)" { \"a ";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)" { ";
! assert(json_find_end(&reader, 0) == MAYBE);
/* array without white space */
reader.js_buf = (char_u *)"[\"a\",123]";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)"[\"a\",123";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"[\"a\",";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"[\"a\"";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"[\"a";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"[\"";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)"[";
! assert(json_find_end(&reader, 0) == MAYBE);
/* array with white space */
reader.js_buf = (char_u *)" [ \"a\" , 123 ] ";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)" [ \"a\" , ";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)" [ \"a\" ";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)" [ \"a ";
! assert(json_find_end(&reader, 0) == MAYBE);
reader.js_buf = (char_u *)" [ ";
! assert(json_find_end(&reader, 0) == MAYBE);
}
static int
***************
*** 157,171 ****
reader.js_used = 0;
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
reader.js_cookie = " [ \"a\" , 123 ] ";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)" [ \"a\" , ";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)" [ \"a\" ";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)" [ \"a";
! assert(json_find_end(&reader) == OK);
reader.js_buf = (char_u *)" [ ";
! assert(json_find_end(&reader) == OK);
}
/*
--- 157,171 ----
reader.js_used = 0;
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
reader.js_cookie = " [ \"a\" , 123 ] ";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)" [ \"a\" , ";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)" [ \"a\" ";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)" [ \"a";
! assert(json_find_end(&reader, 0) == OK);
reader.js_buf = (char_u *)" [ ";
! assert(json_find_end(&reader, 0) == OK);
}
/*
*** ../vim-7.4.1278/src/proto/json.pro 2016-02-02 18:19:52.790743971 +0100
--- src/proto/json.pro 2016-02-07 17:56:55.907785968 +0100
***************
*** 1,7 ****
/* json.c */
! char_u *json_encode(typval_T *val);
! char_u *json_encode_nr_expr(int nr, typval_T *val);
! int json_decode_all(js_read_T *reader, typval_T *res);
! int json_decode(js_read_T *reader, typval_T *res);
! int json_find_end(js_read_T *reader);
/* vim: set ft=c : */
--- 1,7 ----
/* json.c */
! char_u *json_encode(typval_T *val, int options);
! char_u *json_encode_nr_expr(int nr, typval_T *val, int options);
! int json_decode_all(js_read_T *reader, typval_T *res, int options);
! int json_decode(js_read_T *reader, typval_T *res, int options);
! int json_find_end(js_read_T *reader, int options);
/* vim: set ft=c : */
*** ../vim-7.4.1278/src/channel.c 2016-02-07 16:53:08.779395103 +0100
--- src/channel.c 2016-02-07 19:00:23.072301348 +0100
***************
*** 119,125 ****
char_u *ch_callback; /* function to call when a msg is not handled */
cbq_T ch_cb_head; /* dummy node for pre-request callbacks */
! int ch_json_mode; /* TRUE for a json channel */
jsonq_T ch_json_head; /* dummy node, header for circular queue */
int ch_timeout; /* request timeout in msec */
--- 119,125 ----
char_u *ch_callback; /* function to call when a msg is not handled */
cbq_T ch_cb_head; /* dummy node for pre-request callbacks */
! ch_mode_T ch_mode;
jsonq_T ch_json_head; /* dummy node, header for circular queue */
int ch_timeout; /* request timeout in msec */
***************
*** 526,537 ****
}
/*
! * Set the json mode of channel "idx" to TRUE or FALSE.
*/
void
! channel_set_json_mode(int idx, int json_mode)
{
! channels[idx].ch_json_mode = json_mode;
}
/*
--- 526,537 ----
}
/*
! * Set the json mode of channel "idx" to "ch_mode".
*/
void
! channel_set_json_mode(int idx, ch_mode_T ch_mode)
{
! channels[idx].ch_mode = ch_mode;
}
/*
***************
*** 672,678 ****
js_read_T reader;
typval_T listtv;
jsonq_T *item;
! jsonq_T *head = &channels[ch_idx].ch_json_head;
int ret;
if (channel_peek(ch_idx) == NULL)
--- 672,679 ----
js_read_T reader;
typval_T listtv;
jsonq_T *item;
! channel_T *channel = &channels[ch_idx];
! jsonq_T *head = &channel->ch_json_head;
int ret;
if (channel_peek(ch_idx) == NULL)
***************
*** 685,691 ****
reader.js_fill = NULL;
/* reader.js_fill = channel_fill; */
reader.js_cookie = &ch_idx;
! ret = json_decode(&reader, &listtv);
if (ret == OK)
{
/* Only accept the response when it is a list with at least two
--- 686,693 ----
reader.js_fill = NULL;
/* reader.js_fill = channel_fill; */
reader.js_cookie = &ch_idx;
! ret = json_decode(&reader, &listtv,
! channel->ch_mode == MODE_JS ? JSON_JS : 0);
if (ret == OK)
{
/* Only accept the response when it is a list with at least two
***************
*** 854,859 ****
--- 856,863 ----
typval_T *tv;
typval_T err_tv;
char_u *json = NULL;
+ channel_T *channel = &channels[idx];
+ int options = channel->ch_mode == MODE_JS ? JSON_JS : 0;
/* Don't pollute the display with errors. */
++emsg_skip;
***************
*** 861,867 ****
if (is_eval)
{
if (tv != NULL)
! json = json_encode_nr_expr(arg3->vval.v_number, tv);
if (tv == NULL || (json != NULL && *json == NUL))
{
/* If evaluation failed or the result can't be encoded
--- 865,872 ----
if (is_eval)
{
if (tv != NULL)
! json = json_encode_nr_expr(arg3->vval.v_number, tv,
! options);
if (tv == NULL || (json != NULL && *json == NUL))
{
/* If evaluation failed or the result can't be encoded
***************
*** 869,875 ****
err_tv.v_type = VAR_STRING;
err_tv.vval.v_string = (char_u *)"ERROR";
tv = &err_tv;
! json = json_encode_nr_expr(arg3->vval.v_number, tv);
}
if (json != NULL)
{
--- 874,881 ----
err_tv.v_type = VAR_STRING;
err_tv.vval.v_string = (char_u *)"ERROR";
tv = &err_tv;
! json = json_encode_nr_expr(arg3->vval.v_number, tv,
! options);
}
if (json != NULL)
{
***************
*** 900,912 ****
typval_T argv[3];
int seq_nr = -1;
channel_T *channel = &channels[idx];
! int json_mode = channel->ch_json_mode;
if (channel->ch_close_cb != NULL)
/* this channel is handled elsewhere (netbeans) */
return FALSE;
! if (json_mode)
{
/* Get any json message in the queue. */
if (channel_get_json(idx, -1, &listtv) == FAIL)
--- 906,918 ----
typval_T argv[3];
int seq_nr = -1;
channel_T *channel = &channels[idx];
! ch_mode_T ch_mode = channel->ch_mode;
if (channel->ch_close_cb != NULL)
/* this channel is handled elsewhere (netbeans) */
return FALSE;
! if (ch_mode != MODE_RAW)
{
/* Get any json message in the queue. */
if (channel_get_json(idx, -1, &listtv) == FAIL)
*** ../vim-7.4.1278/src/proto/channel.pro 2016-02-05 22:36:09.745738060
+0100
--- src/proto/channel.pro 2016-02-07 18:57:02.674386386 +0100
***************
*** 1,7 ****
/* channel.c */
void channel_gui_register_all(void);
int channel_open(char *hostname, int port_in, int waittime, void
(*close_cb)(void));
! void channel_set_json_mode(int idx, int json_mode);
void channel_set_timeout(int idx, int timeout);
void channel_set_callback(int idx, char_u *callback);
void channel_set_req_callback(int idx, char_u *callback, int id);
--- 1,7 ----
/* channel.c */
void channel_gui_register_all(void);
int channel_open(char *hostname, int port_in, int waittime, void
(*close_cb)(void));
! void channel_set_json_mode(int idx, ch_mode_T ch_mode);
void channel_set_timeout(int idx, int timeout);
void channel_set_callback(int idx, char_u *callback);
void channel_set_req_callback(int idx, char_u *callback, int id);
*** ../vim-7.4.1278/src/eval.c 2016-02-07 15:56:55.930329022 +0100
--- src/eval.c 2016-02-07 18:50:35.690407606 +0100
***************
*** 628,633 ****
--- 628,635 ----
static void f_job_status(typval_T *argvars, typval_T *rettv);
#endif
static void f_join(typval_T *argvars, typval_T *rettv);
+ static void f_jsdecode(typval_T *argvars, typval_T *rettv);
+ static void f_jsencode(typval_T *argvars, typval_T *rettv);
static void f_jsondecode(typval_T *argvars, typval_T *rettv);
static void f_jsonencode(typval_T *argvars, typval_T *rettv);
static void f_keys(typval_T *argvars, typval_T *rettv);
***************
*** 8206,8211 ****
--- 8208,8215 ----
{"job_stop", 1, 1, f_job_stop},
#endif
{"join", 1, 2, f_join},
+ {"jsdecode", 1, 1, f_jsdecode},
+ {"jsencode", 1, 1, f_jsencode},
{"jsondecode", 1, 1, f_jsondecode},
{"jsonencode", 1, 1, f_jsonencode},
{"keys", 1, 1, f_keys},
***************
*** 9829,9835 ****
int port;
int waittime = 0;
int timeout = 2000;
! int json_mode = TRUE;
int ch_idx;
/* default: fail */
--- 9833,9839 ----
int port;
int waittime = 0;
int timeout = 2000;
! ch_mode_T ch_mode = MODE_JSON;
int ch_idx;
/* default: fail */
***************
*** 9868,9875 ****
{
mode = get_dict_string(dict, (char_u *)"mode", FALSE);
if (STRCMP(mode, "raw") == 0)
! json_mode = FALSE;
! else if (STRCMP(mode, "json") != 0)
{
EMSG2(_(e_invarg2), mode);
return;
--- 9872,9883 ----
{
mode = get_dict_string(dict, (char_u *)"mode", FALSE);
if (STRCMP(mode, "raw") == 0)
! ch_mode = MODE_RAW;
! else if (STRCMP(mode, "js") == 0)
! ch_mode = MODE_JS;
! else if (STRCMP(mode, "json") == 0)
! ch_mode = MODE_JSON;
! else
{
EMSG2(_(e_invarg2), mode);
return;
***************
*** 9891,9897 ****
ch_idx = channel_open((char *)address, port, waittime, NULL);
if (ch_idx >= 0)
{
! channel_set_json_mode(ch_idx, json_mode);
channel_set_timeout(ch_idx, timeout);
if (callback != NULL && *callback != NUL)
channel_set_callback(ch_idx, callback);
--- 9899,9905 ----
ch_idx = channel_open((char *)address, port, waittime, NULL);
if (ch_idx >= 0)
{
! channel_set_json_mode(ch_idx, ch_mode);
channel_set_timeout(ch_idx, timeout);
if (callback != NULL && *callback != NUL)
channel_set_callback(ch_idx, callback);
***************
*** 9946,9952 ****
rettv->vval.v_string = NULL;
id = channel_get_id();
! text = json_encode_nr_expr(id, &argvars[1]);
if (text == NULL)
return;
--- 9954,9960 ----
rettv->vval.v_string = NULL;
id = channel_get_id();
! text = json_encode_nr_expr(id, &argvars[1], 0);
if (text == NULL)
return;
***************
*** 14443,14448 ****
--- 14451,14481 ----
}
/*
+ * "jsdecode()" function
+ */
+ static void
+ f_jsdecode(typval_T *argvars, typval_T *rettv)
+ {
+ js_read_T reader;
+
+ reader.js_buf = get_tv_string(&argvars[0]);
+ reader.js_fill = NULL;
+ reader.js_used = 0;
+ if (json_decode_all(&reader, rettv, JSON_JS) != OK)
+ EMSG(_(e_invarg));
+ }
+
+ /*
+ * "jsencode()" function
+ */
+ static void
+ f_jsencode(typval_T *argvars, typval_T *rettv)
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
+ }
+
+ /*
* "jsondecode()" function
*/
static void
***************
*** 14453,14459 ****
reader.js_buf = get_tv_string(&argvars[0]);
reader.js_fill = NULL;
reader.js_used = 0;
! if (json_decode_all(&reader, rettv) != OK)
EMSG(_(e_invarg));
}
--- 14486,14492 ----
reader.js_buf = get_tv_string(&argvars[0]);
reader.js_fill = NULL;
reader.js_used = 0;
! if (json_decode_all(&reader, rettv, 0) != OK)
EMSG(_(e_invarg));
}
***************
*** 14464,14470 ****
f_jsonencode(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_STRING;
! rettv->vval.v_string = json_encode(&argvars[0]);
}
/*
--- 14497,14503 ----
f_jsonencode(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_STRING;
! rettv->vval.v_string = json_encode(&argvars[0], 0);
}
/*
*** ../vim-7.4.1278/src/vim.h 2016-02-04 22:09:44.692012667 +0100
--- src/vim.h 2016-02-07 18:58:15.609627507 +0100
***************
*** 2317,2322 ****
--- 2317,2326 ----
# define MAX_OPEN_CHANNELS 0
#endif
+ /* Options for json_encode() and json_decode. */
+ #define JSON_JS 1 /* use JS instead of JSON */
+ #define JSON_NO_NONE 2 /* v:none item not allowed */
+
#ifdef FEAT_MZSCHEME
/* this is in main.c, cproto can't handle it. */
int vim_main2(int argc, char **argv);
*** ../vim-7.4.1278/src/structs.h 2016-02-07 14:26:12.179054006 +0100
--- src/structs.h 2016-02-07 18:58:24.205538070 +0100
***************
*** 2728,2730 ****
--- 2728,2738 ----
void *js_cookie; /* can be used by js_fill */
};
typedef struct js_reader js_read_T;
+
+ /* mode for a channel */
+ typedef enum
+ {
+ MODE_RAW = 0,
+ MODE_JSON,
+ MODE_JS
+ } ch_mode_T;
*** ../vim-7.4.1278/runtime/doc/eval.txt 2016-02-07 14:26:12.179054006
+0100
--- runtime/doc/eval.txt 2016-02-07 19:14:50.867274749 +0100
***************
*** 1933,1938 ****
--- 1956,1963 ----
job_status({job}) String get the status of a job
job_stop({job} [, {how}]) Number stop a job
join( {list} [, {sep}]) String join {list} items into one
String
+ jsdecode( {string}) any decode JS style JSON
+ jsencode( {expr}) String encode JS style JSON
jsondecode( {string}) any decode JSON
jsonencode( {expr}) String encode JSON
keys( {dict}) List keys in {dict}
***************
*** 4288,4304 ****
converted into a string like with |string()|.
The opposite function is |split()|.
jsondecode({string}) *jsondecode()*
This parses a JSON formatted string and returns the equivalent
in Vim values. See |jsonencode()| for the relation between
JSON and Vim values.
The decoding is permissive:
- A trailing comma in an array and object is ignored.
- - An empty item in an array, two commas with nothing or white
- space in between, results in v:none.
- - When an object member name is not a string it is converted
- to a string. E.g. the number 123 is used as the string
- "123".
- More floating point numbers are recognized, e.g. "1." for
"1.0".
The result must be a valid Vim type:
--- 4382,4414 ----
converted into a string like with |string()|.
The opposite function is |split()|.
+ jsdecode({string}) *jsdecode()*
+ This is similar to |jsondecode()| with these differences:
+ - Object key names do not have to be in quotes.
+ - Empty items in an array (between two commas) are allowed and
+ result in v:none items.
+
+ jsencode({expr}) *jsencode()*
+ This is similar to |jsonencode()| with these differences:
+ - Object key names are not in quotes.
+ - v:none items in an array result in an empty item between
+ commas.
+ For example, the Vim object:
+ [1,v:none,{"one":1}],v:none ~
+ Will be encoded as:
+ [1,,{one:1},,] ~
+ While jsonencode() would produce:
+ [1,null,{"one":1},null] ~
+ This encoding is valid for JavaScript. It is more efficient
+ than JSON, especially when using an array with optional items.
+
+
jsondecode({string}) *jsondecode()*
This parses a JSON formatted string and returns the equivalent
in Vim values. See |jsonencode()| for the relation between
JSON and Vim values.
The decoding is permissive:
- A trailing comma in an array and object is ignored.
- More floating point numbers are recognized, e.g. "1." for
"1.0".
The result must be a valid Vim type:
***************
*** 4320,4326 ****
used recursively: {}
v:false "false"
v:true "true"
! v:none nothing
v:null "null"
Note that using v:none is permitted, although the JSON
standard does not allow empty items. This can be useful for
--- 4430,4436 ----
used recursively: {}
v:false "false"
v:true "true"
! v:none "null"
v:null "null"
Note that using v:none is permitted, although the JSON
standard does not allow empty items. This can be useful for
*** ../vim-7.4.1278/runtime/doc/channel.txt 2016-02-05 22:36:09.733738185
+0100
--- runtime/doc/channel.txt 2016-02-07 17:07:07.666721855 +0100
***************
*** 1,4 ****
! *channel.txt* For Vim version 7.4. Last change: 2016 Feb 05
VIM REFERENCE MANUAL by Bram Moolenaar
--- 1,4 ----
! *channel.txt* For Vim version 7.4. Last change: 2016 Feb 07
VIM REFERENCE MANUAL by Bram Moolenaar
***************
*** 16,22 ****
1. Demo |channel-demo|
2. Opening a channel |channel-open|
! 3. Using a JSON channel |channel-use|
4. Vim commands |channel-commands|
5. Using a raw channel |channel-use|
6. Job control |job-control|
--- 16,22 ----
1. Demo |channel-demo|
2. Opening a channel |channel-open|
! 3. Using a JSON or JS channel |channel-use|
4. Vim commands |channel-commands|
5. Using a raw channel |channel-use|
6. Job control |job-control|
***************
*** 77,82 ****
--- 77,83 ----
"mode" can be: *channel-mode*
"json" - Use JSON, see below; most convenient way. Default.
+ "js" - Use JavaScript encoding, more efficient than JSON.
"raw" - Use raw messages
*channel-callback*
***************
*** 86,116 ****
func Handle(handle, msg)
echo 'Received: ' . a:msg
endfunc
! let handle = ch_open("localhost:8765", 'json', "Handle")
"waittime" is the time to wait for the connection to be made in milliseconds.
The default is zero, don't wait, which is useful if the server is supposed to
be running already. A negative number waits forever.
"timeout" is the time to wait for a request when blocking, using
! ch_sendexpr(). Again in millisecons. The default si 2000 (2 seconds).
! When "mode" is "json" the "msg" argument is the body of the received message,
! converted to Vim types.
When "mode" is "raw" the "msg" argument is the whole message as a string.
! When "mode" is "json" the "callback" is optional. When omitted it is only
! possible to receive a message after sending one.
The handler can be added or changed later: >
call ch_setcallback(handle, {callback})
! When "callback is empty (zero or an empty string) the handler is removed.
NOT IMPLEMENTED YET
The timeout can be changed later: >
call ch_settimeout(handle, {msec})
NOT IMPLEMENTED YET
!
Once done with the channel, disconnect it like this: >
call ch_close(handle)
--- 87,117 ----
func Handle(handle, msg)
echo 'Received: ' . a:msg
endfunc
! let handle = ch_open("localhost:8765", {"callback": "Handle"})
"waittime" is the time to wait for the connection to be made in milliseconds.
The default is zero, don't wait, which is useful if the server is supposed to
be running already. A negative number waits forever.
"timeout" is the time to wait for a request when blocking, using
! ch_sendexpr(). Again in milliseconds. The default is 2000 (2 seconds).
! When "mode" is "json" or "js" the "msg" argument is the body of the received
! message, converted to Vim types.
When "mode" is "raw" the "msg" argument is the whole message as a string.
! When "mode" is "json" or "js" the "callback" is optional. When omitted it is
! only possible to receive a message after sending one.
The handler can be added or changed later: >
call ch_setcallback(handle, {callback})
! When "callback" is empty (zero or an empty string) the handler is removed.
NOT IMPLEMENTED YET
The timeout can be changed later: >
call ch_settimeout(handle, {msec})
NOT IMPLEMENTED YET
! *E906*
Once done with the channel, disconnect it like this: >
call ch_close(handle)
***************
*** 123,134 ****
*E896* *E630* *E631*
==============================================================================
! 3. Using a JSON channel *channel-use*
If {mode} is "json" then a message can be sent synchronously like this: >
let response = ch_sendexpr(handle, {expr})
This awaits a response from the other side.
To send a message, without handling a response: >
call ch_sendexpr(handle, {expr}, 0)
--- 124,138 ----
*E896* *E630* *E631*
==============================================================================
! 3. Using a JSON or JS channel *channel-use*
If {mode} is "json" then a message can be sent synchronously like this: >
let response = ch_sendexpr(handle, {expr})
This awaits a response from the other side.
+ When {mode} is "js" this works the same, except that the messages use
+ JavaScript encoding. See |jsencode()| for the difference.
+
To send a message, without handling a response: >
call ch_sendexpr(handle, {expr}, 0)
***************
*** 231,237 ****
to avoid confusion with message that Vim sends.
{result} is the result of the evaluation and is JSON encoded. If the
! evaluation fails it is the string "ERROR".
Command "expr" ~
--- 235,242 ----
to avoid confusion with message that Vim sends.
{result} is the result of the evaluation and is JSON encoded. If the
! evaluation fails or the result can't be encoded in JSON it is the string
! "ERROR".
Command "expr" ~
*** ../vim-7.4.1278/src/testdir/test_json.vim 2016-02-07 16:53:08.779395103
+0100
--- src/testdir/test_json.vim 2016-02-07 18:36:14.467351645 +0100
***************
*** 32,40 ****
--- 32,43 ----
let s:varl3 = [l3, l3]
let s:jsond1 = '{"a":1,"b":"bee","c":[1,2]}'
+ let s:jsd1 = '{a:1,b:"bee",c:[1,2]}'
let s:vard1 = {"a": 1, "b": "bee","c": [1,2]}
let s:jsond2 = '{"1":1,"2":{"a":"aa","b":{},"c":"cc"},"3":3}'
+ let s:jsd2 = '{"1":1,"2":{a:"aa",b:{},c:"cc"},"3":3}'
let s:jsond2s = " { \"1\" : 1 , \"2\" :\n{ \"a\"\r: \"aa\" , \"b\" :
{\<Tab>} , \"c\" : \"cc\" } , \"3\" : 3 }\r\n"
+ let s:jsd2s = " { \"1\" : 1 , \"2\" :\n{ a\r: \"aa\" , b : {\<Tab>} , c :
\"cc\" } , \"3\" : 3 }\r\n"
let s:vard2 = {"1": 1, "2": 2, "3": 3}
let d2 = {"a": "aa", "b": s:vard2, "c": "cc"}
let s:vard2["2"] = d2
***************
*** 42,52 ****
let d3 = {"a": 1, "b": 2}
let s:vard3 = {"x": d3, "y": d3}
let s:jsond3 = '{"x":{"a":1,"b":2},"y":{"a":1,"b":2}}'
! let s:jsonvals = '[true,false,,null]'
! let s:varvals = [v:true, v:false, v:none, v:null]
! func Test_encode()
call assert_equal(s:json1, jsonencode(s:var1))
call assert_equal(s:json2, jsonencode(s:var2))
call assert_equal(s:json3, jsonencode(s:var3))
--- 45,60 ----
let d3 = {"a": 1, "b": 2}
let s:vard3 = {"x": d3, "y": d3}
let s:jsond3 = '{"x":{"a":1,"b":2},"y":{"a":1,"b":2}}'
+ let s:jsd3 = '{x:{a:1,b:2},y:{a:1,b:2}}'
+ let s:vard4 = {"key": v:none}
+ let s:vard4x = {"key": v:null}
+ let s:jsond4 = '{"key":null}'
+ let s:jsd4 = '{key:null}'
! let s:jsonvals = '[true,false,null,null]'
! let s:varvals = [v:true, v:false, v:null, v:null]
! func Test_json_encode()
call assert_equal(s:json1, jsonencode(s:var1))
call assert_equal(s:json2, jsonencode(s:var2))
call assert_equal(s:json3, jsonencode(s:var3))
***************
*** 69,86 ****
call assert_equal(s:jsond1, jsonencode(s:vard1))
call assert_equal(s:jsond2, jsonencode(s:vard2))
call assert_equal(s:jsond3, jsonencode(s:vard3))
call assert_equal(s:jsonvals, jsonencode(s:varvals))
call assert_fails('echo jsonencode(function("tr"))', 'E474:')
call assert_fails('echo jsonencode([function("tr")])', 'E474:')
- call assert_fails('echo jsonencode({"key":v:none})', 'E474:')
silent! let res = jsonencode(function("tr"))
call assert_equal("", res)
endfunc
! func Test_decode()
call assert_equal(s:var1, jsondecode(s:json1))
call assert_equal(s:var2, jsondecode(s:json2))
call assert_equal(s:var3, jsondecode(s:json3))
--- 77,94 ----
call assert_equal(s:jsond1, jsonencode(s:vard1))
call assert_equal(s:jsond2, jsonencode(s:vard2))
call assert_equal(s:jsond3, jsonencode(s:vard3))
+ call assert_equal(s:jsond4, jsonencode(s:vard4))
call assert_equal(s:jsonvals, jsonencode(s:varvals))
call assert_fails('echo jsonencode(function("tr"))', 'E474:')
call assert_fails('echo jsonencode([function("tr")])', 'E474:')
silent! let res = jsonencode(function("tr"))
call assert_equal("", res)
endfunc
! func Test_json_decode()
call assert_equal(s:var1, jsondecode(s:json1))
call assert_equal(s:var2, jsondecode(s:json2))
call assert_equal(s:var3, jsondecode(s:json3))
***************
*** 103,109 ****
--- 111,119 ----
call assert_equal(s:vard1, jsondecode(s:jsond1))
call assert_equal(s:vard2x, jsondecode(s:jsond2))
+ call assert_equal(s:vard2x, jsondecode(s:jsond2s))
call assert_equal(s:vard3, jsondecode(s:jsond3))
+ call assert_equal(s:vard4x, jsondecode(s:jsond4))
call assert_equal(s:varvals, jsondecode(s:jsonvals))
***************
*** 134,137 ****
--- 144,253 ----
call assert_fails('call jsondecode("[1")', "E474:")
call assert_fails('call jsondecode("[1,")', "E474:")
call assert_fails('call jsondecode("[1 2]")', "E474:")
+
+ call assert_fails('call jsondecode("[1,,2]")', "E474:")
+ endfunc
+
+ let s:jsl5 = '[7,,,]'
+ let s:varl5 = [7, v:none, v:none]
+
+ func Test_js_encode()
+ call assert_equal(s:json1, jsencode(s:var1))
+ call assert_equal(s:json2, jsencode(s:var2))
+ call assert_equal(s:json3, jsencode(s:var3))
+ call assert_equal(s:json4, jsencode(s:var4))
+ call assert_equal(s:json5, jsencode(s:var5))
+
+ if has('multi_byte')
+ call assert_equal(s:jsonmb, jsencode(s:varmb))
+ endif
+
+ call assert_equal(s:jsonnr, jsencode(s:varnr))
+ if has('float')
+ call assert_equal(s:jsonfl, jsencode(s:varfl))
+ endif
+
+ call assert_equal(s:jsonl1, jsencode(s:varl1))
+ call assert_equal(s:jsonl2, jsencode(s:varl2))
+ call assert_equal(s:jsonl3, jsencode(s:varl3))
+
+ call assert_equal(s:jsd1, jsencode(s:vard1))
+ call assert_equal(s:jsd2, jsencode(s:vard2))
+ call assert_equal(s:jsd3, jsencode(s:vard3))
+ call assert_equal(s:jsd4, jsencode(s:vard4))
+
+ call assert_equal(s:jsonvals, jsencode(s:varvals))
+
+ call assert_fails('echo jsencode(function("tr"))', 'E474:')
+ call assert_fails('echo jsencode([function("tr")])', 'E474:')
+
+ silent! let res = jsencode(function("tr"))
+ call assert_equal("", res)
+
+ call assert_equal(s:jsl5, jsencode(s:varl5))
+ endfunc
+
+ func Test_js_decode()
+ call assert_equal(s:var1, jsdecode(s:json1))
+ call assert_equal(s:var2, jsdecode(s:json2))
+ call assert_equal(s:var3, jsdecode(s:json3))
+ call assert_equal(s:var4, jsdecode(s:json4))
+ call assert_equal(s:var5, jsdecode(s:json5))
+
+ if has('multi_byte')
+ call assert_equal(s:varmb, jsdecode(s:jsonmb))
+ endif
+
+ call assert_equal(s:varnr, jsdecode(s:jsonnr))
+ if has('float')
+ call assert_equal(s:varfl, jsdecode(s:jsonfl))
+ endif
+
+ call assert_equal(s:varl1, jsdecode(s:jsonl1))
+ call assert_equal(s:varl2x, jsdecode(s:jsonl2))
+ call assert_equal(s:varl2x, jsdecode(s:jsonl2s))
+ call assert_equal(s:varl3, jsdecode(s:jsonl3))
+
+ call assert_equal(s:vard1, jsdecode(s:jsond1))
+ call assert_equal(s:vard1, jsdecode(s:jsd1))
+ call assert_equal(s:vard2x, jsdecode(s:jsond2))
+ call assert_equal(s:vard2x, jsdecode(s:jsd2))
+ call assert_equal(s:vard2x, jsdecode(s:jsond2s))
+ call assert_equal(s:vard2x, jsdecode(s:jsd2s))
+ call assert_equal(s:vard3, jsdecode(s:jsond3))
+ call assert_equal(s:vard3, jsdecode(s:jsd3))
+ call assert_equal(s:vard4x, jsdecode(s:jsond4))
+ call assert_equal(s:vard4x, jsdecode(s:jsd4))
+
+ call assert_equal(s:varvals, jsdecode(s:jsonvals))
+
+ call assert_equal(v:true, jsdecode('true'))
+ call assert_equal(type(v:true), type(jsdecode('true')))
+ call assert_equal(v:none, jsdecode(''))
+ call assert_equal(type(v:none), type(jsdecode('')))
+ call assert_equal("", jsdecode('""'))
+
+ call assert_equal({'n': 1}, jsdecode('{"n":1,}'))
+
+ call assert_fails('call jsdecode("\"")', "E474:")
+ call assert_fails('call jsdecode("blah")', "E474:")
+ call assert_fails('call jsdecode("true blah")', "E474:")
+ call assert_fails('call jsdecode("<foobar>")', "E474:")
+
+ call assert_fails('call jsdecode("{")', "E474:")
+ call assert_fails('call jsdecode("{foobar}")', "E474:")
+ call assert_fails('call jsdecode("{\"n\",")', "E474:")
+ call assert_fails('call jsdecode("{\"n\":")', "E474:")
+ call assert_fails('call jsdecode("{\"n\":1")', "E474:")
+ call assert_fails('call jsdecode("{\"n\":1,")', "E474:")
+ call assert_fails('call jsdecode("{\"n\",1}")', "E474:")
+ call assert_fails('call jsdecode("{-}")', "E474:")
+
+ call assert_fails('call jsdecode("[foobar]")', "E474:")
+ call assert_fails('call jsdecode("[")', "E474:")
+ call assert_fails('call jsdecode("[1")', "E474:")
+ call assert_fails('call jsdecode("[1,")', "E474:")
+ call assert_fails('call jsdecode("[1 2]")', "E474:")
+
+ call assert_equal(s:varl5, jsdecode(s:jsl5))
endfunc
*** ../vim-7.4.1278/src/version.c 2016-02-07 16:53:08.783395062 +0100
--- src/version.c 2016-02-07 19:08:51.167015826 +0100
***************
*** 749,750 ****
--- 749,752 ----
{ /* Add new patch number below this line */
+ /**/
+ 1279,
/**/
--
hundred-and-one symptoms of being an internet addict:
170. You introduce your wife as "[email protected]" and refer to your
children as "forked processes."
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.