Patch 7.4.1154
Problem:    No support for JSON.
Solution:   Add jsonencode() and jsondecode().  Also add v:false, v:true,
            v:null and v:none.
Files:      src/json.c, src/eval.c, src/proto.h, src/structs.h, src/vim.h,
            src/if_lua.c, src/if_mzsch.c, src/if_ruby.c, src/if_py_both.h,
            src/globals.h, src/Makefile, src/Make_bc3.mak, src/Make_bc5.mak,
            src/Make_cyg_ming.mak, src/Make_dice.mak, src/Make_ivc.mak,
            src/Make_manx.mak, src/Make_morph.mak, src/Make_mvc.mak,
            src/Make_sas.mak, src/Make_vms.mms, src/proto/json.pro,
            src/proto/eval.pro, src/testdir/test_json.vim,
            src/testdir/test_alot.vim, Filelist, runtime/doc/eval.txt


*** ../vim-7.4.1153/src/json.c  2016-01-23 19:32:31.331223590 +0100
--- src/json.c  2016-01-23 19:17:42.068467887 +0100
***************
*** 0 ****
--- 1,509 ----
+ /* vi:set ts=8 sts=4 sw=4:
+  *
+  * VIM - Vi IMproved  by Bram Moolenaar
+  *
+  * Do ":help uganda"  in Vim to read copying and usage conditions.
+  * Do ":help credits" in Vim to see a list of people who contributed.
+  * See README.txt for an overview of the Vim source code.
+  */
+ 
+ /*
+  * json.c: Encoding and decoding JSON.
+  *
+  * Follows this standard: http://www.ietf.org/rfc/rfc4627.txt
+  */
+ 
+ #include "vim.h"
+ 
+ #if defined(FEAT_EVAL) || defined(PROTO)
+ static void json_decode_item(js_read_T *reader, typval_T *res);
+ 
+ /*
+  * Encode "val" into a JSON format string.
+  */
+     char_u *
+ json_encode(typval_T *val)
+ {
+     garray_T ga;
+ 
+     /* Store bytes in the growarray. */
+     ga_init2(&ga, 1, 4000);
+     json_encode_item(&ga, val, get_copyID());
+     return ga.ga_data;
+ }
+ 
+     static void
+ write_string(garray_T *gap, char_u *str)
+ {
+     char_u    *res = str;
+     char_u    numbuf[NUMBUFLEN];
+ 
+     if (res == NULL)
+       ga_concat(gap, (char_u *)"null");
+     else
+     {
+       ga_append(gap, '"');
+       while (*res != NUL)
+       {
+           int c = PTR2CHAR(res);
+ 
+           switch (c)
+           {
+               case 0x08:
+                   ga_append(gap, '\\'); ga_append(gap, 'b'); break;
+               case 0x09:
+                   ga_append(gap, '\\'); ga_append(gap, 't'); break;
+               case 0x0a:
+                   ga_append(gap, '\\'); ga_append(gap, 'n'); break;
+               case 0x0c:
+                   ga_append(gap, '\\'); ga_append(gap, 'f'); break;
+               case 0x0d:
+                   ga_append(gap, '\\'); ga_append(gap, 'r'); break;
+               case 0x22: /* " */
+               case 0x5c: /* \ */
+                   ga_append(gap, '\\');
+                   ga_append(gap, c);
+                   break;
+               default:
+                   if (c >= 0x20)
+                   {
+                       numbuf[mb_char2bytes(c, numbuf)] = NUL;
+                       ga_concat(gap, numbuf);
+                   }
+                   else
+                   {
+                       vim_snprintf((char *)numbuf, NUMBUFLEN,
+                                                        "\\u%04lx", (long)c);
+                       ga_concat(gap, numbuf);
+                   }
+           }
+           mb_cptr_adv(res);
+       }
+       ga_append(gap, '"');
+     }
+ }
+ 
+     void
+ json_encode_item(garray_T *gap, typval_T *val, int copyID)
+ {
+     char_u    numbuf[NUMBUFLEN];
+     char_u    *res;
+     list_T    *l;
+     dict_T    *d;
+ 
+     switch (val->v_type)
+     {
+       case VAR_SPECIAL:
+           switch(val->vval.v_number)
+           {
+               case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
+               case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
+               case VVAL_NONE: break;
+               case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
+           }
+           break;
+ 
+       case VAR_NUMBER:
+           vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
+                                                   (long)val->vval.v_number);
+           ga_concat(gap, numbuf);
+           break;
+ 
+       case VAR_STRING:
+           res = val->vval.v_string;
+           write_string(gap, res);
+           break;
+ 
+       case VAR_FUNC:
+           /* no JSON equivalent, skip */
+           break;
+ 
+       case VAR_LIST:
+           l = val->vval.v_list;
+           if (l == NULL)
+               ga_concat(gap, (char_u *)"null");
+           else
+           {
+               if (l->lv_copyID == copyID)
+                   ga_concat(gap, (char_u *)"[]");
+               else
+               {
+                   listitem_T  *li;
+ 
+                   l->lv_copyID = copyID;
+                   ga_append(gap, '[');
+                   for (li = l->lv_first; li != NULL && !got_int; )
+                   {
+                       json_encode_item(gap, &li->li_tv, copyID);
+                       li = li->li_next;
+                       if (li != NULL)
+                           ga_append(gap, ',');
+                   }
+                   ga_append(gap, ']');
+               }
+           }
+           break;
+ 
+       case VAR_DICT:
+           d = val->vval.v_dict;
+           if (d == NULL)
+               ga_concat(gap, (char_u *)"null");
+           else
+           {
+               if (d->dv_copyID == copyID)
+                   ga_concat(gap, (char_u *)"{}");
+               else
+               {
+                   int         first = TRUE;
+                   int         todo = (int)d->dv_hashtab.ht_used;
+                   hashitem_T  *hi;
+ 
+                   d->dv_copyID = copyID;
+                   ga_append(gap, '{');
+ 
+                   for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
+                                                                        ++hi)
+                       if (!HASHITEM_EMPTY(hi))
+                       {
+                           --todo;
+                           if (first)
+                               first = FALSE;
+                           else
+                               ga_append(gap, ',');
+                           write_string(gap, hi->hi_key);
+                           ga_append(gap, ':');
+                           json_encode_item(gap, &dict_lookup(hi)->di_tv,
+                                                                     copyID);
+                       }
+                   ga_append(gap, '}');
+               }
+           }
+           break;
+ 
+ #ifdef FEAT_FLOAT
+       case VAR_FLOAT:
+           vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
+           ga_concat(gap, numbuf);
+           break;
+ #endif
+       default: EMSG2(_(e_intern2), "json_encode_item()"); break;
+     }
+ }
+ 
+ /*
+  * Skip white space in "reader".
+  */
+     static void
+ json_skip_white(js_read_T *reader)
+ {
+     int c;
+ 
+     while ((c = reader->js_buf[reader->js_used]) == ' '
+                                          || c == TAB || c == NL || c == CAR)
+       ++reader->js_used;
+ }
+ 
+ /*
+  * Make sure there are at least enough characters buffered to read a number.
+  */
+     static void
+ json_fill_buffer(js_read_T *reader UNUSED)
+ {
+     /* TODO */
+ }
+ 
+     static void
+ json_decode_array(js_read_T *reader, typval_T *res)
+ {
+     char_u    *p;
+     typval_T  item;
+     listitem_T        *li;
+ 
+     if (rettv_list_alloc(res) == FAIL)
+       goto fail;
+     ++reader->js_used; /* consume the '[' */
+ 
+     while (TRUE)
+     {
+       json_skip_white(reader);
+       p = reader->js_buf + reader->js_used;
+       if (*p == NUL)
+           goto fail;
+       if (*p == ']')
+       {
+           ++reader->js_used; /* consume the ']' */
+           return;
+       }
+ 
+       if (!reader->js_eof && (int)(reader->js_end - p) < NUMBUFLEN)
+           json_fill_buffer(reader);
+ 
+       json_decode_item(reader, &item);
+       li = listitem_alloc();
+       if (li == NULL)
+           return;
+       li->li_tv = item;
+       list_append(res->vval.v_list, li);
+ 
+       json_skip_white(reader);
+       p = reader->js_buf + reader->js_used;
+       if (*p == ',')
+           ++reader->js_used;
+       else if (*p != ']')
+           goto fail;
+     }
+ fail:
+     res->v_type = VAR_SPECIAL;
+     res->vval.v_number = VVAL_NONE;
+ }
+ 
+     static void
+ json_decode_object(js_read_T *reader, typval_T *res)
+ {
+     char_u    *p;
+     typval_T  tvkey;
+     typval_T  item;
+     dictitem_T        *di;
+     char_u    buf[NUMBUFLEN];
+     char_u    *key;
+ 
+     if (rettv_dict_alloc(res) == FAIL)
+       goto fail;
+     ++reader->js_used; /* consume the '{' */
+ 
+     while (TRUE)
+     {
+       json_skip_white(reader);
+       p = reader->js_buf + reader->js_used;
+       if (*p == NUL)
+           goto fail;
+       if (*p == '}')
+       {
+           ++reader->js_used; /* consume the '}' */
+           return;
+       }
+ 
+       if (!reader->js_eof && (int)(reader->js_end - p) < NUMBUFLEN)
+           json_fill_buffer(reader);
+       json_decode_item(reader, &tvkey);
+       key = get_tv_string_buf_chk(&tvkey, buf);
+       if (key == NULL || *key == NUL)
+       {
+           /* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */
+           if (key != NULL)
+               EMSG(_(e_emptykey));
+           clear_tv(&tvkey);
+           goto fail;
+       }
+ 
+       json_skip_white(reader);
+       p = reader->js_buf + reader->js_used;
+       if (*p != ':')
+       {
+           clear_tv(&tvkey);
+           goto fail;
+       }
+       ++reader->js_used;
+       json_skip_white(reader);
+ 
+       if (!reader->js_eof && (int)(reader->js_end - p) < NUMBUFLEN)
+           json_fill_buffer(reader);
+       json_decode_item(reader, &item);
+ 
+       di = dictitem_alloc(key);
+       clear_tv(&tvkey);
+       if (di == NULL)
+       {
+           clear_tv(&item);
+           goto fail;
+       }
+       di->di_tv = item;
+       dict_add(res->vval.v_dict, di);
+ 
+       json_skip_white(reader);
+       p = reader->js_buf + reader->js_used;
+       if (*p == ',')
+           ++reader->js_used;
+       else if (*p != '}')
+           goto fail;
+     }
+ fail:
+     res->v_type = VAR_SPECIAL;
+     res->vval.v_number = VVAL_NONE;
+ }
+ 
+     static void
+ json_decode_string(js_read_T *reader, typval_T *res)
+ {
+     garray_T    ga;
+     int               len;
+     char_u    *p = reader->js_buf + reader->js_used + 1;
+     int               c;
+     long      nr;
+     char_u    buf[NUMBUFLEN];
+ 
+     ga_init2(&ga, 1, 200);
+ 
+     /* TODO: fill buffer when needed. */
+     while (*p != NUL && *p != '"')
+     {
+       if (*p == '\\')
+       {
+           c = -1;
+           switch (p[1])
+           {
+               case 'b': c = BS; break;
+               case 't': c = TAB; break;
+               case 'n': c = NL; break;
+               case 'f': c = FF; break;
+               case 'r': c = CAR; break;
+               case 'u':
+                   vim_str2nr(p + 2, NULL, &len,
+                                    STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
+                   p += len + 2;
+ #ifdef FEAT_MBYTE
+                   buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
+                   ga_concat(&ga, buf);
+ #else
+                   ga_append(&ga, nr);
+ #endif
+                   break;
+               default: c = p[1]; break;
+           }
+           if (c > 0)
+           {
+               p += 2;
+               ga_append(&ga, c);
+           }
+       }
+       else
+       {
+           len = MB_PTR2LEN(p);
+           if (ga_grow(&ga, len) == OK)
+           {
+               mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
+               ga.ga_len += len;
+           }
+           p += len;
+       }
+       if (!reader->js_eof && (int)(reader->js_end - p) < NUMBUFLEN)
+       {
+           reader->js_used = (int)(p - reader->js_buf);
+           json_fill_buffer(reader);
+           p = reader->js_buf + reader->js_used;
+       }
+     }
+     reader->js_used = (int)(p - reader->js_buf);
+     if (*p == '"')
+     {
+       ++reader->js_used;
+       res->v_type = VAR_STRING;
+       res->vval.v_string = vim_strsave(ga.ga_data);
+     }
+     else
+     {
+       res->v_type = VAR_SPECIAL;
+       res->vval.v_number = VVAL_NONE;
+     }
+     ga_clear(&ga);
+ }
+ 
+ /*
+  * Decode one item and put it in "result".
+  * Must already have skipped white space.
+  */
+     static void
+ json_decode_item(js_read_T *reader, typval_T *res)
+ {
+     char_u    *p = reader->js_buf + reader->js_used;
+ 
+     switch (*p)
+     {
+       case '[': /* array */
+           json_decode_array(reader, res);
+           return;
+ 
+       case '{': /* object */
+           json_decode_object(reader, res);
+           return;
+ 
+       case '"': /* string */
+           json_decode_string(reader, res);
+           return;
+ 
+       case ',': /* comma: empty item */
+       case NUL: /* empty */
+           res->v_type = VAR_SPECIAL;
+           res->vval.v_number = VVAL_NONE;
+           return;
+ 
+       default:
+           if (VIM_ISDIGIT(*p) || *p == '-')
+           {
+               int     len;
+               char_u  *sp = p;
+ #ifdef FEAT_FLOAT
+               if (*sp == '-')
+                   ++sp;
+               sp = skipdigits(sp);
+               if (*sp == '.' || *sp == 'e' || *sp == 'E')
+               {
+                   res->v_type = VAR_FLOAT;
+                   len = string2float(p, &res->vval.v_float);
+               }
+               else
+ #endif
+               {
+                   long nr;
+ 
+                   res->v_type = VAR_NUMBER;
+                   vim_str2nr(reader->js_buf + reader->js_used,
+                           NULL, &len, 0, /* what */
+                           &nr, NULL, 0);
+                   res->vval.v_number = nr;
+               }
+               reader->js_used += len;
+               return;
+           }
+           if (STRNICMP((char *)p, "false", 5) == 0)
+           {
+               reader->js_used += 5;
+               res->v_type = VAR_SPECIAL;
+               res->vval.v_number = VVAL_FALSE;
+               return;
+           }
+           if (STRNICMP((char *)p, "true", 4) == 0)
+           {
+               reader->js_used += 4;
+               res->v_type = VAR_SPECIAL;
+               res->vval.v_number = VVAL_TRUE;
+               return;
+           }
+           if (STRNICMP((char *)p, "null", 4) == 0)
+           {
+               reader->js_used += 4;
+               res->v_type = VAR_SPECIAL;
+               res->vval.v_number = VVAL_NULL;
+               return;
+           }
+           break;
+     }
+ 
+     EMSG(_(e_invarg));
+     res->v_type = VAR_SPECIAL;
+     res->vval.v_number = VVAL_NONE;
+ }
+ 
+ /*
+  * Decode the JSON from "reader" and store the result in "res".
+  */
+     void
+ json_decode(js_read_T *reader, typval_T *res)
+ {
+     json_skip_white(reader);
+     json_decode_item(reader, res);
+     json_skip_white(reader);
+     if (reader->js_buf[reader->js_used] != NUL)
+       EMSG(_(e_invarg));
+ }
+ #endif
*** ../vim-7.4.1153/src/eval.c  2016-01-21 23:34:54.244356654 +0100
--- src/eval.c  2016-01-23 19:42:48.960799020 +0100
***************
*** 99,105 ****
  static char *e_missbrac = N_("E111: Missing ']'");
  static char *e_listarg = N_("E686: Argument of %s must be a List");
  static char *e_listdictarg = N_("E712: Argument of %s must be a List or 
Dictionary");
- static char *e_emptykey = N_("E713: Cannot use empty key for Dictionary");
  static char *e_listreq = N_("E714: List required");
  static char *e_dictreq = N_("E715: Dictionary required");
  static char *e_toomanyarg = N_("E118: Too many arguments for function: %s");
--- 99,104 ----
***************
*** 371,376 ****
--- 370,379 ----
      {VV_NAME("option_old",     VAR_STRING), VV_RO},
      {VV_NAME("option_type",    VAR_STRING), VV_RO},
      {VV_NAME("errors",                 VAR_LIST), 0},
+     {VV_NAME("false",          VAR_SPECIAL), VV_RO},
+     {VV_NAME("true",           VAR_SPECIAL), VV_RO},
+     {VV_NAME("null",           VAR_SPECIAL), VV_RO},
+     {VV_NAME("none",           VAR_SPECIAL), VV_RO},
  };
  
  /* shorthand */
***************
*** 428,434 ****
  static int get_string_tv __ARGS((char_u **arg, typval_T *rettv, int 
evaluate));
  static int get_lit_string_tv __ARGS((char_u **arg, typval_T *rettv, int 
evaluate));
  static int get_list_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
- static int rettv_list_alloc __ARGS((typval_T *rettv));
  static long list_len __ARGS((list_T *l));
  static int list_equal __ARGS((list_T *l1, list_T *l2, int ic, int recursive));
  static int dict_equal __ARGS((dict_T *d1, dict_T *d2, int ic, int recursive));
--- 431,436 ----
***************
*** 443,449 ****
  static int list_join_inner __ARGS((garray_T *gap, list_T *l, char_u *sep, int 
echo_style, int copyID, garray_T *join_gap));
  static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo, 
int copyID));
  static int free_unref_items __ARGS((int copyID));
