# HG changeset patch # User Bram Moolenaar # Date 1617644704 -7200 # Node ID f76398d79c2ed264f687ae3024160038768e44bd # Parent caeae97697d1aa437f9303b5b2282c618bb31245 patch 8.2.2721: Vim9: cannot have a linebreak inside a lambda Commit: https://github.com/vim/vim/commit/2927c07b0ec627c13e863e1b84bec831743bce12 Author: Bram Moolenaar Date: Mon Apr 5 19:41:21 2021 +0200 patch 8.2.2721: Vim9: cannot have a linebreak inside a lambda Problem: Vim9: cannot have a linebreak inside a lambda. Solution: Compile the expression before the arguments. diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -2075,16 +2075,14 @@ def Test_expr7_new_lambda() enddef def Test_expr7_lambda_vim9script() - # TODO: make this work in a :def function var lines =<< trim END - vim9script var v = 10->((a) => a + 2 )() assert_equal(12, v) END - CheckScriptSuccess(lines) + CheckDefAndScriptSuccess(lines) # nested lambda with line breaks lines =<< trim END diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2721, +/**/ 2720, /**/ 2719, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3975,23 +3975,25 @@ compile_subscript( if (**arg == '(') { int argcount = 1; - char_u *expr; - garray_T *stack; + garray_T *stack = &cctx->ctx_type_stack; + int type_idx_start = stack->ga_len; type_T *type; + int expr_isn_start = cctx->ctx_instr.ga_len; + int expr_isn_end; + int arg_isn_count; // 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); + // + // Fist compile the function expression. + if (compile_parenthesis(arg, cctx, ppconst) == FAIL) return FAIL; - } - ++*arg; + + // Remember the next instruction index, where the instructions + // for arguments are being written. + expr_isn_end = cctx->ctx_instr.ga_len; + + // Compile the arguments. if (**arg != '(') { if (*skipwhite(*arg) == '(') @@ -4000,16 +4002,43 @@ compile_subscript( 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; - + // Move the instructions for the arguments to before the + // instructions of the expression and move the type of the + // expression after the argument types. This is what ISN_PCALL + // expects. stack = &cctx->ctx_type_stack; + arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end; + if (arg_isn_count > 0) + { + int expr_isn_count = expr_isn_end - expr_isn_start; + isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count); + + if (isn == NULL) + return FAIL; + mch_memmove(isn, ((isn_T *)cctx->ctx_instr.ga_data) + + expr_isn_start, + sizeof(isn_T) * expr_isn_count); + mch_memmove(((isn_T *)cctx->ctx_instr.ga_data) + + expr_isn_start, + ((isn_T *)cctx->ctx_instr.ga_data) + expr_isn_end, + sizeof(isn_T) * arg_isn_count); + mch_memmove(((isn_T *)cctx->ctx_instr.ga_data) + + expr_isn_start + arg_isn_count, + isn, sizeof(isn_T) * expr_isn_count); + vim_free(isn); + + type = ((type_T **)stack->ga_data)[type_idx_start]; + mch_memmove(((type_T **)stack->ga_data) + type_idx_start, + ((type_T **)stack->ga_data) + type_idx_start + 1, + sizeof(type_T *) + * (stack->ga_len - type_idx_start - 1)); + ((type_T **)stack->ga_data)[stack->ga_len - 1] = type; + } + type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (generate_PCALL(cctx, argcount, (char_u *)"[expression]", type, FALSE) == FAIL)