To: vim_dev@googlegroups.com Subject: Patch 8.2.4116 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4116 Problem: Vim9: cannot use a method with a complex expression in a :def function. Solution: Implement compiling the expression. Files: src/vim9expr.c, src/testdir/test_vim9_expr.vim *** ../vim-8.2.4115/src/vim9expr.c 2022-01-13 21:15:17.241958539 +0000 --- src/vim9expr.c 2022-01-16 20:47:04.130684769 +0000 *************** *** 1583,1588 **** --- 1583,1590 ---- return ret; } + static int compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst); + /* * Compile whatever comes after "name" or "name()". * Advances "*arg" only when something was recognized. *************** *** 1651,1663 **** } else if (*p == '-' && p[1] == '>') { ! char_u *pstart = p; if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; ppconst->pp_is_const = FALSE; - // something->method() // Apply the '!', '-' and '+' first: // -1.0->func() works like (-1.0)->func() if (compile_leader(cctx, TRUE, start_leader, end_leader) == FAIL) --- 1653,1667 ---- } else if (*p == '-' && p[1] == '>') { ! char_u *pstart = p; ! int alt; ! char_u *paren; + // something->method() if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; ppconst->pp_is_const = FALSE; // Apply the '!', '-' and '+' first: // -1.0->func() works like (-1.0)->func() if (compile_leader(cctx, TRUE, start_leader, end_leader) == FAIL) *************** *** 1666,1672 **** --- 1670,1717 ---- p += 2; *arg = skipwhite(p); // No line break supported right after "->". + + // Three alternatives handled here: + // 1. "base->name(" only a name, use compile_call() + // 2. "base->(expr)(" evaluate "expr", then use PCALL + // 3. "base->expr(" Same, find the end of "expr" by "(" if (**arg == '(') + alt = 2; + else + { + // alternative 1 or 3 + p = *arg; + if (!eval_isnamec1(*p)) + { + semsg(_(e_trailing_characters_str), pstart); + return FAIL; + } + if (ASCII_ISALPHA(*p) && p[1] == ':') + p += 2; + for ( ; eval_isnamec(*p); ++p) + ; + if (*p == '(') + { + // alternative 1 + alt = 1; + if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) + return FAIL; + } + else + { + // Must be alternative 3, find the "(". Only works within + // one line. + alt = 3; + paren = vim_strchr(p, '('); + if (paren == NULL) + { + semsg(_(e_missing_parenthesis_str), *arg); + return FAIL; + } + } + } + + if (alt != 1) { int argcount = 1; garray_T *stack = &cctx->ctx_type_stack; *************** *** 1676,1687 **** int expr_isn_end; int arg_isn_count; ! // Funcref call: list->(Refs[2])(arg) ! // or lambda: list->((arg) => expr)(arg) ! // ! // Fist compile the function expression. ! if (compile_parenthesis(arg, cctx, ppconst) == FAIL) ! return FAIL; // Remember the next instruction index, where the instructions // for arguments are being written. --- 1721,1747 ---- int expr_isn_end; int arg_isn_count; ! if (alt == 2) ! { ! // Funcref call: list->(Refs[2])(arg) ! // or lambda: list->((arg) => expr)(arg) ! // ! // Fist compile the function expression. ! if (compile_parenthesis(arg, cctx, ppconst) == FAIL) ! return FAIL; ! } ! else ! { ! *paren = NUL; ! if (compile_expr8(arg, cctx, ppconst) == FAIL ! || *skipwhite(*arg) != NUL) ! { ! *paren = '('; ! semsg(_(e_invalid_expression_str), pstart); ! return FAIL; ! } ! *paren = '('; ! } // Remember the next instruction index, where the instructions // for arguments are being written. *************** *** 1742,1768 **** if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL) return FAIL; } ! else ! { ! // method call: list->method() ! p = *arg; ! if (!eval_isnamec1(*p)) ! { ! semsg(_(e_trailing_characters_str), pstart); ! return FAIL; ! } ! if (ASCII_ISALPHA(*p) && p[1] == ':') ! p += 2; ! for ( ; eval_isnamec(*p); ++p) ! ; ! if (*p != '(') ! { ! semsg(_(e_missing_parenthesis_str), *arg); ! return FAIL; ! } ! if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) ! return FAIL; ! } if (keeping_dict) { keeping_dict = FALSE; --- 1802,1808 ---- if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL) return FAIL; } ! if (keeping_dict) { keeping_dict = FALSE; *** ../vim-8.2.4115/src/testdir/test_vim9_expr.vim 2022-01-16 19:38:04.218156782 +0000 --- src/testdir/test_vim9_expr.vim 2022-01-16 20:41:17.602768656 +0000 *************** *** 3140,3146 **** CheckDefAndScriptSuccess(lines) lines =<< trim END - vim9script def SetNumber(n: number) g:number = n enddef --- 3140,3145 ---- *************** *** 3166,3172 **** unlet g:number END ! CheckScriptSuccess(lines) # TODO: CheckDefAndScriptSuccess() lines =<< trim END def RetVoid() --- 3165,3171 ---- unlet g:number END ! CheckDefAndScriptSuccess(lines) lines =<< trim END def RetVoid() *** ../vim-8.2.4115/src/version.c 2022-01-16 19:38:04.222156780 +0000 --- src/version.c 2022-01-16 20:54:32.090476466 +0000 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 4116, /**/ -- [clop clop] ARTHUR: Old woman! DENNIS: Man! ARTHUR: Man, sorry. What knight lives in that castle over there? DENNIS: I'm thirty seven. ARTHUR: What? DENNIS: I'm thirty seven -- I'm not old! The Quest for the Holy Grail (Monty Python) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///