- static int rettv_dict_alloc __ARGS((typval_T *rettv));
  static dictitem_T *dictitem_copy __ARGS((dictitem_T *org));
  static void dictitem_remove __ARGS((dict_T *dict, dictitem_T *item));
  static dict_T *dict_copy __ARGS((dict_T *orig, int deep, int copyID));
--- 445,450 ----
***************
*** 453,461 ****
  static char_u *echo_string __ARGS((typval_T *tv, char_u **tofree, char_u 
*numbuf, int copyID));
  static char_u *tv2string __ARGS((typval_T *tv, char_u **tofree, char_u 
*numbuf, int copyID));
  static char_u *string_quote __ARGS((char_u *str, int function));
- #ifdef FEAT_FLOAT
- static int string2float __ARGS((char_u *text, float_T *value));
- #endif
  static int get_env_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
  static int find_internal_func __ARGS((char_u *name));
  static char_u *deref_func_name __ARGS((char_u *name, int *lenp, int 
no_autoload));
--- 454,459 ----
***************
*** 617,622 ****
--- 615,622 ----
  static void f_islocked __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_items __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_join __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_jsondecode __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_jsonencode __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_keys __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_last_buffer_nr __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_len __ARGS((typval_T *argvars, typval_T *rettv));
***************
*** 816,822 ****
  static linenr_T get_tv_lnum_buf __ARGS((typval_T *argvars, buf_T *buf));
  static char_u *get_tv_string __ARGS((typval_T *varp));
  static char_u *get_tv_string_buf __ARGS((typval_T *varp, char_u *buf));
