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