Mercurial > vim
comparison src/vim9compile.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 | 1a4e22aa2eb3 |
children | 44611891e22c |
comparison
equal
deleted
inserted
replaced
21207:2a1156d4950f | 21208:09377fd59b2e |
---|---|
2395 /* | 2395 /* |
2396 * Return a pointer to the next line that isn't empty or only contains a | 2396 * Return a pointer to the next line that isn't empty or only contains a |
2397 * comment. Skips over white space. | 2397 * comment. Skips over white space. |
2398 * Returns NULL if there is none. | 2398 * Returns NULL if there is none. |
2399 */ | 2399 */ |
2400 static char_u * | 2400 char_u * |
2401 peek_next_line(cctx_T *cctx) | 2401 peek_next_line_from_context(cctx_T *cctx) |
2402 { | 2402 { |
2403 int lnum = cctx->ctx_lnum; | 2403 int lnum = cctx->ctx_lnum; |
2404 | 2404 |
2405 while (++lnum < cctx->ctx_ufunc->uf_lines.ga_len) | 2405 while (++lnum < cctx->ctx_ufunc->uf_lines.ga_len) |
2406 { | 2406 { |
2428 char_u *p = skipwhite(arg); | 2428 char_u *p = skipwhite(arg); |
2429 | 2429 |
2430 *nextp = NULL; | 2430 *nextp = NULL; |
2431 if (*p == NUL || (VIM_ISWHITE(*arg) && comment_start(p))) | 2431 if (*p == NUL || (VIM_ISWHITE(*arg) && comment_start(p))) |
2432 { | 2432 { |
2433 *nextp = peek_next_line(cctx); | 2433 *nextp = peek_next_line_from_context(cctx); |
2434 if (*nextp != NULL) | 2434 if (*nextp != NULL) |
2435 return *nextp; | 2435 return *nextp; |
2436 } | 2436 } |
2437 return p; | 2437 return p; |
2438 } | 2438 } |
2440 /* | 2440 /* |
2441 * Get the next line of the function from "cctx". | 2441 * Get the next line of the function from "cctx". |
2442 * Skips over empty lines. Skips over comment lines if "skip_comment" is TRUE. | 2442 * Skips over empty lines. Skips over comment lines if "skip_comment" is TRUE. |
2443 * Returns NULL when at the end. | 2443 * Returns NULL when at the end. |
2444 */ | 2444 */ |
2445 static char_u * | 2445 char_u * |
2446 next_line_from_context(cctx_T *cctx, int skip_comment) | 2446 next_line_from_context(cctx_T *cctx, int skip_comment) |
2447 { | 2447 { |
2448 char_u *line; | 2448 char_u *line; |
2449 | 2449 |
2450 do | 2450 do |
3077 static int | 3077 static int |
3078 compile_lambda(char_u **arg, cctx_T *cctx) | 3078 compile_lambda(char_u **arg, cctx_T *cctx) |
3079 { | 3079 { |
3080 typval_T rettv; | 3080 typval_T rettv; |
3081 ufunc_T *ufunc; | 3081 ufunc_T *ufunc; |
3082 evalarg_T evalarg; | |
3083 | |
3084 CLEAR_FIELD(evalarg); | |
3085 evalarg.eval_flags = EVAL_EVALUATE; | |
3086 evalarg.eval_cctx = cctx; | |
3082 | 3087 |
3083 // Get the funcref in "rettv". | 3088 // Get the funcref in "rettv". |
3084 if (get_lambda_tv(arg, &rettv, &EVALARG_EVALUATE) != OK) | 3089 if (get_lambda_tv(arg, &rettv, &evalarg) != OK) |
3085 return FAIL; | 3090 return FAIL; |
3086 | 3091 |
3087 ufunc = rettv.vval.v_partial->pt_func; | 3092 ufunc = rettv.vval.v_partial->pt_func; |
3088 ++ufunc->uf_refcount; | 3093 ++ufunc->uf_refcount; |
3089 clear_tv(&rettv); | 3094 clear_tv(&rettv); |
3533 return OK; | 3538 return OK; |
3534 } | 3539 } |
3535 | 3540 |
3536 /* | 3541 /* |
3537 * Compile whatever comes after "name" or "name()". | 3542 * Compile whatever comes after "name" or "name()". |
3543 * Advances "*arg" only when something was recognized. | |
3538 */ | 3544 */ |
3539 static int | 3545 static int |
3540 compile_subscript( | 3546 compile_subscript( |
3541 char_u **arg, | 3547 char_u **arg, |
3542 cctx_T *cctx, | 3548 cctx_T *cctx, |
3548 { | 3554 { |
3549 char_u *p = skipwhite(*arg); | 3555 char_u *p = skipwhite(*arg); |
3550 | 3556 |
3551 if (*p == NUL || (VIM_ISWHITE(**arg) && comment_start(p))) | 3557 if (*p == NUL || (VIM_ISWHITE(**arg) && comment_start(p))) |
3552 { | 3558 { |
3553 char_u *next = peek_next_line(cctx); | 3559 char_u *next = peek_next_line_from_context(cctx); |
3554 | 3560 |
3555 // If a following line starts with "->{" or "->X" advance to that | 3561 // If a following line starts with "->{" or "->X" advance to that |
3556 // line, so that a line break before "->" is allowed. | 3562 // line, so that a line break before "->" is allowed. |
3557 if (next != NULL && next[0] == '-' && next[1] == '>' | 3563 if (next != NULL && next[0] == '-' && next[1] == '>' |
3558 && (next[2] == '{' || ASCII_ISALPHA(next[2]))) | 3564 && (next[2] == '{' || ASCII_ISALPHA(next[2]))) |
3559 { | 3565 { |
3560 next = next_line_from_context(cctx, TRUE); | 3566 next = next_line_from_context(cctx, TRUE); |
3561 if (next == NULL) | 3567 if (next == NULL) |
3562 return FAIL; | 3568 return FAIL; |
3563 *arg = skipwhite(next); | 3569 *arg = next; |
3564 } | 3570 p = skipwhite(*arg); |
3565 } | 3571 } |
3566 | 3572 } |
3567 if (**arg == '(') | 3573 |
3574 if (*p == '(') | |
3568 { | 3575 { |
3569 garray_T *stack = &cctx->ctx_type_stack; | 3576 garray_T *stack = &cctx->ctx_type_stack; |
3570 type_T *type; | 3577 type_T *type; |
3571 int argcount = 0; | 3578 int argcount = 0; |
3572 | 3579 |
3574 return FAIL; | 3581 return FAIL; |
3575 | 3582 |
3576 // funcref(arg) | 3583 // funcref(arg) |
3577 type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | 3584 type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; |
3578 | 3585 |
3579 *arg = skipwhite(*arg + 1); | 3586 *arg = skipwhite(p + 1); |
3580 if (compile_arguments(arg, cctx, &argcount) == FAIL) | 3587 if (compile_arguments(arg, cctx, &argcount) == FAIL) |
3581 return FAIL; | 3588 return FAIL; |
3582 if (generate_PCALL(cctx, argcount, end_leader, type, TRUE) == FAIL) | 3589 if (generate_PCALL(cctx, argcount, end_leader, type, TRUE) == FAIL) |
3583 return FAIL; | 3590 return FAIL; |
3584 } | 3591 } |
3585 else if (**arg == '-' && (*arg)[1] == '>') | 3592 else if (*p == '-' && p[1] == '>') |
3586 { | 3593 { |
3587 if (generate_ppconst(cctx, ppconst) == FAIL) | 3594 if (generate_ppconst(cctx, ppconst) == FAIL) |
3588 return FAIL; | 3595 return FAIL; |
3589 | 3596 |
3590 // something->method() | 3597 // something->method() |
3592 // -1.0->func() works like (-1.0)->func() | 3599 // -1.0->func() works like (-1.0)->func() |
3593 if (compile_leader(cctx, *start_leader, end_leader) == FAIL) | 3600 if (compile_leader(cctx, *start_leader, end_leader) == FAIL) |
3594 return FAIL; | 3601 return FAIL; |
3595 *start_leader = end_leader; // don't apply again later | 3602 *start_leader = end_leader; // don't apply again later |
3596 | 3603 |
3597 p = *arg + 2; | 3604 p += 2; |
3598 *arg = skipwhite(p); | 3605 *arg = skipwhite(p); |
3599 if (may_get_next_line(p, arg, cctx) == FAIL) | 3606 if (may_get_next_line(p, arg, cctx) == FAIL) |
3600 return FAIL; | 3607 return FAIL; |
3601 if (**arg == '{') | 3608 if (**arg == '{') |
3602 { | 3609 { |
3620 // TODO: base value may not be the first argument | 3627 // TODO: base value may not be the first argument |
3621 if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) | 3628 if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) |
3622 return FAIL; | 3629 return FAIL; |
3623 } | 3630 } |
3624 } | 3631 } |
3625 else if (**arg == '[') | 3632 else if (*p == '[') |
3626 { | 3633 { |
3627 garray_T *stack = &cctx->ctx_type_stack; | 3634 garray_T *stack = &cctx->ctx_type_stack; |
3628 type_T **typep; | 3635 type_T **typep; |
3629 | 3636 |
3630 // list index: list[123] | 3637 // list index: list[123] |
3633 // TODO: more arguments | 3640 // TODO: more arguments |
3634 // TODO: recognize list or dict at runtime | 3641 // TODO: recognize list or dict at runtime |
3635 if (generate_ppconst(cctx, ppconst) == FAIL) | 3642 if (generate_ppconst(cctx, ppconst) == FAIL) |
3636 return FAIL; | 3643 return FAIL; |
3637 | 3644 |
3638 p = *arg + 1; | 3645 ++p; |
3639 *arg = skipwhite(p); | 3646 *arg = skipwhite(p); |
3640 if (may_get_next_line(p, arg, cctx) == FAIL) | 3647 if (may_get_next_line(p, arg, cctx) == FAIL) |
3641 return FAIL; | 3648 return FAIL; |
3642 if (compile_expr0(arg, cctx) == FAIL) | 3649 if (compile_expr0(arg, cctx) == FAIL) |
3643 return FAIL; | 3650 return FAIL; |
3669 { | 3676 { |
3670 emsg(_(e_listdictblobreq)); | 3677 emsg(_(e_listdictblobreq)); |
3671 return FAIL; | 3678 return FAIL; |
3672 } | 3679 } |
3673 } | 3680 } |
3674 else if (**arg == '.' && (*arg)[1] != '.') | 3681 else if (*p == '.' && p[1] != '.') |
3675 { | 3682 { |
3676 if (generate_ppconst(cctx, ppconst) == FAIL) | 3683 if (generate_ppconst(cctx, ppconst) == FAIL) |
3677 return FAIL; | 3684 return FAIL; |
3678 | 3685 |
3679 ++*arg; | 3686 *arg = p + 1; |
3680 if (may_get_next_line(*arg, arg, cctx) == FAIL) | 3687 if (may_get_next_line(*arg, arg, cctx) == FAIL) |
3681 return FAIL; | 3688 return FAIL; |
3682 // dictionary member: dict.name | 3689 // dictionary member: dict.name |
3683 p = *arg; | 3690 p = *arg; |
3684 if (eval_isnamec1(*p)) | 3691 if (eval_isnamec1(*p)) |