- static char_u *get_tv_string_buf_chk __ARGS((typval_T *varp, char_u *buf));
  static dictitem_T *find_var __ARGS((char_u *name, hashtab_T **htp, int 
no_autoload));
  static dictitem_T *find_var_in_ht __ARGS((hashtab_T *ht, int htname, char_u 
*varname, int no_autoload));
  static hashtab_T *find_var_ht __ARGS((char_u *name, char_u **varname));
--- 816,821 ----
***************
*** 915,920 ****
--- 914,925 ----
      set_vim_var_nr(VV_HLSEARCH, 1L);
      set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
      set_vim_var_list(VV_ERRORS, list_alloc());
+ 
+     set_vim_var_nr(VV_FALSE, VVAL_FALSE);
+     set_vim_var_nr(VV_TRUE, VVAL_TRUE);
+     set_vim_var_nr(VV_NONE, VVAL_NONE);
+     set_vim_var_nr(VV_NULL, VVAL_NULL);
+ 
      set_reg_var(0);  /* default for v:register is not 0 but '"' */
  
  #ifdef EBCDIC
***************
*** 3080,3092 ****
      char_u    numbuf[NUMBUFLEN];
      char_u    *s;
  
!     /* Can't do anything with a Funcref or a Dict on the right. */
!     if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT)
      {
        switch (tv1->v_type)
        {
            case VAR_DICT:
            case VAR_FUNC:
                break;
  
            case VAR_LIST:
--- 3085,3099 ----
      char_u    numbuf[NUMBUFLEN];
      char_u    *s;
  
!     /* Can't do anything with a Funcref, Dict, v:true on the right. */
!     if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT
!                                               && tv2->v_type != VAR_SPECIAL)
      {
        switch (tv1->v_type)
        {
            case VAR_DICT:
            case VAR_FUNC:
+           case VAR_SPECIAL:
                break;
  
            case VAR_LIST:
***************
*** 5390,5395 ****
--- 5397,5406 ----
        return FAIL;
      }
  #endif
+     else if (rettv->v_type == VAR_SPECIAL)
+     {
+       return FAIL;
+     }
  
      init_tv(&var1);
      init_tv(&var2);
***************
*** 5999,6005 ****
   * Allocate an empty list for a return value.
   * Returns OK or FAIL.
   */
!     static int
  rettv_list_alloc(rettv)
      typval_T  *rettv;
  {
--- 6010,6016 ----
   * Allocate an empty list for a return value.
   * Returns OK or FAIL.
   */
!     int
  rettv_list_alloc(rettv)
      typval_T  *rettv;
  {
***************
*** 6246,6251 ****
--- 6257,6265 ----
            s1 = get_tv_string_buf(tv1, buf1);
            s2 = get_tv_string_buf(tv2, buf2);
            return ((ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2)) == 0);
+ 
+       case VAR_SPECIAL:
+           return tv1->vval.v_number == tv2->vval.v_number;
      }
  
      EMSG2(_(e_intern2), "tv_equal()");
***************
*** 6838,6843 ****
--- 6852,6868 ----
  }
  
  /*
+  * Return the next (unique) copy ID.
+  * Used for serializing nested structures.
+  */
+     int
+ get_copyID()
+ {
+     current_copyID += COPYID_INC;
+     return current_copyID;
+ }
+ 
+ /*
   * Garbage collection for lists and dictionaries.
   *
   * We use reference counts to be able to free most items right away when they
***************
*** 6883,6890 ****
  
      /* We advance by two because we add one for items referenced through
       * previous_funccal. */
!     current_copyID += COPYID_INC;
!     copyID = current_copyID;
  
      /*
       * 1. Go through all accessible variables and mark all lists and dicts
--- 6908,6914 ----
  
      /* We advance by two because we add one for items referenced through
       * previous_funccal. */
!     copyID = get_copyID();
  
      /*
       * 1. Go through all accessible variables and mark all lists and dicts
***************
*** 7236,7242 ****
   * Allocate an empty dict for a return value.
   * Returns OK or FAIL.
   */
!     static int
  rettv_dict_alloc(rettv)
      typval_T  *rettv;
  {
--- 7260,7266 ----
   * Allocate an empty dict for a return value.
   * Returns OK or FAIL.
   */
!     int
  rettv_dict_alloc(rettv)
      typval_T  *rettv;
  {
***************
*** 7891,7896 ****
--- 7915,7932 ----
            break;
  #endif
  
+       case VAR_SPECIAL:
+           *tofree = NULL;
+           switch (tv->vval.v_number)
+           {
+               case VVAL_FALSE: r = (char_u *)"false"; break;
+               case VVAL_TRUE: r = (char_u *)"true"; break;
+               case VVAL_NONE: r = (char_u *)"none"; break;
+               case VVAL_NULL: r = (char_u *)"null"; break;
+               default: EMSG2(_(e_intern2), "echo_string(special)");
+           }
+           break;
+ 
        default:
            EMSG2(_(e_intern2), "echo_string()");
            *tofree = NULL;
***************
*** 7932,7937 ****
--- 7968,7974 ----
        case VAR_NUMBER:
        case VAR_LIST:
        case VAR_DICT:
+       case VAR_SPECIAL:
            break;
        default:
            EMSG2(_(e_intern2), "tv2string()");
***************
*** 7985,7998 ****
      return s;
  }
  
! #ifdef FEAT_FLOAT
  /*
   * Convert the string "text" to a floating point number.
   * This uses strtod().  setlocale(LC_NUMERIC, "C") has been used to make sure
   * this always uses a decimal point.
   * Returns the length of the text that was consumed.
   */
!     static int
  string2float(text, value)
      char_u    *text;
      float_T   *value;     /* result stored here */
--- 8022,8035 ----
      return s;
  }
  
! #if defined(FEAT_FLOAT) || defined(PROTO)
  /*
   * Convert the string "text" to a floating point number.
   * This uses strtod().  setlocale(LC_NUMERIC, "C") has been used to make sure
   * this always uses a decimal point.
   * Returns the length of the text that was consumed.
   */
!     int
  string2float(text, value)
      char_u    *text;
      float_T   *value;     /* result stored here */
***************
*** 8237,8242 ****
--- 8274,8281 ----
      {"islocked",      1, 1, f_islocked},
      {"items",         1, 1, f_items},
      {"join",          1, 2, f_join},
+     {"jsondecode",    1, 1, f_jsondecode},
+     {"jsonencode",    1, 1, f_jsonencode},
      {"keys",          1, 1, f_keys},
      {"last_buffer_nr",        0, 0, f_last_buffer_nr},/* obsolete */
      {"len",           1, 1, f_len},
***************
*** 14394,14399 ****
--- 14433,14466 ----
  }
  
  /*
+  * "jsondecode()" function
+  */
+     static void
+ f_jsondecode(argvars, rettv)
+     typval_T  *argvars;
+     typval_T  *rettv;
+ {
+     js_read_T reader;
+ 
+     reader.js_buf = get_tv_string(&argvars[0]);
+     reader.js_eof = TRUE;
+     reader.js_used = 0;
+     json_decode(&reader, rettv);
+ }
+ 
+ /*
+  * "jsonencode()" function
+  */
+     static void
+ f_jsonencode(argvars, rettv)
+     typval_T  *argvars;
+     typval_T  *rettv;
+ {
+     rettv->v_type = VAR_STRING;
+     rettv->vval.v_string = json_encode(&argvars[0]);
+ }
+ 
+ /*
   * "keys()" function
   */
      static void
