diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-08-09 23:25:08 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-08-09 23:25:08 +0200 |
commit | 22a0c0c4ecd23b6c43f79ba9b92899ca0b426e29 (patch) | |
tree | 4c2ad3650de93bd7282b196205e862f4c23ce8ba /src/eval.c | |
parent | 0c779e8e4831c538918ae835ce3365af028e36ea (diff) | |
download | vim-git-22a0c0c4ecd23b6c43f79ba9b92899ca0b426e29.tar.gz |
patch 8.1.1834: cannot use a lambda as a methodv8.1.1834
Problem: Cannot use a lambda as a method.
Solution: Implement ->{lambda}(). (closes #4768)
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 150 |
1 files changed, 103 insertions, 47 deletions
diff --git a/src/eval.c b/src/eval.c index 0f9c95fa0..1967f9401 100644 --- a/src/eval.c +++ b/src/eval.c @@ -32,6 +32,7 @@ static char *e_cannot_mod = N_("E995: Cannot modify existing variable"); #ifdef FEAT_FLOAT static char *e_float_as_string = N_("E806: using Float as a String"); #endif +static char *e_nowhitespace = N_("E274: No white space allowed before parenthesis"); #define NAMESPACE_CHAR (char_u *)"abglstvw" @@ -3693,7 +3694,6 @@ eval_func( vim_memset(&funcexe, 0, sizeof(funcexe)); funcexe.firstline = curwin->w_cursor.lnum; funcexe.lastline = curwin->w_cursor.lnum; - funcexe.doesrange = &len; funcexe.evaluate = evaluate; funcexe.partial = partial; funcexe.basetv = basetv; @@ -4822,6 +4822,95 @@ eval7( } /* + * Call the function referred to in "rettv". + */ + static int +call_func_rettv( + char_u **arg, + typval_T *rettv, + int evaluate, + dict_T *selfdict, + typval_T *basetv) +{ + partial_T *pt = NULL; + funcexe_T funcexe; + typval_T functv; + char_u *s; + int ret; + + // need to copy the funcref so that we can clear rettv + if (evaluate) + { + functv = *rettv; + rettv->v_type = VAR_UNKNOWN; + + /* Invoke the function. Recursive! */ + if (functv.v_type == VAR_PARTIAL) + { + pt = functv.vval.v_partial; + s = partial_name(pt); + } + else + s = functv.vval.v_string; + } + else + s = (char_u *)""; + + vim_memset(&funcexe, 0, sizeof(funcexe)); + funcexe.firstline = curwin->w_cursor.lnum; + funcexe.lastline = curwin->w_cursor.lnum; + funcexe.evaluate = evaluate; + funcexe.partial = pt; + funcexe.selfdict = selfdict; + funcexe.basetv = basetv; + ret = get_func_tv(s, -1, rettv, arg, &funcexe); + + /* Clear the funcref afterwards, so that deleting it while + * evaluating the arguments is possible (see test55). */ + if (evaluate) + clear_tv(&functv); + + return ret; +} + +/* + * Evaluate "->method()". + * "*arg" points to the '-'. + * Returns FAIL or OK. "*arg" is advanced to after the ')'. + */ + static int +eval_lambda( + char_u **arg, + typval_T *rettv, + int evaluate, + int verbose) /* give error messages */ +{ + typval_T base = *rettv; + int ret; + + // Skip over the ->. + *arg += 2; + rettv->v_type = VAR_UNKNOWN; + + ret = get_lambda_tv(arg, rettv, evaluate); + if (ret == NOTDONE) + return FAIL; + else if (**arg != '(') + { + if (verbose) + { + if (*skipwhite(*arg) == '(') + semsg(_(e_nowhitespace)); + else + semsg(_(e_missingparen), "lambda"); + } + clear_tv(rettv); + return FAIL; + } + return call_func_rettv(arg, rettv, evaluate, NULL, &base); +} + +/* * Evaluate "->method()". * "*arg" points to the '-'. * Returns FAIL or OK. "*arg" is advanced to after the ')'. @@ -4865,15 +4954,15 @@ eval_method( else if (VIM_ISWHITE((*arg)[-1])) { if (verbose) - semsg(_("E274: No white space allowed before parenthesis")); + semsg(_(e_nowhitespace)); ret = FAIL; } else ret = eval_func(arg, name, len, rettv, evaluate, &base); } - /* Clear the funcref afterwards, so that deleting it while - * evaluating the arguments is possible (see test55). */ + // Clear the funcref afterwards, so that deleting it while + // evaluating the arguments is possible (see test55). if (evaluate) clear_tv(&base); @@ -7455,8 +7544,6 @@ handle_subscript( { int ret = OK; dict_T *selfdict = NULL; - char_u *s; - typval_T functv; // "." is ".name" lookup when we found a dict or when evaluating and // scriptversion is at least 2, where string concatenation is "..". @@ -7473,43 +7560,11 @@ handle_subscript( { if (**arg == '(') { - partial_T *pt = NULL; - funcexe_T funcexe; - - /* need to copy the funcref so that we can clear rettv */ - if (evaluate) - { - functv = *rettv; - rettv->v_type = VAR_UNKNOWN; - - /* Invoke the function. Recursive! */ - if (functv.v_type == VAR_PARTIAL) - { - pt = functv.vval.v_partial; - s = partial_name(pt); - } - else - s = functv.vval.v_string; - } - else - s = (char_u *)""; - - vim_memset(&funcexe, 0, sizeof(funcexe)); - funcexe.firstline = curwin->w_cursor.lnum; - funcexe.lastline = curwin->w_cursor.lnum; - funcexe.evaluate = evaluate; - funcexe.partial = pt; - funcexe.selfdict = selfdict; - ret = get_func_tv(s, -1, rettv, arg, &funcexe); - - /* Clear the funcref afterwards, so that deleting it while - * evaluating the arguments is possible (see test55). */ - if (evaluate) - clear_tv(&functv); + ret = call_func_rettv(arg, rettv, evaluate, selfdict, NULL); - /* Stop the expression evaluation when immediately aborting on - * error, or when an interrupt occurred or an exception was thrown - * but not caught. */ + // Stop the expression evaluation when immediately aborting on + // error, or when an interrupt occurred or an exception was thrown + // but not caught. if (aborting()) { if (ret == OK) @@ -7521,11 +7576,12 @@ handle_subscript( } else if (**arg == '-') { - if (eval_method(arg, rettv, evaluate, verbose) == FAIL) - { - clear_tv(rettv); - ret = FAIL; - } + if ((*arg)[2] == '{') + // expr->{lambda}() + ret = eval_lambda(arg, rettv, evaluate, verbose); + else + // expr->name() + ret = eval_method(arg, rettv, evaluate, verbose); } else /* **arg == '[' || **arg == '.' */ { |