To: vim_dev@googlegroups.com Subject: Patch 8.2.2219 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2219 Problem: Vim9: method call with expression not supported. Solution: Implement expr->(expr)(). Files: src/vim9compile.c, src/testdir/test_vim9_expr.vim *** ../vim-8.2.2218/src/vim9compile.c 2020-12-25 19:25:41.742706213 +0100 --- src/vim9compile.c 2020-12-25 21:46:03.877525095 +0100 *************** *** 2817,2825 **** && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK) { garray_T *stack = &cctx->ctx_type_stack; ! type_T *type; - type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; res = generate_PCALL(cctx, argcount, namebuf, type, FALSE); goto theend; } --- 2817,2824 ---- && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK) { garray_T *stack = &cctx->ctx_type_stack; ! type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; res = generate_PCALL(cctx, argcount, namebuf, type, FALSE); goto theend; } *************** *** 3430,3435 **** --- 3429,3447 ---- } /* + * Skip over an expression, ignoring most errors. + */ + static void + skip_expr_cctx(char_u **arg, cctx_T *cctx) + { + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_cctx = cctx; + skip_expr(arg, &evalarg); + } + + /* * Compile code to apply '-', '+' and '!'. * When "numeric_only" is TRUE do not apply '!'. */ *************** *** 3488,3493 **** --- 3500,3537 ---- } /* + * Compile "(expression)": recursive! + * Return FAIL/OK. + */ + static int + compile_parenthesis(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) + { + int ret; + + *arg = skipwhite(*arg + 1); + if (ppconst->pp_used <= PPSIZE - 10) + { + ret = compile_expr1(arg, cctx, ppconst); + } + else + { + // Not enough space in ppconst, flush constants. + if (generate_ppconst(cctx, ppconst) == FAIL) + return FAIL; + ret = compile_expr0(arg, cctx); + } + *arg = skipwhite(*arg); + if (**arg == ')') + ++*arg; + else if (ret == OK) + { + emsg(_(e_missing_close)); + ret = FAIL; + } + return ret; + } + + /* * Compile whatever comes after "name" or "name()". * Advances "*arg" only when something was recognized. */ *************** *** 3572,3581 **** } else if (**arg == '(') { ! // Funcref call: list->(Refs[2])() ! // or lambda: list->((arg) => expr)() ! // TODO: make this work ! if (compile_lambda_call(arg, cctx) == FAIL) return FAIL; } else --- 3616,3657 ---- } else if (**arg == '(') { ! int argcount = 1; ! char_u *expr; ! garray_T *stack; ! type_T *type; ! ! // Funcref call: list->(Refs[2])(arg) ! // or lambda: list->((arg) => expr)(arg) ! // Fist compile the arguments. ! expr = *arg; ! *arg = skipwhite(*arg + 1); ! skip_expr_cctx(arg, cctx); ! *arg = skipwhite(*arg); ! if (**arg != ')') ! { ! semsg(_(e_missing_paren), *arg); ! return FAIL; ! } ! ++*arg; ! if (**arg != '(') ! { ! semsg(_(e_missing_paren), *arg); ! return FAIL; ! } ! ! *arg = skipwhite(*arg + 1); ! if (compile_arguments(arg, cctx, &argcount) == FAIL) ! return FAIL; ! ! // Compile the function expression. ! if (compile_parenthesis(&expr, cctx, ppconst) == FAIL) ! return FAIL; ! ! stack = &cctx->ctx_type_stack; ! type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! if (generate_PCALL(cctx, argcount, ! (char_u *)"[expression]", type, FALSE) == FAIL) return FAIL; } else *************** *** 3998,4025 **** break; } } ! ! // (expression): recursive! ! *arg = skipwhite(*arg + 1); ! if (ppconst->pp_used <= PPSIZE - 10) ! { ! ret = compile_expr1(arg, cctx, ppconst); ! } ! else ! { ! // Not enough space in ppconst, flush constants. ! if (generate_ppconst(cctx, ppconst) == FAIL) ! return FAIL; ! ret = compile_expr0(arg, cctx); ! } ! *arg = skipwhite(*arg); ! if (**arg == ')') ! ++*arg; ! else if (ret == OK) ! { ! emsg(_(e_missing_close)); ! ret = FAIL; ! } } break; --- 4074,4080 ---- break; } } ! ret = compile_parenthesis(arg, cctx, ppconst); } break; *************** *** 4597,4603 **** * end: */ static int ! compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { char_u *p; int ppconst_used = ppconst->pp_used; --- 4652,4658 ---- * end: */ static int ! compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { char_u *p; int ppconst_used = ppconst->pp_used; *************** *** 4606,4616 **** // Ignore all kinds of errors when not producing code. if (cctx->ctx_skip == SKIP_YES) { ! evalarg_T evalarg; ! ! CLEAR_FIELD(evalarg); ! evalarg.eval_cctx = cctx; ! skip_expr(arg, &evalarg); return OK; } --- 4661,4667 ---- // Ignore all kinds of errors when not producing code. if (cctx->ctx_skip == SKIP_YES) { ! skip_expr_cctx(arg, cctx); return OK; } *** ../vim-8.2.2218/src/testdir/test_vim9_expr.vim 2020-12-25 15:24:19.902942195 +0100 --- src/testdir/test_vim9_expr.vim 2020-12-25 21:53:38.330148915 +0100 *************** *** 2560,2565 **** --- 2560,2598 ---- delete('Xruntime', 'rf') enddef + def Test_expr7_method_call() + new + setline(1, ['first', 'last']) + 'second'->append(1) + "third"->append(2) + assert_equal(['first', 'second', 'third', 'last'], getline(1, '$')) + bwipe! + + var bufnr = bufnr() + var loclist = [{bufnr: bufnr, lnum: 42, col: 17, text: 'wrong'}] + loclist->setloclist(0) + assert_equal([{bufnr: bufnr, + lnum: 42, + col: 17, + text: 'wrong', + pattern: '', + valid: 1, + vcol: 0, + nr: 0, + type: '', + module: ''} + ], getloclist(0)) + + var result: bool = get({n: 0}, 'n', 0) + assert_equal(false, result) + + assert_equal('+string+', 'string'->((s) => '+' .. s .. '+')()) + assert_equal('-text-', 'text'->((s, c) => c .. s .. c)('-')) + + var Join = (l) => join(l, 'x') + assert_equal('axb', ['a', 'b']->(Join)()) + enddef + def Test_expr7_not() var lines =<< trim END *************** *** 2852,2884 **** one) enddef - def Test_expr7_method_call() - new - setline(1, ['first', 'last']) - 'second'->append(1) - "third"->append(2) - assert_equal(['first', 'second', 'third', 'last'], getline(1, '$')) - bwipe! - - var bufnr = bufnr() - var loclist = [{bufnr: bufnr, lnum: 42, col: 17, text: 'wrong'}] - loclist->setloclist(0) - assert_equal([{bufnr: bufnr, - lnum: 42, - col: 17, - text: 'wrong', - pattern: '', - valid: 1, - vcol: 0, - nr: 0, - type: '', - module: ''} - ], getloclist(0)) - - var result: bool = get({n: 0}, 'n', 0) - assert_equal(false, result) - enddef - func Test_expr7_trailing_fails() call CheckDefFailure(['var l = [2]', 'l->{l -> add(l, 8)}'], 'E107:', 2) call CheckDefFailure(['var l = [2]', 'l->{l -> add(l, 8)} ()'], 'E274:', 2) --- 2885,2890 ---- *** ../vim-8.2.2218/src/version.c 2020-12-25 20:24:48.172245018 +0100 --- src/version.c 2020-12-25 21:52:17.594679993 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2219, /**/ -- How To Keep A Healthy Level Of Insanity: 14. Put mosquito netting around your work area. Play a tape of jungle sounds all day. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///