***************
*** 21558,21563 ****
--- 21625,21631 ----
                varp->vval.v_dict = NULL;
                break;
            case VAR_NUMBER:
+           case VAR_SPECIAL:
                varp->vval.v_number = 0;
                break;
  #ifdef FEAT_FLOAT
***************
*** 21759,21765 ****
      return get_tv_string_buf_chk(varp, mybuf);
  }
  
!     static char_u *
  get_tv_string_buf_chk(varp, buf)
      typval_T  *varp;
      char_u    *buf;
--- 21827,21833 ----
      return get_tv_string_buf_chk(varp, mybuf);
  }
  
!     char_u *
  get_tv_string_buf_chk(varp, buf)
      typval_T  *varp;
      char_u    *buf;
***************
*** 22120,22127 ****
      char_u    *s;
      char_u    numbuf[NUMBUFLEN];
  
!     current_copyID += COPYID_INC;
!     s = echo_string(&v->di_tv, &tofree, numbuf, current_copyID);
      list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
                                         s == NULL ? (char_u *)"" : s, first);
      vim_free(tofree);
--- 22188,22194 ----
      char_u    *s;
      char_u    numbuf[NUMBUFLEN];
  
!     s = echo_string(&v->di_tv, &tofree, numbuf, get_copyID());
      list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
                                         s == NULL ? (char_u *)"" : s, first);
      vim_free(tofree);
***************
*** 22435,22440 ****
--- 22502,22508 ----
      switch (from->v_type)
      {
        case VAR_NUMBER:
+       case VAR_SPECIAL:
            to->vval.v_number = from->vval.v_number;
            break;
  #ifdef FEAT_FLOAT
***************
*** 22609,22616 ****
            }
            else if (eap->cmdidx == CMD_echo)
                msg_puts_attr((char_u *)" ", echo_attr);
!           current_copyID += COPYID_INC;
!           p = echo_string(&rettv, &tofree, numbuf, current_copyID);
            if (p != NULL)
                for ( ; *p != NUL && !got_int; ++p)
                {
--- 22677,22683 ----
            }
            else if (eap->cmdidx == CMD_echo)
                msg_puts_attr((char_u *)" ", echo_attr);
!           p = echo_string(&rettv, &tofree, numbuf, get_copyID());
            if (p != NULL)
                for ( ; *p != NUL && !got_int; ++p)
                {
*** ../vim-7.4.1153/src/proto.h 2014-08-10 13:34:59.060785459 +0200
--- src/proto.h 2016-01-22 20:33:01.384289200 +0100
***************
*** 95,100 ****
--- 95,101 ----
  # endif
  # include "hardcopy.pro"
  # include "hashtab.pro"
+ # include "json.pro"
  # include "main.pro"
  # include "mark.pro"
  # include "memfile.pro"
*** ../vim-7.4.1153/src/structs.h       2016-01-19 22:28:54.611593027 +0100
--- src/structs.h       2016-01-23 18:48:44.534435105 +0100
***************
*** 1138,1143 ****
--- 1138,1144 ----
  #define VAR_LIST    4 /* "v_list" is used */
  #define VAR_DICT    5 /* "v_dict" is used */
  #define VAR_FLOAT   6 /* "v_float" is used */
+ #define VAR_SPECIAL 7 /* "v_number" is used */
  
  /* Values for "dv_scope". */
  #define VAR_SCOPE     1       /* a:, v:, s:, etc. scope dictionaries */
***************
*** 2682,2684 ****
--- 2683,2697 ----
    UINT32_T state[8];
    char_u   buffer[64];
  } context_sha256_T;
+ 
+ /*
+  * Structure used for reading in json_decode().
+  */
+ typedef struct
+ {
+     char_u    *js_buf;        /* text to be decoded */
+     char_u    *js_end;        /* NUL in js_buf when js_eof is FALSE */
+     int               js_used;        /* bytes used from js_buf */
+     int               js_eof;         /* when TRUE js_buf is all there is */
+     FILE      *js_fd;         /* file descriptor to read more from */
+ } js_read_T;
*** ../vim-7.4.1153/src/vim.h   2016-01-20 22:47:57.665335718 +0100
--- src/vim.h   2016-01-23 19:38:58.939190501 +0100
***************
*** 1896,1902 ****
  #define VV_OPTION_OLD   60
  #define VV_OPTION_TYPE  61
  #define VV_ERRORS     62
! #define VV_LEN                63      /* number of v: vars */
  
  #ifdef FEAT_CLIPBOARD
  
--- 1896,1912 ----
  #define VV_OPTION_OLD   60
  #define VV_OPTION_TYPE  61
  #define VV_ERRORS     62
! #define VV_FALSE      63
! #define VV_TRUE               64
! #define VV_NULL               65
! #define VV_NONE               66
! #define VV_LEN                67      /* number of v: vars */
! 
! /* used for v_number in VAR_SPECIAL */
! #define VVAL_FALSE    0L
! #define VVAL_TRUE     1L
! #define VVAL_NONE     2L
! #define VVAL_NULL     3L
  
  #ifdef FEAT_CLIPBOARD
  
