Mercurial > vim
comparison src/vim9expr.c @ 28692:bfd8e25fa207 v8.2.4870
patch 8.2.4870: Vim9: expression in :substitute is not compiled
Commit: https://github.com/vim/vim/commit/f3b4895f2727e3849ca10030b251cccd9d1383f3
Author: LemonBoy <thatlemon@gmail.com>
Date: Thu May 5 13:53:03 2022 +0100
patch 8.2.4870: Vim9: expression in :substitute is not compiled
Problem: Vim9: expression in :substitute is not compiled.
Solution: Use an INSTR instruction if possible. (closes https://github.com/vim/vim/issues/10334)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 05 May 2022 15:00:04 +0200 |
parents | d550054e1328 |
children | 723c7d940cba |
comparison
equal
deleted
inserted
replaced
28691:ca54846af861 | 28692:bfd8e25fa207 |
---|---|
565 return res; | 565 return res; |
566 } | 566 } |
567 | 567 |
568 /* | 568 /* |
569 * Compile a string in a ISN_PUSHS instruction into an ISN_INSTR. | 569 * Compile a string in a ISN_PUSHS instruction into an ISN_INSTR. |
570 * "str_offset" is the number of leading bytes to skip from the string. | |
570 * Returns FAIL if compilation fails. | 571 * Returns FAIL if compilation fails. |
571 */ | 572 */ |
572 static int | 573 static int |
573 compile_string(isn_T *isn, cctx_T *cctx) | 574 compile_string(isn_T *isn, cctx_T *cctx, int str_offset) |
574 { | 575 { |
575 char_u *s = isn->isn_arg.string; | 576 char_u *s = isn->isn_arg.string + str_offset; |
576 garray_T save_ga = cctx->ctx_instr; | 577 garray_T save_ga = cctx->ctx_instr; |
577 int expr_res; | 578 int expr_res; |
578 int trailing_error; | 579 int trailing_error; |
579 int instr_count; | 580 int instr_count; |
580 isn_T *instr = NULL; | 581 isn_T *instr = NULL; |
614 isn->isn_arg.instr = instr; | 615 isn->isn_arg.instr = instr; |
615 return OK; | 616 return OK; |
616 } | 617 } |
617 | 618 |
618 /* | 619 /* |
620 * List of special functions for "compile_arguments". | |
621 */ | |
622 typedef enum { | |
623 CA_NOT_SPECIAL, | |
624 CA_SEARCHPAIR, // {skip} in searchpair() and searchpairpos() | |
625 CA_SUBSTITUTE, // {sub} in substitute(), when prefixed with \= | |
626 } ca_special_T; | |
627 | |
628 /* | |
619 * Compile the argument expressions. | 629 * Compile the argument expressions. |
620 * "arg" points to just after the "(" and is advanced to after the ")" | 630 * "arg" points to just after the "(" and is advanced to after the ")" |
621 */ | 631 */ |
622 static int | 632 static int |
623 compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, int is_searchpair) | 633 compile_arguments( |
634 char_u **arg, | |
635 cctx_T *cctx, | |
636 int *argcount, | |
637 ca_special_T special_fn) | |
624 { | 638 { |
625 char_u *p = *arg; | 639 char_u *p = *arg; |
626 char_u *whitep = *arg; | 640 char_u *whitep = *arg; |
627 int must_end = FALSE; | 641 int must_end = FALSE; |
628 int instr_count; | 642 int instr_count; |
645 instr_count = cctx->ctx_instr.ga_len; | 659 instr_count = cctx->ctx_instr.ga_len; |
646 if (compile_expr0(&p, cctx) == FAIL) | 660 if (compile_expr0(&p, cctx) == FAIL) |
647 return FAIL; | 661 return FAIL; |
648 ++*argcount; | 662 ++*argcount; |
649 | 663 |
650 if (is_searchpair && *argcount == 5 | 664 if (special_fn == CA_SEARCHPAIR && *argcount == 5 |
651 && cctx->ctx_instr.ga_len == instr_count + 1) | 665 && cctx->ctx_instr.ga_len == instr_count + 1) |
652 { | 666 { |
653 isn_T *isn = ((isn_T *)cctx->ctx_instr.ga_data) + instr_count; | 667 isn_T *isn = ((isn_T *)cctx->ctx_instr.ga_data) + instr_count; |
654 | 668 |
655 // {skip} argument of searchpair() can be compiled if not empty | 669 // {skip} argument of searchpair() can be compiled if not empty |
656 if (isn->isn_type == ISN_PUSHS && *isn->isn_arg.string != NUL) | 670 if (isn->isn_type == ISN_PUSHS && *isn->isn_arg.string != NUL) |
657 compile_string(isn, cctx); | 671 compile_string(isn, cctx, 0); |
672 } | |
673 else if (special_fn == CA_SUBSTITUTE && *argcount == 3 | |
674 && cctx->ctx_instr.ga_len == instr_count + 1) | |
675 { | |
676 isn_T *isn = ((isn_T *)cctx->ctx_instr.ga_data) + instr_count; | |
677 | |
678 // {sub} argument of substitute() can be compiled if it starts | |
679 // with \= | |
680 if (isn->isn_type == ISN_PUSHS && isn->isn_arg.string[0] == '\\' | |
681 && isn->isn_arg.string[1] == '=') | |
682 compile_string(isn, cctx, 2); | |
658 } | 683 } |
659 | 684 |
660 if (*p != ',' && *skipwhite(p) == ',') | 685 if (*p != ',' && *skipwhite(p) == ',') |
661 { | 686 { |
662 semsg(_(e_no_white_space_allowed_before_str_str), ",", p); | 687 semsg(_(e_no_white_space_allowed_before_str_str), ",", p); |
704 int error = FCERR_NONE; | 729 int error = FCERR_NONE; |
705 ufunc_T *ufunc = NULL; | 730 ufunc_T *ufunc = NULL; |
706 int res = FAIL; | 731 int res = FAIL; |
707 int is_autoload; | 732 int is_autoload; |
708 int has_g_namespace; | 733 int has_g_namespace; |
709 int is_searchpair; | 734 ca_special_T special_fn; |
710 imported_T *import; | 735 imported_T *import; |
711 | 736 |
712 if (varlen >= sizeof(namebuf)) | 737 if (varlen >= sizeof(namebuf)) |
713 { | 738 { |
714 semsg(_(e_name_too_long_str), name); | 739 semsg(_(e_name_too_long_str), name); |
774 | 799 |
775 name = fname_trans_sid(namebuf, fname_buf, &tofree, &error); | 800 name = fname_trans_sid(namebuf, fname_buf, &tofree, &error); |
776 | 801 |
777 // We handle the "skip" argument of searchpair() and searchpairpos() | 802 // We handle the "skip" argument of searchpair() and searchpairpos() |
778 // differently. | 803 // differently. |
779 is_searchpair = (varlen == 6 && STRNCMP(*arg, "search", 6) == 0) | 804 if ((varlen == 6 && STRNCMP(*arg, "search", 6) == 0) |
780 || (varlen == 9 && STRNCMP(*arg, "searchpos", 9) == 0) | 805 || (varlen == 9 && STRNCMP(*arg, "searchpos", 9) == 0) |
781 || (varlen == 10 && STRNCMP(*arg, "searchpair", 10) == 0) | 806 || (varlen == 10 && STRNCMP(*arg, "searchpair", 10) == 0) |
782 || (varlen == 13 && STRNCMP(*arg, "searchpairpos", 13) == 0); | 807 || (varlen == 13 && STRNCMP(*arg, "searchpairpos", 13) == 0)) |
808 special_fn = CA_SEARCHPAIR; | |
809 else if (varlen == 10 && STRNCMP(*arg, "substitute", 10) == 0) | |
810 special_fn = CA_SUBSTITUTE; | |
811 else | |
812 special_fn = CA_NOT_SPECIAL; | |
783 | 813 |
784 *arg = skipwhite(*arg + varlen + 1); | 814 *arg = skipwhite(*arg + varlen + 1); |
785 if (compile_arguments(arg, cctx, &argcount, is_searchpair) == FAIL) | 815 if (compile_arguments(arg, cctx, &argcount, special_fn) == FAIL) |
786 goto theend; | 816 goto theend; |
787 | 817 |
788 is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL; | 818 is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL; |
789 if (ASCII_ISLOWER(*name) && name[1] != ':' && !is_autoload) | 819 if (ASCII_ISLOWER(*name) && name[1] != ':' && !is_autoload) |
790 { | 820 { |
1715 | 1745 |
1716 // funcref(arg) | 1746 // funcref(arg) |
1717 type = get_type_on_stack(cctx, 0); | 1747 type = get_type_on_stack(cctx, 0); |
1718 | 1748 |
1719 *arg = skipwhite(p + 1); | 1749 *arg = skipwhite(p + 1); |
1720 if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL) | 1750 if (compile_arguments(arg, cctx, &argcount, CA_NOT_SPECIAL) == FAIL) |
1721 return FAIL; | 1751 return FAIL; |
1722 if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL) | 1752 if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL) |
1723 return FAIL; | 1753 return FAIL; |
1724 if (keeping_dict) | 1754 if (keeping_dict) |
1725 { | 1755 { |
1846 // Remember the next instruction index, where the instructions | 1876 // Remember the next instruction index, where the instructions |
1847 // for arguments are being written. | 1877 // for arguments are being written. |
1848 expr_isn_end = cctx->ctx_instr.ga_len; | 1878 expr_isn_end = cctx->ctx_instr.ga_len; |
1849 | 1879 |
1850 *arg = skipwhite(*arg + 1); | 1880 *arg = skipwhite(*arg + 1); |
1851 if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL) | 1881 if (compile_arguments(arg, cctx, &argcount, CA_NOT_SPECIAL) |
1882 == FAIL) | |
1852 return FAIL; | 1883 return FAIL; |
1853 | 1884 |
1854 // Move the instructions for the arguments to before the | 1885 // Move the instructions for the arguments to before the |
1855 // instructions of the expression and move the type of the | 1886 // instructions of the expression and move the type of the |
1856 // expression after the argument types. This is what ISN_PCALL | 1887 // expression after the argument types. This is what ISN_PCALL |