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