*** ../vim-7.4.1153/src/if_lua.c        2016-01-09 14:57:10.504884946 +0100
--- src/if_lua.c        2016-01-23 15:16:47.542331948 +0100
***************
*** 499,504 ****
--- 499,510 ----
        case VAR_DICT:
            luaV_pushdict(L, tv->vval.v_dict);
            break;
+       case VAR_SPECIAL:
+           if (tv->vval.v_number <= VVAL_TRUE)
+               lua_pushinteger(L, (int) tv->vval.v_number);
+           else
+               lua_pushnil(L);
+           break;
        default:
            lua_pushnil(L);
      }
***************
*** 510,516 ****
  {
      switch(lua_type(L, pos)) {
        case LUA_TBOOLEAN:
!           tv->v_type = VAR_NUMBER;
            tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos);
            break;
        case LUA_TSTRING:
--- 516,522 ----
  {
      switch(lua_type(L, pos)) {
        case LUA_TBOOLEAN:
!           tv->v_type = VAR_SPECIAL;
            tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos);
            break;
        case LUA_TSTRING:
*** ../vim-7.4.1153/src/if_mzsch.c      2016-01-16 16:20:23.712823243 +0100
--- src/if_mzsch.c      2016-01-23 15:19:22.464702083 +0100
***************
*** 3084,3089 ****
--- 3084,3097 ----
  
        MZ_GC_UNREG();
      }
+     else if (vim_value->v_type == VAR_SPECIAL)
+     {
+       if (vim_value->vval.v_number <= VVAL_TRUE)
+           result = scheme_make_integer((long)vim_value->vval.v_number);
+       else
+           result = scheme_null;
+       MZ_GC_CHECK();
+     }
      else
      {
        result = scheme_void;
***************
*** 3148,3155 ****
        copy_tv(found, tv);
      else if (SCHEME_VOIDP(obj))
      {
!       tv->v_type = VAR_NUMBER;
!       tv->vval.v_number = 0;
      }
      else if (SCHEME_INTP(obj))
      {
--- 3156,3163 ----
        copy_tv(found, tv);
      else if (SCHEME_VOIDP(obj))
      {
!       tv->v_type = VAR_SPECIAL;
!       tv->vval.v_number = VVAL_NULL;
      }
      else if (SCHEME_INTP(obj))
      {
***************
*** 3158,3164 ****
      }
      else if (SCHEME_BOOLP(obj))
      {
!       tv->v_type = VAR_NUMBER;
        tv->vval.v_number = SCHEME_TRUEP(obj);
      }
  # ifdef FEAT_FLOAT
--- 3166,3172 ----
      }
      else if (SCHEME_BOOLP(obj))
      {
!       tv->v_type = VAR_SPECIAL;
        tv->vval.v_number = SCHEME_TRUEP(obj);
      }
  # ifdef FEAT_FLOAT
*** ../vim-7.4.1153/src/if_ruby.c       2016-01-19 13:21:55.829334463 +0100
--- src/if_ruby.c       2016-01-23 15:22:03.583007468 +0100
***************
*** 1032,1037 ****
--- 1032,1042 ----
                }
            }
        }
+     }
+     else if (tv->v_type == VAR_SPECIAL)
+     {
+       if (tv->vval.v_number <= VVAL_TRUE)
+           result = INT2NUM(tv->vval.v_number);
      } /* else return Qnil; */
  
      return result;
*** ../vim-7.4.1153/src/if_py_both.h    2016-01-17 22:36:56.017417164 +0100
--- src/if_py_both.h    2016-01-23 15:26:35.948143016 +0100
***************
*** 810,815 ****
--- 810,834 ----
            }
        }
      }
