comparison src/vim9expr.c @ 27175:6af18c69c59d v8.2.4116

patch 8.2.4116: Vim9: cannot use a method with a complex expression in :def Commit: https://github.com/vim/vim/commit/c73499351aef8b611b13c70ef8706a7e98df67a8 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jan 16 20:59:39 2022 +0000 patch 8.2.4116: Vim9: cannot use a method with a complex expression in :def Problem: Vim9: cannot use a method with a complex expression in a :def function. Solution: Implement compiling the expression.
author Bram Moolenaar <Bram@vim.org>
date Sun, 16 Jan 2022 22:00:04 +0100
parents 98a01021e465
children 63f8dbcf6a74
comparison
equal deleted inserted replaced
27174:10acb2602253 27175:6af18c69c59d
1581 ret = FAIL; 1581 ret = FAIL;
1582 } 1582 }
1583 return ret; 1583 return ret;
1584 } 1584 }
1585 1585
1586 static int compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);
1587
1586 /* 1588 /*
1587 * Compile whatever comes after "name" or "name()". 1589 * Compile whatever comes after "name" or "name()".
1588 * Advances "*arg" only when something was recognized. 1590 * Advances "*arg" only when something was recognized.
1589 */ 1591 */
1590 static int 1592 static int
1649 return FAIL; 1651 return FAIL;
1650 } 1652 }
1651 } 1653 }
1652 else if (*p == '-' && p[1] == '>') 1654 else if (*p == '-' && p[1] == '>')
1653 { 1655 {
1654 char_u *pstart = p; 1656 char_u *pstart = p;
1655 1657 int alt;
1658 char_u *paren;
1659
1660 // something->method()
1656 if (generate_ppconst(cctx, ppconst) == FAIL) 1661 if (generate_ppconst(cctx, ppconst) == FAIL)
1657 return FAIL; 1662 return FAIL;
1658 ppconst->pp_is_const = FALSE; 1663 ppconst->pp_is_const = FALSE;
1659 1664
1660 // something->method()
1661 // Apply the '!', '-' and '+' first: 1665 // Apply the '!', '-' and '+' first:
1662 // -1.0->func() works like (-1.0)->func() 1666 // -1.0->func() works like (-1.0)->func()
1663 if (compile_leader(cctx, TRUE, start_leader, end_leader) == FAIL) 1667 if (compile_leader(cctx, TRUE, start_leader, end_leader) == FAIL)
1664 return FAIL; 1668 return FAIL;
1665 1669
1666 p += 2; 1670 p += 2;
1667 *arg = skipwhite(p); 1671 *arg = skipwhite(p);
1668 // No line break supported right after "->". 1672 // No line break supported right after "->".
1673
1674 // Three alternatives handled here:
1675 // 1. "base->name(" only a name, use compile_call()
1676 // 2. "base->(expr)(" evaluate "expr", then use PCALL
1677 // 3. "base->expr(" Same, find the end of "expr" by "("
1669 if (**arg == '(') 1678 if (**arg == '(')
1679 alt = 2;
1680 else
1681 {
1682 // alternative 1 or 3
1683 p = *arg;
1684 if (!eval_isnamec1(*p))
1685 {
1686 semsg(_(e_trailing_characters_str), pstart);
1687 return FAIL;
1688 }
1689 if (ASCII_ISALPHA(*p) && p[1] == ':')
1690 p += 2;
1691 for ( ; eval_isnamec(*p); ++p)
1692 ;
1693 if (*p == '(')
1694 {
1695 // alternative 1
1696 alt = 1;
1697 if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL)
1698 return FAIL;
1699 }
1700 else
1701 {
1702 // Must be alternative 3, find the "(". Only works within
1703 // one line.
1704 alt = 3;
1705 paren = vim_strchr(p, '(');
1706 if (paren == NULL)
1707 {
1708 semsg(_(e_missing_parenthesis_str), *arg);
1709 return FAIL;
1710 }
1711 }
1712 }
1713
1714 if (alt != 1)
1670 { 1715 {
1671 int argcount = 1; 1716 int argcount = 1;
1672 garray_T *stack = &cctx->ctx_type_stack; 1717 garray_T *stack = &cctx->ctx_type_stack;
1673 int type_idx_start = stack->ga_len; 1718 int type_idx_start = stack->ga_len;
1674 type_T *type; 1719 type_T *type;
1675 int expr_isn_start = cctx->ctx_instr.ga_len; 1720 int expr_isn_start = cctx->ctx_instr.ga_len;
1676 int expr_isn_end; 1721 int expr_isn_end;
1677 int arg_isn_count; 1722 int arg_isn_count;
1678 1723
1679 // Funcref call: list->(Refs[2])(arg) 1724 if (alt == 2)
1680 // or lambda: list->((arg) => expr)(arg) 1725 {
1681 // 1726 // Funcref call: list->(Refs[2])(arg)
1682 // Fist compile the function expression. 1727 // or lambda: list->((arg) => expr)(arg)
1683 if (compile_parenthesis(arg, cctx, ppconst) == FAIL) 1728 //
1684 return FAIL; 1729 // Fist compile the function expression.
1730 if (compile_parenthesis(arg, cctx, ppconst) == FAIL)
1731 return FAIL;
1732 }
1733 else
1734 {
1735 *paren = NUL;
1736 if (compile_expr8(arg, cctx, ppconst) == FAIL
1737 || *skipwhite(*arg) != NUL)
1738 {
1739 *paren = '(';
1740 semsg(_(e_invalid_expression_str), pstart);
1741 return FAIL;
1742 }
1743 *paren = '(';
1744 }
1685 1745
1686 // Remember the next instruction index, where the instructions 1746 // Remember the next instruction index, where the instructions
1687 // for arguments are being written. 1747 // for arguments are being written.
1688 expr_isn_end = cctx->ctx_instr.ga_len; 1748 expr_isn_end = cctx->ctx_instr.ga_len;
1689 1749
1740 1800
1741 type = get_type_on_stack(cctx, 0); 1801 type = get_type_on_stack(cctx, 0);
1742 if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL) 1802 if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL)
1743 return FAIL; 1803 return FAIL;
1744 } 1804 }
1745 else 1805
1746 {
1747 // method call: list->method()
1748 p = *arg;
1749 if (!eval_isnamec1(*p))
1750 {
1751 semsg(_(e_trailing_characters_str), pstart);
1752 return FAIL;
1753 }
1754 if (ASCII_ISALPHA(*p) && p[1] == ':')
1755 p += 2;
1756 for ( ; eval_isnamec(*p); ++p)
1757 ;
1758 if (*p != '(')
1759 {
1760 semsg(_(e_missing_parenthesis_str), *arg);
1761 return FAIL;
1762 }
1763 if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL)
1764 return FAIL;
1765 }
1766 if (keeping_dict) 1806 if (keeping_dict)
1767 { 1807 {
1768 keeping_dict = FALSE; 1808 keeping_dict = FALSE;
1769 if (generate_instr(cctx, ISN_CLEARDICT) == NULL) 1809 if (generate_instr(cctx, ISN_CLEARDICT) == NULL)
1770 return FAIL; 1810 return FAIL;