Mercurial > vim
comparison src/eval.c @ 21208:09377fd59b2e v8.2.1155
patch 8.2.1155: Vim9: cannot handle line break inside lambda
Commit: https://github.com/vim/vim/commit/7a4b8980ea5ecaea061caae7816ea62cc4940011
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Jul 8 17:36:21 2020 +0200
patch 8.2.1155: Vim9: cannot handle line break inside lambda
Problem: Vim9: cannot handle line break inside lambda.
Solution: Pass the compilation context through. (closes https://github.com/vim/vim/issues/6407, closes https://github.com/vim/vim/issues/6409)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Wed, 08 Jul 2020 17:45:06 +0200 |
parents | 667192c5938b |
children | ad13736a1783 |
comparison
equal
deleted
inserted
replaced
21207:2a1156d4950f | 21208:09377fd59b2e |
---|---|
388 int res; | 388 int res; |
389 int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; | 389 int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; |
390 garray_T *gap = &evalarg->eval_ga; | 390 garray_T *gap = &evalarg->eval_ga; |
391 int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags; | 391 int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags; |
392 | 392 |
393 if (vim9script && evalarg->eval_cookie != NULL) | 393 if (vim9script |
394 && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL)) | |
394 { | 395 { |
395 ga_init2(gap, sizeof(char_u *), 10); | 396 ga_init2(gap, sizeof(char_u *), 10); |
397 // leave room for "start" | |
396 if (ga_grow(gap, 1) == OK) | 398 if (ga_grow(gap, 1) == OK) |
397 // leave room for "start" | |
398 ++gap->ga_len; | 399 ++gap->ga_len; |
399 } | 400 } |
400 | 401 |
401 // Don't evaluate the expression. | 402 // Don't evaluate the expression. |
402 if (evalarg != NULL) | 403 if (evalarg != NULL) |
404 *end = skipwhite(*end); | 405 *end = skipwhite(*end); |
405 res = eval1(end, &rettv, evalarg); | 406 res = eval1(end, &rettv, evalarg); |
406 if (evalarg != NULL) | 407 if (evalarg != NULL) |
407 evalarg->eval_flags = save_flags; | 408 evalarg->eval_flags = save_flags; |
408 | 409 |
409 if (vim9script && evalarg->eval_cookie != NULL | 410 if (vim9script |
410 && evalarg->eval_ga.ga_len > 1) | 411 && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL)) |
411 { | 412 { |
412 char_u *p; | 413 if (evalarg->eval_ga.ga_len == 1) |
413 size_t endoff = STRLEN(*end); | 414 { |
414 | 415 // just one line, no need to concatenate |
415 // Line breaks encountered, concatenate all the lines. | 416 ga_clear(gap); |
416 *((char_u **)gap->ga_data) = *start; | 417 gap->ga_itemsize = 0; |
417 p = ga_concat_strings(gap, ""); | 418 } |
418 *((char_u **)gap->ga_data) = NULL; | 419 else |
419 ga_clear_strings(gap); | 420 { |
420 gap->ga_itemsize = 0; | 421 char_u *p; |
421 if (p == NULL) | 422 size_t endoff = STRLEN(*end); |
422 return FAIL; | 423 |
423 *start = p; | 424 // Line breaks encountered, concatenate all the lines. |
424 vim_free(evalarg->eval_tofree); | 425 *((char_u **)gap->ga_data) = *start; |
425 evalarg->eval_tofree = p; | 426 p = ga_concat_strings(gap, ""); |
426 // Compute "end" relative to the end. | 427 |
427 *end = *start + STRLEN(*start) - endoff; | 428 // free the lines only when using getsourceline() |
429 if (evalarg->eval_cookie != NULL) | |
430 { | |
431 *((char_u **)gap->ga_data) = NULL; | |
432 ga_clear_strings(gap); | |
433 } | |
434 else | |
435 ga_clear(gap); | |
436 gap->ga_itemsize = 0; | |
437 if (p == NULL) | |
438 return FAIL; | |
439 *start = p; | |
440 vim_free(evalarg->eval_tofree); | |
441 evalarg->eval_tofree = p; | |
442 // Compute "end" relative to the end. | |
443 *end = *start + STRLEN(*start) - endoff; | |
444 } | |
428 } | 445 } |
429 | 446 |
430 return res; | 447 return res; |
431 } | 448 } |
432 | 449 |
433 /* | 450 /* |
434 * Top level evaluation function, returning a string. | 451 * Top level evaluation function, returning a string. Does not handle line |
452 * breaks. | |
435 * When "convert" is TRUE convert a List into a sequence of lines and convert | 453 * When "convert" is TRUE convert a List into a sequence of lines and convert |
436 * a Float to a String. | 454 * a Float to a String. |
437 * Return pointer to allocated memory, or NULL for failure. | 455 * Return pointer to allocated memory, or NULL for failure. |
438 */ | 456 */ |
439 char_u * | 457 char_u * |
1876 eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext) | 1894 eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext) |
1877 { | 1895 { |
1878 *getnext = FALSE; | 1896 *getnext = FALSE; |
1879 if (current_sctx.sc_version == SCRIPT_VERSION_VIM9 | 1897 if (current_sctx.sc_version == SCRIPT_VERSION_VIM9 |
1880 && evalarg != NULL | 1898 && evalarg != NULL |
1881 && evalarg->eval_cookie != NULL | 1899 && (evalarg->eval_cookie != NULL || evalarg->eval_cctx != NULL) |
1882 && (*arg == NUL || (VIM_ISWHITE(arg[-1]) | 1900 && (*arg == NUL || (VIM_ISWHITE(arg[-1]) |
1883 && *arg == '#' && arg[1] != '{'))) | 1901 && *arg == '#' && arg[1] != '{'))) |
1884 { | 1902 { |
1885 char_u *p = getline_peek(evalarg->eval_getline, evalarg->eval_cookie); | 1903 char_u *p; |
1904 | |
1905 if (evalarg->eval_cookie != NULL) | |
1906 p = getline_peek(evalarg->eval_getline, evalarg->eval_cookie); | |
1907 else | |
1908 p = peek_next_line_from_context(evalarg->eval_cctx); | |
1886 | 1909 |
1887 if (p != NULL) | 1910 if (p != NULL) |
1888 { | 1911 { |
1889 *getnext = TRUE; | 1912 *getnext = TRUE; |
1890 return skipwhite(p); | 1913 return skipwhite(p); |
1900 eval_next_line(evalarg_T *evalarg) | 1923 eval_next_line(evalarg_T *evalarg) |
1901 { | 1924 { |
1902 garray_T *gap = &evalarg->eval_ga; | 1925 garray_T *gap = &evalarg->eval_ga; |
1903 char_u *line; | 1926 char_u *line; |
1904 | 1927 |
1905 line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE); | 1928 if (evalarg->eval_cookie != NULL) |
1929 line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE); | |
1930 else | |
1931 line = next_line_from_context(evalarg->eval_cctx, TRUE); | |
1906 ++evalarg->eval_break_count; | 1932 ++evalarg->eval_break_count; |
1907 if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK) | 1933 if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK) |
1908 { | 1934 { |
1909 // Going to concatenate the lines after parsing. | 1935 // Going to concatenate the lines after parsing. |
1910 ((char_u **)gap->ga_data)[gap->ga_len] = line; | 1936 ((char_u **)gap->ga_data)[gap->ga_len] = line; |
5032 int evaluate = evalarg != NULL | 5058 int evaluate = evalarg != NULL |
5033 && (evalarg->eval_flags & EVAL_EVALUATE); | 5059 && (evalarg->eval_flags & EVAL_EVALUATE); |
5034 int ret = OK; | 5060 int ret = OK; |
5035 dict_T *selfdict = NULL; | 5061 dict_T *selfdict = NULL; |
5036 int check_white = TRUE; | 5062 int check_white = TRUE; |
5037 | 5063 int getnext; |
5038 // When at the end of the line and ".name" follows in the next line then | 5064 char_u *p; |
5039 // consume the line break. Only when rettv is a dict. | 5065 |
5040 if (rettv->v_type == VAR_DICT) | 5066 while (ret == OK) |
5041 { | 5067 { |
5042 int getnext; | 5068 // When at the end of the line and ".name" or "->{" or "->X" follows in |
5043 char_u *p = eval_next_non_blank(*arg, evalarg, &getnext); | 5069 // the next line then consume the line break. |
5044 | 5070 p = eval_next_non_blank(*arg, evalarg, &getnext); |
5045 if (getnext && *p == '.' && ASCII_ISALPHA(p[1])) | 5071 if (getnext |
5072 && ((rettv->v_type == VAR_DICT && *p == '.' | |
5073 && ASCII_ISALPHA(p[1])) | |
5074 || (*p == '-' && p[1] == '>' | |
5075 && (p[2] == '{' || ASCII_ISALPHA(p[2]))))) | |
5046 { | 5076 { |
5047 *arg = eval_next_line(evalarg); | 5077 *arg = eval_next_line(evalarg); |
5048 check_white = FALSE; | 5078 check_white = FALSE; |
5049 } | 5079 } |
5050 } | 5080 |
5051 | 5081 if ((**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC |
5052 // "." is ".name" lookup when we found a dict or when evaluating and | 5082 || rettv->v_type == VAR_PARTIAL)) |
5053 // scriptversion is at least 2, where string concatenation is "..". | 5083 && (!check_white || !VIM_ISWHITE(*(*arg - 1)))) |
5054 while (ret == OK | |
5055 && (((**arg == '[' | |
5056 || (**arg == '.' && (rettv->v_type == VAR_DICT | |
5057 || (!evaluate | |
5058 && (*arg)[1] != '.' | |
5059 && current_sctx.sc_version >= 2))) | |
5060 || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC | |
5061 || rettv->v_type == VAR_PARTIAL))) | |
5062 && (!check_white || !VIM_ISWHITE(*(*arg - 1)))) | |
5063 || (**arg == '-' && (*arg)[1] == '>'))) | |
5064 { | |
5065 if (**arg == '(') | |
5066 { | 5084 { |
5067 ret = call_func_rettv(arg, evalarg, rettv, evaluate, | 5085 ret = call_func_rettv(arg, evalarg, rettv, evaluate, |
5068 selfdict, NULL); | 5086 selfdict, NULL); |
5069 | 5087 |
5070 // Stop the expression evaluation when immediately aborting on | 5088 // Stop the expression evaluation when immediately aborting on |
5077 ret = FAIL; | 5095 ret = FAIL; |
5078 } | 5096 } |
5079 dict_unref(selfdict); | 5097 dict_unref(selfdict); |
5080 selfdict = NULL; | 5098 selfdict = NULL; |
5081 } | 5099 } |
5082 else if (**arg == '-') | 5100 else if (**arg == '-' && (*arg)[1] == '>') |
5083 { | 5101 { |
5084 if (ret == OK) | 5102 if (ret == OK) |
5085 { | 5103 { |
5086 if ((*arg)[2] == '{') | 5104 if ((*arg)[2] == '{') |
5087 // expr->{lambda}() | 5105 // expr->{lambda}() |
5089 else | 5107 else |
5090 // expr->name() | 5108 // expr->name() |
5091 ret = eval_method(arg, rettv, evalarg, verbose); | 5109 ret = eval_method(arg, rettv, evalarg, verbose); |
5092 } | 5110 } |
5093 } | 5111 } |
5094 else // **arg == '[' || **arg == '.' | 5112 // "." is ".name" lookup when we found a dict or when evaluating and |
5113 // scriptversion is at least 2, where string concatenation is "..". | |
5114 else if (**arg == '[' | |
5115 || (**arg == '.' && (rettv->v_type == VAR_DICT | |
5116 || (!evaluate | |
5117 && (*arg)[1] != '.' | |
5118 && current_sctx.sc_version >= 2)))) | |
5095 { | 5119 { |
5096 dict_unref(selfdict); | 5120 dict_unref(selfdict); |
5097 if (rettv->v_type == VAR_DICT) | 5121 if (rettv->v_type == VAR_DICT) |
5098 { | 5122 { |
5099 selfdict = rettv->vval.v_dict; | 5123 selfdict = rettv->vval.v_dict; |
5106 { | 5130 { |
5107 clear_tv(rettv); | 5131 clear_tv(rettv); |
5108 ret = FAIL; | 5132 ret = FAIL; |
5109 } | 5133 } |
5110 } | 5134 } |
5135 else | |
5136 break; | |
5111 } | 5137 } |
5112 | 5138 |
5113 // Turn "dict.Func" into a partial for "Func" bound to "dict". | 5139 // Turn "dict.Func" into a partial for "Func" bound to "dict". |
5114 // Don't do this when "Func" is already a partial that was bound | 5140 // Don't do this when "Func" is already a partial that was bound |
5115 // explicitly (pt_auto is FALSE). | 5141 // explicitly (pt_auto is FALSE). |