+     else if (our_tv->v_type == VAR_SPECIAL)
+     {
+       if (our_tv->vval.v_number == VVAL_FALSE)
+       {
+           ret = Py_False;
+           Py_INCREF(ret);
+       }
+       else if (our_tv->vval.v_number == VVAL_TRUE)
+       {
+           ret = Py_True;
+           Py_INCREF(ret);
+       }
+       else
+       {
+           Py_INCREF(Py_None);
+           ret = Py_None;
+       }
+       return ret;
+     }
      else
      {
        Py_INCREF(Py_None);
*** ../vim-7.4.1153/src/globals.h       2016-01-20 22:47:57.657335800 +0100
--- src/globals.h       2016-01-23 19:04:37.064586103 +0100
***************
*** 1523,1528 ****
--- 1523,1529 ----
  #ifdef FEAT_EVAL
  EXTERN char_u e_readonlyvar[] INIT(= N_("E46: Cannot change read-only 
variable \"%s\""));
  EXTERN char_u e_readonlysbx[] INIT(= N_("E794: Cannot set variable in the 
sandbox: \"%s\""));
+ EXTERN char_u e_emptykey[]    INIT(= N_("E713: Cannot use empty key for 
Dictionary"));
  #endif
  #ifdef FEAT_QUICKFIX
  EXTERN char_u e_readerrf[]    INIT(= N_("E47: Error while reading 
errorfile"));
*** ../vim-7.4.1153/src/Makefile        2016-01-19 13:21:55.829334463 +0100
--- src/Makefile        2016-01-23 19:40:15.862390712 +0100
***************
*** 1487,1492 ****
--- 1487,1493 ----
        hashtab.c \
        if_cscope.c \
        if_xcmdsrv.c \
+       json.c \
        main.c \
        mark.c \
        memfile.c \
***************
*** 1580,1585 ****
--- 1581,1587 ----
        $(HANGULIN_OBJ) \
        objects/if_cscope.o \
        objects/if_xcmdsrv.o \
+       objects/json.o \
        objects/mark.o \
          objects/memline.o \
        objects/menu.o \
***************
*** 1654,1659 ****
--- 1656,1662 ----
        if_python.pro \
        if_python3.pro \
        if_ruby.pro \
+       json.pro \
        main.pro \
        mark.pro \
        memfile.pro \
***************
*** 1986,1991 ****
--- 1989,1996 ----
        test_expand \
        test_hardcopy \
        test_increment \
+       test_json \
+       test_langmap \
        test_lispwords \
        test_menu \
        test_perl \
***************
*** 1993,1998 ****
--- 1998,2004 ----
        test_searchpos \
        test_set \
        test_sort \
+       test_syntax \
        test_undolevels \
        test_unlet \
        test_viminfo \
***************
*** 2770,2775 ****
--- 2776,2784 ----
  objects/integration.o: integration.c
        $(CCC) -o $@ integration.c
  
+ objects/json.o: json.c
+       $(CCC) -o $@ json.c
+ 
  objects/main.o: main.c
        $(CCC) -o $@ main.c
  
***************
*** 3060,3065 ****
--- 3069,3078 ----
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
   globals.h farsi.h arabic.h version.h
+ objects/json.o: json.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
+  ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+  gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
+  arabic.h
  objects/main.o: main.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
   ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
   gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
***************
*** 3114,3120 ****
  objects/os_unix.o: os_unix.c vim.h auto/config.h feature.h os_unix.h 
auto/osdef.h \
   ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
   gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
!  arabic.h if_mzsch.h os_unixx.h
  objects/pathdef.o: auto/pathdef.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
--- 3127,3133 ----
  objects/os_unix.o: os_unix.c vim.h auto/config.h feature.h os_unix.h 
auto/osdef.h \
   ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
   gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
!  arabic.h os_unixx.h
  objects/pathdef.o: auto/pathdef.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
***************
*** 3179,3185 ****
  objects/gui_gtk.o: gui_gtk.c gui_gtk_f.h vim.h auto/config.h feature.h 
os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
!  globals.h farsi.h arabic.h ../pixmaps/stock_icons.h
  objects/gui_gtk_f.o: gui_gtk_f.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
--- 3192,3198 ----
  objects/gui_gtk.o: gui_gtk.c gui_gtk_f.h vim.h auto/config.h feature.h 
os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
!  globals.h farsi.h arabic.h
  objects/gui_gtk_f.o: gui_gtk_f.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
***************
*** 3245,3252 ****
  objects/gui_gtk_x11.o: gui_gtk_x11.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
!  globals.h farsi.h arabic.h gui_gtk_f.h ../runtime/vim32x32.xpm \
!  ../runtime/vim16x16.xpm ../runtime/vim48x48.xpm $(GRESOURCE_HDR)
  objects/gui_x11.o: gui_x11.c vim.h auto/config.h feature.h os_unix.h 
auto/osdef.h \
   ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
   gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
--- 3258,3265 ----
  objects/gui_gtk_x11.o: gui_gtk_x11.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
!  globals.h farsi.h arabic.h auto/gui_gtk_gresources.h gui_gtk_f.h \
!  ../runtime/vim32x32.xpm ../runtime/vim16x16.xpm ../runtime/vim48x48.xpm
  objects/gui_x11.o: gui_x11.c vim.h auto/config.h feature.h os_unix.h 
auto/osdef.h \
   ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
   gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
***************
*** 3278,3284 ****
  objects/if_mzsch.o: if_mzsch.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
!  globals.h farsi.h arabic.h if_mzsch.h mzscheme_base.c
  objects/if_perl.o: auto/if_perl.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
--- 3291,3297 ----
  objects/if_mzsch.o: if_mzsch.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
!  globals.h farsi.h arabic.h if_mzsch.h
  objects/if_perl.o: auto/if_perl.c vim.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
*** ../vim-7.4.1153/src/Make_bc3.mak    2016-01-01 17:56:13.405342815 +0100
--- src/Make_bc3.mak    2016-01-22 20:33:39.219891292 +0100
***************
*** 72,77 ****
--- 72,78 ----
        getchar.obj \
        hardcopy.obj \
        hashtab.obj \
+       json.obj \
        main.obj \
        mark.obj \
        memfile.obj \
*** ../vim-7.4.1153/src/Make_bc5.mak    2016-01-01 17:56:13.405342815 +0100
--- src/Make_bc5.mak    2016-01-22 20:34:07.235596694 +0100
***************
*** 598,603 ****
--- 598,604 ----
        $(OBJDIR)\getchar.obj \
        $(OBJDIR)\hardcopy.obj \
        $(OBJDIR)\hashtab.obj \
+       $(OBJDIR)\json.obj \
        $(OBJDIR)\main.obj \
        $(OBJDIR)\mark.obj \
        $(OBJDIR)\memfile.obj \
*** ../vim-7.4.1153/src/Make_cyg_ming.mak       2016-01-21 20:24:30.524467216 
+0100
--- src/Make_cyg_ming.mak       2016-01-22 20:34:34.503309989 +0100
***************
*** 601,606 ****
--- 601,607 ----
        $(OUTDIR)/getchar.o \
        $(OUTDIR)/hardcopy.o \
        $(OUTDIR)/hashtab.o \
+       $(OUTDIR)/json.o \
        $(OUTDIR)/main.o \
        $(OUTDIR)/mark.o \
        $(OUTDIR)/memfile.o \
*** ../vim-7.4.1153/src/Make_dice.mak   2014-08-10 16:31:47.372709213 +0200
--- src/Make_dice.mak   2016-01-22 20:35:26.646761816 +0100
***************
*** 45,50 ****
--- 45,51 ----
        getchar.c \
        hardcopy.c \
        hashtab.c \
+       json.c \
        main.c \
        mark.c \
        memfile.c \
***************
*** 93,98 ****
--- 94,100 ----
        o/getchar.o \
        o/hardcopy.o \
        o/hashtab.o \
+       o/json.o \
        o/main.o \
        o/mark.o \
        o/memfile.o \
***************
*** 179,184 ****
--- 181,188 ----
  
  o/hashtab.o: hashtab.c        $(SYMS)
  
+ o/json.o:     json.c  $(SYMS)
+ 
  o/main.o: main.c $(SYMS)
  
  o/mark.o: mark.c      $(SYMS)
*** ../vim-7.4.1153/src/Make_ivc.mak    2014-08-10 16:31:47.372709213 +0200
--- src/Make_ivc.mak    2016-01-22 20:36:27.882118188 +0100
***************
*** 229,234 ****
--- 229,235 ----
        "$(INTDIR)/getchar.obj" \
        "$(INTDIR)/hardcopy.obj" \
        "$(INTDIR)/hashtab.obj" \
+       "$(INTDIR)/json.obj" \
        "$(INTDIR)/main.obj" \
        "$(INTDIR)/mark.obj" \
        "$(INTDIR)/mbyte.obj" \
***************
*** 555,560 ****
--- 556,565 ----
  # End Source File
  # Begin Source File
  
+ SOURCE=.\json.c
+ # End Source File
+ # Begin Source File
+ 
  SOURCE=.\main.c
  # End Source File
  # Begin Source File
*** ../vim-7.4.1153/src/Make_manx.mak   2016-01-01 17:56:13.405342815 +0100
--- src/Make_manx.mak   2016-01-22 20:37:07.693699816 +0100
***************
*** 55,60 ****
--- 55,61 ----
        getchar.c \
        hardcopy.c \
        hashtab.c \
+       json.c \
        main.c \
        mark.c \
        memfile.c \
***************
*** 105,110 ****
--- 106,112 ----
        obj/getchar.o \
        obj/hardcopy.o \
        obj/hashtab.o \
+       obj/json.o \
        obj/main.o \
        obj/mark.o \
        obj/memfile.o \
***************
*** 153,158 ****
--- 155,161 ----
        proto/getchar.pro \
        proto/hardcopy.pro \
        proto/hashtab.pro \
+       proto/json.pro \
        proto/main.pro \
        proto/mark.pro \
        proto/memfile.pro \
***************
*** 284,289 ****
--- 287,295 ----
  obj/hashtab.o:        hashtab.c
        $(CCSYM) $@ hashtab.c
  
+ obj/json.o:   json.c
+       $(CCSYM) $@ json.c
+ 
  # Don't use $(SYMS) here, because main.c defines EXTERN
  obj/main.o:   main.c option.h globals.h
        $(CCNOSYM) $@ main.c
*** ../vim-7.4.1153/src/Make_morph.mak  2014-08-10 16:31:47.376709213 +0200
--- src/Make_morph.mak  2016-01-22 20:37:36.097401362 +0100
***************
*** 43,48 ****
--- 43,49 ----
        getchar.c                                               \
        hardcopy.c                                              \
        hashtab.c                                               \
+       json.c                                                  \
        main.c                                                  \
        mark.c                                                  \
        mbyte.c                                                 \
*** ../vim-7.4.1153/src/Make_mvc.mak    2016-01-21 20:24:30.524467216 +0100
--- src/Make_mvc.mak    2016-01-22 20:38:21.608923214 +0100
***************
*** 536,541 ****
--- 536,542 ----
        $(OUTDIR)\getchar.obj \
        $(OUTDIR)\hardcopy.obj \
        $(OUTDIR)\hashtab.obj \
+       $(OUTDIR)\json.obj \
        $(OUTDIR)\main.obj \
        $(OUTDIR)\mark.obj \
        $(OUTDIR)\mbyte.obj \
***************
*** 1202,1207 ****
--- 1203,1210 ----
  $(OUTDIR)/if_tcl.obj: $(OUTDIR) if_tcl.c  $(INCL)
        $(CC) $(CFLAGS) $(TCL_INC) if_tcl.c
  
+ $(OUTDIR)/json.obj:   $(OUTDIR) json.c  $(INCL)
+ 
  $(OUTDIR)/main.obj:   $(OUTDIR) main.c  $(INCL)
  
  $(OUTDIR)/mark.obj:   $(OUTDIR) mark.c  $(INCL)
***************
*** 1329,1334 ****
--- 1332,1338 ----
        proto/getchar.pro \
        proto/hardcopy.pro \
        proto/hashtab.pro \
+       proto/json.pro \
        proto/main.pro \
        proto/mark.pro \
        proto/memfile.pro \
*** ../vim-7.4.1153/src/Make_sas.mak    2014-08-10 16:31:47.376709213 +0200
--- src/Make_sas.mak    2016-01-22 20:39:00.324516517 +0100
***************
*** 108,113 ****
--- 108,114 ----
        getchar.c \
        hardcopy.c \
        hashtab.c \
+       json.c \
        main.c \
        mark.c \
        memfile.c \
***************
*** 157,162 ****
--- 158,164 ----
        getchar.o \
        hardcopy.o \
        hashtab.o \
+       json.o \
        main.o \
        mark.o \
        memfile.o \
***************
*** 206,211 ****
--- 208,214 ----
        proto/getchar.pro \
        proto/hardcopy.pro \
        proto/hashtab.pro \
+       proto/json.pro \
        proto/main.pro \
        proto/mark.pro \
        proto/memfile.pro \
***************
*** 328,333 ****
--- 331,338 ----
  proto/hardcopy.pro:   hardcopy.c
  hashtab.o:            hashtab.c
  proto/hashtab.pro:    hashtab.c
+ json.o:                       json.c
+ proto/json.pro:               json.c
  main.o:                       main.c
  proto/main.pro:               main.c
  mark.o:                       mark.c
*** ../vim-7.4.1153/src/Make_vms.mms    2014-12-17 14:36:10.367090935 +0100
--- src/Make_vms.mms    2016-01-22 20:40:07.259813515 +0100
***************
*** 2,8 ****
  # Makefile for Vim on OpenVMS
  #
  # Maintainer:   Zoltan Arpadffy <[email protected]>
! # Last change:  2014 Aug 10
  #
  # This has script been tested on VMS 6.2 to 8.2 on DEC Alpha, VAX and IA64
  # with MMS and MMK
--- 2,8 ----
  # Makefile for Vim on OpenVMS
  #
  # Maintainer:   Zoltan Arpadffy <[email protected]>
! # Last change:  2016 Jan 22
  #
  # This has script been tested on VMS 6.2 to 8.2 on DEC Alpha, VAX and IA64
  # with MMS and MMK
***************
*** 311,317 ****
  
  SRC = blowfish.c buffer.c charset.c crypt.c, crypt_zip.c diff.c digraph.c 
edit.c eval.c ex_cmds.c ex_cmds2.c \
        ex_docmd.c ex_eval.c ex_getln.c if_xcmdsrv.c fileio.c fold.c getchar.c \
!       hardcopy.c hashtab.c main.c mark.c menu.c mbyte.c memfile.c memline.c 
message.c misc1.c \
        misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c 
search.c sha256.c\
        spell.c syntax.c tag.c term.c termlib.c ui.c undo.c version.c screen.c \
        window.c os_unix.c os_vms.c pathdef.c \
--- 311,317 ----
  
  SRC = blowfish.c buffer.c charset.c crypt.c, crypt_zip.c diff.c digraph.c 
edit.c eval.c ex_cmds.c ex_cmds2.c \
        ex_docmd.c ex_eval.c ex_getln.c if_xcmdsrv.c fileio.c fold.c getchar.c \
!       hardcopy.c hashtab.c json.c main.c mark.c menu.c mbyte.c memfile.c 
memline.c message.c misc1.c \
        misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c 
search.c sha256.c\
        spell.c syntax.c tag.c term.c termlib.c ui.c undo.c version.c screen.c \
        window.c os_unix.c os_vms.c pathdef.c \
***************
*** 320,326 ****
  
  OBJ = blowfish.obj buffer.obj charset.obj crypt.obj, crypt_zip.obj diff.obj 
digraph.obj edit.obj eval.obj \
        ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj \
!       if_xcmdsrv.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj 
main.obj mark.obj \
        menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \
        move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj 
quickfix.obj \
        regexp.obj search.obj sha256.obj spell.obj syntax.obj tag.obj term.obj 
termlib.obj \
--- 320,326 ----
  
  OBJ = blowfish.obj buffer.obj charset.obj crypt.obj, crypt_zip.obj diff.obj 
digraph.obj edit.obj eval.obj \
        ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj \
!       if_xcmdsrv.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj 
json.obj main.obj mark.obj \
        menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \
        move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj 
quickfix.obj \
        regexp.obj search.obj sha256.obj spell.obj syntax.obj tag.obj term.obj 
termlib.obj \
***************
*** 572,577 ****
--- 572,581 ----
   ascii.h keymap.h term.h macros.h option.h structs.h \
   regexp.h gui.h gui_beval.h [.proto]gui_beval.pro ex_cmds.h proto.h \
   globals.h farsi.h arabic.h if_mzsch.h 
+ json.obj : json.c vim.h [.auto]config.h feature.h os_unix.h   \
+  ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h gui_beval.h \
+  [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+  arabic.h version.h
  main.obj : main.c vim.h [.auto]config.h feature.h os_unix.h   \
   ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h gui_beval.h \
   [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
*** ../vim-7.4.1153/src/proto/json.pro  2016-01-23 19:32:31.439222465 +0100
--- src/proto/json.pro  2016-01-23 18:11:31.185430495 +0100
***************
*** 0 ****
--- 1,5 ----
+ /* json.c */
+ char_u *json_encode(typval_T *val);
+ void json_encode_item(garray_T *gap, typval_T *val, int copyID);
+ void json_decode(js_read_T *reader, typval_T *res);
+ /* vim: set ft=c : */
*** ../vim-7.4.1153/src/proto/eval.pro  2016-01-19 13:21:55.833334420 +0100
--- src/proto/eval.pro  2016-01-23 19:42:51.788769620 +0100
***************
*** 46,51 ****
--- 46,52 ----
  void del_menutrans_vars(void);
  char_u *get_user_var_name(expand_T *xp, int idx);
  list_T *list_alloc(void);
+ int rettv_list_alloc(typval_T *rettv);
  void list_unref(list_T *l);
  void list_free(list_T *l, int recurse);
  listitem_T *listitem_alloc(void);
***************
*** 61,71 ****
--- 62,74 ----
  int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
  void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
  void vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2);
+ int get_copyID(void);
  int garbage_collect(void);
  int set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack);
  int set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack);
  int set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, 
list_stack_T **list_stack);
  dict_T *dict_alloc(void);
+ int rettv_dict_alloc(typval_T *rettv);
  void dict_unref(dict_T *d);
  void dict_free(dict_T *d, int recurse);
  dictitem_T *dictitem_alloc(char_u *key);
***************
*** 76,81 ****
--- 79,85 ----
  dictitem_T *dict_find(dict_T *d, char_u *key, int len);
  char_u *get_dict_string(dict_T *d, char_u *key, int save);
  long get_dict_number(dict_T *d, char_u *key);
+ int string2float(char_u *text, float_T *value);
  char_u *get_function_name(expand_T *xp, int idx);
  char_u *get_expr_name(expand_T *xp, int idx);
  int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T 
*rettv);
***************
*** 100,105 ****
--- 104,110 ----
  void clear_tv(typval_T *varp);
  long get_tv_number_chk(typval_T *varp, int *denote);
  char_u *get_tv_string_chk(typval_T *varp);
+ char_u *get_tv_string_buf_chk(typval_T *varp, char_u *buf);
  char_u *get_var_value(char_u *name);
  void new_script_vars(scid_T id);
  void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);
*** ../vim-7.4.1153/src/testdir/test_json.vim   2016-01-23 19:32:31.447222383 
+0100
--- src/testdir/test_json.vim   2016-01-23 19:24:46.212065256 +0100
***************
*** 0 ****
--- 1,91 ----
+ " Test for JSON functions.
+ 
+ let s:json1 = '"str\"in\\g"'
+ let s:var1 = "str\"in\\g"
+ let s:json2 = '"\u0001\u0002\u0003\u0004\u0005\u0006\u0007"'
+ let s:var2 = "\x01\x02\x03\x04\x05\x06\x07"
+ let s:json3 = '"\b\t\n\u000b\f\r\u000e\u000f"'
+ let s:var3 = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ let s:json4 = '"\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"'
+ let s:var4 = "\x10\x11\x12\x13\x14\x15\x16\x17"
+ let s:json5 = '"\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"'
+ let s:var5 = "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ 
+ let s:jsonmb = '"s¢cĴgё"'
+ let s:varmb = "s¢cĴgё"
+ let s:jsonnr = '1234'
+ let s:varnr = 1234
+ let s:jsonfl = '12.34'
+ let s:varfl = 12.34
+ 
+ let s:jsonl1 = '[1,"a",3]'
+ let s:varl1 = [1, "a", 3]
+ let s:jsonl2 = '[1,["a",[],"c"],3]'
+ let s:jsonl2s = "  [\r1  ,  [  \"a\"  ,  [  ]  ,  \"c\"  ]  ,  3\<Tab>]\r\n"
+ let s:varl2 = [1, 2, 3]
+ let l2 = ['a', s:varl2, 'c']
+ let s:varl2[1] = l2
+ let s:varl2x = [1, ["a", [], "c"], 3]
+ 
+ let s:jsond1 = '{"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:jsond2s = "  { \"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
+ let s:vard2x = {"1": 1, "2": {"a": "aa", "b": {}, "c": "cc"}, "3": 3}
+ 
+ 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))
+   call assert_equal(s:json4, jsonencode(s:var4))
+   call assert_equal(s:json5, jsonencode(s:var5))
+ 
+   if has('multi_byte')
+     call assert_equal(s:jsonmb, jsonencode(s:varmb))
+   endif
+ 
+   call assert_equal(s:jsonnr, jsonencode(s:varnr))
+   if has('float')
+     call assert_equal(s:jsonfl, jsonencode(s:varfl))
+   endif
+ 
+   call assert_equal(s:jsonl1, jsonencode(s:varl1))
+   call assert_equal(s:jsonl2, jsonencode(s:varl2))
+ 
+   call assert_equal(s:jsond1, jsonencode(s:vard1))
+   call assert_equal(s:jsond2, jsonencode(s:vard2))
+ 
+   call assert_equal(s:jsonvals, jsonencode(s:varvals))
+ 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))
+   call assert_equal(s:var4, jsondecode(s:json4))
+   call assert_equal(s:var5, jsondecode(s:json5))
+ 
+   if has('multi_byte')
+     call assert_equal(s:varmb, jsondecode(s:jsonmb))
+   endif
+ 
+   call assert_equal(s:varnr, jsondecode(s:jsonnr))
+   if has('float')
+     call assert_equal(s:varfl, jsondecode(s:jsonfl))
+   endif
+ 
+   call assert_equal(s:varl1, jsondecode(s:jsonl1))
+   call assert_equal(s:varl2x, jsondecode(s:jsonl2))
+   call assert_equal(s:varl2x, jsondecode(s:jsonl2s))
+ 
+   call assert_equal(s:vard1, jsondecode(s:jsond1))
+   call assert_equal(s:vard2x, jsondecode(s:jsond2))
+ 
+   call assert_equal(s:varvals, jsondecode(s:jsonvals))
+ endfunc
*** ../vim-7.4.1153/src/testdir/test_alot.vim   2016-01-16 21:50:32.582161520 
+0100
--- src/testdir/test_alot.vim   2016-01-22 20:46:04.516063988 +0100
***************
*** 5,10 ****
--- 5,11 ----
  source test_cursor_func.vim
  source test_delete.vim
  source test_expand.vim
