neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

msgpack.vim (26322B)


      1 if exists('g:loaded_msgpack_autoload')
      2  finish
      3 endif
      4 let g:loaded_msgpack_autoload = 1
      5 
      6 ""
      7 " Check that given value is an integer. Respects |msgpack-special-dict|.
      8 function msgpack#is_int(v) abort
      9  return type(a:v) == type(0) || (
     10        \type(a:v) == type({}) && get(a:v, '_TYPE') is# v:msgpack_types.integer)
     11 endfunction
     12 
     13 ""
     14 " Check that given value is an unsigned integer. Respects 
     15 " |msgpack-special-dict|.
     16 function msgpack#is_uint(v) abort
     17  return msgpack#is_int(a:v) && (type(a:v) == type(0)
     18                                \? a:v >= 0
     19                                \: a:v._VAL[0] > 0)
     20 endfunction
     21 
     22 ""
     23 " True if s:msgpack_init_python() function was already run.
     24 let s:msgpack_python_initialized = 0
     25 
     26 ""
     27 " Cached return of s:msgpack_init_python() used when 
     28 " s:msgpack_python_initialized is true.
     29 let s:msgpack_python_type = 0
     30 
     31 ""
     32 " Create Python functions that are necessary for work. Also defines functions 
     33 " s:msgpack_dict_strftime(format, timestamp) and s:msgpack_dict_strptime(format, 
     34 " string).
     35 "
     36 " @return Zero in case no Python is available, empty string if Python-2 is 
     37 "         available and string `"3"` if Python-3 is available.
     38 function s:msgpack_init_python() abort
     39  if s:msgpack_python_initialized
     40    return s:msgpack_python_type
     41  endif
     42  let s:msgpack_python_initialized = 1
     43  for suf in (has('win32') ? ['3'] : ['', '3'])
     44    try
     45      execute 'python' . suf
     46              \. "\n"
     47              \. "def shada_dict_strftime():\n"
     48              \. "  import datetime\n"
     49              \. "  import vim\n"
     50              \. "  fmt = vim.eval('a:format')\n"
     51              \. "  timestamp = vim.eval('a:timestamp')\n"
     52              \. "  timestamp = [int(v) for v in timestamp['_VAL']]\n"
     53              \. "  timestamp = timestamp[0] * (timestamp[1] << 62\n"
     54              \. "                              | timestamp[2] << 31\n"
     55              \. "                              | timestamp[3])\n"
     56              \. "  time = datetime.datetime.fromtimestamp(timestamp)\n"
     57              \. "  return time.strftime(fmt)\n"
     58              \. "def shada_dict_strptime():\n"
     59              \. "  import calendar\n"
     60              \. "  import datetime\n"
     61              \. "  import vim\n"
     62              \. "  fmt = vim.eval('a:format')\n"
     63              \. "  timestr = vim.eval('a:string')\n"
     64              \. "  timestamp = datetime.datetime.strptime(timestr, fmt)\n"
     65              \. "  try:\n"
     66              \. "    timestamp = int(timestamp.timestamp())\n"
     67              \. "  except:\n"
     68              \. "    try:\n"
     69              \. "      timestamp = int(timestamp.strftime('%s'))\n"
     70              \. "    except:\n"
     71              \. "      timestamp = calendar.timegm(timestamp.utctimetuple())\n"
     72              \. "  if timestamp > 2 ** 31:\n"
     73              \. "    tsabs = abs(timestamp)\n"
     74              \. "    return ('{\"_TYPE\": v:msgpack_types.integer,'\n"
     75              \. "            + '\"_VAL\": [{sign},{v1},{v2},{v3}]}').format(\n"
     76              \. "              sign=(1 if timestamp >= 0 else -1),\n"
     77              \. "              v1=((tsabs >> 62) & 0x3),\n"
     78              \. "              v2=((tsabs >> 31) & (2 ** 31 - 1)),\n"
     79              \. "              v3=(tsabs & (2 ** 31 - 1)))\n"
     80              \. "  else:\n"
     81              \. "    return str(timestamp)\n"
     82      execute  "function s:msgpack_dict_strftime(format, timestamp) abort\n"
     83            \. "  return py" . suf . "eval('shada_dict_strftime()')\n"
     84            \. "endfunction\n"
     85            \. "function s:msgpack_dict_strptime(format, string)\n"
     86            \. "  return eval(py" . suf . "eval('shada_dict_strptime()'))\n"
     87            \. "endfunction\n"
     88      let s:msgpack_python_type = suf
     89      return suf
     90    catch
     91      continue
     92    endtry
     93  endfor
     94 
     95  ""
     96  " strftime() function for |msgpack-special-dict| values.
     97  "
     98  " @param[in]  format     String according to which time should be formatted.
     99  " @param[in]  timestamp  Timestamp (seconds since epoch) to format.
    100  "
    101  " @return Formatted timestamp.
    102  "
    103  " @warning Without +python or +python3 this function does not work correctly. 
    104  "          The Vimscript code contains “reference” implementation which does
    105  "          not really work because of precision loss.
    106  function s:msgpack_dict_strftime(format, timestamp)
    107    return msgpack#strftime(a:format, +msgpack#int_dict_to_str(a:timestamp))
    108  endfunction
    109 
    110  ""
    111  " Function that parses given string according to given format.
    112  "
    113  " @param[in]  format  String according to which string was formatted.
    114  " @param[in]  string  Time formatted according to format.
    115  "
    116  " @return Timestamp.
    117  "
    118  " @warning Without +python or +python3 this function is able to work only with 
    119  "          31-bit (32-bit signed) timestamps that have format 
    120  "          `%Y-%m-%dT%H:%M:%S`.
    121  function s:msgpack_dict_strptime(format, string)
    122    let fmt = '%Y-%m-%dT%H:%M:%S'
    123    if a:format isnot# fmt
    124      throw 'notimplemented-format:Only ' . fmt . ' format is supported'
    125    endif
    126    let match = matchlist(a:string,
    127                         \'\v\C^(\d+)\-(\d+)\-(\d+)T(\d+)\:(\d+)\:(\d+)$')
    128    if empty(match)
    129      throw 'invalid-string:Given string does not match format ' . a:format
    130    endif
    131    call map(match, 'str2nr(v:val, 10)')
    132    let [year, month, day, hour, minute, second] = match[1:6]
    133    " Bisection start and end:
    134    "
    135    " Start: 365 days in year, 28 days in month, -12 hours tz offset.
    136    let bisect_ts_start = (((((year - 1970) * 365
    137                             \+ (month - 1) * 28
    138                             \+ (day - 1)) * 24
    139                            \+ hour - 12) * 60
    140                           \+ minute) * 60
    141                          \+ second)
    142    if bisect_ts_start < 0
    143      let bisect_ts_start = 0
    144    endif
    145    let start_string = strftime(fmt, bisect_ts_start)
    146    if start_string is# a:string
    147      return bisect_ts_start
    148    endif
    149    " End: 366 days in year, 31 day in month, +14 hours tz offset.
    150    let bisect_ts_end = (((((year - 1970) * 366
    151                           \+ (month - 1) * 31
    152                           \+ (day - 1)) * 24
    153                          \+ hour + 14) * 60
    154                         \+ minute) * 60
    155                        \+ second)
    156    let end_string = strftime(fmt, bisect_ts_end)
    157    if end_string is# a:string
    158      return bisect_ts_end
    159    endif
    160    if start_string ># end_string
    161      throw 'internal-start-gt:Internal error: start > end'
    162    endif
    163    if start_string is# end_string
    164      throw printf('internal-start-eq:Internal error: '
    165                  \. 'start(%u)==end(%u), but start(%s)!=string(%s)',
    166                  \bisect_ts_start, bisect_ts_end,
    167                  \string(start_string), string(a:string))
    168    endif
    169    if start_string ># a:string
    170      throw 'internal-start-string:Internal error: start > string'
    171    endif
    172    if end_string <# a:string
    173      throw 'internal-end-string:Internal error: end < string'
    174    endif
    175    while 1
    176      let bisect_ts_middle = (bisect_ts_start/2) + (bisect_ts_end/2)
    177      let middle_string = strftime(fmt, bisect_ts_middle)
    178      if a:string is# middle_string
    179        return bisect_ts_middle
    180      elseif a:string ># middle_string
    181        if bisect_ts_middle == bisect_ts_start
    182          let bisect_ts_start += 1
    183        else
    184          let bisect_ts_start = bisect_ts_middle
    185        endif
    186      else
    187        if bisect_ts_middle == bisect_ts_end
    188          let bisect_ts_end -= 1
    189        else
    190          let bisect_ts_end = bisect_ts_middle
    191        endif
    192      endif
    193      if bisect_ts_start >= bisect_ts_end
    194        throw 'not-found:Unable to find timestamp'
    195      endif
    196    endwhile
    197  endfunction
    198 
    199  return 0
    200 endfunction
    201 
    202 ""
    203 " Wrapper for strftime() that respects |msgpack-special-dict|. May actually use 
    204 " non-standard strftime() implementations for |msgpack-special-dict| values.
    205 "
    206 " @param[in]  format     Format string.
    207 " @param[in]  timestamp  Formatted timestamp.
    208 function msgpack#strftime(format, timestamp) abort
    209  if type(a:timestamp) == type({})
    210    call s:msgpack_init_python()
    211    return s:msgpack_dict_strftime(a:format, a:timestamp)
    212  else
    213    return strftime(a:format, a:timestamp)
    214  endif
    215 endfunction
    216 
    217 ""
    218 " Parse string according to the format.
    219 "
    220 " Requires +python available. If it is not then only supported format is 
    221 " `%Y-%m-%dT%H:%M:%S` because this is the format used by ShaDa plugin. Also in 
    222 " this case bisection will be used (timestamps tried with strftime() up until 
    223 " result matches the string) and only 31-bit (signed 32-bit: with negative 
    224 " timestamps being useless this leaves 31 bits) timestamps will be supported.
    225 "
    226 " @param[in]  format  Time format.
    227 " @param[in]  string  Parsed time string. Must match given format.
    228 "
    229 " @return Timestamp. Possibly as |msgpack-special-dict|.
    230 function msgpack#strptime(format, string) abort
    231  call s:msgpack_init_python()
    232  return s:msgpack_dict_strptime(a:format, a:string)
    233 endfunction
    234 
    235 let s:MSGPACK_HIGHEST_BIT = 1
    236 let s:MSGPACK_HIGHEST_BIT_NR = 0
    237 while s:MSGPACK_HIGHEST_BIT * 2 > 0
    238  let s:MSGPACK_HIGHEST_BIT = s:MSGPACK_HIGHEST_BIT * 2
    239  let s:MSGPACK_HIGHEST_BIT_NR += 1
    240 endwhile
    241 
    242 ""
    243 " Shift given number by given amount of bits
    244 function s:shift(n, s) abort
    245  if a:s == 0
    246    return a:n
    247  elseif a:s < 0
    248    let ret = a:n
    249    for _ in range(-a:s)
    250      let ret = ret / 2
    251    endfor
    252    return ret
    253  else
    254    let ret = a:n
    255    for i in range(a:s)
    256      let new_ret = ret * 2
    257      if new_ret < ret
    258        " Overflow: remove highest bit
    259        let ret = xor(s:MSGPACK_HIGHEST_BIT, ret) * 2
    260      endif
    261      let ret = new_ret
    262    endfor
    263    return ret
    264  endif
    265 endfunction
    266 
    267 let s:msgpack_mask_cache = {
    268      \s:MSGPACK_HIGHEST_BIT_NR : s:MSGPACK_HIGHEST_BIT - 1}
    269 
    270 ""
    271 " Apply a mask where first m bits are ones and other are zeroes to a given 
    272 " number
    273 function s:mask1(n, m) abort
    274  if a:m > s:MSGPACK_HIGHEST_BIT_NR + 1
    275    let m = s:MSGPACK_HIGHEST_BIT_NR + 1
    276  else
    277    let m = a:m
    278  endif
    279  if !has_key(s:msgpack_mask_cache, m)
    280    let p = 0
    281    for _ in range(m)
    282      let p = p * 2 + 1
    283    endfor
    284    let s:msgpack_mask_cache[m] = p
    285  endif
    286  return and(a:n, s:msgpack_mask_cache[m])
    287 endfunction
    288 
    289 ""
    290 " Convert |msgpack-special-dict| that represents integer value to a string. Uses 
    291 " hexadecimal representation starting with 0x because it is the easiest to 
    292 " convert to.
    293 function msgpack#int_dict_to_str(v) abort
    294  let v = a:v._VAL
    295  " 64-bit number:
    296  " 0000000001111111111222222222233333333334444444444555555555566666
    297  " 1234567890123456789012345678901234567890123456789012345678901234
    298  " Split in _VAL:
    299  " 0000000001111111111222222222233 3333333344444444445555555555666 66
    300  " 1234567890123456789012345678901 2345678901234567890123456789012 34
    301  " Split by hex digits:
    302  " 0000 0000 0111 1111 1112 2222 2222 2333 3333 3334 4444 4444 4555 5555 5556 6666
    303  " 1234 5678 9012 3456 7890 1234 5678 9012 3456 7890 1234 5678 9012 3456 7890 1234
    304  "
    305  " Total split:
    306  "                _VAL[3]                              _VAL[2]                      _VAL[1]
    307  " ______________________________________  _______________________________________  __
    308  " 0000 0000 0111 1111 1112 2222 2222 233  3 3333 3334 4444 4444 4555 5555 5556 66  66
    309  " 1234 5678 9012 3456 7890 1234 5678 901  2 3456 7890 1234 5678 9012 3456 7890 12  34
    310  " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^
    311  "                g4                    g3                  g2                    g1
    312  " ********************************** ***  * ********************************** **  **
    313  "                1                    2   3                4                   5   6
    314  " 1: s:mask1(v[3], 28): first 28 bits of _VAL[3]
    315  " 2: s:shift(v[3], -28): last 3 bits of _VAL[3]
    316  " 3: s:mask1(v[2], 1): first bit of _VAL[2]
    317  " 4: s:mask1(s:shift(v[2], -1), 28): bits 2 .. 29 of _VAL[2]
    318  " 5: s:shift(v[2], -29): last 2 bits of _VAL[2]
    319  " 6: s:shift(v[1], 2): _VAL[1]
    320  let g4 = printf('%07x', s:mask1(v[3], 28))
    321  let g3 = printf('%01x', or(s:shift(v[3], -28), s:shift(s:mask1(v[2], 1), 3)))
    322  let g2 = printf('%07x', s:mask1(s:shift(v[2], -1), 28))
    323  let g1 = printf('%01x', or(s:shift(v[2], -29), s:shift(v[1], 2)))
    324  return ((v[0] < 0 ? '-' : '') . '0x' . g1 . g2 . g3 . g4)
    325 endfunction
    326 
    327 ""
    328 " True boolean value.
    329 let g:msgpack#true = {'_TYPE': v:msgpack_types.boolean, '_VAL': 1}
    330 lockvar! g:msgpack#true
    331 
    332 ""
    333 " False boolean value.
    334 let g:msgpack#false = {'_TYPE': v:msgpack_types.boolean, '_VAL': 0}
    335 lockvar! g:msgpack#false
    336 
    337 ""
    338 " NIL value.
    339 let g:msgpack#nil = {'_TYPE': v:msgpack_types.nil, '_VAL': 0}
    340 lockvar! g:msgpack#nil
    341 
    342 ""
    343 " Deduce type of |msgpack-special-dict|.
    344 "
    345 " @return zero if given dictionary is not special or name of the key in 
    346 "         v:msgpack_types dictionary.
    347 function msgpack#special_type(v) abort
    348  if type(a:v) != type({}) || !has_key(a:v, '_TYPE')
    349    return 0
    350  endif
    351  for [k, v] in items(v:msgpack_types)
    352    if a:v._TYPE is v
    353      return k
    354    endif
    355  endfor
    356  return 0
    357 endfunction
    358 
    359 ""
    360 " Mapping that maps type() output to type names.
    361 let s:MSGPACK_STANDARD_TYPES = {
    362  \type(0): 'integer',
    363  \type(0.0): 'float',
    364  \type(''): 'string',
    365  \type([]): 'array',
    366  \type({}): 'map',
    367  \type(v:true): 'boolean',
    368  \type(v:null): 'nil',
    369 \}
    370 
    371 ""
    372 " Deduce type of one of items returned by msgpackparse().
    373 "
    374 " @return Name of a key in v:msgpack_types.
    375 function msgpack#type(v) abort
    376  let special_type = msgpack#special_type(a:v)
    377  if special_type is 0
    378    return s:MSGPACK_STANDARD_TYPES[type(a:v)]
    379  endif
    380  return special_type
    381 endfunction
    382 
    383 ""
    384 " Dump nil value.
    385 function s:msgpack_dump_nil(v) abort
    386  return 'NIL'
    387 endfunction
    388 
    389 ""
    390 " Dump boolean value.
    391 function s:msgpack_dump_boolean(v) abort
    392  return (a:v is v:true || (a:v isnot v:false && a:v._VAL)) ? 'TRUE' : 'FALSE'
    393 endfunction
    394 
    395 ""
    396 " Dump integer msgpack value.
    397 function s:msgpack_dump_integer(v) abort
    398  if type(a:v) == type({})
    399    return msgpack#int_dict_to_str(a:v)
    400  else
    401    return string(a:v)
    402  endif
    403 endfunction
    404 
    405 ""
    406 " Dump floating-point value.
    407 function s:msgpack_dump_float(v) abort
    408  return substitute(string(type(a:v) == type({}) ? a:v._VAL : a:v),
    409                   \'\V\^\(-\)\?str2float(''\(inf\|nan\)'')\$', '\1\2', '')
    410 endfunction
    411 
    412 ""
    413 " Dump |msgpack-special-dict| that represents a string. If any additional 
    414 " parameter is given then it dumps binary string.
    415 function s:msgpack_dump_string(v) abort
    416  if type(a:v) == type({})
    417    let val = a:v
    418  else
    419    let val = {'_VAL': split(a:v, "\n", 1)}
    420  end
    421 
    422  let ret = ['"']
    423  for v in val._VAL
    424    call add(
    425          \ret,
    426          \substitute(
    427            \substitute(v, '["\\]', '\\\0', 'g'),
    428            \'\n', '\\0', 'g'))
    429    call add(ret, '\n')
    430  endfor
    431  let ret[-1] = '"'
    432  return join(ret, '')
    433 endfunction
    434 
    435 ""
    436 " Dump array value.
    437 function s:msgpack_dump_array(v) abort
    438  let val = type(a:v) == type({}) ? a:v._VAL : a:v
    439  return '[' . join(map(val[:], 'msgpack#string(v:val)'), ', ') . ']'
    440 endfunction
    441 
    442 ""
    443 " Dump dictionary value.
    444 function s:msgpack_dump_map(v) abort
    445  let ret = ['{']
    446  if msgpack#special_type(a:v) is 0
    447    for [k, v] in items(a:v)
    448      let ret += [s:msgpack_dump_string({'_VAL': split(k, "\n")}),
    449                 \': ',
    450                 \msgpack#string(v),
    451                 \', ']
    452      unlet v
    453    endfor
    454    if !empty(a:v)
    455      call remove(ret, -1)
    456    endif
    457  else
    458    for [k, v] in sort(copy(a:v._VAL))
    459      let ret += [msgpack#string(k),
    460                 \': ',
    461                 \msgpack#string(v),
    462                 \', ']
    463      unlet k
    464      unlet v
    465    endfor
    466    if !empty(a:v._VAL)
    467      call remove(ret, -1)
    468    endif
    469  endif
    470  let ret += ['}']
    471  return join(ret, '')
    472 endfunction
    473 
    474 ""
    475 " Dump extension value.
    476 function s:msgpack_dump_ext(v) abort
    477  return printf('+(%i)%s', a:v._VAL[0],
    478               \s:msgpack_dump_string({'_VAL': a:v._VAL[1]}))
    479 endfunction
    480 
    481 ""
    482 " Convert msgpack object to a string, like string() function does. Result of the 
    483 " conversion may be passed to msgpack#eval().
    484 function msgpack#string(v) abort
    485  if type(a:v) == type({})
    486    let type = msgpack#special_type(a:v)
    487    if type is 0
    488      let type = 'map'
    489    endif
    490  else
    491    let type = get(s:MSGPACK_STANDARD_TYPES, type(a:v), 0)
    492    if type is 0
    493      throw printf('msgpack:invtype: Unable to convert value %s', string(a:v))
    494    endif
    495  endif
    496  return s:msgpack_dump_{type}(a:v)
    497 endfunction
    498 
    499 ""
    500 " Copy msgpack object like deepcopy() does, but leave types intact
    501 function msgpack#deepcopy(obj) abort
    502  if type(a:obj) == type([])
    503    return map(copy(a:obj), 'msgpack#deepcopy(v:val)')
    504  elseif type(a:obj) == type({})
    505    let special_type = msgpack#special_type(a:obj)
    506    if special_type is 0
    507      return map(copy(a:obj), 'msgpack#deepcopy(v:val)')
    508    else
    509      return {
    510        \'_TYPE': v:msgpack_types[special_type],
    511        \'_VAL': msgpack#deepcopy(a:obj._VAL)
    512      \}
    513    endif
    514  else
    515    return copy(a:obj)
    516  endif
    517 endfunction
    518 
    519 ""
    520 " Convert an escaped character to needed value
    521 function s:msgpack_eval_str_sub(ch) abort
    522  if a:ch is# 'n'
    523    return '", "'
    524  elseif a:ch is# '0'
    525    return '\n'
    526  else
    527    return '\' . a:ch
    528  endif
    529 endfunction
    530 
    531 let s:MSGPACK_SPECIAL_OBJECTS = {
    532  \'NIL': '{''_TYPE'': v:msgpack_types.nil, ''_VAL'': 0}',
    533  \'TRUE': '{''_TYPE'': v:msgpack_types.boolean, ''_VAL'': 1}',
    534  \'FALSE': '{''_TYPE'': v:msgpack_types.boolean, ''_VAL'': 0}',
    535  \'nan': '(-(1.0/0.0-1.0/0.0))',
    536  \'inf': '(1.0/0.0)',
    537 \}
    538 
    539 ""
    540 " Convert msgpack object dumped by msgpack#string() to a Vimscript object
    541 " suitable for msgpackdump().
    542 "
    543 " @param[in]  s             String to evaluate.
    544 " @param[in]  special_objs  Additional special objects, in the same format as 
    545 "                           s:MSGPACK_SPECIAL_OBJECTS.
    546 "
    547 " @return Any value that msgpackparse() may return.
    548 function msgpack#eval(s, special_objs) abort
    549  let s = a:s
    550  let expr = []
    551  let context = []
    552  while !empty(s)
    553    let s = substitute(s, '^\s*', '', '')
    554    if s[0] =~# '\v^\h$'
    555      let name = matchstr(s, '\v\C^\w+')
    556      if has_key(s:MSGPACK_SPECIAL_OBJECTS, name)
    557        call add(expr, s:MSGPACK_SPECIAL_OBJECTS[name])
    558      elseif has_key(a:special_objs, name)
    559        call add(expr, a:special_objs[name])
    560      else
    561        throw 'name-unknown:Unknown name ' . name . ': ' . s
    562      endif
    563      let s = s[len(name):]
    564    elseif (s[0] is# '-' && s[1] =~# '\v^\d$') || s[0] =~# '\v^\d$'
    565      let sign = 1
    566      if s[0] is# '-'
    567        let s = s[1:]
    568        let sign = -1
    569      endif
    570      if s[0:1] is# '0x'
    571        " See comment in msgpack#int_dict_to_str().
    572        let s = s[2:]
    573        let hexnum = matchstr(s, '\v\C^\x+')
    574        if empty(hexnum)
    575          throw '0x-empty:Must have number after 0x: ' . s
    576        elseif len(hexnum) > 16
    577          throw '0x-long:Must have at most 16 hex digits: ' . s
    578        endif
    579        let s = s[len(hexnum):]
    580        let hexnum = repeat('0', 16 - len(hexnum)) . hexnum
    581        let g1 = str2nr(hexnum[0], 16)
    582        let g2 = str2nr(hexnum[1:7], 16)
    583        let g3 = str2nr(hexnum[8], 16)
    584        let g4 = str2nr(hexnum[9:15], 16)
    585        let v1 = s:shift(g1, -2)
    586        let v2 = or(or(s:shift(s:mask1(g1, 2), 29), s:shift(g2, 1)),
    587                   \s:mask1(s:shift(g3, -3), 1))
    588        let v3 = or(s:shift(s:mask1(g3, 3), 28), g4)
    589        call add(expr, printf('{''_TYPE'': v:msgpack_types.integer, '.
    590                             \'''_VAL'': [%i, %u, %u, %u]}',
    591                             \sign, v1, v2, v3))
    592      else
    593        let num = matchstr(s, '\v\C^\d+')
    594        let s = s[len(num):]
    595        if sign == -1
    596          call add(expr, '-')
    597        endif
    598        call add(expr, num)
    599        if s[0] is# '.'
    600          let dec = matchstr(s, '\v\C^\.\d+%(e[+-]?\d+)?')
    601          if empty(dec)
    602            throw '0.-nodigits:Decimal dot must be followed by digit(s): ' . s
    603          endif
    604          let s = s[len(dec):]
    605          call add(expr, dec)
    606        endif
    607      endif
    608    elseif s =~# '\v^\-%(inf|nan)'
    609      call add(expr, '-')
    610      call add(expr, s:MSGPACK_SPECIAL_OBJECTS[s[1:3]])
    611      let s = s[4:]
    612    elseif stridx('="+', s[0]) != -1
    613      let match = matchlist(s, '\v\C^(\=|\+\((\-?\d+)\)|)(\"%(\\.|[^\\"]+)*\")')
    614      if empty(match)
    615        throw '"-invalid:Invalid string: ' . s
    616      endif
    617      call add(expr, '{''_TYPE'': v:msgpack_types.')
    618      if empty(match[1]) || match[1] is# '='
    619        call add(expr, 'string')
    620      else
    621        call add(expr, 'ext')
    622      endif
    623      call add(expr, ', ''_VAL'': [')
    624      if match[1][0] is# '+'
    625        call add(expr, match[2] . ', [')
    626      endif
    627      call add(expr, substitute(match[3], '\v\C\\(.)',
    628                               \'\=s:msgpack_eval_str_sub(submatch(1))', 'g'))
    629      if match[1][0] is# '+'
    630        call add(expr, ']')
    631      endif
    632      call add(expr, ']}')
    633      let s = s[len(match[0]):]
    634    elseif s[0] is# '{'
    635      call add(context, 'map')
    636      call add(expr, '{''_TYPE'': v:msgpack_types.map, ''_VAL'': [')
    637      call add(expr, '[')
    638      let s = s[1:]
    639    elseif s[0] is# '['
    640      call add(context, 'array')
    641      call add(expr, '[')
    642      let s = s[1:]
    643    elseif s[0] is# ':'
    644      call add(expr, ',')
    645      let s = s[1:]
    646    elseif s[0] is# ','
    647      if context[-1] is# 'array'
    648        call add(expr, ',')
    649      else
    650        call add(expr, '], [')
    651      endif
    652      let s = s[1:]
    653    elseif s[0] is# ']'
    654      call remove(context, -1)
    655      call add(expr, ']')
    656      let s = s[1:]
    657    elseif s[0] is# '}'
    658      call remove(context, -1)
    659      if expr[-1] is# "\x5B"
    660        call remove(expr, -1)
    661      else
    662        call add(expr, ']')
    663      endif
    664      call add(expr, ']}')
    665      let s = s[1:]
    666    elseif s[0] is# ''''
    667      let char = matchstr(s, '\v\C^\''\zs%(\\\d+|.)\ze\''')
    668      if empty(char)
    669        throw 'char-invalid:Invalid integer character literal format: ' . s
    670      endif
    671      if char[0] is# '\'
    672        call add(expr, +char[1:])
    673      else
    674        call add(expr, char2nr(char))
    675      endif
    676      let s = s[len(char) + 2:]
    677    else
    678      throw 'unknown:Invalid non-space character: ' . s
    679    endif
    680  endwhile
    681  if empty(expr)
    682    throw 'empty:Parsed string is empty'
    683  endif
    684  return eval(join(expr, ''))
    685 endfunction
    686 
    687 ""
    688 " Check whether two msgpack values are equal
    689 function msgpack#equal(a, b)
    690  let atype = msgpack#type(a:a)
    691  let btype = msgpack#type(a:b)
    692  if atype isnot# btype
    693    return 0
    694  endif
    695  let aspecial = msgpack#special_type(a:a)
    696  let bspecial = msgpack#special_type(a:b)
    697  if aspecial is# bspecial
    698    if aspecial is# 0
    699      if type(a:a) == type({})
    700        if len(a:a) != len(a:b)
    701          return 0
    702        endif
    703        if !empty(filter(keys(a:a), '!has_key(a:b, v:val)'))
    704          return 0
    705        endif
    706        for [k, v] in items(a:a)
    707          if !msgpack#equal(v, a:b[k])
    708            return 0
    709          endif
    710          unlet v
    711        endfor
    712        return 1
    713      elseif type(a:a) == type([])
    714        if len(a:a) != len(a:b)
    715          return 0
    716        endif
    717        let i = 0
    718        for asubval in a:a
    719          if !msgpack#equal(asubval, a:b[i])
    720            return 0
    721          endif
    722          let i += 1
    723          unlet asubval
    724        endfor
    725        return 1
    726      elseif type(a:a) == type(0.0)
    727        return (a:a == a:a ? a:a == a:b : string(a:a) ==# string(a:b))
    728      else
    729        return a:a ==# a:b
    730      endif
    731    elseif aspecial is# 'map' || aspecial is# 'array'
    732      if len(a:a._VAL) != len(a:b._VAL)
    733        return 0
    734      endif
    735      let alist = aspecial is# 'map' ? sort(copy(a:a._VAL)) : a:a._VAL
    736      let blist = bspecial is# 'map' ? sort(copy(a:b._VAL)) : a:b._VAL
    737      let i = 0
    738      for asubval in alist
    739        let bsubval = blist[i]
    740        if aspecial is# 'map'
    741          if !(msgpack#equal(asubval[0], bsubval[0])
    742              \&& msgpack#equal(asubval[1], bsubval[1]))
    743            return 0
    744          endif
    745        else
    746          if !msgpack#equal(asubval, bsubval)
    747            return 0
    748          endif
    749        endif
    750        let i += 1
    751        unlet asubval
    752        unlet bsubval
    753      endfor
    754      return 1
    755    elseif aspecial is# 'nil'
    756      return 1
    757    elseif aspecial is# 'float'
    758      return (a:a._VAL == a:a._VAL
    759             \? (a:a._VAL == a:b._VAL)
    760             \: (string(a:a._VAL) ==# string(a:b._VAL)))
    761    else
    762      return a:a._VAL ==# a:b._VAL
    763    endif
    764  else
    765    if atype is# 'array'
    766      let a = aspecial is 0 ? a:a : a:a._VAL
    767      let b = bspecial is 0 ? a:b : a:b._VAL
    768      return msgpack#equal(a, b)
    769    elseif atype is# 'string'
    770      let a = (aspecial is 0 ? split(a:a, "\n", 1) : a:a._VAL)
    771      let b = (bspecial is 0 ? split(a:b, "\n", 1) : a:b._VAL)
    772      return a ==# b
    773    elseif atype is# 'map'
    774      if aspecial is 0
    775        let akeys = copy(a:a)
    776        if len(a:b._VAL) != len(akeys)
    777          return 0
    778        endif
    779        for [k, v] in a:b._VAL
    780          if msgpack#type(k) isnot# 'string'
    781            " Non-special mapping cannot have non-string keys
    782            return 0
    783          endif
    784          if type(k) == type({})
    785            if (empty(k._VAL)
    786               \|| k._VAL ==# [""]
    787               \|| !empty(filter(copy(k._VAL), 'stridx(v:val, "\n") != -1')))
    788              " Non-special mapping cannot have zero byte in key or an empty key
    789              return 0
    790            endif
    791            let kstr = join(k._VAL, "\n")
    792          else
    793            let kstr = k
    794          endif
    795          if !has_key(akeys, kstr)
    796            " Protects from both missing and duplicate keys
    797            return 0
    798          endif
    799          if !msgpack#equal(akeys[kstr], v)
    800            return 0
    801          endif
    802          call remove(akeys, kstr)
    803          unlet k
    804          unlet v
    805        endfor
    806        return 1
    807      else
    808        return msgpack#equal(a:b, a:a)
    809      endif
    810    elseif atype is# 'float'
    811      let a = aspecial is 0 ? a:a : a:a._VAL
    812      let b = bspecial is 0 ? a:b : a:b._VAL
    813      return (a == a ? a == b : string(a) ==# string(b))
    814    elseif atype is# 'integer'
    815      if aspecial is 0
    816        let sign = a:a >= 0 ? 1 : -1
    817        let a = sign * a:a
    818        let v1 = s:mask1(s:shift(a, -62), 2)
    819        let v2 = s:mask1(s:shift(a, -31), 31)
    820        let v3 = s:mask1(a, 31)
    821        return [sign, v1, v2, v3] == a:b._VAL
    822      else
    823        return msgpack#equal(a:b, a:a)
    824      endif
    825    else
    826      throw printf('internal-invalid-type: %s == %s, but special %s /= %s',
    827                  \atype, btype, aspecial, bspecial)
    828    endif
    829  endif
    830 endfunction