+ source test_json.vim
  source test_lispwords.vim
  source test_menu.vim
  source test_searchpos.vim
*** ../vim-7.4.1153/Filelist    2016-01-16 15:45:09.999436846 +0100
--- Filelist    2016-01-22 20:40:57.799282821 +0100
***************
*** 40,45 ****
--- 40,46 ----
                src/hardcopy.c \
                src/hashtab.c \
                src/keymap.h \
+               src/json.c \
                src/macros.h \
                src/main.c \
                src/mark.c \
***************
*** 132,137 ****
--- 133,139 ----
                src/proto/gui_beval.pro \
                src/proto/hardcopy.pro \
                src/proto/hashtab.pro \
+               src/proto/json.pro \
                src/proto/main.pro \
                src/proto/mark.pro \
                src/proto/mbyte.pro \
*** ../vim-7.4.1153/runtime/doc/eval.txt        2016-01-21 23:32:14.154035915 
+0100
--- runtime/doc/eval.txt        2016-01-23 14:05:58.107086430 +0100
***************
*** 1399,1404 ****
--- 1409,1418 ----
        :endtry
  <             Output: "caught oops".
  
+                                       *v:false* *false-variable*
+ v:false               A Number with value zero. Used to put "false" in JSON.  
See
+               |jsonencode()|.
+ 
                                        *v:fcs_reason* *fcs_reason-variable*
  v:fcs_reason  The reason why the |FileChangedShell| event was triggered.
                Can be used in an autocommand to decide what to do and/or what
***************
*** 1530,1535 ****
--- 1546,1559 ----
                This is the screen column number, like with |virtcol()|.  The
                value is zero when there was no mouse button click.
  
+                                       *v:none* *none-variable*
+ v:none                An empty String. Used to put an empty item in JSON.  See
+               |jsonencode()|.
+ 
+                                       *v:null* *null-variable*
+ v:null                An empty String. Used to put "null" in JSON.  See
+               |jsonencode()|.
+ 
                                        *v:oldfiles* *oldfiles-variable*
  v:oldfiles    List of file names that is loaded from the |viminfo| file on
                startup.  These are the files that Vim remembers marks for.
***************
*** 1695,1700 ****
--- 1719,1728 ----
        :endtry
  <             Output: "Exception from test.vim, line 2"
  
+                                               *v:true* *true-variable*
+ v:true                A Number with value one. Used to put "true" in JSON.  
See
+               |jsonencode()|.
+ 
                                                *v:val* *val-variable*
  v:val         Value of the current item of a |List| or |Dictionary|.  Only
                valid while evaluating the expression used with |map()| and
***************
*** 1901,1906 ****
--- 1929,1936 ----
  islocked( {expr})             Number  TRUE if {expr} is locked
  items( {dict})                        List    key-value pairs in {dict}
  join( {list} [, {sep}])               String  join {list} items into one 
String
+ jsondecode( {string})         any     decode JSON
+ jsonencode( {expr})           String  encode JSON
  keys( {dict})                 List    keys in {dict}
  len( {expr})                  Number  the length of {expr}
  libcall( {lib}, {func}, {arg})        String  call {func} in library {lib} 
with {arg}
***************
*** 4145,4150 ****
--- 4233,4259 ----
                converted into a string like with |string()|.
                The opposite function is |split()|.
  
+ jsondecode({string})                                  *jsondecode()*
+               TODO
+ 
+ jsonencode({expr})                                    *jsonencode()*
+               Encodode {expr} as JSON and return this as a string.
+               The encoding is specified in:
+               http://www.ietf.org/rfc/rfc4627.txt
+               Vim values are converted as follows:
+                  Number               decimal number
+                  Float                floating point number
+                  String               in double quotes (possibly null)
+                  Funcref              nothing
+                  List                 as an array (possibly null); when
+                                       used recursively: []
+                  Dict                 as an object (possibly null); when
+                                       used recursively: {}
+                  v:false              "false"
+                  v:true               "true"
+                  v:none               nothing
+                  v:null               "null"
+ 
  keys({dict})                                          *keys()*
                Return a |List| with all the keys of {dict}.  The |List| is in
                arbitrary order.
*** ../vim-7.4.1153/src/version.c       2016-01-22 22:44:06.377407641 +0100
--- src/version.c       2016-01-23 19:25:13.427781898 +0100
***************
*** 743,744 ****
--- 743,746 ----
  {   /* Add new patch number below this line */
+ /**/
+     1154,
  /**/

-- 
How To Keep A Healthy Level Of Insanity:
7. Finish all your sentences with "in accordance with the prophecy".

 /// 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.

Raspunde prin e-mail lui